SQLite.NET with Xamarin Forms, Managing The Cross Platform Code Differences on iOS, Android and Windows Phone

Cross platform implementation of a data store will always be divergent, file location on each device are different and the SQLite.NET PCL packages have different namespaces meaning reference code has to change for each build.

The first and easiest option for implementing SQLite data storage in a Xamarin Forms shared project is to use conditional compilation where you can tell the complier which code blocks to execute depending on the build configuration.

            ISQLitePlatform sqlitePlatform;
            string folder = string.Empty;
#if __IOS__
            sqlitePlatform = new SQLite.Net.Platform.XamarinIOSSQLitePlatformIOS();
            folder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
#else
#if __ANDROID__
            sqlitePlatform = new SQLite.Net.Platform.XamarinAndroidSQLitePlatformAndroid();
            folder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
#else
            sqlitePlatform = new SQLite.Net.Platform.WindowsPhone8SQLitePlatformWP8();
            folder = Windows.Storage.ApplicationData.Current.LocalFolder.Path + "\\";
#endif
#endif

In the SQLite implementation code above, the complier will only include the code that matches the plaform it's building for, so for an iOS build only the code inside the #if __IOS___ will be incldued. For Android only code inside #if __ANDROID__ and if it doesn't mach either iOS or Android the Windows specific code will be included in the build.

In the SQLite implementation code above, the complier will only include the code that matches the platform it's building for, so for an iOS build only the code inside the #if __IOS___ will be included. For Android only code inside #if __ANDROID__ and if it doesn't match either iOS or Android the Windows specific code will be included in the build.


Alternatively you can separate out the platform dependent code into each project, you already have the ISQLitePlatform interface so it is straightforward to inject the platform dependent libraries using dependency injection.


Xamarin.Forms has a dependency injection framework built in and it's really straight forward to use.


First we create a IDatastore creating a contract for the ISQLitePlatform implementation and the Folder location.

public interface IDataStore
    {
        ISQLitePlatform SqlitePlatform { get; }
        string Folder { get; }
    }


Then we create platform dependent implementations of this interface in each project, to access the Xamarin.Forms injection framework you need to declare the dependency at build time through an attribute applied to the class.

Code:
[assembly: Xamarin.Forms.Dependency(typeof(class))]


For Android

[assembly: Xamarin.Forms.Dependency(typeof(DataStoreDroid))]
namespace Droid.Interfaces
{
    public class DataStoreDroid : IDataStore
    {
        public ISQLitePlatform SqlitePlatform
        {
            get
            {
                return new SQLite.Net.Platform.XamarinAndroidSQLitePlatformAndroid();
            }
        }
        public string Folder
        {
            get
            {
                return Environment.GetFolderPath(Environment.SpecialFolder.Personal);
            }
        }
    }
}


For iOS

[assembly: Xamarin.Forms.Dependency(typeof(DataStoreIos))]
namespace iOS.Interfaces
{
    public class DataStoreIos : IDataStore
    {
        public ISQLitePlatform SqlitePlatform
        {
            get
            {
                return new SQLite.Net.Platform.XamarinIOSSQLitePlatformIOS();
            }
        }
        public string Folder
        {
            get
            {
                var docFolder = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
                return System.IO.Path.Combine(docFolder, "..", "Library");
            }
        }
    }
}


For Windows Phone

[assembly: Xamarin.Forms.Dependency(typeof(DataStoreWp8))]
namespace WinPhone.Interfaces
{
    public class DataStoreWp8 : IDataStore
    {
        public ISQLitePlatform SqlitePlatform
        {
            get
            {
                return new SQLite.Net.Platform.WindowsPhone8SQLitePlatformWP8();
            }
        }
        public string Folder
        {
            get
            {
                return Windows.Storage.ApplicationData.Current.LocalFolder.Path + "\\";
            }
        }
    }
}

Now Xamarin.Forms will inject the correct implementation of IDataStore for each platform at compile time.

Code:
IDataStore DataStore = DependencyService.Get<IDataStore>();

This article shows how simply the platform divergence can be abstracted from the core code base keeping unique code in the project it belongs to. Making future changes easier and less costly.

Posted on 27/03/2015 12:43:51Xamarin