AAPT2

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

AAPT2 (Android 資產封裝工具) 是 Android Studio 和 Android Gradle 外掛程式用來編譯及封裝應用程式資源的一項建構工具。AAPT2 會剖析資源、建立索引,並將資源編譯為適用於 Android 平台的二進位格式。

根據預設,Android Gradle 外掛程式 3.0.0 以上版本會啟用 AAPT2,而您通常不需要自行叫用 aapt2。不過,如果您想在 Android Studio 中使用終端機和自己的建構系統,則可透過指令列使用 AAPT2。您也可以透過指令列偵錯與 AAPT2 相關的建構錯誤。方法很簡單,只要在 Android SDK Build Tools 26.0.2 以上版本,就可以將 AAPT2 視為獨立的工具。

如要從指令列下載 Android SDK Build Tools,請使用 sdkmanager 並執行以下指令:

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

下載 SDK Build Tools 後,您就可以在 android_sdk/build-tools/version/ 中找到 AAPT2。由於 Android SDK Build Tools 的新版本不會頻繁發布,因此 SDK Build Tools 中的 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. 請將您複製的版本名稱貼到以下網址中,並指定目標作業系統: 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. 使用瀏覽器開啟上面的網址後,應該很快就會開始下載 AAPT2。

  5. 解壓您剛下載的 JAR 檔案。 JAR 檔案應包含 aapt2 執行檔,以及某些執行檔相依的程式庫。

編譯

AAPT2 支援所有 Android 資源類型的編譯作業,例如可繪項目和 XML 檔案。叫用 AAPT2 編譯時,應將單一資源檔案當成每次叫用的輸入內容傳遞。AAPT2 會剖析檔案,並產生副檔名為 .flat 的中繼二進位檔案。

雖然您可以使用 --dir 旗標將包含多個資源檔案的資源目錄傳遞給 AAPT2,但這種做法並不會讓您取得增量資源編譯的優勢。這代表在傳遞完整目錄時,AAPT2 會重新編譯目錄中的所有檔案,即使只有一項資源變更也一樣。

視您提供編譯的輸入內容而定,輸出檔案類型可能不同。說明如下表:

輸入 輸出
XML 資源檔案,例如位於 res/values/ 目錄中的 StringStyle *.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。
--no-crunch 停用 PNG 處理功能。

如果您已處理 PNG 檔案,或者您正在建立不需縮減檔案大小的偵錯版本,請使用這個選項。 啟用這個選項可提升執行速度,但會增加輸出檔案大小。

--legacy 使用舊版的 AAPT 時,系統會將允許的錯誤視為警告。

這個旗標應用於非預期的編譯時間錯誤。如要解決使用 AAPT2 時可能遇到的已知行為變更問題,請參閱「使用 AAPT2 時的行為改變」一節。

-v 啟用詳細記錄功能。

在連結階段,AAPT2 會將從編譯階段產生的所有中繼檔案合併,例如資源資料表、二進位 XML 檔案,以及已處理的 PNG 檔案,並將這些檔案封裝為單一 APK。此外,在這個階段會產生其他輔助檔案 (例如 R.java 和 ProGuard 規則檔案)。不過,產生的 APK 不包含 DEX 位元碼,且未簽署。 也就是說,您無法將這個 APK 部署至裝置。如果您不是使用 Android Gradle 外掛程式透過指令列建構應用程式,則可使用其他指令列工具,例如 d8,將 Java 位元碼編譯成 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.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 或其他 APK (例如 framework-res.apk) 的路徑。

如果您在資源檔案中使用含 android 命名空間 (例如 android:id) 的屬性,則此旗標為必填屬性。
-A directory 指定要納入 APK 的素材資源目錄。

您可以使用這個目錄儲存原始版本未經處理的檔案。詳情請參閱「存取原始檔案」一節。

-R file 使用 overlay 語意 (無需使用 <add-resource> 標記) 將個別 .flat 檔案傳遞至連結。

當您提供現有的資源檔案 (重疊或修改) 時,系統會使用給定的最後衝突資源。

--package-id package-id 指定要用於應用程式的套件 ID。

除非與 --allow-reserved-package-id 組合使用,否則您指定的套件 ID 必須大於或等於 0x7f。

--allow-reserved-package-id 允許使用保留的套件 ID。

保留的套件 ID 通常是指派給共用資料庫的 ID,範圍從 0x02 到 0x7e (含)。您可以使用 --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 停用向量可繪項目的自動版本管理功能。 只有在使用向量可繪項目程式庫建構 APK 時,才能使用此項目。
--no-version-transitions 停用轉換資源的自動版本管理功能。 只有在使用轉換支援資料庫建構 APK 時,才能使用此項目。
--no-resource-deduping 在相容設定中,停用含相同數值的資源自動重複資料刪除功能。
--enable-sparse-encoding 使用二進位檔搜尋樹狀結構啟用稀疏項目編碼功能。這適合用來最佳化 APK 大小,但會影響資源擷取效能。
-z 需要標示為「建議」的本地化字串。
-c config 提供以逗號分隔的設定清單。

舉例來說,如果支援資料庫有依附元件 (其中包含多種語言的翻譯),您可以只針對特定語言 (例如英文或西班牙文) 設定篩選資源。

您必須以兩個英文字母組成的 ISO 639-1 語言代碼定義語言設定,亦可選擇在後面接續兩個英文字母 ISO 3166-1-alpha-2 區域代碼,前面加上小寫的「r」 (例如 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 的 套裝組合工具輸入。

--non-final-ids 產生包含非最終資源 ID 的 R.java (參閱 Kotlinc/Javac 編譯期間無法從應用程式程式碼內嵌 ID)。
--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 將 JavaDoc 註解新增至所有產生的 Java 類別。
--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 相關資訊。例如,下列指令會列印指定 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 資產封裝工具的預設版本,現已淘汰。雖然 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。請注意,與兩個其他屬性不同,android 命名空間不包含 foregroundInsidePadding

在舊版 AAPT 中,當您使用 android 命名空間定義 foregroundInsidePadding 屬性時,編譯器會以無訊息模式忽略該屬性。使用 AAPT2 時,編譯器會事先擲回下列建構錯誤:

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

如要解決這個問題,只要將 android:foregroundInsidePadding 替換為 foregroundInsidePadding 即可。

未正確使用 @ 資源參考符號

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 Build Tools 建構第三方程式庫的依附元件,則該應用程式可能會在執行階段異常終止,且不會顯示任何錯誤或警告。這個異常終止情況的可能原因為,在程式庫建立期間,R.java 欄位會宣告 final,因此所有資源 ID 都會內嵌至該程式庫的類別中。

AAPT2 仰賴在建立應用程式時,能將 ID 重新指派給程式庫資源的動作。如果程式庫假設 ID 是 final,且在資料庫 dex 中內嵌這些 ID,則系統會發生執行階段不符的情形。

如要解決這個錯誤,請與程式庫作者聯絡,以使用最新版 Android SDK Build Tools 重新建構程式庫,然後重新發布程式庫。