androidiosxamarindependency-injectionshared-project

Xamarin Sharing A Base Android and iOS Project with multiple Android and iOS apps


I have a project set up so that I can have a different styled app for each of our clients and i'm trying to stream line our design. Currently it is set up so we have our PCL and then an Android and an iOS project for each client. This means that if we change anything on the app side code we have to change it manually across each project.

I have been attempting to change it so we have our PCL and a base Android and iOS project which has the platform specific interface code which each of the other projects with their individual colour styling, images and bundle identifiers can then inherit.

e.g.

I have gotten this to work for Android simply by creating a new android project and adding a reference to the shared android project and PCL.

I am having trouble getting to work for iOS in the same way. It's close, the iOS app compiles as a new app with the correct styling however the DependencyService crashes whenever it tries to access an interface method.

DependencyService.Get<ISystemFunctions>().ToggleTorch();

exception thrown on iOS interface access

Below is the code of my interface in my shared project, however i don't think this is the issue but rather the DependencyService cant find it.

[assembly: Dependency(typeof(SystemFunctions_iOS))]
namespace SharedApp.iOS.iOS_Interfaces
{
    public class SystemFunctions_iOS : ISystemFunctions
    {        
        public SystemFunctions_iOS()
        {   }

        public void ToggleTorch()
        {
            var device = AVCaptureDevice.GetDefaultDevice(AVMediaTypes.Video);
            if (device == null)
                return;

            device.LockForConfiguration(out NSError error);
            if (error != null)
            {
                device.UnlockForConfiguration();
                return;
            }
            else
            {
                device.TorchMode = device.TorchMode == AVCaptureTorchMode.On ? AVCaptureTorchMode.Off : AVCaptureTorchMode.On;
                device.UnlockForConfiguration();
            }
        }
    }
}

Let me know if there is anything else i can share to help with this.


Solution

  • Found the solution to my problem

    In the AppDelegate for iOS.Shared remove the line [Register("AppDelegate")]

    //[Register("AppDelegate")]   NEEDED TO REMOVE THIS
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {        
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());            
    
            return base.FinishedLaunching(app, options);
        }
    }
    

    In the AppDelegate for iOS.ClientThemeX add the line var systemFunctions_iOS = new iOS.Shared.iOS_Interfaces.SystemFunctions_iOS();

    [Register("AppDelegate")]
    public partial class AppDelegate : global::Xamarin.Forms.Platform.iOS.FormsApplicationDelegate
    {
        public override bool FinishedLaunching(UIApplication app, NSDictionary options)
        {
            global::Xamarin.Forms.Forms.Init();
            LoadApplication(new App());
    
            // DO NOT REMOVE THIS. It breaks without it. Don't know why
            // but a similar row will need to be added for each interface added to the project
            var systemFunctions_iOS = new SharedApp.iOS.iOS_Interfaces.SystemFunctions_iOS();
    
            return base.FinishedLaunching(app, options);
        }
    }
    

    removing the AppDelegate register from the shared project makes sense, but i'm not sure why i needed to declare a new object with my interface to work. This interface constructor, as in the question, is empty.

    If anyone could shed any light on this still it would be appreciated, or if there is any advice for a much simpler way of doing this.