Skip to content

Commit

Permalink
[Xamarin.Android.Build.Tasks] <Aapt2Link/> don't check for compiled.f…
Browse files Browse the repository at this point in the history
…lata (#3171)

Fixes: #3169
Context: https://github.com/zijianhuang/xamarinforms4bugs/tree/ResourcesInLib

We discovered a solution that crashes on startup when it is built with
`$(AndroidUseAapt2)=True`:

    Java.Lang.NoClassDefFoundError: Failed resolution of: Landroid/support/v7/appcompat/R$drawable; ---> Java.Lang.ClassNotFoundException: Didn't find class "android.support.v7.appcompat.R$drawable" on path: DexPathList[[zip file "/system/framework/org.apache.http.legacy.boot.jar", zip file "/data/app/com.companyname.Demo2.Android-PozTNMz4ZBMXaHx-doetdQ==/base.apk"],nativeLibraryDirectories=[/data/app/com.companyname.Demo2.Android-PozTNMz4ZBMXaHx-doetdQ==/lib/arm64, /data/app/com.companyname.Demo2.Android-PozTNMz4ZBMXaHx-doetdQ==/base.apk!/lib/arm64-v8a, /system/lib64]]
        --- End of inner exception stack trace ---
        at Java.Interop.JniEnvironment+InstanceMethods.CallNonvirtualVoidMethod (Java.Interop.JniObjectReference instance, Java.Interop.JniObjectReference type, Java.Interop.JniMethodInfo method, Java.Interop.JniArgumentValue* args) [0x00089] in <372c976a2c5d45cb9abb001729e14dbf>:0
        at Java.Interop.JniPeerMembers+JniInstanceMethods.InvokeVirtualVoidMethod (System.String encodedMember, Java.Interop.IJavaPeerable self, Java.Interop.JniArgumentValue* parameters) [0x0005d] in <372c976a2c5d45cb9abb001729e14dbf>:0
        at Android.App.Activity.OnCreate (Android.OS.Bundle savedInstanceState) [0x00031] in <547679cba0d64c03859bc6ab9919a165>:0
        at Xamarin.Forms.Platform.Android.FormsAppCompatActivity.OnCreate (Android.OS.Bundle savedInstanceState) [0x0001d] in <02288cf327c341c79f8385d5db4c09bf>:0
        at Demo2.Droid.MainActivity.OnCreate (Android.OS.Bundle savedInstanceState) [0x00001] in <16681ab0b39d4abe8efd53e748c930e4>:0
        at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (System.IntPtr jnienv, System.IntPtr native__this, System.IntPtr native_savedInstanceState) [0x00011] in <547679cba0d64c03859bc6ab9919a165>:0
        at (wrapper dynamic-method) Android.Runtime.DynamicMethodNameCounter.7(intptr,intptr,intptr)
        --- End of managed Java.Lang.NoClassDefFoundError stack trace ---

This solution is setup in an odd way:

* NetStandard library with Xamarin.Forms/xplat code
* Android head project, where `@(AndroidResource)` is empty
* Android class library with all the resources, activity, etc.

The root cause being that `<Aapt2Link/>` was completely skipped, due
to this condition:

    <Aapt2Link Condition="'$(_AndroidResourceDesignerFile)' != '' And '$(_AndroidUseAapt2)' == 'True' And Exists ('$(_AndroidLibraryFlatArchivesDirectory)\compiled.flata')" ...

The `compiled.flata` file does not exist, because there are no
`@(AndroidResource)` files.

The fix here is to simply remove the `Exists` check; I also added a
new test for this scenario.

There is some further weirdness in this area I will fix in future PRs.
For now, this will be a good patch we could cherry-pick to 16.2.
  • Loading branch information
jonathanpeppers committed Jun 6, 2019
1 parent 74f2168 commit d71b9b2
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -3795,6 +3795,49 @@ public void LibraryProjectsShouldSkipGetPrimaryCpuAbi ()
Assert.IsTrue (b.Output.IsTargetSkipped (target), $"`{target}` should be skipped!");
}
}

[Test]
public void AllResourcesInClassLibrary ([Values (true, false)] bool useAapt2)
{
var path = Path.Combine ("temp", TestName);

// Create a "library" with all the application stuff in it
var lib = new XamarinAndroidApplicationProject {
ProjectName = "MyLibrary",
Sources = {
new BuildItem.Source ("Bar.cs") {
TextContent = () => "public class Bar { }"
},
}
};
lib.SetProperty ("AndroidApplication", "False");
lib.SetProperty ("AndroidUseAapt2", useAapt2.ToString ());

// Create an "app" that is basically empty and references the library
var app = new XamarinAndroidLibraryProject {
ProjectName = "MyApp",
Sources = {
new BuildItem.Source ("Foo.cs") {
TextContent = () => "public class Foo : Bar { }"
},
}
};
app.AndroidResources.Clear (); // No Resources
app.SetProperty ("AndroidResgenFile", "Resources\\Resource.designer.cs");
app.SetProperty ("AndroidApplication", "True");
app.SetProperty ("AndroidUseAapt2", useAapt2.ToString ());

app.References.Add (new BuildItem.ProjectReference ($"..\\{lib.ProjectName}\\{lib.ProjectName}.csproj", lib.ProjectName, lib.ProjectGuid));

using (var libBuilder = CreateDllBuilder (Path.Combine (path, lib.ProjectName)))
using (var appBuilder = CreateApkBuilder (Path.Combine (path, app.ProjectName))) {
Assert.IsTrue (libBuilder.Build (lib), "library build should have succeeded.");
Assert.IsTrue (appBuilder.Build (app), "app build should have succeeded.");

var r_txt = Path.Combine (Root, appBuilder.ProjectDirectory, app.IntermediateOutputPath, "R.txt");
FileAssert.Exists (r_txt);
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -1698,7 +1698,7 @@ because xbuild doesn't support framework reference assemblies.
/>

<Aapt2Link
Condition="'$(_AndroidResourceDesignerFile)' != '' And '$(_AndroidUseAapt2)' == 'True' And Exists ('$(_AndroidLibraryFlatArchivesDirectory)\compiled.flata')"
Condition=" '$(_AndroidResourceDesignerFile)' != '' And '$(_AndroidUseAapt2)' == 'True' "
ContinueOnError="$(DesignTimeBuild)"
ResourceNameCaseMap="$(_AndroidResourceNameCaseMap)"
AssemblyIdentityMapFile="$(_AndroidLibrayProjectAssemblyMapFile)"
Expand Down

0 comments on commit d71b9b2

Please sign in to comment.