Tags: , , , | Categories: Blog Posted by al on 8/3/2010 1:39 AM | Comments (0)


The iPhone is an amazing platform, yet coming for the .NET world, Objective C really makes me feel like I'm going back to the old days of C, now when Novell came out with MonoTouch I thought that I could do something with that.

I spent many years in Visual Studio and working in .NET, going to a Mac with XCode makes it a little hard, Novell started many years ago the Mono project an open source, cross-platform implementation of C# and the CLR that is binary compatible with Microsoft.NET. Mono provides you as well with a version of the Visual Studio for the Mac called MonoDevelop that will make the .NET developer feel better using a Mac or Linux. Those are open source and you can download them from their main page.

MonoTouch is the implementation of that library in the iPhone, iPod Touch and iPad world, allowing developer to create C# based applications that runs on Apple’s iOS by binding on the native libraries. The best part is that, there is no JIT or interpreter shipped with your application, only native code when you deploy to the Apple AppStore as well as MonoTouch does not support VB.NET ;-)

 

Let’s get stated.

So I thought to give MonoTouch a chance. My test is going to be to use the native library created by ESRI to consume maps on the iPhone.  So I downloaded the Beta of the ArcGIS library for the iPhone 4.

Add the native library (.a) to the project just by  right click –> Add –> Add Files, select the library file and add it into the main directory of your project.

PastedGraphic-1

Change the flag to do not build, so MonoDevelop does not try to build the native library on the solution, the latest MonoDevelop already does that, however, is a good idea to check.

PastedGraphic-2

 

Create the .NET dll to bind it all.

Now we needed to create a dll to use with MonoDevelop, there are lots of steps to be able to bind a iPhone native library in MonoTouch, I was lucky enough that Novell gave me all the support I needed. I created an interface from the exisiting library, for that I used a parser provided by Novell to go over the header files The parser can be pointed to a file or a complete directory, and will create the binding to the Objective-C Type.

"mono parser.exe directory"

or

"mono parser.exe file.h"

Miguel de Icaza has a great documentation of the binding details. Please read carefully how to bind each object on the documentation, so you can fix errors after the parser, is very important to learn the Objective-C syntax. I recommend not to do it by hand, use the parser.exe that I compiled already and you can download it to give you 98% of what you need. Download it here 

image

Then that created the C# code and enums, I used those to create the library by using the MonoTouch application bTouch, make sure you run it on a console window, I fixed the errors produce by the parser so you can download the C# code files from here, you'll find that there are 4 files, 2 for the device and 2 for the simulator. You can find the dll created as well that will bind to the ESRI libArcGIS.a iPhone SDK. You can always recreate the dll by running btouch.

/Developer/MonoTouch/usr/bin/btouch -v parserArcGISClassesSim.cs -s:parserArcGISEnumSim.cs

Please Note: There is a bug that Geoff Norton from Novell found on the btouch utility, download this one here that fixes the issue. btouch was fixed in 3.0.12 as well which will be pushed to the stable channel this week.

In the zip you’ll find that I created bindings for the simulator library and for the device library, please use the correct one, otherwise you’ll get an exception like this if you using the incorrect dll bound to the wrong native library.

Unhandled Exception: MonoTouch.Foundation.MonoTouchException: Objective-C exception thrown.  Name: NSInvalidArgumentException Reason: *** -[UIDevice machineType]: unrecognized selector sent to instance 0x6670e90
at (wrapper managed-to-native) MonoTouch.ObjCRuntime.Messaging:IntPtr_objc_msgSend (intptr,intptr)
at MapViewer.AGSMapView..ctor () [0x00000] in <filename unknown>:0
at MapViewer.AppDelegate.FinishedLaunching (MonoTouch.UIKit.UIApplication app, MonoTouch.Foundation.NSDictionary options) [0x00000] in <filename unknown>:0
at (wrapper managed-to-native) MonoTouch.UIKit.UIApplication:UIApplicationMain (int,string[],intptr,intptr)
at MonoTouch.UIKit.UIApplication.Main (System.String[] args, System.String principalClassName, System.String delegateClassName) [0x00000] in <filename unknown>:0
at MonoTouch.UIKit.UIApplication.Main (System.String[] args) [0x00000] in <filename unknown>:0
at MapViewer.Application.Main (System.String[] args) [0x00000] in <filename unknown>:0

Binding it all together.

The last step to link everything; you need to change the project settings as well, all the information is here from MonoTouch.net however the linker has a few issues and Geoff Norton from Novell gave me the perfect flag to avoid the problem, you must also specify use the -ObjC and -all_load linker flags in your project's Other Linker Flags build setting. This is because the ArcGIS library defines objective-c categories which do not get loaded without these flags, is not a problem on the –ObjC like we first thought.

-gcc_flags "-L${ProjectDir} -lArcGIS -framework CFNetwork -force_load ${ProjectDir}/libArcGIS.a"

Now you are ready to write some C# code and with a few simple line of code after adding your Map View using the Interface Viewer.

PastedGraphic-3 PastedGraphic-4 PastedGraphic-5

 

Let’s add the map.

Make sure you create an outlet for the map as is a UIView. The very detail steps to do so are documented here, to work with the Interface Viewer as is the same for MonoTouch than XCode.

Now that you have an outlet for the map called myOutletMap you can go ahead in the Main.cs file and after the application finishes, you can add a tiled layer before the window gets visible to the user.

public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
     // If you have defined a view, add it here:
     // window.AddSubview (navigationController.View);
     MonoTouch.Foundation.NSUrl myurl = new MonoTouch.Foundation.NSUrl("http://server.arcgisonline.com/ArcGIS/rest/services/ESRI_StreetMap_World_2D/MapServer");
     AGSTiledMapServiceLayer second = new AGSTiledMapServiceLayer(myurl); 
     myOutletMap.AddMapLayer(second, "basemap");
     window.MakeKeyAndVisible (); 
     return true;
}
 

Let’s make it easier, download it all!

You can find the complete project source code here to download it and not having to go over all the steps for you to compile and start adding your business logic, the link above is the complete solution. Please make sure you have a license of MonoTouch if you want to deploy as well as a license of ArcGIS products before using it

 

 

 

 

 

 

Cheers

Al

PS. Thanks so much to Novell specially to Miguel de Icaza and Geoff Norton for all the fixes and help.

blog comments powered by Disqus