Xamarin.Android binding to third party SDK with dependencies

I am using VS2015 Update3 with current / updated Xamarin, and am trying to create a binding library to wrap a third party SDK written in Java. I have a C # /. NET background, with little Java experience so far. This SDK depends on 3 other items that are available as AAR or via NuGet.

I was able to create a binding library for the parent AAR with some MetaData.xml tweak to tweak the parameter and return types and patch the accessor class to satisfy its abstract base class, all of which originally prevented the C # .Net Android library binding from building. Now the parent assembly of assemblies builds but cannot execute as it requires other 3 AAR dependencies.

Required dependencies ("#" is an alias for each, mentioned in the post below):

  • "2" β†’ com.android.support:support-v4:25.1.1
  • "3" β†’ com.google.android.gms: play-services-location: 10.2.0
  • "4" β†’ com.google.android.gms: play-services-gcm: 10.2.0

In this case, if I need to create a binding dll to port the parent AAR, which depends on 3 other AARs:

Should I (A) create 4 binding assemblies - the parent assembly Bind_AAR_1.dll, which depends on Bind_AAR_2.dll, Bind_AAR_3.dll and Bind_AAR_4.dll?

OR, should I (B) dig into 2, 3 and 4 AAR files and get the JAR file from each and include them in Bind_AAR_1.dll directly in the Jars folder using "EmbeddedJar" (or some other attribute / setting)?

OR, seeing that 2, 3, and 4 are indeed available via NuGet, should I (C) reference them in the Bind_AAR_1 project using NuGet? Will Javacode in AAR 1 be able to see the code in AAR 2, 3 and 4 if I use NuGet to link / include them?

I've tried variations for each of methods (A), (B), and (C) without getting any luck yet, or a work output that results in more work, which leaves me wondering what is the best / correct way to do this.

As for the related question, is it better to use a Metadata.xml file to explicitly remove everything (classes, etc.) from the resulting generated wrapper API that you don't directly plan to use in your Xamarin project? It looks like it would be nice to restrict the interface and maybe also reduce the build size (and possibly build time) of the binding dlls.

Any help would be appreciated!

Curtis

=============================================== === ======================

4/11/2017 - Update

I am very glad that you have posts from @_JonDouglas! but ... still not able to get this SDK to work.

I tried each of these methods A, B and C and was able to create a binding project (with manipulations done with the /MetaData.xml transform). The third party SDK was developed / documented as part / component in a Java solution. In the vendor documentation, this solution will have 3 dependencies added to its .gradle file, thus providing a reference to these items in the generic Java solution. I have no Java history, so she covers it up here.

Once this happens, when I wrap the SDK (alone or with dependencies using any of the 3 methods) with Visual Studio in the Xamarin Android Binding Assembly, the SDK displays ClassNotFound exceptions at runtime (as indicated by "Google Play not found". "in the logs.) The classes used from the required Java dependencies are created at a later stage using name strings for such class names: try { Class.forName("com.google.android.gms.common.GooglePlayServicesUtil");
//more code here } catch (ClassNotFoundException e) { Log.e("3rd Party SDK", "Google Play not found."); }


It doesn't seem to matter how I create the binding assembly in Visual Studio using any of the three methods above to include the dependency items (1 AAR + 3 Nuget OR 1 AAR + 3 Jars in 1 binding OR 4 AARs in 4 bindings using project links). At runtime, the SDK doesn't seem to see them. Perhaps it makes sense that this won't happen - there is no .gradle (like a csproj file) that points to them in the SDK itself?

I think what I need to do (closer to the vendor team) create a Java solution complete with a .gradle file that includes the SDK as well as 3 dependencies in a Java project, building to generate an AAR file.Then I believe I can create a Xamarin binding node for the resulting AAR. Then I will add a reference to this binding to my .andriod assembly in my solution and continue.

Theory (yet to be proven): [Failed. See Update 4/12 below.] Wrap the Java SDK + its encoded dependencies (explicit in .gradle) in a module / library, and then wrap them in a Xamarin Android binding library. Then all I have to do is figure out which public methods I need to use (and therefore expose) from that wrapper / library module, add those public methods, and forward the calls to the SDK.

Big Picture: I'm trying to develop and code this as a cross-platform Xamarin solution, but I'm working with an Android-specific and IOS-specific SDK that looks to be meant to be part of the app / UI experience (for example, designed for more than just third party link). This aspect of the interface has yet to be reproduced as I haven't seen the SDK features yet.

=============================================== === ======================

4/12/2017 - Update

Theory (FAILED): Wrap the Java SDK + its encoded dependencies (explicit in .gradle) in a module / library and then wrap them in the Xamarin Android binding library. We have coded, built, deployed and tested this. Now I can see that the application is hitting the first level of Java code at runtime, but cannot find any referenced code lower than that (similar dependencies). The wrapper code works fine, but the wrapper at runtime can't find the SDK classes and even the simple Java testing component we tried to use through the wrapper. This is equivalent to the problem we faced with the SDK in the first place where we just created the bindings file for it alone and referenced the rest in the JAR binding assembly or via NuGet. The lower level code is still not found,only the first level of java is executed. Still trying to find a solution.

=============================================== === ======================

4/13/2017 - Update

I've made some progress. One step forward and possibly two steps back, as they say.

Now I understand that the third party SDK needs more Google Play services than just two dependencies. I have decompiled two elements explicitly mentioned and the named class does not exist there. I started exploring the local Android SDK location (as configured in Visual Studio) and found "play-services-6.5.87.AAR". Including this in my binding assembly as EmbeddedResourceJar finally got the SDK code to find the specific class mentioned in the code above.

Using NuGet

I am asking a question about the meaning of the Java wrapper described above since everything needed for dependencies is now included as an EmbeddedReferenceJar. It looks like I should just bind the SDK AAR directly (no Java wrapper layer added). I am rethinking this and trying to create a binding assembly pointing to the AAR SDK in the JARS folder and then enabling Google Play Services using NuGet.

Based on this, (using NuGet to link to Google Play services) I am getting this error: No resource found that matches the given name (at 'value' with value '@integer/google_play_services_version'). {project name} {project path}\AndroidManifest.xml

I have tried many different things to try and get rid of this build time error but no luck.

Don't use NuGet

If I use a JAR file from google play-services-6.5.87.AAR as an inline ResourceJar, I don't get build errors, but I get runtime errors that the SDK cannot find the Android manifest settings. If you have a project like this, am I using Android Manifest correctly? XXX PCL Project --> XXX.Android project <-- My guess is that this is where the AndroidManifest.XML file is located that will be used....? ----> XXX.Android.AARBinding project
------> JARS folder --> 3pVendorSDK.AAR


More digging ....

+3


source to share


2 answers


How I finally got my 3rd Party SD package to work with Xamarin:

Since my solution needs to be cross platform, I have:

  • Assembly: MyApplication (PCL Portable)
  • Assembly: MyApplication.Android
  • Assembly: MyApplication.Android.Binding
    ( Bundling a 3rd party SDK provided as an AAR file)

Compliant .IOS projects / assemblies will follow this naming pattern when we get to that.

Android Binding Assembly

  • Folder for cans
    • Include My3rdParty.AAR File
      Set with Build Action: 'LibraryProjectZip'
  • Folder conversion
    • Metadata.XML - I had to make adjustments to how Visual Studio was supposed to generate the binding code to make sure the types were aligned, etc.
    • I had some methods that returned types that did not display well on .Net, so I used attr elements to set values ​​like "managedType" and "managedReturn".
      Note. You can use more than one attr element in a single method so that it is customized as desired.
    • I had to remove the method (using the remove-node element) that was declared virtual and re-add it to the custom code as an override to satisfy the abstract class definition of its base class.
  • The root folder
    • CustomCode.cs - Re-add one method that needs to be changed from private to public (it was removed via MetaData.xml). (note that the resulting method will be non-functional since it is just an empty stub satisfying the inheritance of the abstract class).

Android Assembly

  • manifesto

    • Lack of accurate / complete SDK documentation. Changes to Sdk manifest information were made here in Android build.
  • Link

    • Add a reference to Android Binding Assembly.
  • Components (NuGet)

    • Since my 3rd party SDK was documenting the dependencies on Google Play services, and I decompiled their code using JD-GUI to check what classes / etc it was trying to use, I added Xamarin.GooglePlayServices.Gcm to this project , not the Binding Assembly project ...

      Note. It was not clear to me in what documentation I would read what level should I contribute depending on the AAR. In one of my many attempts, I followed the path of adding them as a JAR directly (extracted from AAR) to the JARS Assembly JARS folder using the BuildAction of EmbeddedResourceJar. This provided somewhat better runtime results as the required items were found, but it felt ... unwillingly ... It seemed like a recipe for maintenance problems. There must be a better way. Enter NuGet!

      Note. Adding this element results in the following:
    • Xamarin.GooglePlayServices.Base
    • Xamarin.GooglePlayServices.Basement
    • Xamarin.GooglePlayServices.Gcm (the one added via VS Manage NuGet)
    • Xamarin.GooglePlayServices.Iid
    • Xamarin.GooglePlayServices.Tasks
  • Assets

    • My third party SDK used a config.JSON file that needed to be placed here so it could read it at runtime.
      Set with Build Action: "AndroidAsset
  • Build time Additional work:

    • Additional MetaData.XML changes in the Binding Assembly.
      - Some of the generated code had new build errors that occurred at this point when the compiled linking assembly was referencing an Android assembly and a build was attempted.


Assembly Binding Transformation

As stated above, when I built MyApplication.Android.Binding it built perfectly on its own. However, when I referenced it in MyApplication.Android, it generated a new Java code translation build error about the scope of a certain class that does not match what is expected / required. To solve this problem, I went back to the MetaData.xml assembly in the Binding assembly and decided to remove the problem class from the generated Java code interface as I had no plans to call or use.

ADVICE. The easiest way to do this (I found) in Visual Studio is to enable the Show All Files feature in the BindingAssembly project and then browse in the obj \ Debug \ generated \ src \ folders for the problematic class. When you find it, click on it and the generated Java interface code contains XPath statements generated as comments. This is what you need to either change or remove problem classes or methods using the MetaData.XML file.

Wrap-Up

Now all I have to do is write my cross-platform code from above (using Dependency Inversion + Xamarin Forms built-in DependencyService to access each SDK at runtime) and my app should be good to go!

We hope these findings help others who should work with a similar binding scenario.

If you see any content here that is incorrect, or if you have anything you would like to add, please comment!

+4


source


You should be able to do # 3 which you just reference the prebuilt NuGet packages of these existing GPS / support library bindings.

Please make sure you are using the exact version that the binding library expects as google moves the classes all the time.

My personal recommendation is as follows in order of difficulty (easy β†’ hard):



  • NuGet package
  • EmbeddedReferenceJar

    / ReferenceJar

    .jar

    or classes.jar

    (use LibraryProjectZip

    if there is resorption)
  • Linking projects for each dependency

As a best practice, yes, you should use <remove-node>

for items that you won't be using. However, this is mostly used when errors are generated by code that you will not use in the first place. I would just keep things around regardless of here, unless there are quite a few methods that you will never touch, so you can keep your dexcount in mind.

For more help, you can view the bindings guide: https://gist.github.com/JonDouglas/dda6d8ace7d071b0e8cb

+1


source







All Articles