Migrating a Binding to the Unified API
This article covers the steps required to update an existing Xamarin Binding Project to support the Unified APIs for Xamarin.IOS and Xamarin.Mac applications.
Overview
Starting February 1st, 2015 Apple requires that all new submissions to the iTunes and the Mac App Store must be 64 bit applications. As a result, any new Xamarin.iOS or Xamarin.Mac application will need to be using the new Unified API instead of the existing Classic MonoTouch and MonoMac APIs to support 64 bit.
Additionally, any Xamarin Binding Project must also support the new Unified APIs to be included in a 64 bit Xamarin.iOS or Xamarin.Mac project. This article will cover the steps required to update an existing binding project to use the Unified API.
Requirements
The following is required to complete the steps presented in this article:
- Visual Studio for Mac - The latest version of Visual Studio for Mac installed and configured on the development computer.
- Apple Mac - An Apple mac is required to build Binding Projects for iOS and Mac.
Binding projects are not supported in Visual studio on a Windows machine.
Modify the Using Statements
The Unified APIs makes it easier than ever to share code between Mac and iOS as well as allowing you to support 32 and 64 bit applications with the same binary. By dropping the MonoMac and MonoTouch prefixes from the namespaces, simpler sharing is achieved across Xamarin.Mac and Xamarin.iOS application projects.
As a result we will need to modify any of our binding contracts (and other .cs
files in our binding project) to remove the MonoMac and MonoTouch prefixes from our using
statements.
For example, given the following using statements in a binding contract:
using System;
using System.Drawing;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using MonoTouch.ObjCRuntime;
We would strip off the MonoTouch
prefix resulting in the following:
using System;
using System.Drawing;
using Foundation;
using UIKit;
using ObjCRuntime;
Again, we will need to do this for any .cs
file in our binding project. With this change in place, the next step is to update our binding project to use the new Native Data Types.
For more information on the Unified API, please see the Unified API documentation. For more background on supporting 32 and 64 bit applications and information about frameworks see the 32 and 64 bit Platform Considerations documentation.
Update to Native Data Types
Objective-C maps the NSInteger
data type to int32_t
on 32 bit systems and to int64_t
on 64 bit systems. To match this behavior, the new Unified API replaces the previous uses of int
(which in .NET is defined as always being System.Int32
) to a new data type: System.nint
.
Along with the new nint
data type, the Unified API introduces the nuint
and nfloat
types, for mapping to the NSUInteger
and CGFloat
types as well.
Given the above, we need to review our API and ensure that any instance of NSInteger
, NSUInteger
and CGFloat
that we previously mapped to int
, uint
and float
get updated to the new nint
, nuint
and nfloat
types.
For example, given an Objective-C method definition of:
-(NSInteger) add:(NSInteger)operandUn and:(NSInteger) operandDeux;
If the previous binding contract had the following definition:
[Export("add:and:")]
int Add(int operandUn, int operandDeux);
We would update the new binding to be:
[Export("add:and:")]
nint Add(nint operandUn, nint operandDeux);
If we are mapping to a newer version 3rd party library than what we had initially linked to, we need to review the .h
header files for the library and see if any exiting, explicit calls to int
, int32_t
, unsigned int
, uint32_t
or float
have been upgraded to be an NSInteger
, NSUInteger
or a CGFloat
. If so, the same modifications to the nint
, nuint
and nfloat
types will need to be made to their mappings as well.
To learn more about these data type changes, see the Native Types document.
Update the CoreGraphics Types
The point, size and rectangle data types that are used with CoreGraphics
use 32 or 64 bits depending on the device they are running on. When Xamarin originally bound the iOS and Mac APIs we used existing data structures that happened to match the data types in System.Drawing
(RectangleF
for example).
Because of the requirements to support 64 bits and the new native data types, the following adjustments will need to be made to existing code when calling CoreGraphic
methods:
- CGRect - Use
CGRect
instead ofRectangleF
when defining floating point rectangular regions. - CGSize - Use
CGSize
instead ofSizeF
when defining floating point sizes (width and height). - CGPoint - Use
CGPoint
instead ofPointF
when defining a floating point location (X and Y coordinates).
Given the above, we will need to review our API and ensure that any instance of CGRect
, CGSize
or CGPoint
that was previously bound to RectangleF
, SizeF
or PointF
be changed to the native type CGRect
, CGSize
or CGPoint
directly.
For example, given an Objective-C initializer of:
- (id)initWithFrame:(CGRect)frame;
If our previous binding included the following code:
[Export ("initWithFrame:")]
IntPtr Constructor (RectangleF frame);
We would update that code to:
[Export ("initWithFrame:")]
IntPtr Constructor (CGRect frame);
With all of the code changes now in place, we need to modify our binding project or make file to bind against the Unified APIs.
Modify the Binding Project
As the final step to updating our binding project to use the Unified APIs, we need to either modify the MakeFile
that we use to build the project or the Xamarin Project Type (if we are binding from within Visual Studio for Mac) and instruct btouch to bind against the Unified APIs instead of the Classic ones.
Updating a MakeFile
If we are using a makefile to build our binding project into a Xamarin .DLL, we will need to include the --new-style
command line option and call btouch-native
instead of btouch
.
So given the following MakeFile
:
BINDDIR=/src/binding
XBUILD=/Applications/Xcode.app/Contents/Developer/usr/bin/xcodebuild
PROJECT_ROOT=XMBindingLibrarySample
PROJECT=$(PROJECT_ROOT)/XMBindingLibrarySample.xcodeproj
TARGET=XMBindingLibrarySample
BTOUCH=/Developer/MonoTouch/usr/bin/btouch
all: XMBindingLibrary.dll
libXMBindingLibrarySample-i386.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphonesimulator -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphonesimulator/lib$(TARGET).a $@
libXMBindingLibrarySample-arm64.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch arm64 -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $@
libXMBindingLibrarySample-armv7.a:
$(XBUILD) -project $(PROJECT) -target $(TARGET) -sdk iphoneos -arch armv7 -configuration Release clean build
-mv $(PROJECT_ROOT)/build/Release-iphoneos/lib$(TARGET).a $@
libXMBindingLibrarySampleUniversal.a: libXMBindingLibrarySample-armv7.a libXMBindingLibrarySample-i386.a libXMBindingLibrarySample-arm64.a
lipo -create -output $@ $^
XMBindingLibrary.dll: AssemblyInfo.cs XMBindingLibrarySample.cs extras.cs libXMBindingLibrarySampleUniversal.a
$(BTOUCH) -unsafe -out:$@ XMBindingLibrarySample.cs -x=AssemblyInfo.cs -x=extras.cs --link-with=libXMBindingLibrarySampleUniversal.a,libXMBindingLibrarySampleUniversal.a
clean:
-rm -f *.a *.dll
We need to switch from calling btouch
to btouch-native
, so we would adjust our macro definition as follows:
BTOUCH=/Developer/MonoTouch/usr/bin/btouch-native
We would update the call to btouch
and add the --new-style
option as follows:
XMBindingLibrary.dll: AssemblyInfo.cs XMBindingLibrarySample.cs extras.cs libXMBindingLibrarySampleUniversal.a
$(BTOUCH) -unsafe --new-style -out:$@ XMBindingLibrarySample.cs -x=AssemblyInfo.cs -x=extras.cs --link-with=libXMBindingLibrarySampleUniversal.a,libXMBindingLibrarySampleUniversal.a
We can now execute our MakeFile
as normal to build the new 64 bit version of our API.
Updating a Binding Project Type
If we are using a Visual Studio for Mac Binding Project Template to build our API, we'll need to update to the new Unified API version of the Binding Project Template. The easiest way to do this is to start a new Unified API Binding Project and copy over all of the existing code and settings.
Do the following:
Start Visual Studio for Mac.
Select File > New > Solution...
In the New Solution Dialog Box, select iOS > Unified API > iOS Binding Project:
On 'Configure your new project' dialog enter a Name for the new binding project and click the OK button.
Include the 64 bit version of Objective-C library that you are going to be creating bindings for.
Copy over the source code from your existing 32 bit Classic API binding project (such as the
ApiDefinition.cs
andStructsAndEnums.cs
files).Make the above noted changes to the source code files.
With all of these changes in place, you can build the new 64 bit version of the API as you would the 32 bit version.
Summary
In this article we have shown the changes that need to be made to an existing Xamarin Binding Project to support the new Unified APIs and 64 bit devices and the steps required to build the new 64 bit compatible version of an API.