AAPT2(Android 資源打包工具)是一個Android SDK構建工具,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"
例如:sdkmanager "build-tools;29.0.3"
下載 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,具體操作步驟如下:
- 在代碼庫索引中依次轉到 com.android.tools.build > aapt2。
- 複製最新版 AAPT2 的名稱。
-
將複製的版本名稱插入以下網址並指定目標操作系統: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
-
在瀏覽器中導航到該網址,系統應該會隨即開始下載 AAPT2。
-
解壓縮剛剛下載的 JAR 文件。JAR 文件應包含
aapt2
可執行文件和該可執行文件所依賴的一些庫
編譯
AAPT2 支持編譯所有 Android 資源類型,如可繪製對象和 XML 文件。調用 AAPT2 進行編譯時,每次調用都應傳遞一個資源文件作爲輸入。然後,AAPT2 會解析該文件並生成一個擴展名爲.flat的中間二進制文件。
雖然您可以使用 --dir
標誌將包含多個資源文件的資源目錄傳遞給 AAPT2,但如果這樣做,您將無法獲得增量資源編譯的優勢。也就是說,如果傳遞整個目錄,則即使只有一項資源發生了改變,AAPT2 也會重新編譯目錄中的所有文件。
輸出文件的類型可能會因您爲編譯提供的輸入不同而異。下表對此進行了說明:
輸入 | 輸出 |
---|---|
XML 資源文件(如 String 和 Style),它們位於 res/values/ 目錄下。 |
以 *.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/
注意:對於資源文件,輸入文件的路徑必須符合以下結構:path/resource-type[-config]/file
在以下示例中,AAPT2 分別編譯了名爲 values.xml
和 myImage.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 目錄中的已編譯可繪製對象文件的文件名將爲 drawable_img.png.flat
。
編譯選項
您可以將多個選項與 compile
命令搭配使用,如下表中所示:
選項 | 說明 |
---|---|
-o path |
指定已編譯資源的輸出路徑。
這是一個必需的標誌,因爲您必須指定 AAPT2 可將已編譯的資源輸出並存儲到其中的目錄的路徑。 |
--dir directory |
指定要在其中搜索資源的目錄。
雖然您可以使用此標誌通過一個命令編譯多個資源文件,但這樣就無法獲得增量編譯的優勢,因此不建議對大型項目使用。 |
--pseudo-localize |
生成默認字符串的僞本地化版本,如 en-XA 和 en-XB。 |
--no-crunch |
停用 PNG 處理。
如果您已處理 PNG 文件,或者要創建不需要減小文件大小的調試 build,則可使用此選項。啓用此選項可以加快執行速度,但會增大輸出文件大小。 |
--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.flat
和 values_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 |
傳遞要鏈接的單個 .flat 文件,使用 overlay 語義,而不使用 <add-resource> 標記。
如果您提供與現有文件重疊(擴展或修改現有文件)的資源文件,則會使用最後提供的衝突資源。 |
--package-id package-id |
指定要用於應用的軟件包 ID。
除非與 |
--allow-reserved-package-id |
允許使用保留的軟件包 ID。
保留的軟件包 ID 是指通常分配給共享庫的 ID,範圍從 0x02 到 0x7e(包含端點值)。通過使用 此標誌只能用於最低 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 格式生成已編譯的資源。
適合作爲 bundle tool 的輸入,用於生成 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 |
向已生成的所有 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 |
更改插樁的目標軟件包的名稱。
它應與 |
-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 應該直接就可以處理舊版項目,但本節介紹了一些您應該注意的行爲變化。
在以前的 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 版本中,當您使用 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 中,則會出現運行時不匹配的情況。
要解決此錯誤,請與庫創建者聯繫,以使用最新版本的 Android SDK Build Tools 重新構建該庫,然後重新發布該庫。