Objective-C bindings

Xamarin has developed a sophisticated system to call native Objective-C libraries from C# in iOS projects. The core of Xamarin.iOS uses the same technology to call native Apple APIs in UIKit, CoreGraphics, and other iOS frameworks. Developers can create iOS binding projects to expose the 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, and you will 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 activities in your iOS or Android applications. At the time of writing, the version of the Google Analytics SDK was 3.10, so some of these instructions might change as new versions are released.

Working with Objective Sharpie

First, download and install Objective Sharpie from http://tinyurl.com/ObjectiveSharpie, then perform the following steps:

  1. Download the latest Google Analytics SDK for iOS available at https://tinyurl.com/GoogleAnalyticsForiOS.
  2. Create a new iOS Binding Project named GoogleAnalytics.iOS.
  3. Run Objective Sharpie.
  4. Select iOS 7.1 as Target SDK and click on Next.
  5. Add all of the header (*.h) files included with the Google Analytics SDK; you can find these in the Library folder of the download. Click on Next.
  6. Pick a suitable namespace such as GoogleAnalytics and click on Generate.
  7. Copy the resulting ApiDefinition.cs file that was generated into your iOS binding project.
  8. After a few seconds, your C# file will be generated. Click on Quit.

You should have not received any error messages from Objective Sharpie during the process, and when finished, your screen should look like the following screenshot:

Working with Objective Sharpie

Tip

At the time of writing this book, Objective Sharpie does not work properly with Xcode 6.0 and higher. I recommend that you download Xcode 5.1.1 if you run into this issue. You can install two versions of Xcode side by side by renaming an existing one in Finder and installing a second one. You can find older Xcode downloads at https://developer.apple.com/downloads/index.action.

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:

  1. Change the default namespace of the project to GoogleAnalytics. This setting is found in the project options by navigating to General | Main Settings.
  2. Add libGoogleAnalyticsServices.a from the SDK download to the project.
  3. Add using statements for MonoTouch.Foundation, MonoTouch.UIKit, and MonoTouch.ObjCRuntime at the top of the ApiDefinition.cs file.
  4. Remove the multiple duplicate declarations of GAILogLevel. You might also wish to move enumerations to the StructsAndEnums.cs file.
  5. Remove the declaration for GAIErrorCode.
  6. In the SetAll method of GAIDictionaryBuilder, rename the params parameter to parameters, as params is a reserved word in C#.
  7. Remove the duplicate declarations for GAILogger, GAITracker, GAITrackedViewController, and any other duplicate classes you find.
  8. Go through any 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.
  9. Remove all the Verify attributes. These are spots where Objective Sharpie was unsure of the operation it performed. In our example, all of them are fine so it is safe to remove them.

One more error remains regarding Objective Sharpie not being able to generate C# delegates for methods that have callbacks. Navigate to the GAI interface and change the following method:

[Export ("dispatchWithCompletionHandler:")]void DispatchWithCompletionHandler (
    GAIDispatchResultHandler completionHandler);

You will also need to define the following delegate at the top of this file:

public delegate void GAIDispatchResultHandler(
    GAIDispatchResult result);

After going through these 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 means a lot less work.

At this point, if you try 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: Add them to the Frameworks value on the LinkWith attribute, delimited by spaces.
  • Weak Frameworks: Add them to the 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.
  • Dynamic Libraries: Libraries such as 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.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.51.228