Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 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 @@ -139,6 +139,32 @@ string GetNativeTypeNameFromManagedTypeName (string name)
}
}

string GetFixupKey (Instruction instruction, string designerFullName)
{
string line = instruction.ToString ();
int idx = line.IndexOf (designerFullName, StringComparison.Ordinal);
if (idx >= 0) {
return line.Substring (idx + designerFullName.Length);
}
if (instruction.Operand is FieldReference fieldRef &&
(fieldRef.DeclaringType?.ToString()?.Contains (".Resource/") ?? false)) {
var canResolve = false;
try {
var resolved = fieldRef.Resolve ();
canResolve = resolved != null;
} catch (Exception) {
}
if (canResolve)
return null;
var type = fieldRef.DeclaringType.FullName;
var s = type.LastIndexOf ('/');
type = type.Substring (s + 1);
var key = type + "::" + fieldRef.Name;
return key;
}
return null;
}

protected override void FixBody (MethodBody body, TypeDefinition designer)
{
// replace
Expand All @@ -152,18 +178,16 @@ protected override void FixBody (MethodBody body, TypeDefinition designer)
{
if (i.OpCode != OpCodes.Ldsfld)
continue;
string line = i.ToString ();
int idx = line.IndexOf (designerFullName, StringComparison.Ordinal);
if (idx >= 0) {
string key = line.Substring (idx + designerFullName.Length);
var key = GetFixupKey (i, designerFullName);
if (key != null) {
LogMessage ($"Looking for {key}.");
var found = lookup.TryGetValue (key, out MethodDefinition method);
if (!found) {
LogMessage ($"DEBUG! Failed to find {key}! Trying case insensitive lookup.");
found = lookupCaseInsensitive.TryGetValue (key, out method);
}
if (found) {
var importedMethod = designer.Module.ImportReference (method);
var importedMethod = body.Method.Module.ImportReference (method);
var newIn = Instruction.Create (OpCodes.Call, importedMethod);
instructions.Add (i, newIn);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,39 @@ protected bool FindResourceDesigner (AssemblyDefinition assembly, bool mainAppli

}
}

if (string.IsNullOrEmpty(designerFullName)) {
LogMessage ($"Inspecting member references for assembly: {assembly.FullName};");
var memberRefs = assembly.MainModule.GetMemberReferences ();
var memberIdx = 0;
foreach (var memberRef in memberRefs) {
memberIdx++;
string declaringType = memberRef.DeclaringType?.ToString () ?? string.Empty;
if (!declaringType.Contains (".Resource/")) {
continue;
}
if (declaringType.Contains ("_Microsoft.Android.Resource.Designer")) {
continue;
}
var resolved = false;
try {
var def = memberRef.Resolve ();
if (resolved = def != null) {
LogMessage ($"Resolved member `{memberRef?.Name}`");
}
} catch (Exception ex) {
LogMessage ($"Exception resolving member `{memberRef?.Name}`: {ex}");
resolved = false;
}
if (!resolved) {
LogMessage ($"Adding _Linker.Generated.Resource to {assembly.Name.Name}");
designer = new TypeDefinition ("_Linker.Generated", "Resource", TypeAttributes.Public | TypeAttributes.AnsiClass);
designer.BaseType = new TypeDefinition ("System", "Object", TypeAttributes.Public | TypeAttributes.AnsiClass);
return true;
}
}
}

if (string.IsNullOrEmpty(designerFullName))
return false;

Expand Down
53 changes: 53 additions & 0 deletions tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1115,5 +1115,58 @@ public void EnableAndroidStripILAfterAOT ([Values (false, true)] bool profiledAO
Assert.IsTrue(didLaunch, "Activity should have started.");
}

[Test]
public void FixLegacyResourceDesignerStep ([Values (true, false)] bool isRelease)
{
string previousTargetFramework = "net7.0-android";

var library1 = new XamarinAndroidLibraryProject {
IsRelease = isRelease,
TargetFramework = previousTargetFramework,
ProjectName = "Library1",
AndroidResources = {
new AndroidItem.AndroidResource (() => "Resources\\values\\strings2.xml") {
TextContent = () => @"<?xml version=""1.0"" encoding=""utf-8""?>
<resources>
<string name=""hello"">Hi!</string>
</resources>",
},
},
};
var library2 = new XamarinAndroidLibraryProject {
IsRelease = isRelease,
TargetFramework = previousTargetFramework,
ProjectName = "Library2",
OtherBuildItems = {
new BuildItem.Source("Foo.cs") {
TextContent = () => "public class Foo { public static int Hello => Library1.Resource.String.hello; } ",
}
}
};
library2.AndroidResources.Clear ();
library2.SetProperty ("AndroidGenerateResourceDesigner", "false"); // Disable Android Resource Designer generation
library2.AddReference (library1);
proj = new XamarinAndroidApplicationProject {
IsRelease = isRelease,
ProjectName = "MyApp",
};
proj.AddReference (library2);
proj.MainActivity = proj.DefaultMainActivity.Replace ("//${AFTER_ONCREATE}", "Console.WriteLine(Foo.Hello);");

using (var library1Builder = CreateDllBuilder (Path.Combine ("temp", TestName, library1.ProjectName)))
using (var library2Builder = CreateDllBuilder (Path.Combine ("temp", TestName, library2.ProjectName))) {
builder = CreateApkBuilder (Path.Combine ("temp", TestName, proj.ProjectName));
Assert.IsTrue (library1Builder.Build (library1, doNotCleanupOnUpdate: true), $"Build of {library1.ProjectName} should have succeeded.");
Assert.IsTrue (library2Builder.Build (library2, doNotCleanupOnUpdate: true), $"Build of {library2.ProjectName} should have succeeded.");
Assert.IsTrue (builder.Build (proj), $"Build of {proj.ProjectName} should have succeeded.");

RunProjectAndAssert (proj, builder);

WaitForPermissionActivity (Path.Combine (Root, builder.ProjectDirectory, "permission-logcat.log"));
bool didLaunch = WaitForActivityToStart (proj.PackageName, "MainActivity",
Path.Combine (Root, builder.ProjectDirectory, "logcat.log"), 30);
Assert.IsTrue (didLaunch, "Activity should have started.");
}
}
}
}