Binding Third-Party Objective-C Libraries in Xamarin.iOS
Third-party libraries are great. They cut down on the development time significantly by allowing developers not to have to worry about building certain things, like a custom UI control. Unfortunately, many of these controls are written in Objective-C. However, this isn’t a deal breaker for those developing iOS apps in C# with Xamarin, because we have something known as bindings that allow us to reproduce libraries in C# in a minimal amount of time.
People often don’t realize the simplicity (on the user-side) of binding a third-party library. When working with smaller libraries, it is possible to bind them without really any Objective-C knowledge, which comes to a surprise to most. This wasn’t true until recently. Xamarin recently announced the release of Objective Sharpie, a tool that does all the heavy lifting that would normally accompany the binding process. Sometimes, I feel like we make things much harder in the software world than they need to me. It isn’t really required to have an extensive knowledge of how the binding process works or be a NSHipster to bind simple things (though it would certainly be helpful to learn these things). In larger libraries, things can get complicated fast, but for the majority of UI-related libraries, as well as smaller SDKs, you can bind these on your own with little to no Objective-C knowledge. Many times, it can be done in as little as fifteen minutes, especially because the process is pretty reproducible once you get it down.
Binding vs. Converting
One important distinction to be made is that it may be in your best interest to convert a particular library to C# and Xamarin.iOS, rather than bind it. There are certain strengths of each approach, as well as particular circumstances when each technique is particularly useful!
- Little to no Objective-C knowledge
- Quick and straightforward
- Less customization
- Objective-C knowledge
- More customization
Another helpful technique is to bind the library first, and then convert the library to C# such that the API definitions are the same, so you can seamlessly integrate the C# version into your application. This approach allows you to get a library up and running quickly in Xamarin.iOS, and then grant yourself more control and customization with with a C# version later.
Things to Remember
- This guide doesn’t really target those trying to create Android bindings, but Xamarin does have a doc detailing the process quite nicely
- This guide is targeted primarily towards beginners, especially those without much Objective-C knowledge
- The intended result is for you to be able to bind small libraries, nothing to complex (you have to start somewhere)
- The license for the project you are trying to build is permissive (something like MIT)
- The monotouch-bindings repository is always open for your contributions, big or small
- The Xamarin Component Store is waiting for your controls to be submitted! Just make sure the license is permissive, your control has been heavily tested, and that you’ve double-checked with the original author to make sure it’s okay
Let’s assume a few things before we started. First, I assume that the library you are trying to convert is fairly small (one or two classes). Second, I assume that you have at least an introductory level of knowledge of Xamarin.iOS. Finally, I assume that you have all of the latest updates and such from Xamarin.
Before we get started, there are also a few things I want to ensure we have downloaded:
- Objective Sharpie: This is the tool we use to generate bindings for our library
- Command Line Tools: Xcode -> Preferences -> Downloads
Once those are downloaded and installed, it’s time to pick a library to bind. QBFlatButton is a simple project that the rest of this tutorial is going to use. Certainly, you can bind more complex libraries, but I believe the library serves as a great starting point (without all the complexity).
Note: I’ll be adding a video tutorial later, but this was an in-demand tutorial, so I wanted to get it up ASAP!
The first step in binding an Objective-C library is to create what is known as an Objective-C static library. This generates a file with the extension “.a” that you may have seen around. The static library is what is linked against when the binding process takes place. Sometimes, we are given this, but more than often we have to build it ourselves.
The type of static library we are going to be building is called a “FAT” static library, because it contains options for all of the possible architectures (armv6, armv7, armv7s, and i386), instead of just targeting one. The armv7 and armv7s architectures have to do with the device, while the i386 has to do with the iOS Simulator. Note that the downside to this is that we are given a very bloated static library (in most cases, you would create separate static libraries for each architecture, and link those), but it is great for testing and demonstration purposes.
Note: If you ever get lost, or can’t quite get your binding to work, I suggest working with the BindingSample project and changing around your settings to work with your library!
Open Xcode and create a new project by navigating to File -> New -> Project. Under the section, make sure you are under iOS (as opposed to OSX), select Framework & Library, followed by Cocoa Touch Static Library. Give the project a name and location, and then it’s time to get started.
Right-click and delete (Move to Trash) the auto-generated .h and .m files. Add our own that we downloaded earlier by right-clicking the project name, followed by Add Files.
Click the project, and then navigation to File -> New -> Target. Follow the same steps as before, except this time add the suffix Universal to the name (this is a naming convention, nothing that is required). In the project settings, change the setting “Build Active Architectures Only” to no for both Debug and Release. Also, make sure that for the Link Binary with Libraries section you add the UIKit and CoreGraphics frameworks by clicking the + button and searching for the frameworks (Foundation should be in there already).
Next, go to the Build Phases tab. Add the .m file to the Compile Sources section, and add that .h file to the Copy Headers section (you may have to add this section by going to Add Build Phase -> Add Copy Headers.
Now, we need to add a run script so we can create a universal static library. Xcode doesn’t really have an ingenious way of doing this, so we use a build script. I like to use the build script found in the BindingSample repository of monotouch-samples, but we can use them from other sources as well.
In the Build Phases tab, click the + button in the lower-right hand corner labeled “Add Build Phase”, then click Add Run Script. Copy over the script from above into the box.
When you try to build, you will get an error about a pch file (pre-compiled header). To remove this, for each target, search “pch” and delete the field that appears. Recompile and you should be given a .a file. Make sure you click the build scheme and change it to our universal static library! This will generate the .a file used during the binding process.
Navigate to Build/Products/Debug-Universal/ and you should see our .a file! All of the heavy lifting is done!
Open up Objective Sharpie. Click next and set your Target SDK to iOS 6.1 (or whatever the default iOS setting is for you). Next, you must add your header files. I’ve found the most foolproof way is to just select the directory we downloaded, and cut out the junk we don’t need (for example, it may bind an AppDelegate if there is a sample project).
Add the directory for QBFlatButton, enter a namespace definition (you can change this later), and enter a name for the auto-generated file. You should come out with no errors.
Next, open Xamarin Studio and create a new iOS Binding Project. I’ve named mine FlatButton. Now, add the universal .a file we created earlier to our binding project. A drop-down button should be next to the .a once it is loaded into the project. Click this dropdown and open the .linkwith file. Add the frameworks that were under the Link Binary with Libraries section by adding the following to the file, after one of the commas (make sure to add one after this statement):
Frameworks = “UIKit Foundation CoreGraphics”
Open ApiDefinition.cs and copy over the body of the namespace that Objective Sharpie created for us. In our project, an AppDelegate was also added (because we selected the entire directory), so we can delete that. Note that sometimes the interface name gets a bit screwy, so we may want to fix this. Additionally, as a community, can we loose the whole initials prefix in our libraries. It’s riddled with pride, and just looks stupid. To do this, lets rename our interface to:
public partial interface FlatButton
Inside the attribute above the definition for FlatButton, change the contents to:
[BaseType (typeof (UIButton), Name = “QBFlatButton”)]
Note that this name attribute must be the original name used for the class (in Objective-C).
Next, build the project and a .dll will be generated for you to use in your project!
Now that the binding has been generated, it’s probably a good idea to test it (as well as other reasons I’ll mention later). I would suggest trying to recreate the demo application provided with the original library.
PROTIP: If you get an error saying “The native class hasn’t been loaded” on runtime, this usually means your .linkwith, although appearing, is not actually building with your project. You should add this file to your project like you would any other file, recompile, and you should be good to go!
You can see FlatButton on my Github, including the static library project, the binding project, and the demo application.
Once you are comfortable binding simple libraries and want to grow, here are some things I would recommend:
- Read the Programming with Objective-C introduction by Apple. You can skim over most of the document, but pay special attention to the topics of method, property, and delegate declaration in Objective-C. Basically, you only need to be able to read the contents of the header (.h) file of the class!
- Read the Binding Objective-C Libraries and Binding Types Reference Guides from Xamarin. Read them all the way through to get a good overview, and then you can use the document as more of a reference later!
- Be aware of the design paradigms of the C# language, and apply these when you are binding libraries (make it C#-ified!). If you have any experience with C# or .NET, this shouldn’t be a problem. Example: Knowing that properties are better than accessor (getter) and mutator (setter) methods in Objective-C.
Then, once you understand these things:
- Look at other bindings in the monotouch-bindings library. Download the accompanying Objective-C source and compare the two.
- Make small corrections or updates to the bindings in the monotouch-bindings library. (Sidenote: Contributing to open-source projects is one of the best things that has happened to me. You should try it too, even if it is something simple such as a one-line fix!)
- Bind progressively larger libraries until you are doing whole SDKs and complex UI bindings
Certainly, there is lots of room for improvement in the binding process. But as it stands, I believe this is the simplest way to get into binding Objective-C libraries. You won’t be an expert on the binding process, nor will you be able to be able to bind extremely complicated libraries, but this is a solid starting point. The source code for FlatButton (including the static library, the binding, and the demo) is available on Github. Feel free to do what you like with it.
Sebastien Pouliot has also posted a wonderful blog post about producing better bindings for both Xamarin.iOS and Xamarin.Mac.
I’m more than happy to write about lots of different iOS topics, you just have to let me know what you want. I also love constructive feedback of any kind, positive or negative. Just send me an email at firstname.lastname@example.org (Please do not email me for binding help, that is better off for the Xamarin Forums).