Skip to content

Commit 78d5937

Browse files
authored
[Hello-NativeAOTFromAndroid] Add NativeAOT+Android sample (#1218)
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.
1 parent 4e893bf commit 78d5937

File tree

45 files changed

+1345
-4
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1345
-4
lines changed
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using Microsoft.Build.Framework;
2+
using Microsoft.Build.Utilities;
3+
using System;
4+
using System.Linq;
5+
using System.IO;
6+
using System.Collections.Generic;
7+
8+
9+
namespace Java.Interop.BootstrapTasks
10+
{
11+
public class ParseAndroidResources : Task
12+
{
13+
public ITaskItem AndroidResourceFile { get; set; }
14+
public ITaskItem OutputFile { get; set; }
15+
public string DeclaringNamespaceName { get; set; }
16+
public string DeclaringClassName { get; set; }
17+
18+
public override bool Execute ()
19+
{
20+
using (var o = File.CreateText (OutputFile.ItemSpec)) {
21+
o.WriteLine ($"namespace {DeclaringNamespaceName};");
22+
o.WriteLine ();
23+
o.WriteLine ($"partial class {DeclaringClassName} {{");
24+
var resources = ParseAndroidResourceFile (AndroidResourceFile.ItemSpec);
25+
foreach (var declType in resources.Keys.OrderBy (x => x)) {
26+
o.WriteLine ($"\tpublic static class @{declType} {{");
27+
var decls = resources [declType];
28+
foreach (var decl in decls.Keys.OrderBy (x => x)) {
29+
o.WriteLine ($"\t\tpublic const int {decl} = {decls [decl]};");
30+
}
31+
o.WriteLine ("\t}");
32+
}
33+
o.WriteLine ("}");
34+
o.WriteLine ();
35+
}
36+
37+
return !Log.HasLoggedErrors;
38+
}
39+
40+
Dictionary<string, Dictionary<string, string>> ParseAndroidResourceFile (string file)
41+
{
42+
var resources = new Dictionary<string, Dictionary<string, string>> ();
43+
using (var reader = File.OpenText (file)) {
44+
string line;
45+
while ((line = reader.ReadLine ()) != null) {
46+
if (line.StartsWith ("#"))
47+
continue;
48+
var items = line.Split (' ');
49+
if (items.Length != 4)
50+
continue;
51+
var type = items [0];
52+
if (string.Compare (type, "int", StringComparison.Ordinal) != 0)
53+
continue;
54+
var decl = items [1];
55+
var name = items [2];
56+
var value = items [3];
57+
if (!resources.TryGetValue (decl, out var declResources))
58+
resources.Add (decl, declResources = new Dictionary<string, string>());
59+
declResources.Add (name, value);
60+
}
61+
}
62+
63+
return resources;
64+
}
65+
}
66+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.gradle
2+
android.xml.fixed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>$(DotNetTargetFramework)</TargetFramework>
5+
</PropertyGroup>
6+
7+
<Import Project="..\..\TargetFrameworkDependentValues.props" />
8+
9+
<PropertyGroup>
10+
<RootNamespace>Java.Interop.Samples.NativeAotFromAndroid</RootNamespace>
11+
<ImplicitUsings>enable</ImplicitUsings>
12+
<Nullable>enable</Nullable>
13+
<PublishAot>true</PublishAot>
14+
<PublishAotUsingRuntimePack>true</PublishAotUsingRuntimePack>
15+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
16+
<NativeLib>Shared</NativeLib>
17+
<RuntimeIdentifier Condition=" '$(RuntimeIdentifier)' == '' ">linux-bionic-arm64</RuntimeIdentifier>
18+
<!-- Needed for cross-compilation, e.g. build linux-bionic-arm64 from osx-x64 -->
19+
<PlatformTarget>AnyCPU</PlatformTarget>
20+
</PropertyGroup>
21+
22+
<ItemGroup>
23+
<!-- https://github.com/exelix11/SysDVR/blob/master/Client/Client.csproj -->
24+
<!-- Android needs a proper soname property or it will refuse to load the library -->
25+
<LinkerArg Include="-Wl,-soname,lib$(AssemblyName)$(NativeBinaryExt)" />
26+
<TrimmerRootAssembly Include="Hello-NativeAOTFromAndroid" />
27+
</ItemGroup>
28+
29+
<ItemGroup>
30+
<ProjectReference Include="..\..\src\Java.Interop\Java.Interop.csproj" />
31+
<ProjectReference Include="..\..\src\Java.Runtime.Environment\Java.Runtime.Environment.csproj" />
32+
<ProjectReference Include="..\..\src\Java.Base\Java.Base.csproj" />
33+
<ProjectReference Include="..\..\src\Java.Interop.Export\Java.Interop.Export.csproj" />
34+
<ProjectReference
35+
Include="..\..\tools\jcw-gen\jcw-gen.csproj"
36+
ReferenceOutputAssembly="false"
37+
/>
38+
<ProjectReference
39+
Include="..\..\tools\jnimarshalmethod-gen\Xamarin.Android.Tools.JniMarshalMethodGenerator.csproj"
40+
ReferenceOutputAssembly="false"
41+
/>
42+
<ProjectReference
43+
Include="..\..\tools\generator\generator.csproj"
44+
ReferenceOutputAssembly="false"
45+
/>
46+
</ItemGroup>
47+
48+
<Import Project="Hello-NativeAOTFromAndroid.targets" />
49+
</Project>
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
<Project>
2+
3+
<UsingTask AssemblyFile="$(MSBuildThisFileDirectory)..\..\bin\Build$(Configuration)\Java.Interop.BootstrapTasks.dll" TaskName="Java.Interop.BootstrapTasks.ParseAndroidResources" />
4+
5+
<PropertyGroup>
6+
<GeneratorPath>$(UtilityOutputFullPath)generator.dll</GeneratorPath>
7+
<_JcwOutputDir>app/src/main/java/my/</_JcwOutputDir>
8+
<_GradleJniLibsDir>app/src/main/jniLibs/arm64-v8a</_GradleJniLibsDir>
9+
<AndroidNdkDirectory Condition=" '$(AndroidNdkDirectory)' == '' ">$(ANDROID_NDK_HOME)</AndroidNdkDirectory>
10+
<AndroidSdkDirectory Condition=" '$(AndroidSdkDirectory)' == '' ">$(ANDROID_HOME)</AndroidSdkDirectory>
11+
</PropertyGroup>
12+
13+
<PropertyGroup>
14+
<_NdkSysrootAbi Condition=" '$(RuntimeIdentifier)' == 'linux-bionic-arm64' ">aarch64-linux-android</_NdkSysrootAbi>
15+
<_NdkClangPrefix Condition=" '$(RuntimeIdentifier)' == 'linux-bionic-arm64' ">aarch64-linux-android21-</_NdkClangPrefix>
16+
<_NdkSysrootAbi Condition=" '$(RuntimeIdentifier)' == 'linux-bionic-x64' ">x86_64-linux-android</_NdkSysrootAbi>
17+
<_NdkClangPrefix Condition=" '$(RuntimeIdentifier)' == 'linux-bionic-x64' ">x86_64-linux-android21-</_NdkClangPrefix>
18+
<_NdkPrebuiltAbi Condition=" '$(NETCoreSdkRuntimeIdentifier)' == 'osx-x64' ">darwin-x86_64</_NdkPrebuiltAbi>
19+
<_NdkSysrootLibDir>$(AndroidNdkDirectory)/toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/sysroot/usr/lib/$(_NdkSysrootAbi)</_NdkSysrootLibDir>
20+
<_NdkBinDir>$(AndroidNdkDirectory)/toolchains/llvm/prebuilt/$(_NdkPrebuiltAbi)/bin</_NdkBinDir>
21+
</PropertyGroup>
22+
23+
<PropertyGroup Condition="$(RuntimeIdentifier.StartsWith('linux-bionic'))">
24+
<CppCompilerAndLinker>$(_NdkBinDir)/$(_NdkClangPrefix)clang</CppCompilerAndLinker>
25+
<ObjCopyName>$(_NdkBinDir)/llvm-objcopy</ObjCopyName>
26+
</PropertyGroup>
27+
28+
<ItemGroup Condition="$(RuntimeIdentifier.StartsWith('linux-bionic'))">
29+
<LinkerArg Include="-Wl,--undefined-version" />
30+
</ItemGroup>
31+
32+
<Target Name="_ValidateEnvironment"
33+
BeforeTargets="Build">
34+
<Error
35+
Condition=" '$(AndroidNdkDirectory)' == '' Or !Exists($(AndroidNdkDirectory)) "
36+
Text="Set the %24(AndroidNdkDirectory) MSBuild property or the %24ANDROID_NDK_HOME environment variable to the path of the Android NDK."
37+
/>
38+
<Error
39+
Condition=" !Exists($(_NdkSysrootLibDir))"
40+
Text="NDK 'sysroot' dir `$(_NdkSysrootLibDir)` does not exist. You're on your own."
41+
/>
42+
<Error
43+
Condition=" '$(AndroidSdkDirectory)' == '' Or !Exists($(AndroidSdkDirectory)) "
44+
Text="Set the %24(AndroidSdkDirectory) MSBuild property or the %24ANDROID_HOME environment variable to the path of the Android SDK."
45+
/>
46+
</Target>
47+
48+
<ItemGroup>
49+
<_GenerateAndroidBindingInputs Include="$(GeneratorPath)" />
50+
<_GenerateAndroidBindingInputs Include="$(MSBuildThisFileFullPath)" />
51+
<_GenerateAndroidBindingInputs Include="Transforms\**" />
52+
<_GenerateAndroidBindingInputs Include="$(IntermediateOutputPath)mcw\api.xml" />
53+
</ItemGroup>
54+
55+
<Target Name="_GenerateAndroidBinding"
56+
BeforeTargets="CoreCompile"
57+
Inputs="@(_GenerateAndroidBindingInputs)"
58+
Outputs="$(IntermediateOutputPath)mcw\Hello-NativeAOTFromAndroid.projitems">
59+
<MakeDir Directories="$(IntermediateOutputPath)mcw" />
60+
<PropertyGroup>
61+
<Generator>"$(GeneratorPath)"</Generator>
62+
<_GenFlags>--public --global</_GenFlags>
63+
<_Out>-o "$(IntermediateOutputPath)mcw"</_Out>
64+
<_Codegen>--codegen-target=JavaInterop1</_Codegen>
65+
<_Fixup>--fixup=Transforms/Metadata.xml</_Fixup>
66+
<_Enums1>--preserve-enums --enumflags=Transforms/enumflags --enumfields=Transforms/map.csv --enummethods=Transforms/methodmap.csv</_Enums1>
67+
<_Enums2>--enummetadata=$(IntermediateOutputPath)mcw/enummetadata</_Enums2>
68+
<_Assembly>"--assembly=$(AssemblyName)"</_Assembly>
69+
<_TypeMap>--type-map-report=$(IntermediateOutputPath)mcw/type-mapping.txt</_TypeMap>
70+
<_Api>android.xml</_Api>
71+
<_Dirs>--enumdir=$(IntermediateOutputPath)mcw</_Dirs>
72+
<_FullIntermediateOutputPath>$([System.IO.Path]::GetFullPath('$(IntermediateOutputPath)'))</_FullIntermediateOutputPath>
73+
<_LangFeatures>--lang-features=nullable-reference-types,default-interface-methods,nested-interface-types,interface-constants</_LangFeatures>
74+
</PropertyGroup>
75+
<ItemGroup>
76+
<_RefAsmDir Include="@(ReferencePathWithRefAssemblies->'%(RootDir)%(Directory).'->Distinct())" />
77+
<_Lib Include="@(_RefAsmDir->'-L &quot;%(Identity)&quot;')" />
78+
<_JavaBaseRef Include="@(ReferencePathWithRefAssemblies)"
79+
Condition=" '%(FileName)' == 'Java.Base' "
80+
/>
81+
<_Ref Include="@(_JavaBaseRef->'-r &quot;%(FullPath)&quot;')" />
82+
</ItemGroup>
83+
<ItemGroup>
84+
<!-- I can't find a good way to trim the trailing `\`, so append with `.` so we can sanely quote for $(_Libpath) -->
85+
</ItemGroup>
86+
<Exec
87+
Command="$(DotnetToolPath) $(Generator) $(_GenFlags) $(_ApiLevel) $(_Out) @(_Lib, ' ') @(_Ref, ' ') $(_Codegen) $(_Fixup) $(_Enums1) $(_Enums2) $(_Versions) $(_Annotations) $(_Assembly) $(_TypeMap) $(_LangFeatures) $(_Dirs) $(_Api) $(_WithJavadocXml)"
88+
IgnoreStandardErrorWarningFormat="True"
89+
/>
90+
<ItemGroup>
91+
<Compile Include="$(_FullIntermediateOutputPath)\mcw\**\*.cs" KeepDuplicates="False" />
92+
</ItemGroup>
93+
<XmlPeek
94+
Namespaces="&lt;Namespace Prefix='msbuild' Uri='http://schemas.microsoft.com/developer/msbuild/2003' /&gt;"
95+
XmlInputPath="$(IntermediateOutputPath)mcw\Hello-NativeAOTFromAndroid.projitems"
96+
Query="/msbuild:Project/msbuild:PropertyGroup/msbuild:DefineConstants/text()" >
97+
<Output TaskParameter="Result" PropertyName="_GeneratedDefineConstants" />
98+
</XmlPeek>
99+
<PropertyGroup>
100+
<DefineConstants>$(DefineConstants);$([System.String]::Copy('$(_GeneratedDefineConstants)').Replace ('%24(DefineConstants);', ''))</DefineConstants>
101+
</PropertyGroup>
102+
</Target>
103+
104+
<Target Name="_CreateJavaCallableWrappers"
105+
Condition=" '$(TargetPath)' != '' "
106+
BeforeTargets="_BuildAppApk"
107+
Inputs="$(TargetPath)"
108+
Outputs="$(_JcwOutputDir).stamp">
109+
<RemoveDir Directories="$(_JcwOutputDir)" />
110+
<MakeDir Directories="$(_JcwOutputDir)" />
111+
<ItemGroup>
112+
<!-- I can't find a good way to trim the trailing `\`, so append with `.` so we can sanely quote for $(_Libpath) -->
113+
<_JcwGenRefAsmDirs Include="@(ReferencePathWithRefAssemblies->'%(RootDir)%(Directory).'->Distinct())" />
114+
</ItemGroup>
115+
<PropertyGroup>
116+
<_JcwGen>"$(UtilityOutputFullPath)/jcw-gen.dll"</_JcwGen>
117+
<_Target>--codegen-target JavaInterop1</_Target>
118+
<_Output>-o "$(_JcwOutputDir)"</_Output>
119+
<_Libpath>@(_JcwGenRefAsmDirs->'-L "%(Identity)"', ' ')</_Libpath>
120+
</PropertyGroup>
121+
<Exec Command="$(DotnetToolPath) $(_JcwGen) &quot;$(TargetPath)&quot; $(_Target) $(_Output) $(_Libpath)" />
122+
<Touch Files="$(_JcwOutputDir).stamp" AlwaysCreate="True" />
123+
</Target>
124+
125+
<Target Name="_AddMarshalMethods"
126+
Condition=" '$(TargetPath)' != '' "
127+
Inputs="$(TargetPath)"
128+
Outputs="$(IntermediateOutputPath).added-marshal-methods"
129+
AfterTargets="_CreateJavaCallableWrappers">
130+
<ItemGroup>
131+
<!-- I can't find a good way to trim the trailing `\`, so append with `.` so we can sanely quote for $(_Libpath) -->
132+
<_JnimmRefAsmDirs Include="@(RuntimePackAsset->'%(RootDir)%(Directory).'->Distinct())" />
133+
</ItemGroup>
134+
<PropertyGroup>
135+
<_JnimarshalmethodGen>"$(UtilityOutputFullPath)/jnimarshalmethod-gen.dll"</_JnimarshalmethodGen>
136+
<_Verbosity>-v -v --keeptemp</_Verbosity>
137+
<_Libpath>-L "$(TargetDir)" @(_JnimmRefAsmDirs->'-L "%(Identity)"', ' ')</_Libpath>
138+
<!-- <_Output>-o "$(IntermediateOutputPath)/jonp"</_Output> -->
139+
</PropertyGroup>
140+
141+
<Exec Command="$(DotnetToolPath) $(_JnimarshalmethodGen) &quot;$(TargetPath)&quot; $(_Verbosity) $(_Libpath)" />
142+
143+
<!-- the IlcCompile target uses files from `$(IntermediateOutputPath)`, not `$(TargetPath)`, so… update both? -->
144+
<Copy SourceFiles="$(TargetPath)" DestinationFolder="$(IntermediateOutputPath)" />
145+
146+
<Touch Files="$(IntermediateOutputPath).added-marshal-methods" AlwaysCreate="True" />
147+
</Target>
148+
149+
<ItemGroup>
150+
<_BuildAppApkInput Include="$(MSBuildThisFileFullPath)" />
151+
<_BuildAppApkInput Include="app\src\main\java\**\*.java" />
152+
<_BuildAppApkInput Include="app\src\main\AndroidManifest.xml" />
153+
<_BuildAppApkInput Include="app\**\build.gradle" />
154+
<_BuildAppApkInput Include="$(NativeBinary)" />
155+
<_BuildAppApkInput Include="$(OutputPath)java-interop.jar" />
156+
</ItemGroup>
157+
158+
<PropertyGroup>
159+
<_AfterBuildDependsOnTargets>
160+
_CreateJavaCallableWrappers;
161+
_AddMarshalMethods;
162+
</_AfterBuildDependsOnTargets>
163+
</PropertyGroup>
164+
165+
<Target Name="_AfterBuild"
166+
AfterTargets="Build"
167+
DependsOnTargets="$(_AfterBuildDependsOnTargets)"
168+
/>
169+
170+
<PropertyGroup>
171+
<_GradleRtxtPath>app\build\intermediates\runtime_symbol_list\release\R.txt</_GradleRtxtPath>
172+
</PropertyGroup>
173+
174+
<Target Name="_BuildRtxt"
175+
BeforeTargets="CoreCompile"
176+
Inputs="@(_BuildAppApkInput)"
177+
Outputs="$(_GradleRtxtPath);$(IntermediateOutputPath)R.g.cs">
178+
<Exec
179+
Command="&quot;$(GradleWPath)&quot; $(GradleArgs) :app:processReleaseResources"
180+
EnvironmentVariables="JAVA_HOME=$(JavaSdkDirectory);APP_HOME=$(GradleHome);ANDROID_HOME=$(AndroidSdkDirectory)"
181+
WorkingDirectory="$(MSBuildThisFileDirectory)"
182+
/>
183+
<ParseAndroidResources
184+
AndroidResourceFile="$(_GradleRtxtPath)"
185+
OutputFile="$(IntermediateOutputPath)R.g.cs"
186+
DeclaringNamespaceName="$(RootNamespace)"
187+
DeclaringClassName="R"
188+
/>
189+
<ItemGroup>
190+
<FileWrites Include="$(IntermediateOutputPath)R.g.cs" />
191+
<Compile Include="$(IntermediateOutputPath)R.g.cs" />
192+
</ItemGroup>
193+
</Target>
194+
195+
<Target Name="_BuildAppApk"
196+
AfterTargets="Publish"
197+
Inputs="@(_BuildAppApkInput)"
198+
Outputs="app/build/outputs/apk/release/app-release.apk">
199+
<MakeDir Directories="$(_GradleJniLibsDir);app/lib" />
200+
<ItemGroup>
201+
<_GradleBuildSource Include="$(NativeBinary)" />
202+
<_GradleBuildTarget Include="$(_GradleJniLibsDir)\lib$(AssemblyName)$(NativeBinaryExt)" />
203+
204+
<_GradleBuildSource Include="$(OutputPath)java-interop.jar" />
205+
<_GradleBuildTarget Include="app\lib\java-interop.jar" />
206+
</ItemGroup>
207+
<Copy
208+
SourceFiles="@(_GradleBuildSource)"
209+
DestinationFiles="@(_GradleBuildTarget)"
210+
/>
211+
<Exec
212+
Command="&quot;$(GradleWPath)&quot; $(GradleArgs) assembleRelease > gradle.log"
213+
EnvironmentVariables="JAVA_HOME=$(JavaSdkDirectory);APP_HOME=$(GradleHome);ANDROID_HOME=$(AndroidSdkDirectory)"
214+
WorkingDirectory="$(MSBuildThisFileDirectory)"
215+
/>
216+
<Copy
217+
SourceFiles="app/build/outputs/apk/release/app-release.apk"
218+
DestinationFiles="$(OutputPath)net.dot.jni.helloandroid-Signed.apk"
219+
/>
220+
</Target>
221+
</Project>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using System.Runtime.InteropServices;
2+
3+
using Java.Interop;
4+
5+
namespace Java.Interop.Samples.NativeAotFromAndroid;
6+
7+
static class JavaInteropRuntime
8+
{
9+
static JniRuntime? runtime;
10+
11+
[UnmanagedCallersOnly (EntryPoint="JNI_OnLoad")]
12+
static int JNI_OnLoad (IntPtr vm, IntPtr reserved)
13+
{
14+
try {
15+
AndroidLog.Print (AndroidLogLevel.Info, "JavaInteropRuntime", "JNI_OnLoad()");
16+
LogcatTextWriter.Init ();
17+
return (int) JniVersion.v1_6;
18+
}
19+
catch (Exception e) {
20+
AndroidLog.Print (AndroidLogLevel.Error, "JavaInteropRuntime", $"JNI_OnLoad() failed: {e}");
21+
return 0;
22+
}
23+
}
24+
25+
[UnmanagedCallersOnly (EntryPoint="JNI_OnUnload")]
26+
static void JNI_OnUnload (IntPtr vm, IntPtr reserved)
27+
{
28+
AndroidLog.Print(AndroidLogLevel.Info, "JavaInteropRuntime", "JNI_OnUnload");
29+
runtime?.Dispose ();
30+
}
31+
32+
// symbol name from `$(IntermediateOutputPath)obj/Release/osx-arm64/h-classes/net_dot_jni_hello_JavaInteropRuntime.h`
33+
[UnmanagedCallersOnly (EntryPoint="Java_net_dot_jni_nativeaot_JavaInteropRuntime_init")]
34+
static void init (IntPtr jnienv, IntPtr klass)
35+
{
36+
Console.WriteLine ($"C# init()");
37+
try {
38+
var options = new JreRuntimeOptions {
39+
EnvironmentPointer = jnienv,
40+
TypeManager = new NativeAotTypeManager (),
41+
UseMarshalMemberBuilder = false,
42+
JniGlobalReferenceLogWriter = new LogcatTextWriter (AndroidLogLevel.Debug, "NativeAot:GREF"),
43+
JniLocalReferenceLogWriter = new LogcatTextWriter (AndroidLogLevel.Debug, "NativeAot:LREF"),
44+
};
45+
runtime = options.CreateJreVM ();
46+
}
47+
catch (Exception e) {
48+
AndroidLog.Print (AndroidLogLevel.Error, "JavaInteropRuntime", $"JavaInteropRuntime.init: error: {e}");
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)