3
votes

I am using Freshmvvm for my Xamarin forms project. I am using a camera and want to use platform specific features. So, I was wondering how can I use IOC controls to use platform specific feature.

Freshmvvm.FreshIOC.Container.Register<ICamera,Camera>();

If I call this code from the App class, Should I need to have camera class in both iOS and Android projects, if yes then how to let the app class know we want to implement a Camera class of one specific platform? or is there a better way to use IOC control and inject the interfaces into the contructors of the page models(view models) when we want to use it ?

3

3 Answers

4
votes

I think what you're after is the Dependency Service. This enables you to access native feature.

This way you have to create an interface in your shared code for instance ICamera.

public interface ICamera
{
   void TakePicture();
}

Now you can implement this interface in the platform specific projects.

For instance on iOS you might implement it like this:

public class CameraImplementation : ICamera { public void TakePicture() { // iOS code here } }

Now the key here is how you register this. You can do this by adding a tag like this above your namespace of the platform specific implementation, like this:

[assembly: Xamarin.Forms.Dependency (typeof (CameraImplementation))]
namespace yourapp
{
   // CameraImplementation class here
}

The same goes for Android. If you keep the naming the same you can even copy and paste this tag.

3
votes

Disclaimer: I’m very new to IOC, DI, and FreshMvvm. Just got this working for myself and wanted to share to help some others out there just in case they stumbled upon this forum like I did.

DependencyService provided by Xamarin Forms is fantastic, yet still limited (e.g. cannot implement constructor injection). It also can become a bit of a hassle to implement Unit Testing while making use of DependencyService. Here is a tutorial that will take you through some steps if you insist on using DependencyService but also want to unit test your code. It is a service locator, which is more difficult (in my opinion) to test than Dependency Injection is.

Instead of using that, I just used FreshMvvm’s IOC to access platform specific code. Everything @WickedW said is completely right. I just tweaked the last step a little.

Instead of resolving the dependencies directly:

IFileHelper fileHelper = FreshMvvm.FreshIOC.Container.Resolve<IFileHelper>();
string dbPath = fileHelper.GetLocalFilePath("CoreSQLite.db3");

I used constructor injection:

Public class MainPageModel : FreshBasePageModel
{
    public string YourLabelText { get; set;}
    IFileHelper _fileHelper;
    public MainPageModel(IFileHelper fileHelper)
    {
        _fileHelper = fileHelper
    }

    // This is implemented by FreshBasePageModel
    public override void Init(object initData)
    {
        YourLabelText = _fileHelper.GetLocalFilePath(“CoreSQLite.db3”);
    }   
}

Make sure to register your platform specific class before you load the app:

FreshMvvm.FreshIOC.Container.Register<IFileHelper, FileHelper>();
global::Xamarin.Forms.Forms.Init();
LoadApplication(new App());

return base.FinishedLaunching(app, options);

I had to do that because I resolve my MainPageModel in the constructor of my App.xaml.cs:

public App()
    {
        InitializeComponent();

        var page = FreshPageModelResolver.ResolvePageModel<MainPageModel>();
        var navContainer = new FreshNavigationContainer(page);
        MainPage = navContainer;
    }

@WickedW had the platform specific implementation completely on point, then I just used Michael Ridland’s FreshMvvm n=2 video to figure out constructor injection because it was a feature I needed personally. Hope this helps people who struggled to figure this out like myself 😊.

2
votes

DependencyService built into Xamarin Forms will do the business, but if you wanted to ONLY use the IOC in FreshMvvm you can -

a) register your platform specific class(es) near the Forms Init method (IOS follows) -

public override bool FinishedLaunching(UIApplication app, NSDictionary options)
{
        global::Xamarin.Forms.Forms.Init();

        InitIoc();

        LoadApplication(new App());

        return base.FinishedLaunching(app, options);
}

private void InitIoc()
{
        FreshMvvm.FreshIOC.Container.Register<IFileHelper, FileHelper>();
}

with your class existing on the platform side as usual -

public class FileHelper : IFileHelper
{
    public string GetLocalFilePath(string filename)
    {
        string docFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);

and then resolve that class when using it in your PCL / Forms project -

IFileHelper fileHelper = FreshMvvm.FreshIOC.Container.Resolve<IFileHelper>();
string dbPath = fileHelper.GetLocalFilePath("CoreSQLite.db3");

...