链接 .NET MAUI Android 应用
生成应用时,.NET Multi-platform App UI (.NET MAUI) 可以使用称作 ILLink 的链接器减小应用的整体大小。 ILLink 通过分析编译器生成的中间代码来减小大小。 这会删除未使用的方法、属性、字段、事件、结构和类,以生成仅包含运行应用所需的代码和程序集依赖项的应用。
链接器行为
链接器使你能剪裁 .NET MAUI Android 应用。 启用剪裁后,链接器会保持程序集不变,并通过删除应用不使用的类型和成员来减小 SDK 程序集的大小。
可以为应用的每个生成配置来配置链接器行为。 默认情况下,对调试版本将禁用剪裁,而对发布版本将启用剪裁。
警告
为应用的调试配置启用链接器可能会妨碍调试体验,因为这可能会删除使你能够检查对象状态的属性访问器。
确保启用剪裁:
在 Visual Studio 的“解决方案资源管理器”中,右键单击 .NET MAUI 应用项目,然后选择“属性”。 然后,导航到“Android”>“选项”选项卡,并确保为发布版本配置启用剪裁:
保留代码
使用剪裁器时,它有时会删除你可能已动态调用的代码,甚至间接调用。 可以通过使用 DynamicDependency
特性批注这些成员来指示剪裁器保留成员。 此特性可用于表示与成员类型和子集或特定成员的依赖关系。
重要说明
BCL 中的无法以静态方式确定会由应用使用的所有成员都将被删除。
DynamicDependency
特性可以应用于构造函数、字段和方法:
[DynamicDependency("Helper", "MyType", "MyAssembly")]
static void RunHelper()
{
var helper = Assembly.Load("MyAssembly").GetType("MyType").GetMethod("Helper");
helper.Invoke(null, null);
}
在此示例中,DynamicDependency
可确保保留 Helper
方法。 如果没有属性,剪裁将删除Helper
或完全删除MyAssembly
MyAssembly
(如果未在其他位置引用)。
该特性可指定要通过 string
或 DynamicallyAccessedMembers
特性保留的成员。 类型和程序集要么在属性上下文中隐式指定,要么在属性中显式指定(对于类型和程序集名称,通过 Type
或 string
指定)。
类型和成员字符串使用 C# 文档注释 ID 字符串格式的变体,不带成员前缀。 成员字符串不应包含声明类型的名称,并且可以省略参数以保留指定名称的所有成员。 以下示例展示了有效的用途:
[DynamicDependency("Method()")]
[DynamicDependency("Method(System,Boolean,System.String)")]
[DynamicDependency("MethodOnDifferentType()", typeof(ContainingType))]
[DynamicDependency("MemberName")]
[DynamicDependency("MemberOnUnreferencedAssembly", "ContainingType", "UnreferencedAssembly")]
[DynamicDependency("MemberName", "Namespace.ContainingType.NestedType", "Assembly")]
// generics
[DynamicDependency("GenericMethodName``1")]
[DynamicDependency("GenericMethod``2(``0,``1)")]
[DynamicDependency("MethodWithGenericParameterTypes(System.Collections.Generic.List{System.String})")]
[DynamicDependency("MethodOnGenericType(`0)", "GenericType`1", "UnreferencedAssembly")]
[DynamicDependency("MethodOnGenericType(`0)", typeof(GenericType<>))]
保留程序集
可以指定应从剪裁过程中排除的程序集,同时允许剪裁其他程序集。 当无法轻松使用 DynamicDependency
属性或不控制正在剪裁的代码时,此方法非常有用。
当它剪裁所有程序集时,可以通过在项目文件中设置 TrimmerRootAssembly
MSBuild 项来指示修整程序跳过程序集:
<ItemGroup>
<TrimmerRootAssembly Include="MyAssembly" />
</ItemGroup>
注意
设置 .dll
MSBuild 属性时不需要 TrimmerRootAssembly
扩展。
如果修整程序跳过程序集,则它被视为 根目录,这意味着它及其所有静态理解的依赖项都会保留。 可以通过将更多 TrimmerRootAssembly
MSBuild 属性添加到 <ItemGroup>
,来跳过其他程序集。
保留程序集、类型和成员
可以传递剪裁器 XML 说明文件,该文件指定需要保留哪些程序集、类型和成员。
若要在剪裁所有程序集时从剪裁过程中排除成员,请将项目文件中的 MSBuild 项设置为 TrimmerRootDescriptor
定义要排除的成员的 XML 文件:
<ItemGroup>
<TrimmerRootDescriptor Include="MyRoots.xml" />
</ItemGroup>
然后,XML 文件使用剪裁器 描述符格式 来定义要排除的成员:
<linker>
<assembly fullname="MyAssembly">
<type fullname="MyAssembly.MyClass">
<method name="DynamicallyAccessedMethod" />
</type>
</assembly>
</linker>
在此示例中,XML 文件指定了应用动态访问的方法,该方法被排除在修整之外。
当 XML 中列出程序集、类型或成员时,默认操作将保留,这意味着无论剪裁器认为它是否使用,它都会保留在输出中。
注意
保留标记所包含的内容并不确定。 如果未提供下一级的详细信息,它将包括所有子级。 如果列出的程序集没有任何类型,则将保留该程序集的所有类型和成员。
将程序集标记为剪裁安全
如果你项目中有一个库,或者你是可重用库的开发人员,并且希望修整程序将程序集视为可修整的,则可以通过将 IsTrimmable
MSBuild 属性添加到程序集的项目文件中来将程序集标记为安全剪裁:
<PropertyGroup>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
这会将程序集标记为“可剪裁”,并为该项目启用剪裁警告。 “可剪裁”意味着程序集被视为与剪裁兼容,生成程序集时不应显示剪裁警告。 在经过剪裁的应用中使用时,会在最终输出中删除程序集未使用的成员。
在 .NET 9+ 中使用本机 AOT 部署时,将 IsAotCompatible
MSBuild 属性设置为 true
的同时,也会将 true
值分配给 IsTrimmable
属性,并启用其他 AOT 分析器的生成属性。 有关 AOT 分析器的详细信息,请参阅 AOT 兼容性分析器。 有关 .NET MAUI 的本机 AOT 部署的更多信息,请参阅 本机 AOT 部署。
将项目文件中的 IsTrimmable
MSBuild 属性设置为 true
会将 AssemblyMetadata
属性插入程序集:
[assembly: AssemblyMetadata("IsTrimmable", "True")]
或者,可以将 AssemblyMetadata
特性添加到程序集中,而无需将 IsTrimmable
MSBuild 属性添加到程序集的项目文件中。
注意
如果为程序集设置了 IsTrimmable
MSBuild 属性,则会替代 AssemblyMetadata("IsTrimmable", "True")
特性。 这使你可以选择为程序集启用剪裁(即使程序集没有该特性),也可以禁止裁剪具有该特性的程序集。
抑制分析警告
启用剪裁器后,它会删除不可静态访问的 IL。 因此,使用反射或其他模式创建动态依赖项的应用可能会中断运行。 若要警告此类模式,在将程序集标记为剪裁安全时,库作者应将 SuppressTrimAnalysisWarnings
MSBuild 属性设置为 false
:
<PropertyGroup>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
</PropertyGroup>
不抑制剪裁分析警告将包括有关整个应用的警告,其中包括你自己的代码、库代码以及 SDK 代码。
显示详细警告
对于每个来自 PackageReference
的程序集,剪裁分析最多为其生成一个警告,以指示程序集的内部机制与剪裁功能不兼容。 作为库作者,将程序集标记为剪裁安全时,应通过将 MSBuild 属性设置为TrimmerSingleWarn
false
:
<PropertyGroup>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>
该设置显示所有详细警告,而不是将其折叠为每个程序集的单个警告。