AAPT2

AAPT2(Android Asset Packaging Tool)は、Android Studio と Android Gradle Plugin がアプリのリソースをコンパイル、パッケージ化するために使用するビルドツールです。AAPT2 はリソースを解析してインデックスに登録し、Android プラットフォーム向けに最適化されたバイナリ形式にコンパイルします。

Android Gradle Plugin 3.0.0 以上ではデフォルトで AAPT2 が有効になっており、通常はデベロッパー自身が aapt2 を呼び出す必要はありません。ただし、Android Studio ではなく、ターミナルや独自のビルドシステムを使用する場合は、コマンドラインから AAPT2 を使用できます。AAPT2 に関するビルドエラーをコマンドラインからデバッグすることもできます。AAPT2 を使用するには、Android Studio SDK Build Tools 26.0.2 以上からスタンドアロン ツールの AAPT2 を探します。

コマンドラインから Android SDK Build Tools をダウンロードするには、sdkmanager を使用して次のコマンドを実行します。

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

SDK Build Tools をダウンロードすると、AAPT2 が android_sdk/build-tools/version/ に含まれています。Android SDK Build Tools の新しいリビジョンはあまり頻繁にはリリースされないので、SDK Build Tools に含まれる AAPT2 は最新版ではない可能性があります。AAPT2 の最新版を入手するには Google Maven から AAPT2 をダウンロードする方法についての説明をご覧ください。

Linux または Mac でコマンドラインから AAPT2 を使用するには、aapt2 コマンドを実行します。Windows では、aapt2.exe コマンドを実行します。AAPT2 は増分コンパイルを可能にすることで、リソースの高速コンパイルをサポートしています。これは、リソースの処理を 2 つのステップに分割することで実現されています。

  • コンパイル: リソース ファイルをバイナリ形式にコンパイルします。
  • リンク: コンパイル済みのすべてのファイルをマージし、それを単一のパッケージにパッケージ化します。

この分割により、増分ビルドのパフォーマンスが向上します。たとえば、単一のファイルを変更した場合、再コンパイルが必要なのはそのファイルだけです。

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 のバージョン]/aapt2-[AAPT2 のバージョン]-[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 は、ドローアブルや XML ファイルなど、すべての Android リソースタイプのコンパイルをサポートしています。AAPT2 を呼び出してコンパイルする際、呼び出しごとに入力として、単一のリソース ファイルを渡す必要があります。AAPT2 がそのファイルを解析し、バイナリの中間ファイルを生成して、.flat 拡張子を付けます。

複数のリソース ファイルを含むリソース ディレクトリを、--dir フラグを使って AAPT2 に渡すことができますが、その場合は、リソースの増分コンパイルによるメリットは受けられません。つまり、ディレクトリ全体を渡すので、リソースを 1 つしか変更していなくても、AAPT2 はディレクトリ内のすべてのファイルを再コンパイルします。

出力ファイル形式は、コンパイルに指定する入力によって異なることがあります。これについては、下記の表で説明します。

入力 出力
XML リソース ファイル(res/values/ ディレクトリにある文字列スタイルなど) *.asrc.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 リソースをスキャンするディレクトリを指定します。

このフラグを使用して 1 つのコマンドで複数のリソース ファイルをコンパイルできますが、増分コンパイルのメリットがなくなるため、大規模なプロジェクトには使用しないでください。

--pseudo-localize en-XA や en-XB などのデフォルト文字列の擬似ローカライズ バージョンを生成します。
--no-crunch PNG 処理を無効にします。

PNG ファイルが処理済みの場合や、ファイルサイズを削減する必要がないデバッグ用ビルドを作成する場合に、このオプションを使用します。このオプションを有効にすると実行は速くなりますが、出力ファイルサイズが大きくなります。

--legacy AAPT の以前のバージョンでは許容されていたエラーを警告として扱います。

このフラグは、予期しないコンパイル時エラーのために使用する必要があります。AAPT2 の使用時に発生する動作変更による既知の問題を解決するには、AAPT2 での動作の変更点についての説明をご覧ください。

-v 詳細ログを有効にします。

リンクフェーズで AAPT2 は、コンパイル フェーズで生成した中間ファイル(リソース テーブル、バイナリ XML ファイル、処理済みの PNG ファイルなど)をすべてマージして、単一の APK にパッケージ化します。さらにこのフェーズで、その他の補助ファイル(R.java ファイル、ProGuard ルールファイルなど)を生成できます。ただし、生成された APK には DEX バイトコードは含まれず、署名もされていません。そのため、この APK をデバイスにデプロイすることはできません。コマンドラインからアプリをビルドするのに Android Gradle Plugin を使用しない場合、d8 などの他のコマンドライン ツールを使用して Java バイトコードを DEX バイトコードにコンパイルし、apksigner を使用して APK に署名することができます。

link を使用する一般的な構文は次のとおりです。

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

次の例で AAPT2 は、2 つの中間ファイル(drawable_Image.flatvalues_values.arsc.flat)と AndroidManifest.xml ファイルをマージします。そしてその結果を android.jar ファイルにリンクします。このファイルには Android パッケージで定義されたリソースが保管されます。

     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 に含めるアセット ディレクトリを指定します。

このディレクトリを使用して、処理する前の元のファイルを保存できます。詳しくは、元のファイルにアクセスする場合についての説明をご覧ください。

-R file <add-resource> タグを使用せずに overlay セマンティクスを使用して、リンクする .flat ファイルを個別に渡します。

既存のファイルをオーバーレイ(拡張または変更)するリソース ファイルを指定すると、競合するリソースのうち、最後に指定されたものが使用されます。

--package-id package-id アプリに使用するパッケージ ID を指定します。

パッケージ ID は、--allow-reserved-package-id. と組み合わせて指定する場合を除いて、0x7f 以上を指定する必要があります。

--allow-reserved-package-id 予約済みのパッケージ ID の使用を許可します。

予約済みのパッケージ ID とは、共有ライブラリに通常割り当てられる 0x02~0x7e の範囲の ID です。--allow-reserved-package-id を指定すると、予約済みのパッケージ ID の範囲にある ID を割り当てることができます。

これは、min-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 Library を使って APK をビルドする場合にのみ使用します。
--no-version-transitions 遷移リソースの自動バージョン管理を無効にします。これは、Transition Support Library を使って APK をビルドする場合にのみ使用します。
--no-resource-deduping 互換性のある設定間で同一の値を持つリソースの自動重複除去を無効にします。
--enable-sparse-encoding バイナリ検索ツリーを使用してスパース エントリのエンコードを有効にします。これは APK サイズの最適化には有効ですが、リソースの取得パフォーマンスが犠牲になります。
-z "suggested" とマークされた文字列のローカライズを必須とします。
-c config カンマで区切られた設定のリストを指定します。

たとえば、サポート ライブラリ(複数の言語の翻訳を含む)に対して依存関係がある場合、指定した言語設定(英語、スペイン語など)にのみリソースをフィルタできます。

言語設定は 2 文字の ISO 639-1 言語コードによって定義する必要があります。地域コードが必要であれば、直後に小文字の「r」の後に、2 文字の ISO 3166-1-alpha-2 地域コードを指定します(例: en-rUS)。

--preferred-density density AAPT2 が最も近い密度を選択して、その他はすべて削除できるようにします。

アプリで使用できるピクセル密度の修飾子には、ldpi、hdpi、xhdpi などがあります。優先する密度を指定すると、AAPT2 は最も近い密度を選択してリソース テーブルに保存し、その他はすべて削除します。

--output-to-dir APK の内容を -o で指定したディレクトリに出力します。

このフラグを指定してエラーが発生した場合、Android SDK Build Tools 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 を生成する bundletool の入力に適した形式です。

--non-final-ids 非 final リソース ID の付いた R.java を生成します(アプリのコードからこれらの ID への参照は kotlinc / javac のコンパイル中にはインライン化されません)。
--emit-ids path リソースタイプの名前とその ID マッピングのリストを含めて、指定したパスにファイルを発行します。--stable-ids とともに指定することをおすすめします。
--stable-ids outputfilename.ext --emit-ids を指定して生成されたファイルに、リソースタイプの名前とそれに割り当てられた ID のリストを含めて使用します。

リンクの際にリソースが削除されたり、新しいリソースが追加されたりしても、このオプションによって、割り当てられた ID を固定しておくことができます。

--custom-package package_name R.java をその中に生成する Java のカスタム パッケージを指定します。
--extra-packages package_name 同じ R.java ファイルを生成しますが、別のパッケージ名を付けます。
--add-javadoc-annotation annotation 生成されたすべての Java クラスに 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 詳細な出力を有効にします。

ダンプ

dump は、link コマンドで生成される APK に関するリソースとマニフェストの情報を出力するために使用されます。下記のように dump を指定して、コンソールに情報を出力できます。

    aapt2 dump output.apk
    

ダンプの構文

dump を使用する一般的な構文は次のとおりです。

    aapt2 dump filename.apk [options]
    

ダンプ オプション

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 には、foregroundInsidePaddingandroid:foregroundandroid:foregroundGravity の 3 つの属性があります。foregroundInsidePadding は他の 2 つの属性とは異なり、android 名前空間には含まれません。

AAPT の以前のバージョンでは、foregroundInsidePadding 属性を android 名前空間で定義しても、コンパイラは何も表示せずに無視していました。AAPT2 では、コンパイラが早い段階でこれを把握し、次のようなビルドエラーをスローします。

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

この問題を解決するには、android:foregroundInsidePaddingforegroundInsidePadding にただ置き換えます。

@ リソース参照シンボルの誤った使用

AAPT2 では、リソース参照シンボル(@)を省略したり、誤った場所に指定したりすると、ビルドエラーがスローされます。たとえば、style 属性を指定する際、次のようにこのシンボルを省略したとします。

    <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 Build Tools の古いバージョンを使ってビルドされたサードパーティのライブラリと依存関係にあるアプリは、ランタイムに、エラーも警告も表示されずにクラッシュすることがあります。こうしたクラッシュが発生するのは、ライブラリの作成中、R.java フィールドが final と宣言され、その結果そのライブラリのクラス内に、リソース ID がすべてインライン化されるからです。

AAPT2 はアプリのビルド時に、ライブラリ リソースに ID を再割り当てできることに依存しています。ライブラリが ID を final と見なし、ライブラリ dex にインライン化する場合、ランタイム時に不一致が発生します。

このエラーを解決するには、ライブラリの作成者に連絡し、Android SDK Build Tools の最新版を使用して、ライブラリを再度ビルドし、公開し直すように依頼してください。