I work with this library full time and so I am familiar with its ins and outs and it becomes difficult for me to see things through the eyes of someone approaching it with no exposure. This post aims to clarify some design and architecture decisions around the .NET variant of Couchbase Lite 2.0.
Currently as a product, Couchbase Lite is going to claim support for at least the following:
- Windows (probably 7+), including UWP
- macOS / OS X (probably 10.9+)
- Ubuntu 14.04+
- iOS 9+
- Android 4.1+
If we have the resources, we may have CentOS 7+ and tvOS on that list. As the .NET developer this means I have to deploy to all of them since .NET is so versatile. That takes quite a bit of time for one person. But anyway, Couchbase Lite on all platforms starts at the bottom with the C++ library LiteCore. The vast majority of functionality is here, and this allows more consistent behavior between platforms as well as fixing most issues once and having the fix and/or enhancement be available for all variants (Objective-C, Swift, Java, .NET). The downside here is that to support a new platform, LiteCore must be built for that platform. That means that the platform must have a C++11 compatible compiler (usually not a problem) and dynamic linking support (maybe a problem? I’m not sure and maybe some embedded systems do not).
LiteCore has a C interface, which means that all of the functionality needed to run Couchbase Lite is exposed outside the dynamic library through C functions. This is important because managed languages need symbols to bind to and C is a very simple language to bind to. C++ is practically impossible because of arbitrary name mangling. Lots of languages can bind to C, but the main point is both Java and .NET can and so that’s good enough for us. So what you will see in the LiteCore repo is a directory called CSharp which contains all the bindings and they will line up one to one with the C interface.
Couchbase Lite itself is (currently) built against .NET Standard 1.4. This is the highest version that allows UWP support at the moment. That means that only one build artifact is made that runs on all platforms. That has its own problems, though, because some platforms are sandboxed, for example, and we need a platform specific way to get a default directory for any given platform. Enter DEPENDENCY INJECTION! Each platform we support has a corresponding support assembly (e.g Couchbase.Lite.Support.UWP). The responsibilities of this packages are two things:
- Deliver the native libraries for the platform in question (Couchbase.Lite would be huge if it had all of them)
- Provide concrete implementations of the interfaces that are declared for dependency injection.
The interfaces designed for dependency injection can be found in src\Couchbase.Lite\API\DI in the repo. In addition, ILoggerProvider from Microsoft is also one that can be provided. More information on this interface can be found in this article.
So to support a new platform for Couchbase Lite, two things need to happen. There needs to be a native build for said platform, and the proper classes need to be registered for DI. It might be possible that a new platform already covers an architecture that has a native build. An example of this is Unity3D, which covers all of the architectures that I listed in Couchbase Lite support. This means that Unity3D will only need to include the native components, and then make its own DI classes and it should run.
Hopefully anybody who wants to try to support their favorite platform without waiting for Couchbase to officially support it can have an easier time now!