Using Good Dynamics SDK v1.8.x with Xamarin.iOS

After following  the “Getting Started” guide in the latest GOOD Dynamics documentation, you’ve undoubtedly encountered this error while trying to run your Xamarin.iOS application using GOOD Dynamics:

“MonoTouch.Foundation.MonoTouchException: Objective-C exception thrown.  Name: NSInternalInconsisenter code heretencyException Reason: AppDelegate does not implement UIApplicationDelegate. Check that the class is correct and it conforms to this protocol.

at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging:void_objc_msgSend_IntPtr (intptr,intptr,intptr)

at GDBinding.GDiOS.InitializeWithClassConformingToUIApplicationDelegate (MonoTouch.ObjCRuntime.Class applicationDelegate)

[0x00000] in <filename unknown>:0

at GDTest.Application.Main (System.String[] args) [0x00006]”

This error has been a show stopper for most anyone attempting to get GOOD Dynamics working with Xamarin. Fortunately, the fix is fairly straightforward. The issue results from the binding hiding the inheritance between GDiOSDelegate and UIApplicationDelegate. We know it’s implemented behind the scenes in Good, so we can safely tell the runtime that it is indeed implemented:

using System;
using System.Collections.Generic;
using System.Linq;
using MonoTouch.Foundation;
using MonoTouch.UIKit;
using GoodDynamics;
using MonoTouch.ObjCRuntime;
using System.Runtime.InteropServices;

namespace GoodDynamicsExample
{
    public class Application
    {
        static string ApplicationDelegateName = "AppDelegate";

        [DllImport ("/usr/lib/libobjc.dylib")]
        static extern bool class_addProtocol (IntPtr cls, IntPtr protocol);

        [DllImport ("/usr/lib/libobjc.dylib")]
        static extern IntPtr objc_getProtocol (string name);

        // This is the main entry point of the application.
        static void Main (string[] args)
        {
            //We need to manually add the missing UIApplicationDelegate protocol to our AppDelegate at runtime.
            //This lets GDiOS.InitializeWithClassNameConformingToUIApplicationDelegate succeed.
            var p = objc_getProtocol ("UIApplicationDelegate");
            class_addProtocol (Class.GetHandle (ApplicationDelegateName), p);

            GDiOS.InitializeWithClassNameConformingToUIApplicationDelegate (ApplicationDelegateName);

            UIApplication.Main (args, null, ApplicationDelegateName);
        }
    }
}

After the application is able to detect that inheritance, it begins to call methods that GOOD has implemented behind the scenes to intercept the application lifecycle. Calls to “application:didFinishLaunchingwithOptions:” have been modified to include a “gd” preface. These methods MUST be accounted for inside of your AppDelegate class. The full list can be found below:

[Export("gdWindow")]
public override UIWindow Window { get;  set; }

[Export("gdApplication:didFinishLaunchingWithOptions:")]
private bool gdFinishedLaunching(UIApplication app, NSDictionary options)
{
    return FinishedLaunching(app, options);
}

[Export("gdApplication:openURL:sourceApplication:annotation:")]
private bool gdOpenUrl(UIApplication application, NSUrl url, string sourceApplication, NSObject annotation)
{
    return OpenUrl(application, url, sourceApplication, annotation);
}

[Export("gdApplicationWillResignActive:")]
private void gdApplicationWillResignActive(UIApplication application)
{
    OnResignActivation(application);
}

[Export("gdApplicationDidEnterBackground:")]
private void gdApplicationDidEnterBackground(UIApplication application)
{
    DidEnterBackground(application);
}

[Export("gdApplicationWillEnterForeground:")]
private void gdApplicationWillEnterForeground(UIApplication application)
{
    WillEnterForeground(application);
}

[Export("gdApplicationWillTerminate:")]
private void gdApplicationWillTerminate(UIApplication application)
{
    WillTerminate(application);
}

[Export("handleEvent")]
public override void HandleEvent (GDAppEvent anEvent)
{
    //your own implementation here
}

The next setting that needs to be set is we need to tell Xamarin that this is a C++ library. To do this, under your iOS project settings (not the binding project), navigate to the iOS Build section. Under “Additional Monotouch Arguments” add the flag –cxx.

Up until v1.8.x of the GOOD Dynamics SDK, this would have been enough to get GOOD Dynamics running under Xamarin. However, with the release of v1.8.x, a new process has been added as a requirement to the compilation process. This process is known as FIPS Linking. Any application that does not undergo this process will crash on start. There are a few things that need to be done to your application in order to support this process.

First, navigate to your GOOD Dynamics SDK install directory, specifically the FIPS_module folder. This should be located here: “/Good Technology/GOOD.platform/FIPS_module/”. Inside of this directory you should find a folder for each system architecture iOS supports. In each one of these folders you’re going to need to make the following changes to account for differences between the XCode and Xamarin compilation processes. Inside of each bin folder (for each architecture) you should find a file called “gd_fipsld”. Copy this file and rename it to “ld”.

Now, open this file and change the following section:

/bin/rm -f "${TARGET}"
echo trying to link with $CC
${CC}	${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \
		"${PREMAIN_C}" \
		${_WL_PREMAIN} "$@"
echo end of trying to link with $CC ...

To this:

/bin/rm -f "${TARGET}"
echo trying to link with $CC
OLD_ARGS=$@
NEW_ARGS=${OLD_ARGS//iphoneos_version_min /miphoneos-version-min=}
NEW_ARGS=${NEW_ARGS//syslibroot/isysroot}
${CC}	${CANISTER_O_CMD:+"${CANISTER_O_CMD}"} \
		"${PREMAIN_C}" \
		${_WL_PREMAIN} $NEW_ARGS
echo end of trying to link with $CC ...

Once this is done, go back to your Xamarin.iOS project settings and navigate to the iOS Build section (where we added the –cxx flag before). We’re going to instruct Xamarin studio to use this new linker during its compilation process using an undocumented gcc_flag. First, make sure that you set Linker Behavior to “Link All Assemblies”. Next, add this after the –cxx flag:

--gcc_flags="-framework QuickLook -framework SystemConfiguration -framework Security -framework MobileCoreServices -framework QuartzCore -framework CoreTelephony -framework MessageUI -framework AdSupport -B /'Good Technology'/Good.platform/FIPS_module/armv7s.sdk/bin"

Lastly, make sure that, in your GD.LinkWith.cs file in your binding project, “ForceLoad = true” is not present. Be sure to set the architecture version to your target compilation (e.g. armv7s.sdk, i386.sdk, etc.).

After all this.. you should now have a successfully bound and running application using the Good Dynamics SDK with Xamarin.iOS!

Big thanks goes to Sebastien Pouliot at Xamarin and Simon Brooks at Good Technologies, as well as Stephen Gray at YARG, Ltd. for collaborating with us at West Monroe Partners on this solution over the past few weeks.

BzWsMruIEAADsj8

Sebastien Pouliot, John Sprunger, Jason Farrell, Stephen Gray, and Greg Gammon (via Skype) working on the fix during the Xamarin Evolve conference.

You can find the Good Dynamics Xamarin.iOS binding and sample project on our GitHub.

UPDATE:
In order to get this to run in the simulator, there are two additional steps that need to be accounted for. In the i386 version of the linker, add this line just after the modification for “iphoneos_version_min”:

NEW_ARGS=${NEW_ARGS//ios_simulator_version_min /mios-simulator-version-min=}

After that, another additional monotouch argument needs to be provided. This argument is:

--registrar:static

Our mobility consulting professionals have extensive experience developing enterprise and consumer mobile apps using Xamarin on the Apple iOS, Android, and Windows Phone platforms. We’ve built numerous apps utilizing Good Dynamics.  Contact us for more information on how we can work with you to build highly secure, cross-platform mobile applications.

1 Comment

  • Erik May 11, 2015 7:42 am

    I finally managed to get this working. The class_addProtocol was not needed in the end, because I’m using a weak delegate for the GDiOSDelegate (this was necessary for Xamarin Forms).

    I’m not able to get the GDHttpRequest to work though, it needs IntPtr (char * in ObjC). Did you guys get this working, and if so – how?

Your email address will not be published. Required fields are marked *

Phone: 312-602-4000
Email: marketing@westmonroepartners.com
222 W. Adams
Chicago, IL 60606
Show Buttons
Share On Facebook
Share On Twitter
Share on LinkedIn
Hide Buttons