diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs
index 86ffb5bf8a4..f96dc8783cd 100644
--- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs
+++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/IncrementalBuildTest.cs
@@ -102,6 +102,81 @@ public class Foo {
}
}
+ [Test]
+ public void JniRemappingCountsSurviveIncrementalBuild ()
+ {
+ const AndroidRuntime runtime = AndroidRuntime.CoreCLR;
+ const bool isRelease = true;
+ if (IgnoreUnsupportedConfiguration (runtime, release: isRelease)) {
+ return;
+ }
+
+ var proj = new XamarinAndroidApplicationProject {
+ IsRelease = isRelease,
+ OtherBuildItems = {
+ new AndroidItem._AndroidRemapMembers ("Remap.xml") {
+ Encoding = Encoding.UTF8,
+ TextContent = () => """
+
+
+
+
+""",
+ },
+ },
+ };
+ proj.SetRuntime (runtime);
+
+ using (var b = CreateApkBuilder ()) {
+ Assert.IsTrue (b.Build (proj), "first build failed");
+ AssertJniRemappingCounts (proj, b, expectedTypeCount: 1, expectedMethodCount: 1);
+ var remapSourceTimestamps = GetJniRemappingSourceTimestamps (proj, b);
+
+ proj.MainActivity += Environment.NewLine + "// Force an incremental C# rebuild.";
+ proj.Touch ("MainActivity.cs");
+ Assert.IsTrue (b.Build (proj, doNotCleanupOnUpdate: true, saveProject: false), "second build failed");
+ AssertJniRemappingCounts (proj, b, expectedTypeCount: 1, expectedMethodCount: 1);
+ AssertJniRemappingSourceTimestamps (remapSourceTimestamps);
+ }
+ }
+
+ void AssertJniRemappingCounts (XamarinAndroidApplicationProject proj, ProjectBuilder builder, uint expectedTypeCount, uint expectedMethodCount)
+ {
+ string objDirPath = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath);
+ var envFiles = EnvironmentHelper.GatherEnvironmentFiles (objDirPath, "arm64-v8a;x86_64", required: true, runtime: AndroidRuntime.CoreCLR);
+ var appConfig = (EnvironmentHelper.ApplicationConfig_CoreCLR) EnvironmentHelper.ReadApplicationConfig (envFiles, AndroidRuntime.CoreCLR);
+ Assert.AreEqual (expectedTypeCount, appConfig.jni_remapping_replacement_type_count, "jni_remapping_replacement_type_count should be preserved.");
+ Assert.AreEqual (expectedMethodCount, appConfig.jni_remapping_replacement_method_index_entry_count, "jni_remapping_replacement_method_index_entry_count should be preserved.");
+ }
+
+ Dictionary GetJniRemappingSourceTimestamps (XamarinAndroidApplicationProject proj, ProjectBuilder builder)
+ {
+ string objDirPath = Path.Combine (Root, builder.ProjectDirectory, proj.IntermediateOutputPath, "android");
+ var timestamps = new Dictionary (StringComparer.Ordinal);
+ foreach (string abi in new [] { "arm64-v8a", "x86_64" }) {
+ string path = Path.Combine (objDirPath, $"jni_remap.{abi}.ll");
+ FileAssert.Exists (path);
+ timestamps.Add (path, File.GetLastWriteTimeUtc (path));
+ }
+ return timestamps;
+ }
+
+ void AssertJniRemappingSourceTimestamps (Dictionary expectedTimestamps)
+ {
+ foreach (var expectedTimestamp in expectedTimestamps) {
+ Assert.AreEqual (
+ expectedTimestamp.Value,
+ File.GetLastWriteTimeUtc (expectedTimestamp.Key),
+ $"{expectedTimestamp.Key} should not be touched when regenerated with unchanged contents."
+ );
+ }
+ }
+
[Test]
public void CheckNothingIsDeletedByIncrementalClean ([Values] bool enableMultiDex, [Values] AndroidRuntime runtime)
{
diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
index 539ee59f193..fd444a89512 100644
--- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
+++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets
@@ -1646,21 +1646,22 @@ because xbuild doesn't support framework reference assemblies.
<_GenerateAndroidRemapNativeCodeDependsOn>
_ConvertAndroidMamMappingFileToXml;
_CollectAndroidRemapMembers;
- _PrepareAndroidRemapNativeAssemblySources
+ _PrepareAndroidRemapNativeAssemblySources;
+ _GetGeneratePackageManagerJavaInputs
+ Inputs="@(_GeneratePackageManagerJavaInputs);$(_XARemapMembersFilePath)"
+ Outputs="$(_AndroidStampDirectory)_GenerateAndroidRemapNativeCode.stamp">
-
+
<_GeneratePackageManagerJavaInputs Include="@(_GenerateJavaStubsInputs)" />
+ <_GeneratePackageManagerJavaInputs Include="$(_XARemapMembersFilePath)" Condition=" '@(_AndroidRemapMembers->Count())' != '0' " />