I am trying to wrap the ESRI ArcGIS map sdk for android for use in Mono for Android. I have successfully wrapped the iOS version using MonoTouch. However, doing the same thing for Android seems to be MUCH harder. Here are the issues I have run into and solved:
Trying to directly wrap the ArcGIS jar was a nightmare. It is very large and complicated that generated hundreds of warnings and errors in MonoDevelop as a binding project. I thought of a clever idea to use containment and write my own third party jar containing my own MapView class that "contains" an ESRI map view component. That way I only have to wrap my own very small third party jar and use the ArcGIS jar as a reference jar. Any functionality I need from the real ESRI map component, I just delegate from my own mapView class. This allows me to only wrap the functionality that I need. It seems like it might work and have made great progress.
In addition to the ArcGIS jar being a reference jar, it also relies on two other reference jars. That means I have 1 jar to be wrapped, my own, and three reference jars. I submitted a separate email to you guys explaining a possible bug in the mono for android build scripts where more than 1 reference jar caused the same android identifier to be used for all of them causing a duplicate error message. See my other email for details. I worked around this by unzipping all 3 reference jars and rezipping into a single reference jar. Hopefully, you can fix this bug.
Not only does the ArcGIS third party component jar require 2 other reference jars, but it also makes use of a native .so library. I saw the android simulator trying to load the library in the LogCat. I added the .so to the project and set its build action to AndroidNativeLibrary. That fixed that issue.
I thought I would finally get success, but I have run into something that stumps me. It looks like the ESRI ArcGIS jar is obfuscated such that the Dalvik VM cannot understand it when run from mono for android. Obviously, it works fine in pure java mode. The LogCat shows the errors below when trying to find classes. What can I do about this issue? I wonder if my solution to issue #2 above where I unzipped the ArcGIS jar and rezipped joining in other jars is the cause of this problem? I don't think so as I unzipped my combined jar and it looks like it has all the necessary parts. Also, I wouldn't have gotten as far as I did where it tried to load the native library if this combined jar was bad.
01-19 02:39:54.419: E/mono(1507): WARNING: The runtime version supported by this application is unavailable. 01-19 02:39:54.430: E/mono(1507): Using default runtime: v2.0.50727 01-19 02:39:54.599: W/monodroid-gc(1507): GREF GC Threshold: 1800 01-19 02:39:56.719: W/dalvikvm(1507): Unable to resolve superclass of Lcom/esri/core/geometry/MultiPath; (709) 01-19 02:39:56.719: W/dalvikvm(1507): Link of class 'Lcom/esri/core/geometry/MultiPath;' failed 01-19 02:39:56.719: E/dalvikvm(1507): Could not find class 'com.esri.core.geometry.MultiPath', referenced from method com.esri.android.map.MapSurface.a 01-19 02:39:56.719: W/dalvikvm(1507): VFY: unable to resolve instanceof 585 (Lcom/esri/core/geometry/MultiPath;) in Lcom/esri/android/map/MapSurface; 01-19 02:39:56.719: D/dalvikvm(1507): VFY: replacing opcode 0x20 at 0x00e3 01-19 02:39:56.730: W/dalvikvm(1507): Unable to resolve superclass of Lcom/esri/core/geometry/MultiPath; (709) 01-19 02:39:56.730: W/dalvikvm(1507): Link of class 'Lcom/esri/core/geometry/MultiPath;' failed 01-19 02:39:56.730: W/dalvikvm(1507): Unable to resolve superclass of Lcom/esri/core/geometry/Polygon; (585) 01-19 02:39:56.730: W/dalvikvm(1507): Link of class 'Lcom/esri/core/geometry/Polygon;' failed 01-19 02:39:56.730: E/dalvikvm(1507): Could not find class 'com.esri.core.geometry.Polygon', referenced from method com.esri.android.map.MapSurface.h 01-19 02:39:56.740: W/dalvikvm(1507): VFY: unable to resolve new-instance 638 (Lcom/esri/core/geometry/Polygon;) in Lcom/esri/android/map/MapSurface; 01-19 02:39:56.740: D/dalvikvm(1507): VFY: replacing opcode 0x22 at 0x0018 01-19 02:39:56.740: W/dalvikvm(1507): Unable to resolve superclass of Lcom/esri/core/geometry/MultiPath; (709) 01-19 02:39:56.740: W/dalvikvm(1507): Link of class 'Lcom/esri/core/geometry/MultiPath;' failed 01-19 02:39:56.740: W/dalvikvm(1507): Unable to resolve superclass of Lcom/esri/core/geometry/Polygon; (585) 01-19 02:39:56.740: W/dalvikvm(1507): Link of class 'Lcom/esri/core/geometry/Polygon;' failed 01-19 02:39:56.740: W/dalvikvm(1507): VFY: unable to find class referenced in signature (Lcom/esri/core/geometry/Polygon;) 01-19 02:39:56.760: W/dalvikvm(1507): Unable to resolve superclass of Lcom/esri/core/geometry/MultiPath; (709) 01-19 02:39:56.760: W/dalvikvm(1507): Link of class 'Lcom/esri/core/geometry/MultiPath;' failed 01-19 02:39:56.760: W/dalvikvm(1507): Unable to resolve superclass of Lcom/esri/core/geometry/Polygon; (585) 01-19 02:39:56.760: W/dalvikvm(1507): Link of class 'Lcom/esri/core/geometry/Polygon;' failed 01-19 02:39:56.760: D/dalvikvm(1507): DexOpt: unable to opt direct call 0x0d9a at 0x1a in Lcom/esri/android/map/MapSurface;.h 01-19 02:39:56.790: D/dalvikvm(1507): Trying to load lib /data/data/Test.Test/lib/libGLMapCore.so 0x41492bb0 01-19 02:39:57.130: D/dalvikvm(1507): Added shared lib /data/data/Test.Test/lib/libGLMapCore.so 0x41492bb0 01-19 02:39:57.140: W/ApplicationContext(1507): Unable to create external cache directory 01-19 02:39:57.330: E/dalvikvm(1507): Could not find class 'com.esri.core.geometry.J', referenced from method com.esri.core.geometry.Point.<init> 01-19 02:39:57.330: W/dalvikvm(1507): VFY: unable to resolve new-instance 574 (Lcom/esri/core/geometry/J;) in Lcom/esri/core/geometry/Point; 01-19 02:39:57.330: D/dalvikvm(1507): VFY: replacing opcode 0x22 at 0x0009 01-19 02:39:57.330: E/dalvikvm(1507): Could not find class 'com.esri.core.geometry.J', referenced from method com.esri.core.geometry.Point.i 01-19 02:39:57.340: W/dalvikvm(1507): VFY: unable to resolve new-instance 574 (Lcom/esri/core/geometry/J;) in Lcom/esri/core/geometry/Point; 01-19 02:39:57.340: D/dalvikvm(1507): VFY: replacing opcode 0x22 at 0x000f 01-19 02:39:57.340: W/dalvikvm(1507): VFY: unable to find class referenced in signature (Lcom/esri/core/geometry/J;) 01-19 02:39:57.340: W/dalvikvm(1507): VFY: unable to resolve instance field 1109 01-19 02:39:57.340: D/dalvikvm(1507): VFY: replacing opcode 0x53 at 0x000a 01-19 02:39:57.340: W/dalvikvm(1507): VFY: unable to resolve instance field 1107 01-19 02:39:57.350: D/dalvikvm(1507): VFY: replacing opcode 0x53 at 0x0020 01-19 02:39:57.350: W/dalvikvm(1507): VFY: unable to find class referenced in signature (Lcom/esri/core/geometry/J;) 01-19 02:39:57.350: W/dalvikvm(1507): VFY: unable to find class referenced in signature (Lcom/esri/core/geometry/J;) 01-19 02:39:57.350: W/dalvikvm(1507): VFY: unable to find class referenced in signature (Lcom/esri/core/geometry/J;) 01-19 02:39:57.350: W/dalvikvm(1507): VFY: unable to find class referenced in signature (Lcom/esri/core/geometry/J;) 01-19 02:39:57.350: W/dalvikvm(1507): VFY: unable to find class referenced in signature (Lcom/esri/core/geometry/i;) 01-19 02:39:57.359: I/dalvikvm(1507): Could not find method com.esri.core.geometry.i.a, referenced from method com.esri.core.geometry.Point.a 01-19 02:39:57.359: W/dalvikvm(1507): VFY: unable to resolve virtual method 4112: Lcom/esri/core/geometry/ --------------------------------------------------------
Posts
I am just about to look into integrating this jar into my Mono for Android project as well, so any support Xamarin can muster to resolve these issues would be much appreciated! Did you get any followup offline, Shawn?
This was filed as bug #9696, which will be fixed in the forthcoming 4.6 release, and you can fix the issue locally by making a one-line change to
Xamarin.Android.Bindings.targets
.I find that doubtful, but we can dig deeper. As per the logcat, the problem is:
What is the superclass of
com.esri.core.geometry.MultiPath
?So Dalvik can't find
com.esri.core.geometry.x
. This is where we can begin investigation: has that type been compiled into the.apk
?dexdump
is an Android SDK tool; it disassembles a.dex
file, which is the Dalvik bytecode that is actually executed on the device (sans the parts that are executed by mono). Output contains every type, field, contained within the.apk
.Redirect the output to a file (or
less
, etc.). What you want to see is if thecom.esri.core.geometry.x
is present. Type names are in JNI format (as seen above), so you'll want to look for:If the type doesn't exist, there's something wrong with your compilation; double check everything to make sure that
ArcGIS_Android.jar
is being fully included into your application.How did you unzip and rezip them? On what operating system?
.zip
file entries can be case-sensitive, particularly when dealing with obfuscated code:and...boom, there we go, two entries which differ only in case, and one of them happens to be the class we're interested in.
I suspect you extracted your
.jar
on Windows or OS X (both of which default to case-insensitive filesystems), so your final.jar
probably only contains one of those types, not both, which would explain everything else.Jonathan, that is one awesome answer to my question! Very good information contained within. Yes, you are exactly correct, my combined jar did not contain all case versions of all class files. Two things worth mentioned here for others:
I applied the patch for bug 9696 and it solved both of my problems. I no longer had to use my bad combined jar to workaround the bug and could put the 3 separate reference jars in the binding project. Those carried over to the app project and onto the simulator and the app ran great with an ESRI map view inside.
Before hearing about the patch for bug 9696, I was able to workaround my bad combined jar issue. Not knowing it was a bad combined jar at the time, I still used it in my binding project to satisfy any build references, but I did NOT want it to carry over (or embed) into the app for runtime on the simulator. I discovered that if I set my bad combined jar to buildaction = ReferenceJar, that it uses it only to satisfy build references but does NOT embed it in the final app. But, of course, I need those jars files embedded in the app somehow. Therefore, I just copied the 3 real separate jars into the app project in Assets and set their buildaction = AndroidJavaLibrary. It worked great.
Obviously, solution #1 is the right choice. I just wanted to explain everything for the benefit of others.
So I am seeing different results when creating a binding project for ArcGIS (after tracking down a copy of joda-time-2.1.jar to resolve a bunch of dependencies):
I notice in the generated file
__NamespaceMapping__.cs
that Mono appears to camel case the namespaces for the generated C#, and this is probably ambiguating the meaning ofModule
(since Java has a lower-case namespace module, and a class in the same parent namespace Module. Is there any way to disable the auto-capitalization of namespaces in a binding project? It seems likely this has come up in the past, and might again in the future.PS. I just noticed these in the build log, too:
PPS. I have gotten a bit further after discovering Metadata.xml as a way of removing chunks of java I don't need to call, however the bindings generator capitalizing getType() -> GetType() is obviously problematic for base object APIs that C# expects. Any way to turn off auto capitalization here as well?
After some fighting, I have ArcGIS 10.1 (the brand new one) binding with the following lines added to Metadata.xml:
Note that the xml delimiters are culled as I wasn't sure how to get this forum to actually show the text with the delimiters in there (and pre wasn't cutting it).
This is entirely preliminary, but I figured I would leave the info here in case anyone still cares.
Hi there,
I'm trying to achieve the same thing. Before I spend valuable time, could you please let me know, how you setup your binding projects.
thanks, Chris
@ShawnCastrianni, @GeoffEvans, and anyone else. I have to create a binding for Esri maps, but being relatively new to Android I'm having a bit of a problem. I've downloaded 10.2 of their SDK, unzipped it and added
arcgis-android-api.jar
arcgis-android-app-framework.jar
as embedded jars,
and
jackson-core-lgpl-1.9.5.jar, jackson-mapper-lgpl-1.9.5.jar and jcifs-1.3.17.jar as embedded reference jars
to an Android Java Bindings Library.
I just can't get past what appears to be the same issue that Shawn had with the MultiPath class - MultiVertexGeometry does not exist in Com.Esri.Core.Geometry
I don't know what to do to resolve it. This is my first attempt at binding a library.
I took another crack at binding ESRI and I was successful the second time around with more experience.
Below is the final metadata.xml file I came up with that I am using in production with great results. This metadata.xml file was created against 10.1.1 of the ESRI SDK. Hopefully, you won't have to make any changes to make it work against 10.2 ESRI.
<metadata> <remove-node path="/api/package[@name='com.esri.android.map.popup']" /> <remove-node path="/api/package[@name='com.esri.core.geometry']/class[@name='Geometry']/field[@name='m_description']" /> <remove-node path="/api/package[starts-with(@name,'com.esri.core.internal')]" /> <remove-node path="/api/package[@name='com.esri.core.portal']" /> <remove-node path="/api/package[@name='com.esri.core.symbol']/class[@name='PictureMarkerSymbol']/constructor/parameter[@type='java.lang.String']/.." /> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='Geometry']/method[@name='getType']" name="managedName">getGeometryType</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='Envelope']/method[@name='getType']" name="managedName">getGeometryType</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='Line']/method[@name='getType']" name="managedName">getGeometryType</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='Point']/method[@name='getType']" name="managedName">getGeometryType</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='Polygon']/method[@name='getType']" name="managedName">getGeometryType</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='Polyline']/method[@name='getType']" name="managedName">getGeometryType</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='MultiPoint']/method[@name='getType']" name="managedName">getGeometryType</attr> <attr path="/api/package[@name='com.esri.core.symbol']/class[@name='MultiLayerSymbol']/method[@name='copy']" name="return">com.esri.core.symbol.Symbol</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='MultiPath']" name="extends">com.esri.core.geometry.Geometry</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='MultiPath']" name="extends-generic-aware">com.esri.core.geometry.Geometry</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='MultiPoint']" name="extends">com.esri.core.geometry.Geometry</attr> <attr path="/api/package[@name='com.esri.core.geometry']/class[@name='MultiPoint']" name="extends-generic-aware">com.esri.core.geometry.Geometry</attr> <attr path="/api/package[@name='com.esri.core.tasks.ags.geocode']/class[@name='LocatorGeocodeResult']" name="extends">java.lang.Object</attr> <attr path="/api/package[@name='com.esri.core.tasks.ags.geocode']/class[@name='LocatorGeocodeResult']" name="extends-generic-aware">java.lang.Object</attr> </metadata>
Thanks @ShawnCastrianni, Unfortunately I'm still getting build errors and hundreds of warnings with this metadata. I did manage to mangle it yesterday to build, but it crashed spectacularly at runtime.
Can I ask you, which .jars have you included in the project. I have the 5 I mentioned above - do you have the same, with the same build actions?
Do you have to include any of the .so files ? sorry for the really noob questions, if I could have picked an easier first binding project I would have
Cheers,
Greg
same problem here.
arcgis-android-api.jar arcgis-android-app-framework.jar
as embedded jars,
and
jackson-core-lgpl-1.9.5.jar, jackson-mapper-lgpl-1.9.5.jar and jcifs-1.3.17.jar as embedded reference jars
to an Android Java Bindings Library.
Lot of errors when building.
Hours spent tweaking metadata.xml.
when I get back to my computer, I will post a more detailed answer. however, it will be based on esri 10.1.1. if you guys are trying to get 10.2 to work, that could explain all of your errors. could you guys try 10.1.1 instead to see if you can get that to work in the meantime until I get back to my computer. I can attach my csproj file.
Is it possible to download 10.1? I had a look last night but missed it.
Interesting. It looks like ESRI has created a whole new page for Android SDK. The new one has the link to 10.2, but the old one is still up and contains all the previous downloads, including 10.1.1 u1. Here is a direct link:
downloads.esri.com/secure/FE33D4997D59028602DEB3B3AC4F87EB/0D3F0765CE469F9E4C77C98023907DE1/528BED67/ArcGISAndroidSDK_v10.1.1-u1.zip
If that direct link doesn't work, here is a top level page that will reveal a link to 10.1.1
resources.arcgis.com/en/communities/runtime-android/
Here are step by step instructions for getting 10.1.1 u1 to work:
I have attached a zip of my solution with both projects below. I have deleted all the ESRI files since I am not allowed to redistribute those.
Here is a zip of my solution for the above steps.
@ShawnCastrianni, I have to say, "OMG", thank you. I will be checking this out as soon as I can.
@ShawnCastrianni, I haven't got access to 10.1 yet (I will have to wait until tomorrow when I can get the password for the esri site), but I have got it to build using a version 2 .2 of the sdk. Thanks.
Did it crash spectacularly at runtime this time or can you get a test application like my attached zip file to work?
No, I think I'll have to try with 10.1 - I get an initialisation error. The spectacular runtime crash I hit before was actually a build error (Java heap), once I figured that out the build worked. I'm on my way to work where I can get 10.1 and will try again.
@ShawnCastrianni, I've got it all working now - my issue with v2 was that I forgot to check the build action when I added the different .so files. I now have it working with 10.1 - thanks a heap for your help.
Cheers.
I have downloaded this example but it says "Could not find android.jar for API level 18".
I need it to work for API level 15. Will it work?
Has anyone been able to find a way to get version 10.2 of the SDK working with Xamarin?
I will be upgrading to 10.2 in a few days. I will post my solution here when done.
I have had some success getting Xamarin working with 10.2. I don't know how good of a solution this is, as I have only done basic testing, but here is the Metadata.xml file attached.
I haven't fully tested this yet, but I went through my procedure to get 10.2 to compile. Below is my metadata.xml file. It is similar to FrankSmith's but I think it doesn't remove as much as his. I actually need the query and renderer stuff so I did not remove all of that as he did. Also, I will not bother posting the full solution zip since the procedure is the same as my lengthy post except:
Here is the metadata.xml file:
Thanks, Shawn, for the improved version.
-Frank
I have been trying to get ESRI 10.2 working with an Android application and all the above has been very useful, so thank you!
But... I'm using Visual Studio 2012 and it seems as if the binding project isn't being created correctly. I add it as a reference to my Android application but it doesn't pick up "Com.Esri.Android.Map.xxx" (it thinks the reference is missing). I also try to open the reference in the object browser, but it doesn't expand out.
If I create the binding project using Xamarin Studio and then add it to my VS2012 application everything works fine. So it suggests there's a problem creating the binding project in Visual Studio.
I've tried creating the binding project in VS2010 too and use .Net 3.5, 4.0 and 4.5, but still no joy.
Any ideas?
Thanks,
Thank you Shawn for your work here!
Got it in just a couple of Minutes THANKS GUYS!
Shawn;
I'm hoping you (or someone else) can help? I'm fairly new to Xamarin and trying to figure out how to use Esri on an Android device.
I've downloaded your sample application and included the necessary ArcGIS files. Everything compiles just fine, but it blows up at run time on both the Arm Emulator and my Samsung S3.
It crashes here:
It crashes on the last line of that method (JNIEnv.FinishCreateInstance)
with this error:
04-14 14:17:20.790 W/ContextImpl(11683): Unable to create external cache directory An unhandled exception occured.
I am not so sure the "Unable to create external cache directory" is an actual error. If you use DDMS to view the entire device log, do you see anything else useful? Maybe you can attach your full log to a post and myself or someone else can spot something.
I'm unfamiliar with the DDMS tool. I did use the Android Debug Bridge to check out the log and here are my results (filtered):
Command: adb logcat MonoDroid-Debugger:D monodroid-gc:D Mono:W dalvikvm:W mono-rt:V *:S
Also, the exception that I'm getting is this:
The code is throwing an exception on this line in the Com.Esri.Android.Map.MapView.cs file:
If you followed all the steps in my post, then I am not sure at the moment. Maybe something you can try in the short term is to switch to android-17 (4.2.2). I can see from your logcat that you are using android-19. I have my app running with esri against android-17 so maybe something in the android sdk changed that makes esri not compatible with android-19. I doubt this is the answer, but is something to try. When I get a chance, I will try my test program against 19 and see what happens.
With this new information, I would double check the Build Action in your Xamarin project of all of the ESRI native files, both jars and so's. libruntimecore_java.so should be AndroidNativeLibrary, arcgis-android.*.jar should be EmbeddedJar, all other jars should be EmbeddedReferenceJar. The total number of jars should be 5. 2 esri specific and 3 extra dependency jars.
This step is very easy to forget so that is why I suggest double checking. When Java loads a class, it must also locate all dependent classes which would come from these extra 3 jars so if they are not marked with EmbeddedReferenceJar, they probably can't be found at runtime.
I downloaded your sample project linked in this thread. Added the 10.1.1 esri jar files and the two .so files. I'm trying to run this on both a real device (Samsung S3) and the google emulator(ARM).
In the Core project under Jars
In the Android Project under Assets
I just triple checked these to make sure I didn't miss the settings and they are correct.
Also - I just tried API 17 - still a no go.
For ESRI 10.1.1, that all sounds correct. I have never tested ESRI 10.1.1 with android-19, so I would still try android-17 just to see what happens. For ESRI 10.2, they have a different set of jars so my previous post before this one says how to set the BuildAction for those 5 jars.
Unfortunately, nothing you have said sounds wrong. Until I get a chance to try a few things, my only short term suggestion is android-17.
Android API Level 17 didn't help - I get the exact same crash.
I've posted on S/O - maybe someone else can help and/or benefit if a solution is found. I'm sure I must be doing something wrong - since so many people here have it working, I just wish I knew what!
http://stackoverflow.com/questions/23092347/binding-arcgis-esri-sdk-in-xamarin-android
I tried running the solution in Xamarin Studio (instead of VS2013) and I got a different exception:
no method with name='requestRender' signature='(Z)V' in class Lcom/esri/android/map/MapSurface;
Here's the stack trace:
Just tried to bind the latest version of the SDK (10.2.3) and to make it work I had to add the following line to the Metadata.xml file
<remove-node path="/api/package[@name='com.esri.core.tasks.query']/class[@name='OutStatistics']" />
For some reason when tested in GenyMotion the screen stays black, or just displays a grid. It's working fine on a phisycal device anyway.
As a reminder, remember to add the right permissions to the app manifest!
Hi to everyone,
I successfully created an Android esri map project using latest 10.2.3 release. Everything seems to work just fine except from the esri map events like esriMap.OnLongPressListener. How can i use this listener from c#?
Thanks