前文java
aapt2(Android Asset Packageping Tool)是用來 編譯和打包 app資源文件的構建工具。aapt2 解析、索引並將資源編譯成適合Android 平臺的二進制格式.android
aap2將資源文件的編譯分爲2個步驟:git
編譯階段:
解析資源文件並生成擴展名爲.flat的中間二進制文件github
**連接階段: **
將編譯階段生成的全部中間文件(資源表、二進制XML文件和處理過的PNG文件)合併到一個APK中,此外在此資源還能夠生成其餘輔助文件,如R.java文件和ProGurad規則文件。 此時生成的APK文件並不包含DEX文件。bash
aapt只有一個編譯過程,aapt2將資源編譯分爲2個部分能夠實現資源文件的增量編譯。app
可使用dump命令查看apk文件內的resouces信息ide
aapt2 dump <xx.apk>
複製代碼
compile: 編譯res文件夾下的資源文件生成 flat文件工具
aapt2 compile --dir <res-path> -o res.zip -v
複製代碼
參數含義:
--dir :資源文件路徑,編譯整個文件夾下的資源文件
-o: 指定文件
-v: verbose logging佈局
增量編譯,及只從新編譯變化的資源文件post
aapt2 compile <file-path> -o <outputPath>
複製代碼
參數含義:
-o:由於這裏是指定文件編譯,因此-o 標識flat文件保存的文件夾
link: 連接資源文件 及AndroiedManifest.xml 生成只包含資源的apk文件,並生成R類
aapt2 link res.zip \
-I ~/Library/Android/sdk/platforms/android-28/android.jar \
--java package/ \
--manifest app/src/main/AndroidManifest.xml \
-o res.apk -v
複製代碼
編譯過程當中,可能出現 style/Theme.AppCompat.Light.DarkActionBar not found.這是由於,咱們引用的第三方庫的資源並無被編譯,所以出現資源找不到的問題。而使用gradle 編譯時,會合並全部資源統一進行編譯,所以不會出現類型問題. 此時,可將對第三方資源的引用去除,改成只用使用android sdk內的資源,好比將主題改成 <style name="AppTheme" parent="android:Theme.Holo.Light.DarkActionBar">
aapt2編譯後的apk文件包含哪些內容:
一個完整的aapt2編譯後的壓縮文件應該包含如下資源
1.res文件夾內的圖片及xml資源(只包含圖片、佈局)
2.assets文件夾
3.二進制AndroidManifest.xml
4.資源索引表 resources.arsc
5.R類文件
Demo中使用的資源不包含 assets 文件,在實際開發過程,在link 階段,能夠經過
-A
指定assets路徑。
在aapt的編譯過程當中,除了assets資源外,其餘的資源(string、color、layout等)都會被賦予一個資源ID.
資源的ID常量值保存在R類文件中供在開發階段使用。
/* AUTO-GENERATED FILE. DO NOT MODIFY. * * This class was automatically generated by the * aapt tool from the resource data it found. It * should not be modified by hand. */
package com.hellobike.androidbuildintroduce;
public final class R {
public static final class color {
public static final int colorAccent=0x7f010000;
public static final int colorPrimary=0x7f010001;
public static final int colorPrimaryDark=0x7f010002;
}
public static final class drawable {
public static final int ic_launcher_background=0x7f020001;
public static final int ic_launcher_foreground=0x7f020002;
}
public static final class layout {
public static final int activity_main=0x7f030000;
}
public static final class mipmap {
public static final int ic_launcher=0x7f040000;
public static final int ic_launcher_round=0x7f040001;
}
public static final class string {
public static final int app_name=0x7f050000;
}
public static final class style {
/** * Base application theme. */
public static final int AppTheme=0x7f060000;
}
}
複製代碼
資源Id爲16進制8位 int值,組成爲ppttdddd,前2位表示packageId,第3-4位表示資源類別(resouceTypeId),後4位標識該資源類別下的資源ID(resouceId)。
其中系統的packageID爲[01-7f)之間,應用程序的packageId默認爲7f。 typeId 沒有明細的映射關係,Id的值的分配爲aapt2在處理過程當中 根據資源類別被處理的前後從1開始遞增1分配。resouceId同理,不過是從0開始遞增的
在開發階段,咱們能夠經過aapt生成的R類中的id 引用具體的資源,而 resources.arsc文件是一個資源索引表,供在程序運行時根據id索引到具體的資源。這裏咱們不分析運行時索引資源的過程,只分析reousce.arsc中的內容結構。
直接去分析二進制的resources.arsc會比較困難,這裏開發者能夠藉助AS 自帶的Anaylyze Apk來分析 resouces.arsc中的內容。開發者能夠直接將一個apk文件拖到AS中,AS會自動使用Anaylyze Apk工具打開
結合aapt2工具的源代碼,能夠看出資源索引表的內容大概包含如下部分
1.ResouceTablePackage
紅色圈選的部分列出了這個資源索引表包含的package,通常一個應用只會有一個package,而且這個package的id默認爲7f.
class ResourceTablePackage {
public:
Maybe<uint8_t> id;
std::string name;
std::vector<std::unique_ptr<ResourceTableType>> types;
ResourceTablePackage() = default;
ResourceTableType* FindType(ResourceType type);
ResourceTableType* FindOrCreateType(const ResourceType type);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceTablePackage);
};
複製代碼
2.ResourceTableType
一個package關聯不少resouceTypes,好比你的應用下包含了xml、stirng、layout、則這裏就會有對應的type,每一個type之下關聯所屬類型的ResouceEntry
/**
* Represents a resource type, which holds entries defined
* for this type.
*/
class ResourceTableType {
public:
/**
* The logical type of resource (string, drawable, layout, etc.).
*/
const ResourceType type;
/**
* The type ID for this resource.
*/
Maybe<uint8_t> id;
/**
* Whether this type is public (and must maintain the same
* type ID across builds).
*/
Symbol symbol_status;
/**
* List of resources for this type.
*/
std::vector<std::unique_ptr<ResourceEntry>> entries;
explicit ResourceTableType(const ResourceType type) : type(type) {}
ResourceEntry* FindEntry(const android::StringPiece& name);
ResourceEntry* FindOrCreateEntry(const android::StringPiece& name);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceTableType);
};
複製代碼
3.Entry
一個ResourceEntry就是一個資源項,一個資源項根據不一樣的配置可能會有不一樣的值,好比string entry能夠設置多國語言,layout entry能夠根據設備分辨率設置不一樣的佈局
**
/**
* Represents a resource entry, which may have
* varying values for each defined configuration.
*/
class ResourceEntry {
public:
/**
* The name of the resource. Immutable, as
* this determines the order of this resource
* when doing lookups.
*/
const std::string name;
/**
* The entry ID for this resource.
*/
Maybe<uint16_t> id;
/**
* Whether this resource is public (and must maintain the same entry ID across
* builds).
*/
Symbol symbol_status;
/**
* The resource's values for each configuration.
*/
std::vector<std::unique_ptr<ResourceConfigValue>> values;
explicit ResourceEntry(const android::StringPiece& name) : name(name.to_string()) {}
ResourceConfigValue* FindValue(const ConfigDescription& config);
ResourceConfigValue* FindValue(const ConfigDescription& config,
const android::StringPiece& product);
ResourceConfigValue* FindOrCreateValue(const ConfigDescription& config,
const android::StringPiece& product);
std::vector<ResourceConfigValue*> FindAllValues(const ConfigDescription& config);
std::vector<ResourceConfigValue*> FindValuesIf(
const std::function<bool(ResourceConfigValue*)>& f);
private:
DISALLOW_COPY_AND_ASSIGN(ResourceEntry);
};
複製代碼
4.ResouceConfigValue
reouceConfigValue即資源項具體的值。
**
class ResourceConfigValue {
public:
/** * The configuration for which this value is defined. */
const ConfigDescription config;
/** * The product for which this value is defined. */
const std::string product;
/** * The actual Value. */
std::unique_ptr<Value> value;
ResourceConfigValue(const ConfigDescription& config, const android::StringPiece& product)
: config(config), product(product.to_string()) {}
private:
DISALLOW_COPY_AND_ASSIGN(ResourceConfigValue);
};
複製代碼
另外也可使用aapt2命令查看resouces.arsc文件的具體內容
aapt2 dupms <xx.apk>
複製代碼
這裏我直接將輸出內容保存到txt中,並使用sublime查看
aapt2 dumps <xx.apk> >> ./outputs.txt
複製代碼
能夠看到輸出的內容和咱們在AS中看到的內容實際上是同樣的,只不過這裏是文本格式標識,結構採用縮進的方式。