Xamarin has developed a sophisticated system for calling native Objective-C libraries from C# in iOS projects. The core of Xamarin.iOS
uses this same technology to call native Apple APIs in
UIKit, CoreGraphics, and other iOS frameworks. Developers can create iOS binding projects to expose Objective-C classes and methods to C# using simple interfaces and attributes.
To aid in creating Objective-C bindings, Xamarin has created a small tool named Objective Sharpie that can process Objective-C header files for you and export the valid C# definitions to add to a binding project. This tool is a great starting point for most bindings that will get your binding three-fourths of the way complete. You will also want to hand edit and fine tune things to be more C# friendly in a lot of cases.
As an example, we will write a binding for the Google Analytics library for iOS. It is a simple and useful library that can track the user activity in your iOS or Android applications. At the time of writing, the version of the Google Analytics SDK was 3.02, so some of these instructions may change as new versions are released.
First download and install Objective Sharpie from http://tinyurl.com/ObjectiveSharpie and perform the following steps:
GoogleAnalytics.iOS
.(*.h
) files included with the Google Analytics SDK; you can find these in the Library
folder of the download. Click on Next.GoogleAnalytics
and click on Generate.ApiDefinition.cs
file that was generated into your iOS binding project.When finished, you should have not received any error messages from Objective Sharpie during the process, and your screen should look like the following screenshot:
Now if you return to your binding project, you'll notice that Objective Sharpie has generated an interface definition for every class discovered in the header files of the library. It has also generated many enum
values that the library uses and changed casing and naming conventions to follow C# more closely where possible.
As you read through the binding, you'll notice several C# attributes that define different aspects about the Objective-C library such as the following:
BaseType
: This declares an interface as an Objective-C class. The base class (also called superclass) is passed in to the attribute. If it has no base class, NSObject
should be used.Export
: This declares a method or property on an Objective-C class. A string that maps the Objective-C name to the C# name is passed in. Objective-C method names are generally in the following form: myMethod:someParam:someOtherParam
.Static
: This marks a method or property as static
in C#.Bind
: This is used on properties to map a getter or setter to a different Objective-C method. Objective-C properties can rename a getter or setter for a property.NullAllowed
: This allows null
to be passed to a method or property. By default, an exception is thrown if this occurs.Field
: This declares an Objective-C field that is exposed as a public variable in C#.Model
: This identifies a class to Xamarin.iOS
to have methods that can be optionally overridden. This is generally used on Objective-C delegates.Internal
: This flags the generated member with the C# internal keyword. It can be used to hide certain members that you don't want to expose to the outside world.Abstract
: This identifies an Objective-C method as required, which goes hand in hand with Model
. In C# it will generate an abstract method.The only other rule to know is how to define constructors. Xamarin had to invent a convention for this, since C# interfaces do not support constructors.
To define a constructor besides the default one, use the following code:
[Export("initWithFrame:")] IntPtr Constructor(RectangleF frame);
This would define a constructor on the class that takes in RectangleF
as a parameter. The method name, Constructor
, and the return type, IntPtr,
signal the Xamarin compiler to generate a constructor.
Now, let's return to our binding project to finish setting up everything. If you compile the project at this point, you'll get a few compiler errors. Let's fix them one by one as follows:
GoogleAnalytics
. This setting is found in the project options under General | Main Settings.libGoogleAnalyticsServices.a
from the SDK download to the project.using
statements for MonoTouch.Foundation
, MonoTouch.UIKit
, and MonoTouch.ObjCRuntime
at the top of the file.GAILogLevel
. You may also wish to move any enumerations
to the StructsAndEnums.cs
file.GAIErrorCode
.SetAll
method of GAIDictionaryBuilder
, rename the params
parameter to parameters
, as params
is a reserved word in C#.GAILogger
, GAITracker
, and GAITrackedViewController
.Field
declarations and change [Field("Foobar")]
to [Field("Foobar", "__Internal")]
. This tells the compiler where the field resides; in this case, it will be included internally in our binding project.Verify
attributes. These are spots where Objective-C Sharpie was unsure of the operation it performed. In our example, all of them are fine; so, it is safe to remove them.After going through those issues, you should be able to compile the binding and get no errors. You could have read the Objective-C header files and written the definitions yourself by hand; however, using Objective Sharpie generally requires a lot less work.
At this point, if you tried to use the library in an iOS project, you would get an error such as the following:
Error MT5210: Native linking failed, undefined symbol: _FooBar. Please verify that all the necessary frameworks have been referenced and native libraries are properly linked in.
We need to define the other frameworks and libraries that the Objective-C library uses. This is very similar to how references work in C#. If we review the Google Analytics documentation, it says that you must add CoreData
, SystemConfiguration
, and libz.dylib
. Additionally, you must add a weak reference to AdSupport
.
Open libGoogleAnalyticsServices.linkwith.cs
that was created automatically nested underneath the *.a
file and make the following changes:
[assembly: LinkWith ("libGoogleAnalyticsServices.a",LinkTarget.ArmV7 | LinkTarget.ArmV7s | LinkTarget.Simulator,LinkerFlags = "-lz",Frameworks = "CoreData SystemConfiguration",WeakFrameworks = "AdSupport",ForceLoad = true)]
We added references to frameworks in the following ways:
Frameworks
value on the LinkWith
attribute, delimited by spaces.WeakFrameworks
property on the LinkWith
attribute in the same manner. Weak frameworks are libraries that can be ignored if they are not found. In this case, AdSupport
was added in iOS 6; however, this library will still work on older versions of iOS.libz.dylib
; can be declared in LinkerFlags
. Generally, you drop the .dylib
extension and replace lib
with –l
.After these changes are implemented, you will be able to successfully use the library from iOS projects. For complete documentation on Objective-C bindings, visit the Xamarin documentation site at http://docs.xamarin.com/ios.
18.225.149.32