Google은 흑인 공동체를 위한 인종 간 평등을 진전시키기 위해 노력하고 있습니다. Google에서 어떤 노력을 하고 있는지 확인하세요.

AAPT2

AAPT2(Android Asset Packaging Tool)는 Android 스튜디오 및 Android Gradle 플러그인이 앱의 리소스를 컴파일하고 패키징하는 데 사용하는 빌드 도구입니다. AAPT2는 리소스를 Android 플랫폼에 최적화된 바이너리 형식으로 파싱하고 색인을 생성하며 컴파일합니다.

Android Gradle 플러그인 3.0.0 이상에서는 기본적으로 AAPT2를 사용 설정하므로 일반적으로 aapt2를 직접 호출할 필요가 없습니다. 그러나 Android 스튜디오보다 터미널 및 자체 빌드 시스템 사용을 선호한다면 명령줄에서 AAPT2를 사용할 수 있습니다. 명령줄에서 AAPT2와 관련된 빌드 오류를 디버그할 수도 있습니다. 이렇게 하려면 Android SDK 빌드 도구 26.0.2 이상에서 AAPT2를 독립형 도구로 찾을 수 있습니다.

명령줄에서 Android SDK 빌드 도구를 다운로드하려면 sdkmanager를 사용하여 다음 명령어를 실행합니다.

sdkmanager "build-tools;build-tools-version"

SDK 빌드 도구를 다운로드하고 나면 android_sdk/build-tools/version/에 있는 AAPT2를 찾을 수 있습니다. Android SDK 빌드 도구의 최신 버전은 자주 출시되지 않으므로 SDK 빌드 도구에 포함된 AAPT2가 최신 버전이 아닐 수 있습니다. AAPT2의 최신 버전을 받으려면 Google Maven에서 AAPT2 다운로드를 참조하세요.

Linux 또는 Mac의 명령줄에서 AAPT2를 사용하려면 aapt2 명령어를 실행합니다. Windows의 경우 aapt2.exe 명령어를 실행합니다. AAPT2에서는 증분 컴파일을 사용 설정하여 리소스를 더 빨리 컴파일할 수 있습니다. 이렇게 하려면 리소스 처리를 두 단계로 나누어 실행합니다.

  • 컴파일: 리소스 파일을 바이너리 형식으로 컴파일합니다.
  • 링크: 컴파일된 모든 파일을 병합하여 단일 패키지로 패키징합니다.

이렇게 분할하면 증분 빌드의 성능 향상에 도움이 됩니다. 예를 들어 파일 하나가 변경된 경우 그 파일만 다시 컴파일하면 됩니다.

Google Maven에서 AAPT2 다운로드

빌드 도구에 번들로 포함되지 않은 AAPT2의 최신 버전이 필요한 경우 다음과 같이 Google Maven 저장소에서 AAPT2를 다운로드하면 됩니다.

  1. 저장소 색인에서 com.android.tools.build > aapt2로 이동합니다.
  2. AAPT2 최신 버전의 이름을 복사합니다.
  3. 복사한 버전 이름을 다음 URL에 삽입하고 타겟 운영체제를 지정합니다. https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/aapt2-version/aapt2-aapt2-version-[windows | linux | osx].jar

    예를 들어 Windows용 버전 3.2.0-alpha18-4804415를 다운로드하려면 다음을 사용합니다. https://dl.google.com/dl/android/maven2/com/android/tools/build/aapt2/3.2.0-alpha18-4804415/aapt2-3.2.0-alpha18-4804415-windows.jar

  4. 브라우저에서 URL로 이동하면 곧 AAPT2 다운로드가 시작됩니다.

  5. 방금 다운로드한 JAR 파일의 패키지를 해제합니다. JAR 파일에는 aapt2 실행 파일과 실행 파일에서 사용하는 라이브러리가 포함되어야 합니다.

컴파일

AAPT2는 모든 Android 리소스 유형(예: 드로어블 및 XML 파일)의 컴파일을 지원합니다. 컴파일을 위해 AAPT2를 호출할 경우 호출당 입력으로 단일 리소스 파일을 전달해야 합니다. 그런 다음 AAPT2는 파일을 파싱하고 확장자가 .flat인 중간 바이너리 파일을 생성합니다.

--dir 플래그를 사용하여 리소스 파일이 두 개 이상 포함된 리소스 디렉터리를 AAPT2에 전달할 수 있지만, 그렇게 하면 증분 리소스 컴파일의 이점을 얻지 못합니다. 즉, 전체 디렉터리를 전달하면 AAPT2는 리소스가 하나만 변경되었더라도 디렉터리의 모든 파일을 다시 컴파일합니다.

출력 파일 형식은 컴파일용으로 제공한 입력에 따라 다를 수 있습니다. 이에 관한 설명은 다음 표에 나와 있습니다.

입력 출력
문자열스타일과 같은 res/values/ 디렉터리의 XML 리소스 파일 확장자가 *.arsc.flat인 리소스 테이블
다른 모든 리소스 파일 res/values/ 디렉터리에 있는 파일 이외의 모든 파일은 확장자가 *.flat인 바이너리 XML 파일로 변환됩니다. 또한 기본적으로 모든 PNG 파일이 크런치되며 *.png.flat 확장자를 채택합니다. PNG를 압축하지 않도록 선택하면 컴파일하는 동안 --no-crunch 옵션을 사용할 수 있습니다.

AAPT2 출력 파일은 실행 파일이 아니므로 APK를 생성하려면 나중에 링크 단계에서 이러한 바이너리 파일을 입력으로 포함해야 합니다. 그러나 생성된 APK 파일은 Android 기기에 즉시 배포할 수 있는 실행 파일이 아닙니다. DEX 파일(컴파일된 바이트 코드)이 포함되어 있지 않고 서명되지 않았기 때문입니다.

컴파일 구문

compile을 사용하는 일반적인 구문은 다음과 같습니다.

aapt2 compile path-to-input-files [options] -o output-directory/

다음 예에서 AAPT2는 이름이 각각 values.xmlmyImage.png인 리소스 파일을 컴파일합니다.

aapt2 compile project_root/module_root/src/main/res/values-en/
strings.xml -o compiled/
aapt2 compile project_root/module_root/src/main/res/drawable
/myImage.png -o compiled/

위 표와 같이 출력 파일의 이름은 입력 파일 이름 및 그 상위 디렉터리의 이름(리소스 유형 및 구성)에 따라 달라집니다. strings.xml이 입력인 위 예의 경우 aapt2는 자동으로 출력 파일의 이름을 values-en_strings.arsc.flat으로 지정합니다. 반면 드로어블 디렉터리에 저장되는 컴파일된 드로어블 파일의 파일 이름은 drawable_img.png.flat이 됩니다.

컴파일 옵션

아래 표와 같이 compile 명령어와 함께 사용할 수 있는 여러 옵션이 있습니다.

옵션 설명
-o path 컴파일된 리소스의 출력 경로를 지정합니다.

AAPT2가 컴파일된 리소스를 출력 및 저장할 수 있는 디렉터리의 경로를 지정해야 하므로 이 옵션은 필수 플래그입니다.

--dir directory 리소스를 검색할 디렉터리를 지정합니다.

이 플래그를 사용하면 하나의 명령어로 여러 리소스 파일을 컴파일할 수 있지만, 이 경우 증분 컴파일의 이점을 활용할 수 없으므로 대규모 프로젝트에는 사용하면 안 됩니다.

--pseudo-localize en-XA 및 en-XB 같은 기본 문자열의 pseudo-localized 버전을 생성합니다.
--no-crunch PNG 처리를 사용 중지합니다.

PNG 파일을 이미 처리했거나 파일 크기 축소가 필요 없는 디버그 빌드를 만드는 중인 경우 이 옵션을 사용합니다. 그러면 실행 속도는 빨라지지만 출력 파일 크기가 커집니다.

--legacy 이전 버전의 AAPT를 사용할 때 허용되는 오류를 경고로 처리합니다.

이 플래그는 예기치 않은 컴파일 시간 오류에 사용해야 합니다. AAPT2를 사용하는 동안 발생할 수 있는 알려진 동작 변경사항을 해결하려면 AAPT2의 동작 변경사항을 읽어보세요.

-v 상세 로깅을 사용 설정합니다.

링크 단계에서 AAPT2는 컴파일 단계에서 생성된 모든 중간 파일(예: 리소스 테이블, 바이너리 XML 파일, 처리된 PNG 파일)을 병합하여 단일 APK로 패키징합니다. R.java 및 ProGuard 규칙 파일과 같은 기타 보조 파일도 이 단계에서 생성될 수 있습니다. 그러나 생성된 APK는 DEX 바이트 코드를 포함하지 않으며 서명되어 있지 않습니다. 즉, 이 APK를 기기에 배포할 수 없습니다. Android Gradle 플러그인을 사용하여 명령줄에서 앱을 빌드하지 않는 경우 d8과 같은 다른 명령줄 도구를 사용하여 자바 바이트 코드를 DEX 바이트 코드로 컴파일하고 apksigner를 사용하여 APK에 서명할 수 있습니다.

link를 사용하는 일반적인 구문은 다음과 같습니다.

aapt2 link path-to-input-files [options] -o
outputdirectory/outputfilename.apk --manifest AndroidManifest.xml

다음 예에서 AAPT2는 drawable_Image.flatvalues_values.arsc.flat이라는 중간 파일 두 개와 AndroidManifest.xml 파일을 병합합니다. AAPT2는 Android 패키지에 정의된 리소스를 보유한 android.jar 파일을 기준으로 결과를 연결합니다.

 aapt2 link -o output.apk
 -I android_sdk/platforms/android_version/android.jar
    compiled/res/values_values.arsc.flat
    compiled/res/drawable_Image.flat --manifest /path/to/AndroidManifest.xml -v

link 명령어와 함께 다음 옵션을 사용할 수 있습니다.

옵션 설명
-o path 연결된 리소스 APK의 출력 경로를 지정합니다.

연결된 리소스를 포함할 수 있는 출력 APK의 경로를 지정해야 하므로 이 옵션은 필수 플래그입니다.

--manifest file 빌드할 Android 매니페스트 파일의 경로를 지정합니다.

매니페스트 파일은 패키지 이름 및 애플리케이션 ID와 같은 앱 관련 필수 정보를 포함하므로 이 옵션은 필수 플래그입니다.

-I 플랫폼의 android.jar 경로 또는 기능을 빌드하는 동안 유용할 수 있는 framework-res.apk와 같은 다른 APK의 경로를 제공합니다.

리소스 파일에서 android 네임스페이스가 있는 속성(예: android:id)을 사용하는 경우 이 플래그는 필수입니다.
-A directory APK에 포함할 assets 디렉터리를 지정합니다.

처리되지 않은 원본 파일을 저장하는 데 이 디렉터리를 사용할 수 있습니다. 자세한 내용은 원본 파일 액세스를 참조하세요.

-R file <add-resource> 태그를 사용하지 않고 overlay 의미 체계를 사용하여 연결할 개별 .flat 파일을 전달합니다.

기존 파일을 오버레이(확장 또는 수정)하는 리소스 파일을 제공하면, 지정된 마지막 충돌 리소스가 사용됩니다.

--package-id package-id 앱에 사용할 패키지 ID를 지정합니다.

지정한 패키지 ID는 0x7f보다 크거나 같아야 합니다. 단 --allow-reserved-package-id와 함께 사용되는 경우는 예외입니다.

--allow-reserved-package-id 예약된 패키지 ID를 사용할 수 있습니다.

예약된 패키지 ID는 일반적으로 공유 라이브러리에 할당되며 0x02~0x7e 범위(포함)에 속하는 ID입니다. --allow-reserved-package-id을 사용하여 예약된 패키지 ID의 범위에 속하는 ID를 할당할 수 있습니다.

최소 SDK 버전이 26 이하인 패키지에만 사용해야 합니다.

--java directory R.java를 생성할 디렉터리를 지정합니다.
--proguard proguard_options ProGuard 규칙의 출력 파일을 생성합니다.
--proguard-conditional-keep-rules 기본 dex에 관한 ProGuard 규칙의 출력 파일을 생성합니다.
--no-auto-version 자동 스타일 및 레이아웃 SDK 버전 관리를 사용 중지합니다.
--no-version-vectors 벡터 드로어블의 자동 버전 관리를 사용 중지합니다. Vector Drawable 라이브러리로 APK를 빌드할 경우에만 사용하세요.
--no-version-transitions 전환 리소스의 자동 버전 관리를 사용 중지합니다. Transition Support 라이브러리로 APK를 빌드할 경우에만 사용하세요.
--no-resource-deduping 호환 가능한 구성 전체에서 동일한 값을 가진 리소스의 자동 중복 제거를 사용 중지합니다.
--enable-sparse-encoding 바이너리 검색 트리를 사용하여 희소 항목의 인코딩을 사용 설정합니다. 이는 APK 크기를 최적화하는 데에는 유용하지만, 리소스 검색 성능이 저하됩니다.
-z 'suggested'로 표시된 문자열의 현지화가 필요합니다.
-c config 쉼표로 구분된 구성 목록을 제공합니다.

예를 들어, 여러 언어의 번역이 포함되어 있는 지원 라이브러리의 종속 항목이 있는 경우 영어 또는 스페인어와 같은 특정 언어 구성에 대해서만 리소스를 필터링할 수 있습니다.

두 글자로 된 ISO 639-1 언어 코드 및 원하는 경우 두 글자로 된 ISO 3166-1-alpha-2 지역 코드(앞에 소문자 'r' 표시, 예: en-rUS)로 언어 구성을 정의해야 합니다.

--preferred-density density AAPT2가 가장 근접한 일치 밀도를 선택하고 다른 모든 밀도를 제거하도록 허용합니다.

ldpi, hdpi 및 xhdpi와 같이 앱에서 사용할 수 있는 몇 가지 픽셀 밀도 한정자가 있습니다. 원하는 밀도를 지정하면 AAPT2는 리소스 테이블에서 가장 근접한 일치 밀도를 선택하여 저장하고 다른 밀도는 모두 삭제합니다.

--output-to-dir -o로 지정된 디렉터리에 APK 콘텐츠를 출력합니다.

이 플래그 사용 시 오류가 발생하면 Android SDK 빌드 도구 28.0.0 이상으로 업그레이드하여 문제를 해결할 수 있습니다.

--min-sdk-version min-sdk-version AndroidManifest.xml에 사용할 기본 최소 SDK 버전을 설정합니다.
--target-sdk-version target-sdk-version AndroidManifest.xml에 사용할 기본 타겟 SDK 버전을 설정합니다.
--version-code version-code 존재하지 않는 경우 AndroidManifest.xml에 삽입할 버전 코드(정수)를 지정합니다.
--compile-sdk-version-name compile-sdk-version-name 존재하지 않는 경우 AndroidManifest.xml에 삽입할 버전 이름을 지정합니다.
--proto-format 컴파일된 리소스를 Protobuf 형식으로 생성합니다.

Android App Bundle 생성용 번들 도구에 입력으로 사용하기에 적합합니다.

--non-final-ids 최종이 아닌 리소스 ID로 R.java를 생성합니다. 앱 코드의 ID 참조는 kotlinc/javac 컴파일 중에 인라인되지 않습니다.
--emit-ids path 리소스 유형 이름과 각 ID 매핑의 목록을 사용하여 지정된 경로에서 파일을 생성합니다. --stable-ids와 함께 사용하는 것이 좋습니다.
--stable-ids outputfilename.ext 리소스 유형 이름과 각 이름에 할당된 ID의 목록이 포함된 --emit-ids로 생성된 파일을 사용합니다.

이 옵션을 사용하면 연결하는 동안 새 리소스를 삭제하거나 추가할 때도 할당된 ID가 안정적으로 유지됩니다.

--custom-package package_name R.java를 생성할 맞춤 자바 패키지를 지정합니다.
--extra-packages package_name 동일한 R.java 파일을 생성하지만 패키지 이름은 다릅니다.
--add-javadoc-annotation annotation 생성된 모든 자바 클래스에 JavaDoc 주석을 추가합니다.
--output-text-symbols path 지정된 파일에서 R 클래스의 리소스 기호를 포함하는 텍스트 파일을 생성합니다.

출력 파일의 경로를 지정해야 합니다.

--auto-add-overlay <add-resource> 태그를 사용하지 않고 오버레이에서 새 리소스를 추가할 수 있습니다.
--rename-manifest-package manifest-package AndroidManifest.xml에서 패키지 이름을 다시 지정합니다.
--rename-instrumentation-target-package instrumentation- target-package 계측을 위한 타겟 패키지의 이름을 변경합니다.

--rename-manifest-package와 함께 사용해야 합니다.

-0 extension

압축하지 않을 파일의 확장자를 지정합니다.

--split path:config[,config[..]] 구성 집합을 기반으로 리소스를 분할하여 다른 버전의 APK를 생성합니다.

구성 집합과 함께 출력 APK의 경로를 지정해야 합니다.

-v 출력을 훨씬 자세히 표시할 수 있습니다.

덤프

dumplink 명령어를 사용하여 생성한 APK 관련 정보를 출력하는 데 사용됩니다. 예를 들어 다음 명령어는 특정 APK의 리소스 테이블에서 콘텐츠를 출력합니다.

aapt2 dump resources output.apk

덤프 구문

dump를 사용하는 일반적인 구문은 다음과 같습니다.

aapt2 dump sub-command filename.apk [options]

덤프 하위 명령어

dump 명령어로 다음 하위 명령어 중 하나를 지정해야 합니다.

하위 명령어설명
apc 컴파일 중에 생성된 AAPT2 컨테이너(APC)의 콘텐츠를 출력합니다.
badging APK의 매니페스트에서 추출한 정보를 출력합니다.
configurations APK의 리소스에서 사용하는 모든 구성을 출력합니다.
packagename APK의 패키지 이름을 출력합니다.
permissions APK의 매니페스트에서 추출한 권한을 출력합니다.
strings APK의 리소스 테이블 문자열 풀에 있는 콘텐츠를 출력합니다.
styleparents APK에 사용된 스타일의 상위 요소를 출력합니다.
resources APK 리소스 테이블의 콘텐츠를 출력합니다.
xmlstrings APK의 컴파일된 xml에서 문자열을 출력합니다.
xmltree APK의 컴파일된 xml에서 트리를 출력합니다.

덤프 옵션

dump와 함께 다음 옵션을 사용할 수 있습니다.

옵션설명
--no-values 리소스를 표시할 때 값의 출력을 억제합니다.
--file file 파일을 APK에서 덤프할 인수로 지정합니다.
-v 결과가 더욱 상세하게 출력됩니다.

AAPT2 사용 시 동작 변경사항

AAPT2 이전에는 AAPT가 Android Asset Packaging Tool의 기본 버전이었으며 지금은 지원이 중단되었습니다. AAPT2를 이전 프로젝트에서 즉시 사용할 수 있지만 이 섹션에서는 반드시 알아야 할 몇 가지 동작 변경사항을 설명합니다.

Android 매니페스트의 요소 계층 구조

이전 버전의 AAPT에서는 Android 매니페스트의 잘못된 노드에 요소가 중첩되어 있으면 이를 무시하거나 경고를 보냈습니다. 예를 들어 다음 샘플을 살펴보겠습니다.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.myname.myapplication">
   <application
       ...
       <activity android:name=".MainActivity">
           <intent-filter>
               <action android:name="android.intent.action.MAIN" />
               <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
           <action android:name="android.intent.action.CUSTOM" />
       </activity>
   </application>
</manifest>

이전 버전의 AAPT에서는 위치가 잘못된 <action> 태그를 간단히 무시했습니다. 그러나 AAPT2에서는 다음과 같은 오류가 발생합니다.

AndroidManifest.xml:15: error: unknown element <action> found.

문제를 해결하려면 매니페스트 요소를 올바르게 중첩해야 합니다. 자세한 내용은 매니페스트 파일 구조를 참조하세요.

리소스 선언

더 이상 name 속성에서 리소스 유형을 표시할 수 없습니다. 예를 들어 다음 샘플은 attr 리소스 항목을 잘못 선언합니다.

<style name="foo" parent="bar">
    <item name="attr/my_attr">@color/pink</item>
</style>

이렇게 리소스 유형을 선언하면 다음과 같은 빌드 오류가 발생합니다.

Error: style attribute 'attr/attr/my_attr (aka my.package:attr/attr/my_attr)'
not found.

이 오류를 해결하려면 type="attr"을 사용하여 유형을 명시적으로 선언합니다.

<style name="foo" parent="bar">
  <item type="attr" name="my_attr">@color/pink</item>
</style>

또한 <style> 요소를 선언할 때 그 상위 요소도 스타일 리소스 유형이어야 합니다. 그렇지 않으면 다음과 비슷한 오류가 발생합니다.

Error: (...) invalid resource type 'attr' for parent of style

ForegroundLinearLayout이 포함된 Android 네임스페이스

ForegroundLinearLayout에는 foregroundInsidePadding, android:foreground, android:foregroundGravity라는 세 가지 속성이 포함됩니다. foregroundInsidePadding은 다른 두 개의 속성과 달리 android 네임스페이스에 포함되지 않습니다.

이전 버전의 AAPT에서는 foregroundInsidePadding 속성을 android 네임스페이스로 정의하면 컴파일러가 자동으로 이를 무시했습니다. AAPT2를 사용하면 컴파일러가 이 문제를 조기에 발견하고 다음과 같은 빌드 오류를 발생시킵니다.

Error: (...) resource android:attr/foregroundInsidePadding is private

이 문제를 해결하려면 android:foregroundInsidePaddingforegroundInsidePadding으로 교체하세요.

리소스 참조 기호 @의 잘못된 사용

AAPT2에서는 리소스 참조 기호(@)를 생략하거나 잘못된 위치에 배치하면 빌드 오류가 발생합니다. 예를 들어 다음은 스타일 속성을 지정할 때 참조 기호를 생략한 경우입니다.

<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
  ...
  <!-- Note the missing '@' symbol when specifying the resource type. -->
  <item name="colorPrimary">color/colorPrimary</item>
</style>

AAPT2에서는 모듈을 빌드할 때 다음과 같은 빌드 오류가 발생합니다.

ERROR: expected color but got (raw string) color/colorPrimary

그리고 다음은 android 네임스페이스에서 리소스에 액세스할 때 참조 기호를 잘못 포함한 경우입니다.

...
<!-- When referencing resources from the 'android' namespace, omit the '@' symbol. -->
<item name="@android:windowEnterAnimation"/>

AAPT2에서는 모듈을 빌드할 때 다음과 같은 빌드 오류가 발생합니다.

Error: style attribute '@android:attr/windowEnterAnimation' not found

라이브러리의 잘못된 구성

앱에 Android SDK 빌드 도구의 이전 버전을 사용하여 빌드된 타사 라이브러리의 종속 항목이 있는 경우, 런타임 시 오류나 경고를 표시하지 않고 앱이 비정상 종료될 수 있습니다. 라이브러리를 만드는 동안 R.java 필드가 final로 선언되어 모든 리소스 ID가 라이브러리의 클래스에서 인라인 처리되므로 이러한 비정상 종료가 발생할 수 있습니다.

AAPT2는 앱을 빌드할 때 ID를 라이브러리 리소스에 다시 할당할 수 있는 기능에 의존합니다. 라이브러리가 ID를 final로 가정하고 라이브러리 dex에서 인라인 처리하면 런타임 불일치가 발생합니다.

이 오류를 해결하려면 라이브러리 작성자에게 문의하여 최신 버전의 Android SDK 빌드 도구를 사용하는 라이브러리를 다시 빌드하여 라이브러리를 다시 게시합니다.