Skip to content

Bindings via Gradle/Maven? #4528

Description

@jonpryor

It would be "interesting"/cool if, instead of binding a .jar or .aar file, we could instead bind a gradle or maven "artifact name" and all dependencies within one binding project.

Is this at all practical or possible?


jpobst:

I've been giving this some thought recently, and maybe we should do less automatically for the user (since that's where the dragons live), and focus first on helping the user ensure they are creating correct bindings.

TL:DR

We will initially focus on tackling two pain points of binding from Maven:

  • Acquiring the .jar/.aar and the related .pom from Maven
  • Using the .pom to verify that required Java dependencies are being fulfilled

Let's take an example: Square's okhttp3 version 4.10.0 available in Maven.

Editor's note: we have an official binding for this library, but for the sake of an example.

Target Package

For the sake of simplicity, let's work from Maven directly instead of gradlew:

// Include is {group}:{id} because it has to be unique
// We can start with supporting Central and Google, maybe a URL if that's all we need for unauthenticated repositories
// Repository default is "Central", Bind and Pack default is "True", shown for completeness

<MavenAndroidLibrary Include="com.squareup.okhttp3:okhttp" Version="4.10.0" Repository="Central" Bind="True" Pack="True" />

With this information, we can use MavenNet to download:

We can also allow this to come from somewhere on the file system if the user provides a .jar/.aar and a .pom:

// Syntax is debatable
<LocalAndroidLibrary Include="com.squareup.okhttp3:okhttp" Version="4.10.0" Package="okhttp-4.10.0.jar" Pom="okhttp-4.10.0.pom" />

Because we are retrieving a .pom, we can start to do some dependency work for the user with a custom MSBuild task, and if they compile at this point they will receive the following build errors:

Error XA0000: Dependency 'com.squareup.okio:okio-jvm' version '3.0.0' not satisfied.
Error XA0000: Dependency 'org.jetbrains.kotlin:kotlin-stdlib' version '1.6.20' not satisfied.

Dependencies

In our example above, we saw that we can prevent the user from missing dependencies by requiring a .pom file. Dependencies can be fulfilled in 4 ways:

  • NuGet <PackageReference>
  • Included in this binding via <MavenAndroidLibrary> or <LocalAndroidLibrary>
  • Another bindings project <ProjectReference>
  • Explicitly ignored

NuGet <PackageReference>

Automatically finding matching NuGet packages is out of scope, but no matter how they get here, we can validate that they meet the required dependency. This is the preferred mechanism because it uses a single canonical package and won't cause multiple versions of Java artifacts to conflict in our application. Additionally, NuGet packages have already taken care of transitive dependencies, so the user doesn't need to worry about them.

We definitely have a package for Kotlin Stdlib >= 1.6.20, so let's use that:

<PackageReference Include="Xamarin.Kotlin.StdLib" Version="1.7.10" />

Ideally, we'll use package metadata or a metadata file inside the package to tell us the Java version that this package binds (1.7.10). This will appease our tooling and when the user rebuilds, the Kotlin dependency error will disappear.

We can also allow the user to manually specify what Java dependency a NuGet package fulfills if needed:

// Q: Will VS tooling preserve our metadata if it updates the package?
<PackageReference Include="Xamarin.Kotlin.StdLib" Version="1.7.10" JavaArtifact="org.jetbrains.kotlin:kotlin-stdlib" JavaVersion="1.7.10" />

Included in this binding via <MavenAndroidLibrary> or <LocalAndroidLibrary>

If there isn't a NuGet package for our Java dependency, we can use the same mechanism to add an additional artifact to this project:

// Bind = false if we don't need a C# binding for this one
<MavenAndroidLibrary Include="com.squareup.okio:okio-jvm" Version="3.2.0" Repository="Central" Bind="False" Pack="True" />

Unlike NuGet packages, this package's dependencies are not covered, so adding this package adds new dependency errors:

Error XA0000: Dependency 'org.jetbrains.kotlin:kotlin-stdlib-jdk8' version '1.6.20' not satisfied.
Error XA0000: Dependency 'org.jetbrains.kotlin:kotlin-stdlib-common' version '1.6.20' not satisfied.

These will now need to be resolved too.

Another bindings project <ProjectReference>

The user could also have a <ProjectReference> to another Android Bindings library that fulfills a dependency.

<ProjectReference Include="../okio/okio.csproj" JavaArtifact="com.squareup.okio:okio-jvm" JavaVersion="3.2.0" />

TODO: Would the user need to specify JavaArtifact and JavaVersion or could we fish it out of the project somehow?

In this scenario, transitive dependencies would not be checked, the referenced project is expected to take care of itself.

Explicitly ignored

Sometimes the user knows better than us (or thinks they do), and we should allow them to explicitly ignore a dependency.

<MavenIgnoredDependency Include="com.squareup.okio:okio-jvm" Version="3.2.0" />

Benefits

Updateable

Unlike a "build it once" system, when a new version of the package is released the user simply needs to change the version number:

<MavenAndroidLibrary Include="com.squareup.okhttp3:okhttp" Version="5.0.0" />

If the new version needs newer dependencies, the user will be required to update them rather than be allowed to build a package with bad dependencies.

Error XA0000: Dependency 'com.squareup.okio:okio-jvm' version '4.0.0' not satisfied.

Extensible

This system currently avoids the dragons of "find dependencies for the user", but that could be added later when we think we've solved it. The dependency verification outlined here would still be essential in that scenario as well.

Simpler?

Does not involve gradlew or Android Studio.

Limitations

  • Authenticated Maven feeds are out of scope and will not be usable.

Activity

  1. transferred this issue fromdotnet/java-interopon Apr 6, 2020
  2. added
    Area: BindingsIssues in Java Library Binding projects.
    enhancementProposed change to current functionality.
    on Apr 6, 2020
  3. added this to the Under Consideration milestone on Apr 6, 2020
  4. JonDouglas commented on Apr 15, 2020

    @JonDouglas
    Contributor

    @jonpryor That's something @EgorBo did awhile back:

    https://github.com/EgorBo/Xamarin.GradleBindings

    https://marketplace.visualstudio.com/items?itemName=EgorBogatov.XamarinGradleBindings

    It's definitely something we hear from users often.

    In other words, a tool that could generate a binding project based on a maven package & it's dependencies.

    How feasible is it to create a binding project that gets a user say 90% the way there with their Metadata.xml to just consume in a project?

  5. bramborman commented on May 3, 2020

    @bramborman

    Was just going to open an issue about the same feature and found this.. I really miss the VS extension as it doesn't support VS 2019 but having the functionality built-in would be much better.

    The think I missed in the extension however was that it was just for generating a new binding project. There was no way (or I didn't find it) to update the .jar or .aar after the binding project was created. So if I was to maintain a binding library, when an update to the underlying native lib would come, I'd have to recreate the project or find another way to get the updated versions of these files after the project was created (which I found kinda hard compared to for example NuGet)...

    So the imo best approach for this would be to make it work similarly to how NuGets are consumed by adding an MSBuild item like <GradleReference Include="GradleLibName" Version="1.2.3" />. Of course a graphical package manager similar to the NuGet one would be great, but at least such support to easily reference (and update by changing the version attribute) would be a huge step forward 😊.

  6. jaceDeng commented on Apr 6, 2021

    @jaceDeng

    GradleReference is a good idea. Before I bind such a library, I had to download all gradle dependent AAR or jar files. If we do this through msbuild, I think it will greatly reduce our work of binding Android library.

  7. self-assigned this
    on Sep 13, 2022
  8. MagicAndre1981 commented on Sep 13, 2022

    @MagicAndre1981

    here is also a similar thing:

    IKVM.Maven.Sdk - IKVM support for Maven dependencies
    https://github.com/ikvm-revived/ikvm-maven#ikvmmavensdk---ikvm-support-for-maven-dependencies

    IKVM.Maven.Sdk is a set of MSBuild extensions for referencing Maven artifacts within .NET SDK projects.

  9. jpobst commented on Sep 13, 2022

    @jpobst
    Contributor

    Interesting IKVM link. This is what I'm currently considering: #5352 (comment).

    Moved above ^^

  10. tuyen-vuduc commented on Jun 22, 2023

    @tuyen-vuduc

    This is a good idea. However, I think if .NET for Android can run as a part of the gradle process, it'll be much better. The same way that Flutter/RN do its job. We don't have to bind everything if we don't need to.

    I am in process of building my library to support resolve native libraries using Gradle, so we don't have to embed them within the nuget packages.

    ETA: July 2023

  11. tuyen-vuduc commented on Jul 20, 2023

    @tuyen-vuduc

    Forks, I finally made my approach public for everyone to use and enhance.

    Please check it out here.

    P/S: Sorry for no documentation yet, I am going to publish a how-to post in next few days.

  12. jpobst commented on Jul 25, 2023

    @jpobst
    Contributor

    I don't guess I ever posted a link on this issue. Here is the prototype of the approach mentioned in the issue description:
    https://github.com/jpobst/Prototype.Android.MavenBindings

  13. tuyen-vuduc commented on Jul 25, 2023

    @tuyen-vuduc

    @jpobst I checked your link previously, but it doesn't leverage Gradle yet. By downloading manually ourself, we recreate the wheel. Your prototype will far from complete if you also want to have maven repository authentication as well.

    In my findings, many dependencies aren't even listed in POM, but still understood by gradle when building using Android Studio :D . Xamarin.Android/.NET Android has to adopt.

  14. changed the title [-]Bindings via Gradle/Maven?[/-] [+]Bindings via Gradle/Maven? (Part 1)[/+] on Oct 19, 2023
  15. changed the title [-]Bindings via Gradle/Maven? (Part 1)[/-] [+]Bindings via Gradle/Maven?[/+] on Oct 19, 2023
  16. tuyen-vuduc commented on Feb 5, 2024

    @tuyen-vuduc

    I found that we have a great progress to have a new CSPROJ item to include a native lib from a Maven repo directly. However,

    • we have to use .NET9 to enable that feature
    • we cannot use a Maven repository protected with credentials

    I managed to create my own NuGet package, Dependency.Gradle which we can use Gradle to download the dependencies for us and already use that one for all my recent binding libraries which can be found the source in the repo Dotnet Binding Utils.

    I believe by using Gradle, it's much better and more aligned with the Android native.

  17. locked and limited conversation to collaborators on Apr 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

Area: BindingsIssues in Java Library Binding projects.enhancementProposed change to current functionality.

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions