dotnet / android

.NET for Android provides open-source bindings of the Android SDK for use with .NET managed languages such as C#
MIT License
1.94k stars 533 forks source link

Bind library that uses Java 11 source code #6142

Closed 4brunu closed 7 months ago

4brunu commented 3 years ago

Hi,

Since Android Studio Gradle Plugin, it's possible to use some Java 11 source code in all Android versions https://developer.android.com/studio/releases/gradle-plugin#java-11

Is it possible to bind a native android library (.aar), that uses Java 11 source code?

I tried to create a native android library and deployed it in a sample project to Android 5.1.

public class JavaElevenAPI {

    public static String stringTest() {

        var arrInteger = new Integer[]{5, 9, 3, 6, 2, 4, 8, 7, 1};
        long cnt = Arrays.stream(arrInteger).filter(
                (@NotNull var a) -> (a != null && a > 5)).count();
        System.out.println(cnt);

        return Long.toString(cnt);
    }
}

Is Android Studio with the native library and the native app, everything worked as expected.

When binding the native library in Xamarin, it builds, but it cashes in runtime with the following error.

java.lang.NoSuchMethodError
No static method stream([Ljava/lang/Object;)Ljava/util/stream/Stream; in class Ljava/util/Arrays; or its super classes (declaration of 'java.util.Arrays' appears in /system/framework/core-libart.jar)

For this to work, it's necessary to use in conjunction with Core Library Dessugaring. https://developer.android.com/studio/write/java8-support#library-desugaring

Since coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' doesn't exist in Xamarin, I added that library as a dependency.

Is there any way to solve this? Is this supported in Xamarin?

Thanks

jpobst commented 3 years ago

Did adding coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' as a dependency fix the issue?

4brunu commented 3 years ago

No.

But actually, now that you are mentioning this, I made some more tests, and I think the problem is related to coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' that work in some cases just by adding the dependency, like java.time but not with streams for example. On the other hand, Java features, like java 10 var, works!

public class JavaElevenAPI {
    public static String stringTestVar() {
        // var - java 10 feature - works!
        // doesn't need coreLibraryDesugaring
        var arrInteger = new Integer[]{5, 9, 3, 6, 2, 4, 8, 7, 1};

        return Long.toString(arrInteger[3]);
    }

    public static String stringTestArrays() {
        // streams - coreLibraryDesugaring - doesn't work!
        // should work with coreLibraryDesugaring
        // No static method stream([Ljava/lang/Object;)Ljava/util/stream/Stream; in class Ljava/util/Arrays; or its super classes (declaration of 'java.util.Arrays' appears in /system/framework/core-libart.jar)

        var arrInteger = new Integer[]{5, 9, 3, 6, 2, 4, 8, 7, 1};
        long cnt = Arrays.stream(arrInteger).filter(
                (@NotNull var a) -> (a != null && a > 5)).count();
        System.out.println(cnt);

        return Long.toString(cnt);
    }

    public static String stringTestOffsetDateTime() {
        // java.time introduced in java 8, works in all Android API level with coreLibraryDesugaring! 
        return OffsetDateTime.now().toString();
    }
}

So the issue seems to be related to coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'.

jpobst commented 3 years ago

It looks like the com.android.tools:desugar_jdk_libs:1.1.5 library contains the stream method:

image

However your error message indicates it is looking for Arrays.stream (Object[]) when it needs to be looking for DesugarArrays.stream (Object[]), so it seems like the desugar process is missing it.

Perhaps the r8 we ship is too old. We can see if bumping it to the latest helps: https://github.com/xamarin/xamarin-android/pull/6149.

jonpryor commented 3 years ago

Related: https://github.com/xamarin/xamarin-android/issues/4574#issuecomment-615363285

Aside/snark: desugaring is a process wherein you take Java byte code that our JNI-based binding infrastructure can deal with, and possibly turn it into something that our binding infrastructure doesn't deal with.

Thus the question: can we deal with it?

I think an approach would be to extend Java.Interop.JniPeerMembers to "know about" these related types, e.g. Desugar prefix, $-CC suffix, and update JniPeerMembers.JniStaticMethods.GetMethodInfo() so that if Members.JniPeerType.GetStaticMethod() throws, we try to lookup the method on one of the "related" types.

I'm not entirely fond of that idea from a performance perspective, nor am I entirely sure it'll work, but it's something to try, maybe?

4brunu commented 3 years ago

That explains why adding com.android.tools:desugar_jdk_libs:1.1.5 has a dependency allows the usage of java.time in old Android versions, because for example OffsetDateTime has the original name.

4brunu commented 2 years ago

@jonpryor Hi, Since https://github.com/xamarin/java.interop/issues/867 is now closed, is this issue also fixed? Is any extra step necessary to integrate with Java 11 API and com.android.tools:desugar_jdk_libs:1.1.5? Thanks

jtorvald commented 1 year ago

Any update on this? We are unable to upgrade the Twilio Bindings for https://github.com/xamarin-bindings-for-twilio/TwilioVideoXamarinAndroid/

We need to be able to create new bindings because there is a security alert in Google Play: "Security - Vulnerable WebRTC Versions "

codeanees commented 1 year ago

@jonathanpeppers @jamesmontemagno @jonpryor @jpobst Any update on this issue? This is something show stopper for us to use Twilio.Video binding library. Please expedite the same to fix the issue.

jpobst commented 7 months ago

We believe desugar remapping is now fully supported in net8.0-android and beyond.

https://github.com/xamarin/java.interop/pull/1077