ProGuard

Xamarin.Android ProGuard는 Java 클래스 파일 축소, 최적화 및 사전 검증 도구입니다. 사용되지 않는 코드를 검색 및 제거하고, 바이트 코드를 분석 및 최적화합니다. 이 가이드에서는 ProGuard가 작동하는 방법, ProGuard를 프로젝트에서 사용하는 방법과 구성하는 방법을 설명합니다. 또한 ProGuard 구성의 몇 가지 예를 제공합니다.

개요

ProGuard는 패키지 애플리케이션에서 사용되지 않는 클래스, 필드, 메서드 및 특성을 검색하고 제거합니다. 참조된 라이브러리에 대해서도 동일한 작업을 수행할 수 있습니다(64k 참조 제한에 도달하지 않도록 하는 데 도움이 됨). 또한 Android SDK에서 ProGuard 도구는 바이트 코드를 최적화하고 사용되지 않는 코드 지침을 제거합니다. ProGuard는 입력 jar를 읽은 다음, 축소, 최적화, 사전 검증하고, 하나 이상의출력 jar에 결과를 기록합니다.

ProGuard는 다음 단계를 통해 입력 APK를 처리합니다.

  1. 축소 단계 – ProGuard는 사용되는 클래스 및 클래스 멤버를 재귀적으로 결정합니다. 다른 모든 클래스와 클래스 멤버는 삭제됩니다.

  2. 최적화 단계 – ProGuard는 코드를 추가로 최적화합니다. 여러 가지 최적화 중에서도 진입점이 아닌 클래스 및 메서드를 비공개, 정적 또는 최종으로 만들 수 있고, 사용하지 않는 매개 변수를 제거할 수 있으며, 일부 메서드를 인라인할 수 있습니다.

  3. 난독 처리 단계 – 네이티브 Android 개발에서 ProGuard는 진입점이 아닌 클래스 및 클래스 멤버의 이름을 바꿉니다. 진입점을 그대로 유지하면 원래 이름으로 여전히 액세스할 수 있습니다. 그러나 앱이 IL(중간 언어)로 컴파일되기 때문에 이 단계는 Xamarin.Android에서 지원되지 않습니다.

  4. 사전 준비 단계 – 런타임에 앞서 Java 바이트 코드에서 검사 수행하고 Java VM의 이점을 위해 클래스 파일에 주석을 추가합니다. 이는 진입점을 알 필요가 없는 유일한 단계입니다.

이러한 각 단계는 선택 사항입니다. 다음 섹션에서 설명하겠지만, Xamarin.Android ProGuard는 이 단계 중 일부만 사용합니다.

Xamarin.Android의 ProGuard

Xamarin.Android ProGuard 구성은 APK를 난독 처리하지 않습니다. 사실 ProGuard를 통한 난독 처리를 활성화하는 것은 불가능합니다(사용자 지정 구성 파일을 사용해도 불가능). 따라서 Xamarin.Android의 ProGuard는 축소최적화 단계만 수행합니다.

Shrinking and optimization steps

ProGuard를 사용하기 전에 미리 알아두어야 할 중요한 항목은 Xamarin.Android 빌드 프로세스 내에서의 작동 방식입니다. 이 프로세스는 두 가지 단계를 사용합니다.

  1. Xamarin Android 링커

  2. ProGuard

이러한 각 단계는 다음에 설명합니다.

링커 단계

Xamarin.Android 링커는 애플리케이션의 정적 분석을 적용하여 다음을 확인합니다.

  • 실제로 사용되는 어셈블리.

  • 실제로 사용되는 유형.

  • 실제로 사용되는 멤버.

링커는 항상 ProGuard 단계 전에 실행됩니다. 따라서 링커는 ProGuard가 실행되는 어셈블리/유형/멤버를 스트라이프할 수 있습니다. (Xamarin.Android에서 연결하는 방법에 대한 자세한 내용은 Android에서 연결을 참조하세요.)

ProGuard 단계

링커 단계가 성공적으로 완료되면 ProGuard가 실행되어 사용하지 않는 Java 바이트 코드를 제거합니다. 이는 APK를 최적화하는 단계입니다.

ProGuard 사용

앱 프로젝트에서 ProGuard를 사용하려면 먼저 ProGuard를 활성화해야 합니다. 다음으로, Xamarin.Android 빌드 프로세스가 기본 ProGuard 구성 파일을 사용하도록 하거나, ProGuard에서 사용할 사용자 지정 구성 파일을 직접 만들 수 있습니다.

ProGuard 활성화

앱 프로젝트에서 ProGuard를 활성화하려면 다음 단계를 수행합니다.

  1. 프로젝트가 릴리스 구성으로 설정되어 있는지 확인합니다(ProGuard가 실행되려면 링커가 실행되어야 하므로 중요함).

    Select Release configuration

  2. 속성 > Android 옵션 창의 코드 축소기 드롭다운 목록에서 ProGuard 선택합니다.

    Proguard code shrinker selected

대부분의 Xamarin.Android 앱에서는 Xamarin.Android가 제공하는 기본 ProGuard 구성 파일만으로도 사용되지 않는 코드만 모두 제거할 수 있습니다. 기본 ProGuard 구성을 보려면 obj\Release\proguard\proguard_xamarin.cfg에서 파일을 엽니다.

다음 예제는 일반적으로 생성된 proguard_xamarin.cfg 파일을 보여 줍니다.

# This is Xamarin-specific (and enhanced) configuration.

-dontobfuscate

-keep class mono.MonoRuntimeProvider { *; <init>(...); }
-keep class mono.MonoPackageManager { *; <init>(...); }
-keep class mono.MonoPackageManager_Resources { *; <init>(...); }
-keep class mono.android.** { *; <init>(...); }
-keep class mono.java.** { *; <init>(...); }
-keep class mono.javax.** { *; <init>(...); }
-keep class opentk.platform.android.AndroidGameView { *; <init>(...); }
-keep class opentk.GameViewBase { *; <init>(...); }
-keep class opentk_1_0.platform.android.AndroidGameView { *; <init>(...); }
-keep class opentk_1_0.GameViewBase { *; <init>(...); }

-keep class android.runtime.** { <init>(***); }
-keep class assembly_mono_android.android.runtime.** { <init>(***); }
# hash for android.runtime and assembly_mono_android.android.runtime.
-keep class md52ce486a14f4bcd95899665e9d932190b.** { *; <init>(...); }
-keepclassmembers class md52ce486a14f4bcd95899665e9d932190b.** { *; <init>(...); }

# Android's template misses fluent setters...
-keepclassmembers class * extends android.view.View {
   *** set*(***);
}

# also misses those inflated custom layout stuff from xml...
-keepclassmembers class * extends android.view.View {
   <init>(android.content.Context,android.util.AttributeSet);
   <init>(android.content.Context,android.util.AttributeSet,int);
}

다음 섹션에서는 사용자 지정 ProGuard 구성 파일을 만드는 방법을 설명합니다.

ProGuard 사용자 지정

필요에 따라 사용자 지정 ProGuard 구성 파일을 추가하여 ProGuard 도구를 더 세부적으로 제어할 수 있습니다. 예를 들어 ProGuard에 어떤 클래스를 유지할지 명시적으로 알려줄 수 있습니다. 이렇게 하려면 솔루션 탐색기속성 창에서 새 .cfg 파일을 만들고 ProGuardConfiguration 빌드 동작을 적용합니다.

ProguardConfiguration build action selected

이 구성 파일은 Xamarin.Android proguard_xamarin.cfg 파일을 대체하지 않습니다. 두 파일은 모두 ProGuard에서 사용되기 때문입니다.

ProGuard가 애플리케이션을 제대로 분석할 수 없는 경우가 있을 수 있습니다. 이 경우 애플리케이션에 실제로 필요한 코드를 잠재적으로 제거할 수 있습니다. 그러면 사용자 지정 ProGuard 구성 파일에 -keep 줄을 추가할 수 있습니다.

-keep public class MyClass

이 예제에서는 ProGuard가 건너뛰도록 할 클래스의 실제 이름으로 MyClass가 설정됩니다.

또한 [Register] 주석을 사용하여 고유한 이름을 등록할 수 있고, 이러한 이름을 사용하여 ProGuard 규칙을 사용자 지정할 수 있습니다. Adapters, Views, BroadcastReceivers, Services, ContentProviders, Activities 및 Fragments의 이름을 등록할 수 있습니다. [Register] 사용자 지정 특성을 사용하는 방법에 대한 자세한 내용은 JNI 사용을 참조하세요.

ProGuard 옵션

ProGuard는 작동을 세부적으로 제어하도록 구성할 수 있는 다양한 옵션을 제공합니다. ProGuard Manual은 ProGuard 사용에 대한 완전한 참조 설명서를 제공합니다.

Xamarin.Android는 다음과 같은 ProGuard 옵션을 지원합니다.

다음 옵션은 Xamarin.Android에 의해 무시됩니다.

ProGuard 및 Android Nougat

Android 7.0 이상에서 ProGuard를 사용하려는 경우 최신 버전의 ProGuard를 다운로드해야 합니다. Android SDK는 JDK 1.8과 호환되는 새 버전을 제공하지 않기 때문입니다.

NuGet 패키지를 사용하여 최신 버전의 proguard.jar를 설치할 수 있습니다. 기본 Android SDK proguard.jar를 업데이트하는 방법에 대한 자세한 내용은 이 스택 오버플로 설명을 참조하세요.

ProGuard의 모든 버전은 SourceForge 페이지에서 찾을 수 있습니다.

ProGuard 구성 예제

ProGuard 구성 파일의 두 예제는 다음과 같습니다. 이 경우에는 Xamarin.Android 빌드 프로세스가 input, outputlibrary jar를 제공합니다. 따라서 -keep 같은 기타 옵션에 집중할 수 있습니다.

간단한 Android 활동

다음 예제에서는 간단한 Android 활동에 대한 구성을 보여줍니다.

-injars  bin/classes
-outjars bin/classes-processed.jar
-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar

-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic

-keep public class mypackage.MyActivity

완전한 Android 애플리케이션

다음 예제에서는 완전한 Android 앱에 대한 구성을 보여줍니다.

-injars  bin/classes
-injars  libs
-outjars bin/classes-processed.jar
-libraryjars /usr/local/java/android-sdk/platforms/android-9/android.jar

-dontpreverify
-repackageclasses ''
-allowaccessmodification
-optimizations !code/simplification/arithmetic
-keepattributes *Annotation*

-keep public class * extends android.app.Activity
-keep public class * extends android.app.Application
-keep public class * extends android.app.Service
-keep public class * extends android.content.BroadcastReceiver
-keep public class * extends android.content.ContentProvider

-keep public class * extends android.view.View {
public <init>(android.content.Context);
public <init>(android.content.Context, android.util.AttributeSet);
public <init>(android.content.Context, android.util.AttributeSet, int);
public void set*(...);
}

-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet);
}

-keepclasseswithmembers class * {
public <init>(android.content.Context, android.util.AttributeSet, int);
}

-keepclassmembers class * implements android.os.Parcelable {
static android.os.Parcelable$Creator CREATOR;
}

-keepclassmembers class **.R$* {
public static <fields>;
}

ProGuard 및 Xamarin.Android 빌드 프로세스

다음 섹션에서는 Xamarin.Android 릴리스 빌드 중에 ProGuard가 실행되는 방법을 설명합니다.

ProGuard가 실행하는 명령은 무엇인가요?

ProGuard는 단순히 Android SDK와 함께 제공되는 .jar입니다. 따라서 명령에서 호출됩니다.

java -jar proguard.jar options ...

ProGuard 작업

ProGuard 작업은 Xamarin.Android.Build.Tasks.dll 어셈블리 내에서 발견됩니다. _CompileDex 대상에 포함된 _CompileToDalvikWithDx 대상에 포함되어 있습니다.

다음 목록에서는 파일 >새 프로젝트를 사용하여 새 프로젝트를 만든 후 생성되는 기본 매개 변수의 예를 제공합니다.

ProGuardJarPath = C:\Android\android-sdk\tools\proguard\lib\proguard.jar
AndroidSdkDirectory = C:\Android\android-sdk\
JavaToolPath = C:\Program Files (x86)\Java\jdk1.8.0_92\\bin
ProGuardToolPath = C:\Android\android-sdk\tools\proguard\
JavaPlatformJarPath = C:\Android\android-sdk\platforms\android-25\android.jar
ClassesOutputDirectory = obj\Release\android\bin\classes
AcwMapFile = obj\Release\acw-map.txt
ProGuardCommonXamarinConfiguration = obj\Release\proguard\proguard_xamarin.cfg
ProGuardGeneratedReferenceConfiguration = obj\Release\proguard\proguard_project_references.cfg
ProGuardGeneratedApplicationConfiguration = obj\Release\proguard\proguard_project_primary.cfg
ProGuardConfigurationFiles

    {sdk.dir}tools\proguard\proguard-android.txt;
    {intermediate.common.xamarin};
    {intermediate.references};
    {intermediate.application};
    ;

JavaLibrariesToEmbed = C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v7.0\mono.android.jar
ProGuardJarInput = obj\Release\proguard\__proguard_input__.jar
ProGuardJarOutput = obj\Release\proguard\__proguard_output__.jar
DumpOutput = obj\Release\proguard\dump.txt
PrintSeedsOutput = obj\Release\proguard\seeds.txt
PrintUsageOutput = obj\Release\proguard\usage.txt
PrintMappingOutput = obj\Release\proguard\mapping.txt

다음 예제는 IDE에서 실행되는 일반적인 ProGuard 명령을 보여줍니다.

C:\Program Files (x86)\Java\jdk1.8.0_92\\bin\java.exe -jar C:\Android\android-sdk\tools\proguard\lib\proguard.jar -include obj\Release\proguard\proguard_xamarin.cfg -include obj\Release\proguard\proguard_project_references.cfg -include obj\Release\proguard\proguard_project_primary.cfg "-injars 'obj\Release\proguard\__proguard_input__.jar';'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\MonoAndroid\v7.0\mono.android.jar'" "-libraryjars 'C:\Android\android-sdk\platforms\android-25\android.jar'" -outjars "obj\Release\proguard\__proguard_output__.jar" -optimizations !code/allocation/variable

문제 해결

파일 문제

ProGuard가 구성 파일을 읽을 때 다음과 같은 오류 메시지가 표시될 수 있습니다.

Unknown option '-keep' in line 1 of file 'proguard.cfg'

이 문제는 일반적으로 Windows에서 .cfg 파일에 잘못된 인코딩이 있는 경우에 발생합니다. ProGuard는 텍스트 파일에 있는 바이트 순서 표시(BOM)를 처리할 수 없습니다. BOM이 있는 경우 ProGuard는 위의 오류와 함께 종료됩니다.

이 문제를 방지하려면 파일을 BOM 없이 저장할 수 있는 텍스트 편집기에서 사용자 지정 구성 파일을 편집합니다. 이 문제를 해결하려면 텍스트 편집기의 인코딩이 UTF-8로 설정되어 있는지 확인합니다. 예를 들어 텍스트 편집기 Notepad++는 파일을 저장할 때 Encoding > Encode in UTF-8 Without BOM을 선택하면 BOM 없이 파일을 저장할 수 있습니다.

기타 이슈

ProGuard 문제 해결 페이지에는 ProGuard 사용 시 발생할 수 있는 일반적인 문제 및 해결책이 설명되어 있습니다.

요약

이 가이드에서는 Xamarin.Android에서 ProGuard가 작동하는 방법, ProGuard를 앱 프로젝트에서 사용하는 방법과 구성하는 방법을 설명합니다. 예제 ProGuard 구성을 제공하고 일반적인 문제에 대한 해결책을 설명합니다. ProGuard 도구 및 Android에 대한 자세한 내용은 코드 축소 및 리소스를 참조하세요.