4、Android SDK命令行工具AAPT2

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,具體操作步驟如下:

  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 資源文件(如 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 必須大於或等於 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 格式生成已編譯的資源。

適合作爲 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 更改插樁的目標軟件包的名稱。

 

它應與 --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 應該直接就可以處理舊版項目,但本節介紹了一些您應該注意的行爲變化。

在以前的 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: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 重新構建該庫,然後重新發布該庫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章