aapt2 资源 compile 过程
前言
從Android Studio 3.0開始,google默認開啟了aapt2作為資源編譯的編譯器,aapt2的出現,為資源的增量編譯提供了支持。當然使用過程中也會遇到一些問題,我們可以通過在gradle.properties中配置android.enableAapt2=false來關閉aapt2。
使用方式
aapt2將原先的資源編譯打包過程拆分成了兩部分,即編譯和鏈接,這樣就能很好的提升資源的編譯性能,比如只有一個資源文件發送改變時,你只需要重新編譯改變的文件,然后將其與其他未改變的資源進行鏈接即可。而之前的aapt是將所有資源進行merge,merge完后將所有資源進行編譯,產生一個資源ap_文件,該文件是一個壓縮包,這樣帶來的后果就是即使只改變了一個資源文件,也要進行全量編譯。這篇文章主要講一下aapt2的compile的流程,link的流程比較復雜,后續講解。
首先來看看其compile命令的使用姿勢。
| 12345678910 | aapt2 compile [options] -o arg files...Options:-o arg Output path --dir arg Directory to scan for resources --pseudo-localize Generate resources for pseudo-locales (en-XA and ar-XB) --no-crunch Disables PNG processing --legacy Treat errors that used to be valid in AAPT as warnings -v Enables verbose logging -h Displays this help menu |
編譯過程使用aapt2 compile命令,它有一系列的參數。
-o參數指定了編譯文件輸出的路徑,這個參數可以是目錄,也可以是文件,取決于輸入的資源文件是目錄還是文件。假如輸入的是目錄,則輸出的是個zip壓縮包,參數值必須是個文件;輸入的是單個資源文件,則輸出的是一個flat文件,參數值必須是個目錄,輸出的文件名由aapt2生成。
–dir用于指定掃描的資源目錄,該參數用于資源的批量編譯,不用指定一個個文件單獨編譯。
–pseudo-localize參數在aapt中也有,主要是生成偽本地化信息,如en-XA和ar-XB
–no-crunch表示禁用png文件的壓縮等處理
–legacy表示將aapt中認為是警告的地方作為錯誤拋出,并終止編譯
-v參數將開啟編譯日志的輸出
-h參數則會輸出上面的使用幫助信息
用Android Studio 3.0新建一個新的空項目。我們嘗試使用命令行進行資源編譯。打開終端,進入當前項目根目錄
| 1 | aapt2 compile -o ./build ./app/src/main/res/values/strings.xml |
以上命令將string.xml進行了編譯,最終編譯產物位于項目根目錄下的build目錄中,其文件名為該文件上級目錄名_該文件名.arsc.flat,即values_strings.arsc.flat,這是values文件夾下的文件的命名,可以看到xml后綴變成了arsc,這是代碼中覆蓋文件后綴導致的。我們來看下其他文件,我們編譯一個布局文件
| 1 | aapt2 compile -o ./build ./app/src/main/res/layout/activity_main.xml |
以上命令會編譯產生layout_activity_main.xml.flat文件,即上級文件目錄名_該文件名.flat,這是非values資源的命名方式
看下圖片資源編譯會產生什么
| 1 | aapt2 compile -o ./build ./app/src/main/res/mipmap-xhdpi/ic_launcher.png |
以上命令會編譯產生mipmap-xhdpi_ic_launcher.png.flat文件,命名方式和layout一樣
將上面三個文件連起來一起編譯就是
| 1 | aapt2 compile -o ./build ./app/src/main/res/mipmap-xhdpi/ic_launcher.png ./app/src/main/res/layout/activity_main.xml ./app/src/main/res/values/strings.xml |
上面是單個文件的編譯方式,下面看看直接編譯整個目錄
| 1 | aapt2 compile -o ./build/res.apk --dir ./app/src/main/res/ |
該命令為產生一個res.apk的文件,該文件是一個zip壓縮包,里面包含了編譯好的資源文件,如下圖所示
將以上流程總結為一張圖
flat文件結構解析
那么編譯產生的flat文件到底是什么東西呢,不同類型的文件其flat格式是不同的,這里以普通文件舉例,即compileFile產生的flat文件(compilePng、compileXml產生的flat文件和compileFile是類似的),先來看一張結構圖
從上圖可以看到,flat文件其實就是一種特定的文件格式,文件開頭4個字節(32位)表示當前flat文件中的文件個數k,緊跟著8個字節(64位)的數據,表示后面緊跟著的protobuf數據的大小n,接著就是跟著n個字節的protobuf數據,接著是8個字節(64位)的真實數據大小m,緊跟在后面的就是m個字節的真實數據。依次循環k次這種文件結構,最終就是flat文件了。
其中protobuf部分的數據Format.proto的定義如下,非values資源使用的是CompiledFile
| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195 | syntax = "proto2";option optimize_for = LITE_RUNTIME;package aapt.pb;message ConfigDescription { optional bytes data = 1; optional string product = 2;}message StringPool { optional bytes data = 1;}message CompiledFile { message Symbol { optional string resource_name = 1; optional uint32 line_no = 2;} optional string resource_name = 1; optional ConfigDescription config = 2; optional string source_path = 3; repeated Symbol exported_symbols = 4;}message ResourceTable { optional StringPool string_pool = 1; optional StringPool source_pool = 2; optional StringPool symbol_pool = 3; repeated Package packages = 4;}message Package { optional uint32 package_id = 1; optional string package_name = 2; repeated Type types = 3;}message Type { optional uint32 id = 1; optional string name = 2; repeated Entry entries = 3;}message SymbolStatus { enum Visibility {Unknown = 0;Private = 1;Public = 2;} optional Visibility visibility = 1; optional Source source = 2; optional string comment = 3; optional bool allow_new = 4;}message Entry { optional uint32 id = 1; optional string name = 2; optional SymbolStatus symbol_status = 3; repeated ConfigValue config_values = 4;}message ConfigValue { optional ConfigDescription config = 1; optional Value value = 2;}message Source { optional uint32 path_idx = 1; optional uint32 line_no = 2; optional uint32 col_no = 3;}message Reference { enum Type {Ref = 0;Attr = 1;} optional Type type = 1; optional uint32 id = 2; optional uint32 symbol_idx = 3; optional bool private = 4;}message Id {}message String { optional uint32 idx = 1;}message RawString { optional uint32 idx = 1;}message FileReference { optional uint32 path_idx = 1;}message Primitive { optional uint32 type = 1; optional uint32 data = 2;}message Attribute { message Symbol { optional Source source = 1; optional string comment = 2; optional Reference name = 3; optional uint32 value = 4;} optional uint32 format_flags = 1; optional int32 min_int = 2; optional int32 max_int = 3; repeated Symbol symbols = 4;}message Style { message Entry { optional Source source = 1; optional string comment = 2; optional Reference key = 3; optional Item item = 4;} optional Reference parent = 1; optional Source parent_source = 2; repeated Entry entries = 3;}message Styleable { message Entry { optional Source source = 1; optional string comment = 2; optional Reference attr = 3;} repeated Entry entries = 1;}message Array { message Entry { optional Source source = 1; optional string comment = 2; optional Item item = 3;} repeated Entry entries = 1;}message Plural { enum Arity {Zero = 0;One = 1;Two = 2;Few = 3;Many = 4;Other = 5;} message Entry { optional Source source = 1; optional string comment = 2; optional Arity arity = 3; optional Item item = 4;} repeated Entry entries = 1;}message Item { optional Reference ref = 1; optional String str = 2; optional RawString raw_str = 3; optional FileReference file = 4; optional Id id = 5; optional Primitive prim = 6;}message CompoundValue { optional Attribute attr = 1; optional Style style = 2; optional Styleable styleable = 3; optional Array array = 4; optional Plural plural = 5;}message Value { optional Source source = 1; optional string comment = 2; optional bool weak = 3; optional Item item = 4; optional CompoundValue compound_value = 5; } |
以上是非values資源產生的flat文件的文件格式,而values類型的資源,其實是以上數據格式的閹割版,即只有protobuf部分的數據結構,其結構為上面proto格式部分的ResourceTable部分
gradle中compile流程
gradle中主要由OutOfProcessAaptV2和AaptV2CommandBuilder類承載aapt2的執行,關鍵函數如下
| 12345678910111213141516171819202122232425262728293031323334353637383940 | @Nullable@Overrideprotected CompileInvocation makeCompileProcessBuilder(@NonNull CompileResourceRequest request) throws AaptException {Preconditions.checkArgument(request.getInput().isFile(), "!file.isFile()");Preconditions.checkArgument(request.getOutput().isDirectory(), "!output.isDirectory()"); return new CompileInvocation( new ProcessInfoBuilder().setExecutable(getAapt2ExecutablePath()).addArgs("compile").addArgs(AaptV2CommandBuilder.makeCompile(request)), new File(request.getOutput(),Aapt2RenamingConventions.compilationRename(request.getInput())));}public static ImmutableList<String> makeCompile(@NonNull CompileResourceRequest request) {ImmutableList.Builder<String> parameters = new ImmutableList.Builder(); if (request.isPseudoLocalize()) {parameters.add("--pseudo-localize");} if (!request.isPngCrunching()) { // Only pass --no-crunch for png files and not for 9-patch files as that breaks them. String lowerName = request.getInput().getPath().toLowerCase(Locale.US); if (lowerName.endsWith(SdkConstants.DOT_PNG)&& !lowerName.endsWith(SdkConstants.DOT_9PNG)) {parameters.add("--no-crunch");}}parameters.add("--legacy");parameters.add("-o", request.getOutput().getAbsolutePath());parameters.add(request.getInput().getAbsolutePath()); return parameters.build();} |
很簡單,就是簡單的命令拼接,和上面說的是完全一樣的。
總結
開啟了aapt2后,資源的增量編譯會加速編譯速度,但是有些場景aapt2并不是很合適,因此必要的情況下,建議關閉aapt2,比如jenkins上構建時,我們并不需要增量編譯,因此可以關閉,可以通過gradle參數達到關閉的效果,命令如下
| 1 | gradle assembleRelease -Pandroid.enableAapt2=false |
簡單總結了幾種不適合使用aapt2的場景
- 插件化和熱修復中,需要使用public.xml的場景
- 構建過程,需要動態增刪改資源的場景,如刪除一部分線上不應該出現的資源
總結
以上是生活随笔為你收集整理的aapt2 资源 compile 过程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: aapt2 适配之资源 id 固定
- 下一篇: Android Studio Libra