-
Notifications
You must be signed in to change notification settings - Fork 519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[trimming] preserve custom views and $(AndroidHttpClientHandlerType)
#8954
base: main
Are you sure you want to change the base?
Conversation
Fixes: xamarin#8797 Here are two cases `TrimMode=full` can break applications: * `$(AndroidHttpClientHandlerType)` set to a custom type * Custom views (Android `.xml`) that are not referenced in C# code In the `MarkJavaObjects` trimmer step we can preserve both of these cases by: * Passing in `$(AndroidHttpClientHandlerType)`, preserve the public, parameterless constructor of the type * Pass in `$(_CustomViewMapFile)`, preserve `IJavaObject` types if they are found in the map file
markContext.RegisterMarkTypeAction (type => ProcessType (type)); | ||
} | ||
|
||
bool IsActiveFor (AssemblyDefinition assembly) | ||
{ | ||
return assembly.MainModule.HasTypeReference ("System.Net.Http.HttpMessageHandler") || assembly.MainModule.HasTypeReference ("Android.Util.IAttributeSet"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The point of this, is we don't want to iterate over every type in every assembly.
Is Android.Util.IAttributeSet
required for any custom view?
xamarin-android/tests/Mono.Android-Tests/Mono.Android-Test.Library/CustomTextView.cs
Line 9 in 14b70ac
public CustomTextView (Context context, IAttributeSet attributes) : base (context, attributes) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See:
- https://stackoverflow.com/a/36342089/83444
- https://ataulm.com/2019/10/28/resolving-view-attributes.html
IAttributeSet
is used so that the View can obtain any XML attributes specified on the view. The above stack overflow answer has a good example of this:
<com.anjithsasindran.RectangleView
app:radiusDimen="5dp"
app:rectangleBackground="@color/yellow"
app:circleBackground="@color/green" />
The AttributeSet
is how the RectangleView
constructor would lookup the values for @app:radiusDimen
, @app:rectangleBackground
, and @app:circleBackground
.
I believe, but cannot quickly verify, that the (Context, IAttributeSet)
constructor is always used/preferred by Android.
// NOTE: ensure the C# compiler has a reference to the library | ||
new Mono.Android_Test.Library.Foo (); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was another problem, when we have a @(ProjectReference)
to the class library containing Mono.Android_Test.Library
-- there was no C# code using types from the library. And so the C# compiler would omit the assembly reference, and the trimmer did not even receive it as input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -48,6 +48,8 @@ public void ProcessAssembly (AssemblyDefinition assembly, string androidHttpClie | |||
} | |||
|
|||
// Custom views in Android .xml files | |||
if (!type.ImplementsIJavaObject (cache)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
set.Add (value); | ||
} | ||
return map; | ||
return LoadCustomViewMapFile (mapFile); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't we "register" mapFile
? (And why didn't we do this before, given that the beginning of this method calls .GetRegisteredTaskObjectAssemblyLocal<…>(…)
?)
var map = LoadCustomViewMapFile (mapFile);
if (map != null) {
engine.RegisterTaskObject (mapFile, map, RegisteredTaskObjectLifetime.Build, allowEarlyCollection: false);
}
return map;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RegisterTaskObjectAssemblyLocall call happens inside LoadCustomViewMapFile
see
var cachedMap = engine?.GetRegisteredTaskObjectAssemblyLocal<Dictionary<string, HashSet<string>>> (mapFile, RegisteredTaskObjectLifetime.Build); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh the code changed... ah cos of the linker can't use RegisterTaskObject
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry just actually read your comment (its early). The Registration of the file happens in SaveCustomViewMapFile
.
Fixes: #8797
Here are two cases
TrimMode=full
can break applications:$(AndroidHttpClientHandlerType)
set to a custom typeCustom views (Android
.xml
) that are not referenced in C# codeIn the
MarkJavaObjects
trimmer step we can preserve both of these cases by:Passing in
$(AndroidHttpClientHandlerType)
, preserve the public, parameterless constructor of the typePass in
$(_CustomViewMapFile)
, preserveIJavaObject
types if they are found in the map file