앱을 빌드할 때, .NET 다중 플랫폼 앱 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);
}
이 예제에서는 Helper 메서드를 유지하기 위해 DynamicDependency를 사용합니다. 특성이 없으면, 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 속성을 쉽게 사용할 수 없거나, 트리밍되는 코드를 제어할 수 없는 경우에 유용할 수 있습니다.
모든 어셈블리를 트리밍할 때 프로젝트 파일에서 MSBuild 항목을 설정 TrimmerRootAssembly 하여 어셈블리를 건너뛰도록 트리머에게 지시할 수 있습니다.
<ItemGroup>
<TrimmerRootAssembly Include="MyAssembly" />
</ItemGroup>
주의
.dll MSBuild 속성을 설정할 때는 TrimmerRootAssembly 확장이 필요하지 않습니다.
트리머가 어셈블리를 건너뛰면 루팅된 것으로 간주됩니다. 즉, 해당 어셈블리와 정적으로 확인된 모든 종속성이 유지됩니다.
TrimmerRootAssembly에 MSBuild 속성을 더 추가하여 <ItemGroup> 추가 어셈블리를 건너뛸 수 있습니다.
어셈블리, 형식 및 멤버 유지
보존해야 하는 어셈블리, 형식 및 멤버를 지정하는 XML 설명 파일을 트리머에 전달할 수 있습니다.
모든 어셈블리를 트리밍할 때 트리밍 프로세스에서 멤버를 제외하려면 프로젝트 파일의 TrimmerRootDescriptor MSBuild 항목을 제외할 멤버를 정의하는 XML 파일로 설정합니다.
<ItemGroup>
<TrimmerRootDescriptor Include="MyRoots.xml" />
</ItemGroup>
그런 다음 XML 파일은 트리머 설명자 형식 을 사용하여 제외할 멤버를 정의합니다.
<linker>
<assembly fullname="MyAssembly">
<type fullname="MyAssembly.MyClass">
<method name="DynamicallyAccessedMethod" />
</type>
</assembly>
</linker>
이 예제에서 XML 파일은 트리밍에서 제외되는 앱에서 동적으로 액세스하는 메서드를 지정합니다.
어셈블리, 형식 또는 멤버가 XML에 나열되면 기본 동작은 유지입니다. 즉, 트리머가 사용한다고 생각하는지 여부에 관계없이 출력에 유지됩니다.
주의
보존 태그는 모호하게 포괄적입니다. 다음 수준의 세부 정보를 제공하지 않으면 모든 자식이 포함됩니다. 어셈블리가 형식 없이 나열되면 어셈블리의 모든 형식과 멤버가 유지됩니다.
어셈블리를 안전하게 트리밍된 상태로 표시
프로젝트에 라이브러리가 있거나 재사용 가능한 라이브러리의 개발자이고 트리머가 어셈블리를 트리밍 가능한 것으로 처리하려는 경우 어셈블리의 프로젝트 파일에 MSBuild 속성을 추가하여 IsTrimmable 어셈블리를 트리밍 안전으로 표시할 수 있습니다.
<PropertyGroup>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
이렇게 하면 어셈블리가 "트리밍 가능"으로 표시되고 해당 프로젝트에 대한 트리밍 경고가 활성화됩니다. "트리밍 가능"이면 어셈블리가 트리밍과 호환되는 것으로 간주되며 어셈블리가 빌드될 때 트리밍 경고가 없어야 합니다. 트리밍된 앱에서 사용되는 경우 어셈블리의 사용되지 않은 멤버는 최종 출력에서 제거됩니다.
.NET 9 이상에서 네이티브 AOT 배포를 사용하는 경우 IsAotCompatible MSBuild 속성을 true 설정하면 true 속성에 IsTrimmable 값도 할당되고 추가 AOT 분석기 빌드 속성이 활성화됩니다. AOT 분석기에 대한 자세한 내용은 AOT 호환성 분석기을 참조하세요. .NET MAUI용 Native AOT 배포에 대한 자세한 내용은 Native AOT 배포참조하세요.
IsTrimmable MSBuild 속성을 true 프로젝트 파일에서 설정하면 어셈블리에 AssemblyMetadata 특성이 추가됩니다.
[assembly: AssemblyMetadata("IsTrimmable", "True")]
대안적으로, IsTrimmable MSBuild 속성을 어셈블리의 프로젝트 파일에 추가하지 않고도, 어셈블리에 AssemblyMetadata 특성을 추가할 수 있습니다.
주의
어셈블리에 대해 IsTrimmable MSBuild 속성이 설정된 경우, 이는 AssemblyMetadata("IsTrimmable", "True") 특성을 재정의합니다. 이렇게 하면 특성이 없는 경우에도 어셈블리를 트리밍으로 선택하거나 특성이 있는 어셈블리의 트리밍을 사용하지 않도록 설정할 수 있습니다.
분석 경고 표시 안 함
트리머를 사용하도록 설정하면 정적으로 연결할 수 없는 IL이 제거됩니다. 리플렉션 또는 동적 종속성을 만드는 다른 패턴을 사용하는 앱은 결과적으로 손상될 수 있습니다. 이러한 패턴에 대해 경고하기 위해 어셈블리를 트리밍 안전으로 표시할 때는 라이브러리 작성자가 MSBuild 속성을 SuppressTrimAnalysisWarnings의 값으로 false 설정해야 합니다.
<PropertyGroup>
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
</PropertyGroup>
트리밍 분석 경고를 억제하지 않으면 사용자 고유의 코드, 라이브러리 코드, SDK 코드를 포함하여 전체 앱에 대한 경고가 포함됩니다.
자세한 경고 표시
트리밍 분석은 어셈블리의 내부가 트리밍과 호환되지 않음을 나타내는 각 어셈블리에 PackageReference 대해 최대 하나의 경고를 생성합니다. 라이브러리 작성자로서 어셈블리를 트리밍 안전으로 표시할 때, 모든 어셈블리에 대해 개별 경고를 사용하도록 TrimmerSingleWarn MSBuild 속성을 다음과 같이 설정해야 합니다: false.
<PropertyGroup>
<TrimmerSingleWarn>false</TrimmerSingleWarn>
</PropertyGroup>
이 설정은 어셈블리당 단일 경고로 축소하는 대신 모든 자세한 경고를 표시합니다.
.NET MAUI