Xamarin is a tool and platform for developing cross platform mobile applications. The company I work at (mParticle) enables developers to send data to many analytics services by integrating our SDK once instead of an SDK for each of those analytics services. Not only does this save time and money, developers also love it. In the spirit delighting developers, we decided to write a Xamarin SDK for our service. The purpose of this post is just to share my experience and some technical tidbits I think are useful. (There are plenty of more detailed tutorials on bindings so I won’t dive too deep.)
Start from scratch or binding?
With Xamarin, you usually have two choices when it comes to writing an SDK. You can start from scratch ideally with a PCL project that is generic enough to target all platforms or you can create a binding project which essentially “wraps” the native libraries in a C# API.
If your SDK doesn’t access any native functionality (or very little of it), you’re probably better of just creating a PCL A PCL will also giving you more flexibility for other platforms beyond the standard iOS, Android and UWP.
In our case, since we rely on a lot of the underlying native API (for instance around install tracking), we decided to go with the binding approach.
The way I decided to structure the project was as follows:
- Bindings — where the native bindings project live
- Library — where the simplified API lives
- Samples — Contains both Native and Forms samples that use the SDK
If your core native library is an aar/jar, you simply create an Android binding project and include it in the Jar folder and set the build action to LibraryProjectZip for aar or EmbeddedJar for jar. Things get slightly more complicated when you have dependencies. For any jar-type dependencies you can include them in the same binding project and set the build action to EmbeddedReferenceJar. For aar-type dependancies, you actually need to create another Android binding project and reference it in your main binding project. We actually had this problem and decided to combine core and dependent aar instead.
Bindings rarely work on the first try. Thankfully, Xamarin has improved quite a bit since the early days. Fixing the binding project essentially involves editing a file in your binding project call Metadata.xml. It helps you control the C#output of the binding generator. Majority of the fixes include simply removing classes/packages from the C#API since we only wanted to expose the commonly used public API. Other fixes include changing the visibility of a method or renaming field and parameter names. See here for examples.
We did have some issues using the Java doc to C# docs feature which is essentially suppose to generate nice XML summary comments and name the method parameters correctly. Ultimately, we didn’t need this since we would be calling our binding project from another C# project so we could (and did) just added XML there. More on that later.
iOS libraries usually come in two flavors: a static library or a framework. Both are supported in Xamarin but we ultimately decided to go with framework. Whatever you decide, the first step is to use a tool called ObjectiveSharpie to generate the C# API.
Then, create a new Xamarin iOS binding project. You’ll need to copy whatever C# code was generated from the ObjectiveSharpie command into the corresponding C# files in the project. You may need to fiddle with it a little bit since the ObjectiveSharpie generated code may be missing a namespace. Similar to Android, the bindings generator is not perfect. iOS is however a little bit easier since you can just edit the ApiDefinition.cs C# file directly (instead of an XML file).
The most common fix we had to do was adding [Protocol] to some classes. Visual Studio for Mac will incorrectly show compile errors so first try and actually build the binding project. Also, be careful if your library is using reflection to detect and use another library (as we do for our optional kits). You may have to disable SmartLink on that particular dependency library.
Writing a Cross Platform API
Once we finished our binding project, our calls look something (though not exactly) like this:
new NSString("Hello world"),
The point is exaggerated a bit here but essentially the method names differed and so did the datatypes. One of the biggest advantages of Xamarin is code sharing which means you can write code once and share it among multiple projects (or in this case platforms). So we felt we could improve on this and essentially allow users to make a single call like this for both Android and iOS
To achieve this, we had to write a platform-independent interface which would be implemented for each platform. We also used a “bait-and-switch” PCL technique as outlined here. Using this technique meant we could deploy a single NuGet package instead of one for each platform.
- Always use the stable Xamarin build. Beta builds are likely to break things especially if you switch back to Stable.
- Turn on the most verbose logging output to see exactly what is going.
- Test your library on both an emulator/simulator and real device.
- If the sample iOS app with your SDK runs on Simulator but not on the device (or vice versa), check to make sure your native library has all the required architecture slices (x86_64, i386, etc.)
- Be sure to include all dependent frameworks (like UIKit, SystemConfiguration, etc) when including your native library.
- You can debug the native Android library easily if you have the source code and then attaching to the process in Android studio
- You can also debug the native iOS library but you need to make sure optimization is turned off for the framework/static library.
- Google thoroughly for your issues but if you’re absolutely stuck, ask for help. There’s a very active and responsive community on StackOverflow (as long you attach the right tags or use the right description) and there is also a slack channel which has some active members.
Developing a binding for Xamarin is definitely one of the most challenging (read: frustrating) experiences. Part of this was my knowledge gap around Xamarin / Native iOS and how the architectures matter. The other part was dealing with Xamarin bugs or cryptic errors. If you have lots of issues like me, I highly recommend trying out Rider though support may be limited.
Creating the nuspec file for our NuGet was mostly a manual process. I wish I had Googled earlier/harder for it but it looks like there was a Visual Studio template for it. Perhaps, it should be a default template in Visual Studio for Mac.
Credit and References
- Here is the final binding: https://github.com/mParticle/mparticle-xamarin-sdk
- My colleague Sam Dozor who helped review and fix many issues with the SDK.
- James Montemagno and his awesome blog here: https://blog.xamarin.com/creating-reusable-plugins-for-xamarin-forms/
- Countless threads on StackOverflow and Xamarin forums
Oh and by the way, if you liked this project or what we’re doing at mParticle, check out our hiring page here as we have lots of positions. Reference this blog post if you like.
If you find any issues or mistakes in this posting, comment below and I’ll fix them as soon as possible.