@@ -135,6 +135,11 @@ public void NativeAOT ()
135135 proj . SetProperty ( "PublishAot" , "true" ) ;
136136 proj . SetProperty ( "PublishAotUsingRuntimePack" , "true" ) ;
137137 proj . SetProperty ( "AndroidNdkDirectory" , AndroidNdkPath ) ;
138+ proj . SetProperty ( "_ExtraTrimmerArgs" , "--verbose" ) ;
139+
140+ // Required for java/util/ArrayList assertion below
141+ proj . MainActivity = proj . DefaultMainActivity
142+ . Replace ( "//${AFTER_ONCREATE}" , "new Android.Runtime.JavaList (); new Android.Runtime.JavaList<int> ();" ) ;
138143
139144 using var b = CreateApkBuilder ( ) ;
140145 Assert . IsTrue ( b . Build ( proj ) , "Build should have succeeded." ) ;
@@ -165,6 +170,43 @@ public void NativeAOT ()
165170 Assert . IsNotNull ( method , $ "{ linkedMonoAndroidAssembly } should contain { typeName } .{ methodName } ") ;
166171 }
167172
173+ var typemap = new Dictionary < string , TypeReference > ( ) ;
174+ var linkedRuntimeAssembly = Path . Combine ( intermediate , "linked" , "Microsoft.Android.Runtime.NativeAOT.dll" ) ;
175+ FileAssert . Exists ( linkedRuntimeAssembly ) ;
176+ using ( var assembly = AssemblyDefinition . ReadAssembly ( linkedRuntimeAssembly ) ) {
177+ var type = assembly . MainModule . Types . FirstOrDefault ( t => t . Name == "NativeAotTypeManager" ) ;
178+ Assert . IsNotNull ( type , $ "{ linkedRuntimeAssembly } should contain NativeAotTypeManager") ;
179+ var method = type . Methods . FirstOrDefault ( m => m . Name == "InitializeTypeMappings" ) ;
180+ Assert . IsNotNull ( method , "NativeAotTypeManager should contain InitializeTypeMappings" ) ;
181+
182+ foreach ( var i in method . Body . Instructions ) {
183+ if ( i . OpCode != Mono . Cecil . Cil . OpCodes . Ldstr )
184+ continue ;
185+ if ( i . Operand is not string javaName )
186+ continue ;
187+ if ( i . Next . Operand is not TypeReference t )
188+ continue ;
189+ typemap . Add ( javaName , t ) ;
190+ }
191+
192+ // Basic types
193+ AssertTypeMap ( "java/lang/Object" , "Java.Lang.Object" ) ;
194+ AssertTypeMap ( "java/lang/String" , "Java.Lang.String" ) ;
195+ AssertTypeMap ( "[Ljava/lang/Object;" , "Java.Interop.JavaArray`1" ) ;
196+ AssertTypeMap ( "java/util/ArrayList" , "Android.Runtime.JavaList" ) ;
197+ AssertTypeMap ( "android/app/Activity" , "Android.App.Activity" ) ;
198+ AssertTypeMap ( "android/widget/Button" , "Android.Widget.Button" ) ;
199+ Assert . IsFalse ( StringAssertEx . ContainsText ( b . LastBuildOutput ,
200+ "Duplicate typemap entry for java/util/ArrayList => Android.Runtime.JavaList`1" ) ,
201+ "Should get log message about duplicate Android.Runtime.JavaList`1!" ) ;
202+
203+ // Special *Invoker case
204+ AssertTypeMap ( "android/view/View$OnClickListener" , "Android.Views.View/IOnClickListener" ) ;
205+ Assert . IsFalse ( StringAssertEx . ContainsText ( b . LastBuildOutput ,
206+ "Duplicate typemap entry for android/view/View$OnClickListener => Android.Views.View/IOnClickListenerInvoker" ) ,
207+ "Should get log message about duplicate IOnClickListenerInvoker!" ) ;
208+ }
209+
168210 var dexFile = Path . Combine ( intermediate , "android" , "bin" , "classes.dex" ) ;
169211 FileAssert . Exists ( dexFile ) ;
170212 foreach ( var className in mono_classes ) {
@@ -180,6 +222,15 @@ public void NativeAOT ()
180222 foreach ( var nativeaot_file in nativeaot_files ) {
181223 Assert . IsTrue ( zip . ContainsEntry ( nativeaot_file , caseSensitive : true ) , $ "APK must contain `{ nativeaot_file } `.") ;
182224 }
225+
226+ void AssertTypeMap ( string javaName , string managedName )
227+ {
228+ if ( typemap . TryGetValue ( javaName , out var reference ) ) {
229+ Assert . AreEqual ( managedName , reference . ToString ( ) ) ;
230+ } else {
231+ Assert . Fail ( $ "InitializeTypeMappings should contain Ldstr \" { javaName } \" !") ;
232+ }
233+ }
183234 }
184235
185236 [ Test ]
0 commit comments