链接 .NET MAUI iOS 应用
生成应用时,.NET Multi-platform App UI (.NET MAUI) 可以使用称作 ILLink 的链接器减小应用的整体大小。 ILLink 通过分析编译器生成的中间代码来减小大小。 这会删除未使用的方法、属性、字段、事件、结构和类,以生成仅包含运行应用所需的代码和程序集依赖项的应用。
链接器行为
对于在 iOS 和 Mac Catalyst 上运行的 .NET MAUI 应用,此链接器支持使用三种模式:
- 不链接。 禁用链接可确保不会修改程序集。
- 仅链接 SDK 程序集。 在此模式下,链接器会保持程序集不变,并通过删除应用不使用的类型和成员来减小 SDK 程序集的大小。
- 链接所有程序集。 链接所有程序集时,链接器会执行额外的优化,使应用的体积尽可能小。 它会修改源代码的中间代码,如果是以链接器静态分析无法检测到的方法使用功能,可能会使应用中断运行。 在这些情况下,为了让应用可以正常工作,可能需要调整源代码。
可以针对应用的每个生成配置对链接器行为进行配置。
警告
为应用的调试配置启用链接器可能会妨碍调试体验,因为这可能会删除使你能够检查对象状态的属性访问器。
要在 Visual Studio 中配置链接器行为:
在“解决方案资源管理器”中,右键单击 .NET MAUI 应用项目,然后选择“属性”。 然后,导航到“iOS”>“生成”选项卡,并将“链接器行为”下拉列表设置为所需的链接器行为:
保留代码
使用剪裁器时,它有时会删除你可能已动态调用的代码,甚至间接调用。 可以通过使用 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
方法。 如果没有属性,剪裁将删除MyAssembly
或完全删除Helper
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>
注意
设置 TrimmerRootAssembly
MSBuild 属性时不需要 .dll
扩展。
如果修整程序跳过程序集,则它被视为 根目录,这意味着它及其所有静态理解的依赖项都会保留。 可以通过将更多 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>
这会将程序集标记为“可剪裁”,并为该项目启用剪裁警告。 “可剪裁”意味着程序集被视为与剪裁兼容,生成程序集时不应显示剪裁警告。 在经过剪裁的应用中使用时,会在最终输出中删除程序集未使用的成员。
将项目文件中的 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>
该设置显示所有详细警告,而不是将其折叠为每个程序集的单个警告。