Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1832,14 +1832,53 @@ public void BuildPropsBreaksConvertResourcesCasesOnSecondBuild ([Values (Android
Assert.IsTrue (secondAssemblyWrite > firstAssemblyWrite,
$"Assembly write time was not updated on partially incremental build. Before: {firstAssemblyWrite}. After: {secondAssemblyWrite}.");

// TODO: NativeAOT fails this with "Apk write time was not updated on partially incremental build. Before: 1/1/1981 1:01:02 AM. After: 1/1/1981 1:01:02 AM."
if (runtime != AndroidRuntime.NativeAOT) {
Assert.IsTrue (secondApkWrite > firstApkWrite,
$"Apk write time was not updated on partially incremental build. Before: {firstApkWrite}. After: {secondApkWrite}.");
}
Assert.IsTrue (secondApkWrite > firstApkWrite,
$"Apk write time was not updated on partially incremental build. Before: {firstApkWrite}. After: {secondApkWrite}.");
}
}

[Test]
public void UniversalApkFromBundleIsIncremental ()
{
if (IgnoreUnsupportedConfiguration (AndroidRuntime.CoreCLR, release: true)) {
return;
}

var proj = new XamarinAndroidApplicationProject {
IsRelease = true,
};
proj.SetRuntime (AndroidRuntime.CoreCLR);
proj.SetProperty (KnownProperties.RuntimeIdentifier, "android-arm64");
proj.SetProperty ("AndroidPackageFormats", "aab;apk");

using var builder = CreateApkBuilder ();
Assert.IsTrue (builder.Build (proj), "First build should have succeeded.");
builder.Output.AssertTargetIsNotSkipped ("_CreateUniversalApkFromBundle");

var outputDirectory = Path.Combine (Root, builder.ProjectDirectory, proj.OutputPath);
var signedApk = Directory.GetFiles (outputDirectory, "*-Signed.apk", SearchOption.AllDirectories).Single ();
var firstWriteTime = File.GetLastWriteTimeUtc (signedApk);

Assert.IsTrue (builder.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "No-op build should have succeeded.");
builder.Output.AssertTargetIsSkipped ("_CreateUniversalApkFromBundle");
Assert.AreEqual (firstWriteTime, File.GetLastWriteTimeUtc (signedApk), "No-op builds should preserve the signed APK timestamp.");

Assert.IsTrue (
builder.Build (proj, parameters: new [] { "AndroidBundleToolExtraArgs=--overwrite" }, doNotCleanupOnUpdate: true, saveProject: false),
"Changing bundletool arguments should have succeeded.");
builder.Output.AssertTargetIsNotSkipped ("_CreateUniversalApkFromBundle");

Assert.IsTrue (
builder.Build (proj, parameters: new [] { "AndroidBundleToolExtraArgs=" }, doNotCleanupOnUpdate: true, saveProject: false),
"Clearing bundletool arguments should have succeeded.");
builder.Output.AssertTargetIsNotSkipped ("_CreateUniversalApkFromBundle");

Assert.IsTrue (
builder.Build (proj, parameters: new [] { "AndroidBundleToolExtraArgs=" }, doNotCleanupOnUpdate: true, saveProject: false),
"No-op build after clearing bundletool arguments should have succeeded.");
builder.Output.AssertTargetIsSkipped ("_CreateUniversalApkFromBundle");
}

[Test]
public void AfterILLinkAdditionalStepsIsSkippedOnSecondBuild ([Values (AndroidRuntime.CoreCLR, AndroidRuntime.NativeAOT)] AndroidRuntime runtime)
{
Expand Down
27 changes: 25 additions & 2 deletions src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
Original file line number Diff line number Diff line change
Expand Up @@ -976,11 +976,15 @@ because xbuild doesn't support framework reference assemblies.
<_PropertyCacheItems Include="AndroidDexTool=$(AndroidDexTool)" />
<_PropertyCacheItems Include="AndroidLinkTool=$(AndroidLinkTool)" />
<_PropertyCacheItems Include="AndroidLinkResources=$(AndroidLinkResources)" />
<_PropertyCacheItems Include="AndroidBundleToolExtraArgs=$(AndroidBundleToolExtraArgs)" />
<_PropertyCacheItems Include="AndroidKeyStore=$(AndroidKeyStore)" />
<_PropertyCacheItems Include="AndroidPackageFormat=$(AndroidPackageFormat)" />
<_PropertyCacheItems Include="EmbedAssembliesIntoApk=$(EmbedAssembliesIntoApk)" />
<_PropertyCacheItems Include="AndroidLinkMode=$(AndroidLinkMode)" />
<_PropertyCacheItems Include="AndroidLinkSkip=$(AndroidLinkSkip)" />
<_PropertyCacheItems Include="AndroidSdkBuildToolsVersion=$(AndroidSdkBuildToolsVersion)" />
<_PropertyCacheItems Include="Aapt2ToolPath=$(Aapt2ToolPath)" />
<_PropertyCacheItems Include="Aapt2ToolExe=$(Aapt2ToolExe)" />
<_PropertyCacheItems Include="AndroidSdkPath=$(_AndroidSdkDirectory)" />
<_PropertyCacheItems Include="AndroidNdkPath=$(_AndroidNdkDirectory)" />
<_PropertyCacheItems Include="JavaSdkPath=$(_JavaSdkDirectory)" />
Expand Down Expand Up @@ -2672,12 +2676,26 @@ because xbuild doesn't support framework reference assemblies.
<Delete Files="%(ApkAbiFilesUnaligned.FullPath)" />
</Target>

<Target Name="_PrepareCreateUniversalApkFromBundle"
DependsOnTargets="_ResolveAndroidTooling;_ResolveXamarinAndroidTools">
<PropertyGroup>
<_UniversalApkAapt2ToolExe Condition=" '$(Aapt2ToolExe)' != '' ">$(Aapt2ToolExe)</_UniversalApkAapt2ToolExe>
<_UniversalApkAapt2ToolExe Condition=" '$(_UniversalApkAapt2ToolExe)' == '' and '$(OS)' == 'Windows_NT' ">aapt2.exe</_UniversalApkAapt2ToolExe>
<_UniversalApkAapt2ToolExe Condition=" '$(_UniversalApkAapt2ToolExe)' == '' ">aapt2</_UniversalApkAapt2ToolExe>
<_UniversalApkAapt2ToolPath>$([System.IO.Path]::Combine('$(Aapt2ToolPath)', '$(_UniversalApkAapt2ToolExe)'))</_UniversalApkAapt2ToolPath>
<!-- Preserve the previous always-run behavior for custom signing credentials or bundletool
arguments, which can change without changing the input AAB. -->
<_UniversalApkAlwaysRunInput Condition=" '$(AndroidKeyStore)' == 'True' or '$(AndroidBundleToolExtraArgs)' != '' ">$(IntermediateOutputPath)__always_rebuild_universal_apk__</_UniversalApkAlwaysRunInput>
</PropertyGroup>
</Target>

<Target Name="_CreateUniversalApkFromBundle"
Condition=" '$(AndroidPackageFormat)' == 'aab' And $(_AndroidAdditionalPackageFormats.Contains('apk')) "
Inputs="$(_AppBundleIntermediate)"
DependsOnTargets="_PrepareCreateUniversalApkFromBundle"
Inputs="$(_AppBundleIntermediate);$(_AndroidBuildPropertiesCache);@(_AndroidMSBuildAllProjects);$(AndroidBundleToolJarPath);$(_UniversalApkAapt2ToolPath);$(_ApkKeyStore);$(_UniversalApkAlwaysRunInput)"
Outputs="$(OutDir)$(_AndroidPackage)-Signed.apk"
>
<!-- Delete the existing files or bundetool will fail. -->
<!-- Delete the existing files or bundletool will fail. -->
<Delete Files="$(_UniversalApkSetIntermediate);$(OutDir)$(_AndroidPackage)*-Signed.apk" />
<BuildApkSet
ToolPath="$(JavaToolPath)"
Expand All @@ -2687,6 +2705,7 @@ because xbuild doesn't support framework reference assemblies.
AdbToolPath="$(AdbToolPath)"
AdbTarget="$(AdbTarget)"
Aapt2ToolPath="$(Aapt2ToolPath)"
Aapt2ToolExe="$(Aapt2ToolExe)"
AppBundle="$(_AppBundleIntermediate)"
Output="$(_UniversalApkSetIntermediate)"
KeyStore="$(_ApkKeyStore)"
Expand All @@ -2705,6 +2724,9 @@ because xbuild doesn't support framework reference assemblies.
<FileWrites Include="$(OutDir)$(_AndroidPackage)-Signed.apk" />
</ItemGroup>
<UnzipToFolder Sources="$(_UniversalApkSetIntermediate)" DestinationDirectories="$(OutDir)" Files="@(_FilestoExtract)" />
<!-- bundletool's universal.apk has a fixed ZIP timestamp, which otherwise leaves this target
perpetually out of date relative to the unchanged input AAB. -->
<Touch Files="$(OutDir)$(_AndroidPackage)-Signed.apk" />
</Target>

<Target Name="_CollectApplicationArtifacts"
Expand Down Expand Up @@ -2904,6 +2926,7 @@ because xbuild doesn't support framework reference assemblies.
AdbToolPath="$(AdbToolPath)"
AdbTarget="$(AdbTarget)"
Aapt2ToolPath="$(Aapt2ToolPath)"
Aapt2ToolExe="$(Aapt2ToolExe)"
AppBundle="$(_AppBundleIntermediate)"
Output="$(_ApkSetIntermediate)"
KeyStore="$(_ApkKeyStore)"
Expand Down
Loading