Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Xamarin: Cross-Platform Mobile Application Development

You're reading from   Xamarin: Cross-Platform Mobile Application Development Master the skills required to develop cross-platform applications from drawing board to app store(s) using Xamarin

Arrow left icon
Product type Course
Published in Aug 2016
Publisher Packt
ISBN-13 9781787120129
Length 1049 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Authors (3):
Arrow left icon
Jonathan Peppers Jonathan Peppers
Author Profile Icon Jonathan Peppers
Jonathan Peppers
George Taskos George Taskos
Author Profile Icon George Taskos
George Taskos
Can Bilgin Can Bilgin
Author Profile Icon Can Bilgin
Can Bilgin
Arrow right icon
View More author details
Toc

Chapter 9. Third-party Libraries

Xamarin supports a subset of the .NET framework, but for the most part, it includes all the standard APIs you would expect in the .NET base class libraries. Because of this, a large portion of C#'s open source libraries can be used directly in Xamarin projects. Additionally, if an open source project doesn't have a Xamarin or portable class library version, porting the code to be used in a Xamarin project can often be very straightforward. Xamarin also supports calling native Objective-C and Java libraries, so we will explore these as additional means of reusing existing code.

In this chapter, we will cover the following:

  • The Xamarin Component Store
  • NuGet
  • Porting existing C# libraries
  • Objective-C bindings
  • Java bindings

The Xamarin Component Store

The primary and obvious way to add third-party components to your project is via the Xamarin Component Store. The Component Store is fairly similar to NuGet, which we will cover later, except that the Component Store also contains premium components that are not free. All Xamarin components are required to include full sample projects and a getting started guide, while NuGet does not inherently provide documentation in its packages.

All the Xamarin.iOS and Xamarin.Android projects come with a Components folder. To get started, simply right-click on the folder and select Get More Components to launch the store dialog, as shown in the following screenshot:

The Xamarin Component Store

At the time of writing this module, there are well over 200 components available to enhance your iOS and Android applications. This is a great place to find the most common components to use within your Xamarin applications. Each component is complete with artwork. You might possibly need a demonstration video, reviews, and other information before purchasing a premium component.

The most common components

The most well-known and useful components are as follows:

  • Json.NET: This is the de facto standard for parsing and serializing JSON with C#
  • RestSharp: This is a commonly used simple REST client for .NET
  • SQLite.NET: This is a simple Object Relational Mapping (ORM) to use when working with local SQLite databases in your mobile applications
  • Facebook SDK: This is the standard SDK provided by Facebook to integrate its services into your apps
  • Xamarin.Mobile: This is a cross-platform library to access your device's contacts, GPS, photo library, and camera with a common API
  • ActionBarSherlock: This is a powerful ActionBar replacement for Android

Note that some of these libraries are native Java or Objective-C libraries, while some are plain C#. Xamarin is built from the ground up to support calling native libraries, so the Component Store offers many of the common libraries that Objective-C or Java developers would leverage when developing mobile applications.

You can also submit your own components to the Component Store. If you have a useful open source project or just want to earn some extra cash, creating a component is simple. We won't be covering it in this module, but you can navigate to http://components.xamarin.com/submit for full documentation on the subject, as shown in the following screenshot:

The most common components

Porting existing C# libraries

Even though Xamarin is becoming a popular platform, many open source .NET libraries are simply not up to speed with supporting Xamarin.iOS and Xamarin.Android. However, in these cases, you are definitely not out of luck. Often, if there is a Silverlight or Windows Phone version of the library, you can simply create an iOS or Android class library and add the files with no code changes.

To help with this process, Xamarin has created an online service tool to scan your existing code and determine how far off a library is from being portable. Navigate to http://scan.xamarin.com and upload any *.exe or *.dll file to have its methods analyzed for cross-platform development. After the scanning process, you'll get a report of the porting percentage (how much your component / application is portable to all platforms: Android, iOS, Windows Phone, and Windows Store).

The following screenshot is a sample report of the Lucene .NET client library:

Porting existing C# libraries

If the library is running a high percentage on portability, you should have a relatively easy time porting it to Android or iOS. In most cases, it can even be easier to port the library to Xamarin than Windows Phone or WinRT.

To illustrate this process, let's port an open source project that doesn't have Xamarin or a portable class library support. I have selected a dependency injection library called Ninject due to its usefulness and relationship to ninjas. You can find out more about the library at http://www.ninject.org.

Let's begin setting up the library to work with Xamarin projects as follows:

  1. First, download the source code for Ninject from https://github.com/ninject/Ninject.
  2. Open Ninject.sln in Xamarin Studio.
  3. Add a new iOS Library Project named Ninject.iOS.
  4. Link all the files from the Ninject main project. Make sure you use the Add Existing Folder dialog to speed up this process.

Tip

If you aren't familiar with GitHub, I recommend that you download the desktop client for Mac found at http://mac.github.com.

Now try to build the Ninject.iOS project; you will get several compiler errors in a file named DynamicMethodFactory.cs, as shown in the following screenshot:

Porting existing C# libraries

Open DynamicMethodFactory.cs and notice the following code at the top of the file:

#if !NO_LCG
#region Using Directivesusing System;
  using System.Reflection;
  using System.Reflection.Emit;
  using Ninject.Components;
#endregion

/// *** File contents here ***

#endif

It is not possible to use System.Reflection.Emit on iOS due to Apple's platform restrictions. Luckily, the library writers have created a preprocessor directive called NO_LCG (which stands for Lightweight Code Generation) to allow the library to run on platforms that do not support System.Reflection.Emit.

To fix our iOS project, open the project options and navigate to the Build | Compiler section. Add NO_LCG to the Define Symbols field for both Debug and Release in the Configuration drop-down menu. Click on OK to save your changes. Notice how the entire file is now highlighted with a light gray color in Xamarin Studio, as shown in the following screenshot. This means that the code will be omitted from being compiled.

Porting existing C# libraries

If you compile the project now, it will be completed successfully and a Ninject.iOS.dll file will be created, which you can reference from any Xamarin.iOS project. You can also reference the Ninject.iOS project directly instead of using the *.dll file.

At this point, you might wish to repeat the process to create a Xamarin.Android class library project. Luckily, Xamarin.Android supports System.Reflection.Emit, so you can skip adding the additional preprocessor directive if you wish.

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 module, 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.

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 module, 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.

Java bindings

In the same manner as iOS, Xamarin has provided full support for calling into Java libraries from C# with Xamarin.Android. The native Android SDKs function in this way and developers can leverage the Android Java Bindings project to take advantage of other native Java libraries in C#. The main difference here is that not a lot has to be done by hand in comparison to Objective-C bindings. The Java syntax is very similar to that of C#, so many mappings are exactly one-to-one. In addition, Java has metadata information included with its libraries, which Xamarin uses to automatically generate the C# code required for calling into Java.

As an example, let's make a binding for the Android version of the Google Analytics SDK. Before we begin, download the SDK from http://tinyurl.com/GoogleAnalyticsForAndroid. At the time of writing, the version of the Android SDK 3.01, so some of these instructions might change over time.

Let's begin creating a Java binding as follows:

  1. Start a new Android Java Bindings Library project in Xamarin Studio. You can use the same solution as we did for iOS if you wish.
  2. Name the project GoogleAnalytics.Droid.
  3. Add libGoogleAnalyticsServices.jar from the Android SDK to the project under the Jars folder. By default, the build action for the file will be EmbeddedJar. This packs the jar file into the DLL, which is the best option for ease of use.
  4. Build the project. You will get a few errors, which we'll address in a moment.

Most of the time you spend working on Java bindings will be to fix small issues that prevent the generated C# code from compiling. Don't fret; a lot of libraries will work on the first try without having to make any changes at all. Generally, the larger the Java library is, the more work you have to do to get it working from C#.

The following are the types of issues you might run into:

  • Java obfuscation: If the library is run through an obfuscation tool such as ProGuard, the class and method names might not be valid C# names.
  • Covariant return types: Java has different rules for return types in overridden virtual methods than C# does. For this reason, you might need to modify the return type for the generated C# code to compile.
  • Visibility: The rules that Java has for accessibility are different from those of C#; the visibility of methods in subclasses can be changed. Sometimes, you will have to change visibility in C# to get it to compile.
  • Naming collisions: Sometimes, the C# code generator can get things a bit wrong and generate two members or classes with the same name.
  • Java generics: The use of generic classes in Java can often cause issues in C#.

So before we get started on solving these issues in our Java binding, let's first clean up the namespaces in the project. Java namespaces are of the form com.mycompany.mylibrary by default, so let's change the definition to match C# more closely. In the Transforms directory of the project, open Metadata.xml and add the following XML tag inside the root metadata node:

<attr path="/api/package[@name='com.google.analytics.tracking
  .android']" name="managedName">GoogleAnalytics.Tracking</attr>

The attr node tells the Xamarin compiler what needs to be replaced in the Java definition with another value. In this case, we are replacing managedName of the package with GoogleAnalytics.Tracking because it will make much more sense in C#. The path value might look a bit strange, which is because it uses an XML matching query language named XPath. In general, just think of it as a pattern matching query for XML. For full documentation on XPath syntax, check out some of the many resources online such as http://w3schools.com/xpath.

You might be asking yourself at this point, what is the XPath expression matching against? Return to Xamarin Studio and right-click on the solution at the top. Navigate to Display Options | Show All Files. Open api.xml under the obj/Debug folder. This is the Java definition file that describes all the types and methods within the Java library. If you notice, the XML here directly correlates to the XPath expressions we'll be writing.

In our next step, let's remove all the packages (or namespaces) we don't plan on using in this library. This is generally a good idea for large libraries since you don't want to waste time fixing issues with parts of the library you won't even be calling from C#. Note that it doesn't actually remove the Java code; it just prevents the generation of any C# declarations for calling it from C#.

Add the following declarations in Metadata.xml:

<remove-node
  path="/api/package[@name='com.google.analytics
  .containertag.common']" />
<remove-node
  path="/api/package[@name='com.google.analytics
  .containertag.proto']" />
<remove-node
  path="/api/package[@name='com.google.analytics
  .midtier.proto.containertag']" />
<remove-node
  path="/api/package[@name='com.google.android
  .gms.analytics.internal']" />
<remove-node
  path="/api/package[@name='com.google.android
  .gms.common.util']" />
<remove-nodepath="/api/package[@name='com.google.tagmanager']" />
<remove-node
  path="/api/package[@name='com.google.tagmanager.proto']" />
<remove-node
  path="/api/package[@name='com.google.tagmanager.protobuf.nano']" />

Now when you build the library, we can start resolving issues. The first error you will receive will be something like the following:

GoogleAnalytics.Tracking.GoogleAnalytics.cs(74,74): 
    Error CS0234: The type or namespace name 'TrackerHandler' 
    does not exist in the namespace 'GoogleAnalytics.Tracking'. 
    Are you missing an assembly reference?

If we locate TrackerHandler within the api.xml file, we'll see the following class declaration:

<class
  abstract="true" deprecated="not deprecated"
  extends="java.lang.Object"
  extends-generic-aware="java.lang.Object"
  final="false" name="TrackerHandler"
  static="false" visibility=""/>

So, can you spot the problem? We need to fill out the visibility XML attribute, which for some reason is blank. Add the following line to Metadata.xml:

<attr
  path="/api/package[@name='com.google.analytics
  .tracking.android']/class[@name='TrackerHandler']"
  name="visibility">public</attr>

This XPath expression will locate the TrackerHandler class inside the com.google.analytics.tracking.android package and change visibility to public.

If you build the project now, it will complete successfully with one warning. In Java binding projects, it is a good idea to fix warnings since they generally indicate that a class or method is being omitted from the binding. Notice the following warning:

GoogleAnalytics.Droid: Warning BG8102: 
    Class GoogleAnalytics.Tracking.CampaignTrackingService has   
    unknown base type android.app.IntentService (BG8102)  
    (GoogleAnalytics.Droid)

To fix this issue, locate the type definition for CampaignTrackingService in api.xml, which is as follows:

<class
  abstract="false" deprecated="not deprecated"
  extends="android.app.IntentService"
  extends-generic-aware="android.app.IntentService"
  final="false" name="CampaignTrackingService"
  static="false" visibility="public">

The way to fix the issue here is to change the base class to the Xamarin.Android definition for IntentService. Add the following code to Metadata.xml:

<attr
  path="/api/package[@name='com.google.analytics
  .tracking.android']/class[@name='CampaignTrackingService']"
  name="extends">mono.android.app.IntentService</attr>

This changes the extends attribute to use the IntentService found in Mono.Android.dll. I located the Java name for this class by opening Mono.Android.dll in Xamarin Studio's Assembly Browser. Let's take a look at the Register attribute, as shown in the following screenshot:

Java bindings

To inspect the *.dll files in Xamarin Studio, you merely have to open them. You can also double-click on any assembly in the References folder in your project.

If you build the binding project now, we're left with one last error, which is as follows:

GoogleAnalytics.Tracking.CampaignTrackingService.cs(24,24): 
    Error CS0507: 
    'CampaignTrackingService.OnHandleIntent(Intent)': 
    cannot change access modifiers when overriding 'protected'    
    inherited member 
    'IntentService.OnHandleIntent(Android.Content.Intent)' 
    (CS0507) (GoogleAnalytics.Droid)

If you navigate to the api.xml file, you can see the definition for OnHandleIntent as follows:

<method
  abstract="false" deprecated="not deprecated" final="false"
  name="onHandleIntent" native="false" return="void"
  static="false" synchronized="false" visibility="public">

We can see here that the Java method for this class is public, but the base class is protected. So, the best way to fix this is to change the C# version to protected as well. Writing an XPath expression to match this is a bit more complicated, but luckily Xamarin has an easy way to retrieve it. If you double-click on the error message in the Errors pad of Xamarin Studio, you'll see the following comment in the generated C# code:

// Metadata.xml XPath method reference:
  path="/api/package[@name='com.google.analytics
  .tracking.android']/class[@name='CampaignTrackingService']
  /method[@name='onHandleIntent' and count(parameter)=1 and
  parameter[1][@type='android.content.Intent']]"

Copy this value to path and add the following to Metadata.xml:

<attr path="/api/package[@name='com.google.analytics
  .tracking.android']/class[@name='CampaignTrackingService']
  /method[@name='onHandleIntent' and count(parameter)=1 and
  parameter[1][@type='android.content.Intent']]"
  name="visibility">protected</attr>

Now, we can build the project and get zero errors and zero warnings. The library is now ready for use within your Xamarin.Android projects.

However, if you start working with the library, notice how the parameter names for the methods are p0, p1, p2, and so on. Here are a few method definitions of the EasyTracker class:

public static EasyTracker GetInstance(Context p0);
public static void SetResourcePackageName(string p0);
public virtual void ActivityStart(Activity p0);
public virtual void ActivityStop(Activity p0);

You can imagine how difficult it would be to consume a Java library without knowing the proper parameter names. The reason the parameters are named this way is because the Java metadata for its libraries does not include the information to set the correct name for each parameter. So, Xamarin.Android does the best thing it can and autonames each parameter sequentially.

To rename the parameters in this class, we can add the following to Metadata.xml:

<attr path="/api/package[@name='com.google.analytics
  .tracking.android']/class[@name='EasyTracker']
  /method[@name='getInstance']/parameter[@name='p0']"
  name="name">context</attr>
<attr path="/api/package[@name='com.google.analytics
  .tracking.android']/class[@name='EasyTracker']
  /method[@name='setResourcePackageName']/parameter[@name='p0']"
  name="name">packageName</attr>
<attr path="/api/package[@name='com.google.analytics
  .tracking.android']/class[@name='EasyTracker']
  /method[@name='activityStart']/parameter[@name='p0']"
  name="name">activity</attr>
<attr path="/api/package[@name='com.google.analytics
  .tracking.android']/class[@name='EasyTracker']
  /method[@name='activityStop']/parameter[@name='p0']"
  name="name">activity</attr>

On rebuilding the binding project, this will effectively rename the parameters for these four methods in the EasyTracker class. At this time, I would recommend that you go through the classes you plan on using in your application and rename the parameters so that it will make more sense to you. You might need to refer to the Google Analytics documentation to get the naming correct. Luckily, there is a javadocs.zip file included in the SDK that provides HTML reference for the library.

For a full reference on implementing Java bindings, make sure you check out Xamarin's documentation site at http://docs.xamarin.com/android. There are certainly more complicated scenarios than what we ran into when creating a binding for the Google Analytics library.

Summary

In this chapter, we added libraries from the Xamarin Component Store to Xamarin projects and ported an existing C# library, Ninject, to both Xamarin.iOS and Xamarin.Android. Next, we installed Objective Sharpie and explored its usage to generate Objective-C bindings. Finally, we wrote a functional Objective-C binding for the Google Analytics SDK for iOS and a Java binding for the Google Analytics SDK for Android. We also wrote several XPath expressions to clean up the Java binding.

There are several available options to use the existing third-party libraries from your Xamarin.iOS and Xamarin.Android applications. We looked at everything from using the Xamarin Component Store, porting existing code and setting up Java and Objective-C libraries to be used from C#. In the next chapter, we will cover the Xamarin.Mobile library as a way to access a user's contacts, camera, and GPS location.

You have been reading a chapter from
Xamarin: Cross-Platform Mobile Application Development
Published in: Aug 2016
Publisher: Packt
ISBN-13: 9781787120129
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime