-
Notifications
You must be signed in to change notification settings - Fork 64
[Hello-NativeAOTFromAndroid] Add NativeAOT+Android sample #1218
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
b23d06e to
886852f
Compare
27c79dc to
fe45822
Compare
Context: 2197579 Commit 2197579 added `samples/Hello-NativeAOTFromJNI`, which demonstrated the use of NativeAOT to create a native library which could be loaded and used by a Java application. What else supports loading native libraries for use by a "Java" environment? Android! Take the core infrastructure from `Hello-NativeAOTFromJNI`, have the binary output target `linux-bionic-arm64` -- the `$(RuntimeIdentifier)` for .NET using Android's "bionic" libc while *not* using .NET for Android -- and then use `gradlew` to package that native library into an Android application. Add "degrees" of Android and Gradle Integration: * `samples/Hello-NativeAOTFromAndroid/app` is an Android project with Gradle build scripts. * `gradlew :app:processReleaseResources` is executed as a pre-build step to get an `R.txt` describing all the Android Resources contained within the Android project. The new `<ParseAndroidResources/>` task parses `R.txt` and generates an `R.g.cs`, allowing C# code to reference some Android resources, such as the Android layout to display. * `android.xml` contains a (very!) minimal API description of `android.jar`. It is used in a pre-build step to produce bindings of `android.app.Activity` and `android.os.Bundle` (among others), allowing us to write a C# subclass of `Activity` and show something on-screen. * After the C# build, we: * use `jcw-gen` to generate Java Callable Wrappers (JCW) of `Java.Lang.Object` subclasses, * use `jnimarshalmethod-gen` to generate JNI marshal methods for methods such as `MainActivity.OnCreate()`, so that C# code can override Java methods. * As a post-`Publish` step, we copy various artifacts into the Android project structure so that they can be packaged into the Android `app-release.apk`, then invoke `gradlew assembleRelease` to generate `app-release.apk`. Update `generator` to support using `Java.Base.dll` as a referenced assembly for binding purposes, in particular by supporting the use of `[JniTypeSignatureAttribute]` on already bound types. No usable bindings of types in `android.xml` could be generated without this. Update `jcw-gen` to appropriately support `[JniTypeSignature(GenerateJavaPeer=false)]` when determining the constructors that a Java Callable Wrapper should contain. Failure to do so meant that the JCW for `MainActivity` contained constructors that shouldn't be there, resulting in `javac` errors. Update `jcw-gen` to and support `JavaInterop1`-style method overrides. Failure to do so meant that the JCW for `MainActivity` *didn't* declare an `onCreate()` method.
fe45822 to
f937715
Compare
jonathanpeppers
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall, nothing seems too concerning. 👍
| [UnmanagedCallersOnly (EntryPoint="Java_net_dot_jni_nativeaot_JavaInteropRuntime_init")] | ||
| static void init (IntPtr jnienv, IntPtr klass) | ||
| { | ||
| Console.WriteLine ($"C# init()"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you wanted to remove:
| Console.WriteLine ($"C# init()"); | |
| Console.WriteLine ("C# init()"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The C# compiler is able to optimize the former into the latter, meaning there isn't a reason to not use $"…" strings everywhere. This has the added benefit that you don't need to remember to add $ to your strings when you do want to use formatted strings, which is something I occasionally forget…
| method = bmethod; | ||
|
|
||
| if (method.AnyCustomAttributes (typeof (RegisterAttribute))) { | ||
| if (GetMethodRegistrationAttributes (method).Any ()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this called by xamarin-android at all?
Just want to make sure we wouldn't make this too much worse:
I guess this could create an attribute instance, an IEnumerable, and then call .Any().
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes this codepath is used by .NET for Android, in which case the problem with this change is that it could introduce additional object allocations that aren't needed. I'll look into updating this.
Don't ignore the IL2026 warning; it isn't even emitted! "Optimize" `CecilExtensions.GetBaseRegisteredMethod()` to avoid unnecessary object allocations by adding a new `CecilExtensions.HasMethodRegistrationAttributes()` method.
Changes: dotnet/java-interop@4e893bf...78d5937 * dotnet/java-interop@78d59371: [Hello-NativeAOTFromAndroid] Add NativeAOT+Android sample (dotnet/java-interop#1218) Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Context: 2197579
Commit 2197579 added
samples/Hello-NativeAOTFromJNI, whichdemonstrated the use of NativeAOT to create a native library which
could be loaded and used by a Java application.
What else supports loading native libraries for use by a "Java"
environment? Android!
Take the core infrastructure from
Hello-NativeAOTFromJNI, havethe binary output target
linux-bionic-arm64--the
$(RuntimeIdentifier)for .NET using Android's "bionic" libcwhile not using .NET for Android -- and then use
gradlewtopackage that native library into an Android application.
Add "degrees" of Android and Gradle Integration:
samples/Hello-NativeAOTFromAndroid/appis an Android projectwith Gradle build scripts.
gradlew :app:processReleaseResourcesis executed as a pre-buildstep to get an
R.txtdescribing all the Android Resourcescontained within the Android project. The new
<ParseAndroidResources/>task parsesR.txtand generates anR.g.cs, allowing C# code to reference some Android resources,such as the Android layout to display.
android.xmlcontains a (very!) minimal API description ofandroid.jar. It is used in a pre-build step to produce bindingsof
android.app.Activityandandroid.os.Bundle(among others),allowing us to write a C# subclass of
Activityand showsomething on-screen.
After the C# build, we:
jcw-gento generate Java Callable Wrappers (JCW) ofJava.Lang.Objectsubclasses,jnimarshalmethod-gento generate JNI marshal methodsfor methods such as
MainActivity.OnCreate(), so thatC# code can override Java methods.
As a post-
Publishstep, we copy various artifacts into theAndroid project structure so that they can be packaged into the
Android
app-release.apk, then invokegradlew assembleReleaseto generate
app-release.apk.Update
generatorto support usingJava.Base.dllas a referencedassembly for binding purposes, in particular by supporting the use
of
[JniTypeSignatureAttribute]on already bound types. No usablebindings of types in
android.xmlcould be generated without this.Update
jcw-gento appropriately support[JniTypeSignature(GenerateJavaPeer=false)]when determining theconstructors that a Java Callable Wrapper should contain. Failure to
do so meant that the JCW for
MainActivitycontained constructorsthat shouldn't be there, resulting in
javacerrors.Update
jcw-gento and supportJavaInterop1-style method overrides.Failure to do so meant that the JCW for
MainActivitydidn'tdeclare an
onCreate()method.