Commit b45929f
committed
[Xamarin.Android.Build.Tasks] fix detection of "Android libraries" (#8904)
Fixes: dotnet/maui#18819
Context: https://github.com/kernshen/NoJavaPeer.git
Context: #4225 (comment)
An assembly's assembly references do not include transitive
dependencies. Given:
// Mono.Android.dll
namespace Java.Lang {
public partial class Object {}
}
// MauiLib1.dll
namespace MauiLib1 {
public class BaseClass : Java.Lang.Object {}
}
// MauiLib2.dll
namespace MauiLib2 {
public class DerivedClass3 : MauiLib1.BaseClass {}
}
then the assembly references for `MauiLib1.dll` will include
`Mono.Android.dll` (it directly references a type from it),
while the assembly references for `MauiLib2.dll` will include
`MauiLib1.dll` (it directly references a type from it) *but*
`MauiLib2.dll` *will not* have an assembly reference to
`Mono.Android.dll`.
This is how things have worked since .NET Framework 1.0. This should
not be surprising.
[As part of the .NET for Android][0] [`SignAndroidPackage`][1] target,
Java Callable Wrappers (JCWs) need to be emitted for all
`Java.Lang.Object` subclasses. This in turn requires
*loading all assemblies* to *find* the `Java.Lang.Object` subclasses.
As a performance optimization, we only load assemblies which we
believed could contain `Java.Lang.Object` subclasses:
1. Assemblies with `'%(TargetFrameworkIdentifier)' == 'MonoAndroid'`,
which is "carry over" from how Xamarin.Android did things,
and works if a .NET for Android project references a
Xamarin.Android project.
2. Assemblies with an assembly reference to `Mono.Android.dll`.
Assemblies with transitive dependencies were caught by (1)…
in Xamarin.Android.
With .NET for Android, that is no longer the case:
`%(TargetFrameworkIdentifier)` is now always `.NETCoreApp`. This in
turn meant that the only assemblies that could be used to generate
JCWs were those which directly referenced `Mono.Android.dll`!
Enter dotnet/maui#18819 and kernshen/NoJavaPeer, which contains
MAUI and .NET for Android solutions with the above transitive reference
structure:
1. `MauiLib1.dll` / `AndroidLib1.dll` references `Mono.Android.dll`,
exports `BaseClass`
2. `MauiLib2.dll` / `AndroidLib2.dll` references `*Lib1.dll` *and not*
`Mono.Android.dll`; exports `DerivedClass3` which inherits `BaseClass`.
3. App project attempts to instantiate `DerivedClass3`.
The result: a runtime exception:
Only System.NotSupportedException Message=Cannot create instance of type 'MauiLib2.DerivedClass3': no Java peer type found.
at Java.Interop.JniPeerMembers.JniInstanceMethods..ctor(Type declaringType) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 22
at Java.Interop.JniPeerMembers.JniInstanceMethods.GetConstructorsForType(Type declaringType) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 77
at Java.Interop.JniPeerMembers.JniInstanceMethods.StartCreateInstance(String constructorSignature, Type declaringType, JniArgumentValue* parameters) in /Users/runner/work/1/s/xamarin-android/external/Java.Interop/src/Java.Interop/Java.Interop/JniPeerMembers.JniInstanceMethods.cs:line 139
at Java.Lang.Object..ctor() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34/mcw/Java.Lang.Object.cs:line 37
at MauiLib1.BaseClass..ctor()
at MauiLib2.DerivedClass..ctor() in C:\Project\Maui\MauiApp1\MauiLib2\Platforms\Android\DerivedClass.cs:line 7
at MauiApp1.App..ctor(IServiceProvider serviceProvider) in C:\Project\Maui\MauiApp1\MauiApp1\App.xaml.cs:line 18
The exception occurs because there is no JCW for `DerivedClass3`, and
there isn't a JCW for `DerivedClass3` because `MauiLib2.dll` was not
processed at all, because it had no assembly reference to
`Mono.Android.dll`.
As a workaround, update `MauiLib2.dll` to contain an assembly reference
to `Mono.Android.dll`.
*Fix* this scenario by updating
`MonoAndroidHelper.IsMonoAndroidAssembly()` to consider these to be
.NET for Android assemblies:
1. Assemblies with `%(TargetFrameworkIdentifier)` *containing*
`Android`. (This doesn't actually change anything; it's a
simplification.)
2. Assemblies with `%(TargetPlatformIdentifier)` *containing*
`Android`.
*This* causes `MauiLib2.dll` to be treated as a .NET for Android
assembly, fixing the bug.
3. Assemblies with an assembly reference to `Mono.Android.dll`.
The addition of check (2) allows assemblies with only transitive
(non-) references to `Mono.Android.dll` to be properly considered,
allowing JCWs to be emitted for types within them.
Update the `BuildWithLibraryTests.ProjectDependencies()` unit test to
better check for this scenario.
[0]: https://github.com/xamarin/xamarin-android/wiki/Blueprint#after-build
[1]: https://learn.microsoft.com/en-us/dotnet/android/building-apps/build-targets#signandroidpackage1 parent 272887a commit b45929f
File tree
2 files changed
+25
-9
lines changed- src/Xamarin.Android.Build.Tasks
- Tests/Xamarin.Android.Build.Tests
- Utilities
2 files changed
+25
-9
lines changedLines changed: 19 additions & 8 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
269 | 269 | | |
270 | 270 | | |
271 | 271 | | |
272 | | - | |
273 | | - | |
274 | | - | |
275 | | - | |
276 | | - | |
| 272 | + | |
277 | 273 | | |
278 | 274 | | |
279 | 275 | | |
| |||
283 | 279 | | |
284 | 280 | | |
285 | 281 | | |
286 | | - | |
| 282 | + | |
287 | 283 | | |
288 | 284 | | |
289 | 285 | | |
| |||
309 | 305 | | |
310 | 306 | | |
311 | 307 | | |
312 | | - | |
313 | | - | |
| 308 | + | |
| 309 | + | |
314 | 310 | | |
315 | 311 | | |
316 | 312 | | |
| |||
321 | 317 | | |
322 | 318 | | |
323 | 319 | | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
324 | 324 | | |
325 | 325 | | |
326 | 326 | | |
| |||
332 | 332 | | |
333 | 333 | | |
334 | 334 | | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
335 | 346 | | |
336 | 347 | | |
337 | 348 | | |
| |||
Lines changed: 6 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
277 | 277 | | |
278 | 278 | | |
279 | 279 | | |
| 280 | + | |
280 | 281 | | |
281 | | - | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
282 | 287 | | |
283 | 288 | | |
284 | 289 | | |
| |||
0 commit comments