Android重疊包與資源合併一見
前言
在 Android逆向分析(2) APK的打包與安裝 一文中對資源編譯過程的介紹中,筆者提到了overlay(重疊包)這個概念,一位每天都被自己帥醒的好友看了那篇東西后,來問我這個重疊包究竟是個什麼東西,筆者想了想,確實這個概念有很多同學們都不甚瞭解,搜尋了一下網上了介紹,也幾乎沒有看到任何對這個的講解,只有 老羅的部落格 提到過
–mOverlay:表示當前正在編譯的資源的重疊包。重疊包是什麼概念呢?假設我們正在編譯的是Package-1,這時候我們可以設定另外一個Package-2,用來告訴aapt,如果Package-2定義有和Package-1一樣的資源,那麼就用定義在Package-2的資源來替換掉定義在Package-1的資源。通過這種Overlay機制,我們就可以對資源進行定製,而又不失一般性。
那我們應該怎麼怎麼去使用重疊包呢?它又能用在什麼地方,帶來什麼便利呢?
aapt overlay
我們看看aapt的命令help裡是怎麼描述的,省略版:
Usage: aapt l[ist] [-v] [-a] file.{zip,jar,apk} List contents of Zip-compatible archive. aapt d[ump] [--values] [--include-meta-data] WHAT file.{apk} [asset [asset ...]] ... aapt p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \ ... [--utf16] [--auto-add-overlay] \ ... [-S resource-sources [-S resource-sources ...]] \ [-F apk-file] [-J R-file-dir] \ ... Package the android resources. It will read assets and resources that are supplied with the -M -A -S or raw-files-dir arguments. The -J -P -F and -R options control which files are output. ... Modifiers: ... # 特別說明下,這就是前一篇我們說到的include的base set啦,比如android.jar -I add an existing package to base include set ... # overlay通過-S指定,可以指定多個目錄, -S directory in which to find resources. Multiple directories will be scanned and the first match found (left to right) will take precedence. ... # 自動新增overlays包裡的資源 --auto-add-overlay Automatically add resources that are only in overlays. ...
舉個例子
aapt package \
-M AndroidManifest.xml \
-m -J gen \
-S src/com/example/res \
-S src/com/example/ui/res
假如我們有如上的aapt命令輸入,那麼當 src/com/example/res 與 src/com/example/ui/res 有相同資源的時候,就會使用前者的,這裡對資源替換的粒度是resource而不是檔案,比如兩個資料夾的values/string.xml都有對同一個string id的描述,最後就會使用前者的字串。
然後我們再來看看 --auto-add-overlay 有什麼用,
假如我們在 src/com/example/ui/res 定義了資源string a,但是在 src/com/example/res 卻沒有這個string,那就會報錯,因為基礎包裡是沒有那個資源的,這時候就需要加上 --auto-add-overlay ,於是就會自動把新的資源都新增進去。
overlay大致就是這麼一回事啦。
Gradle實踐
aaptOptions
google的官方文件簡直說了和沒說一樣。還是自己來吧,用AS的模板新建一個Testapp工程,隨便建兩個res資料夾,各放兩個strings.xml,結構為:
├── res
│ ├── drawable
│ ├── layout
│ │ ├── activity_main.xml
│ │ └── content_main.xml
│ ├── menu
│ │ └── menu_main.xml
│ ├── mipmap-xxxhdpi
│ │ └── ic_launcher.png
│ └── values
│ ├── colors.xml
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── res2
│ └── values
│ └── strings.xml
└── res3
└── values
└── strings.xml
res2和res3分別定義了一個string hehe ,value分別為 hehe res2 和 hehe res3 。
content_main.xml的TextView使用了 hehe (原來就是那個Hello World)。當然這裡as會報錯,因為res2和res3並沒有標示為資原始檔夾。
在module的build.gradle裡:
android {
...
aaptOptions {
additionalParameters '-S',
'/Users/yifan/dev/github/Testapp/app/src/main/res3',
'-S',
'/Users/yifan/dev/github/Testapp/app/src/main/res2',
'--auto-add-overlay'
noCompress 'foo', 'bar'
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
...
}
然後我們試圖編譯:
All input files are considered out-of-date for incremental task ':app:processDebugResources'.
Starting process 'command '/Users/yifan/dev/sdk/adt-bundle-mac-sdk/build-tools/23.0.2/aapt''. Working directory: /Users/yifan/dev/github/Testapp/app Command: /Users/yifan/dev/sdk/adt-bundle-mac-sdk/build-tools/23.0.2/aapt package -f --no-crunch -I /Users/yifan/dev/sdk/adt-bundle-mac-sdk/platforms/android-23/android.jar -M /Users/yifan/dev/github/Testapp/app/build/intermediates/manifests/full/debug/AndroidManifest.xml -S /Users/yifan/dev/github/Testapp/app/build/intermediates/res/merged/debug -A /Users/yifan/dev/github/Testapp/app/build/intermediates/assets/debug -m -J /Users/yifan/dev/github/Testapp/app/build/generated/source/r/debug -F /Users/yifan/dev/github/Testapp/app/build/intermediates/res/resources-debug.ap_ --debug-mode --custom-package cn.zhaiyifan.testapp -0 apk -S /Users/yifan/dev/github/Testapp/app/src/main/res2 --output-text-symbols /Users/yifan/dev/github/Testapp/app/build/intermediates/symbols/debug
Successfully started process 'command '/Users/yifan/dev/sdk/adt-bundle-mac-sdk/build-tools/23.0.2/aapt''
/Users/yifan/dev/github/Testapp/app/build/intermediates/res/merged/debug/values-af/values-af.xml:3 : AAPT: Resource at abc_action_bar_home_description appears in overlay but not in the base package; use <add-resource> to add.
...
...各種類似報錯
/usr/local/google/buildbot/src/googleplex-android/mnc-supportlib-release/frameworks/support/v7/appcompat/res/color/switch_thumb_material_light.xml:19 : AAPT: No resource found that matches the given name (at 'color' with value '@color/switch_thumb_normal_material_light').
:app:processDebugResources FAILED
:app:processDebugResources (Thread[main,5,main]) completed. Took 10.493 secs.
看到 <add-resource> 這個,大概知道啥問題了…於是在 additionalParameters 最後又加上了 --auto-add-overlay ,成功編譯執行。
在螢幕中央,顯示了hehe res3,交換-S順序後則變成了hehe res2,符合我們第一節中說到的,選擇首個匹配原則。
不僅是string,anim,layout等等資源都可以使用重疊包來進行動態指定。
資源合併
和aapt的overlay有關,但使用場景略有不同,也介紹一下。
Google在Android Tools Project Site專門為此開了一個頁面: Resource Merging(資源合併) 。
在過去的編譯系統中,資源合併是通過傳給aapt一個作為重疊包的資原始檔夾列表來做的,再加上–auto-add-overlay來確保在重疊包裡的新資源會被自動新增(預設行為只會過載既有資源)。
基礎Gradle的編譯系統的一個目標就是提供更大的靈活性,而另一個經常並問到的功能要求則是能擁有多個資原始檔夾。aapt無法去處理這個,所以新的編譯系統引進了一種新的超越aapt的合併機制,生成一個單獨的,合併的,資原始檔夾並提供給aapt。這個合併機制擁有增量的優點,既因為Gradle的輸入/輸出變更檢測,又因為其實現方式(可以只使用唯一一個變更檔案來做重新merge)。
合併的資源來自3種來源:
- 主資源,和main sourceSet相關聯,大多位於src/main/res
- Variant重疊包,來自Build Type和Flavor(s).
- Library專案依賴,通過它們的aar bundle提供資源。
優先順序
優先順序為:BuildType -> Flavor -> main -> Dependencies.
這意味著如果一個資源同時在Build Type和main存在,會使用Build Type裡的。
需要注意的是合併的scope,同樣(型別,名字)的資源但標示符不同的,是分開處理的。
即如果src/main/res有:
- res/layout/foo.xml
- res/layout-land/foo.xml
而src/debug/res有: - res/layout/foo.xml
則合併後的資原始檔夾會包含預設的來自src/debug/res的foo.xml,但橫屏版本則會選擇src/main/res下的。
PS: android的資源有19個維度,見 Grouping Resource Types 的Table 2,這19個維度會唯一指定1個資源(qualifier標示符)。在老羅的資源介紹部落格中曾經提到過18個維度,現在變成了19是因為多了Round screen這個維度,用於描述Android Wear,添加於API 23.
處理多個資原始檔夾
每個sourceSet可以定義多個資原始檔夾,舉個例子:
android.sourceSets { main.res.srcDirs = ['src/main/res', 'src/main/res2'] }
這種情況下,兩個資原始檔夾具有相同優先順序,即如果一個資源在兩個資料夾都聲明瞭,合併會報錯。
Library依賴的優先順序順序
根據傳遞的依賴,Library專案的實際集被工程視為一個圖,而不是平鋪的列表,然後合併機制只會處理一個平優先順序列表。
如果我們考慮如下例子的依賴關係:
專案 -> A, B (意味著A的優先順序高於B)
A -> C, D
B -> C
則最後的優先順序list為A, D, B, C,同時保證了A和B可以過載C。
小測試
繼續在之前我們建立的工程的基礎上做個小測試吧。在sourceSet加上res2資料夾,最後build.gradle的android域如下:
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "cn.zhaiyifan.testapp"
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
aaptOptions {
additionalParameters '-S',
'/Users/yifan/dev/github/Testapp/app/src/main/res3',
'-S',
'/Users/yifan/dev/github/Testapp/app/src/main/res2',
'--auto-add-overlay'
noCompress 'foo', 'bar'
ignoreAssetsPattern '!.svn:!.git:!.ds_store:!*.scc:.*:<dir>_*:!CVS:!thumbs.db:!picasa.ini:!*~'
}
android.sourceSets {
main.res.srcDirs = ['src/main/res', 'src/main/res2']
}
}
執行後發現介面顯示了 hehe res2,符合預期,因為res2已經和res合併了,所以先找到了build/intermediates/res/merged/debug下的string,沒有用res3的。
使用場景
不同的buildType、渠道下的包,使用不同的資源,做一些定製,而不用侵入程式碼本身的邏輯。
總結
我們瞭解了Android aapt overlay的機制,以及gradle下的資源合併,並分別編寫運行了demo驗證資源生效的結果。
參考文獻
相關推薦
Android重疊包與資源合併一見
前言 在 Android逆向分析(2) APK的打包與安裝 一文中對資源編譯過程的介紹中,筆者提到了overlay(重疊包)這個概念,一位每天都被自己帥醒的好友看了那篇東西后,來問我這個重疊包究竟是個什麼東西,筆者想了想,確實這個概念有很多同學們都不甚瞭解,搜尋了一下網上了介紹,也幾乎沒有看到任何對這個
【Android 熱修復與外掛化 一】帶你入門Android外掛化(附demo)
本文為博主Colin原創文章,歡迎轉載。 https://blog.csdn.net/colinandroid/article/details/79431502 一. 背景 Android外掛化作為每個合格的Android程式設計師都必須會的技術,被各大廠廣泛使用。隨著各大廠對
Android 熱修復與外掛化 一
熱修復 : 支付寶、優酷、微信 剛釋出的應用就發現了比較嚴重的bug 有一些小的功能想即時推送給使用者去使用 外掛化 : 美團、淘寶、酷狗 解決應用越來越大所帶來的各種技術限制,方法數超過65
Unity - Apk包的代碼與資源提取
ron 來講 如果 情況 取代 asset con list blog https://www.cnblogs.com/programmer-kaima/p/5847429.html 最近在研究如何給Unity遊戲進行加密,讓別人不能輕易破解你的apk包,不過網上的加密
Solution of issue: Android soft keyboard overlap with input div on browser【Android虛擬鍵盤與輸入框重疊解決方案】
Android soft keyboard overlap with input div on browser 【Android虛擬鍵盤與輸入框重疊】 給個英文標題,因為我知道絕大部分人搜資料都用英文搜。 問題: 在Android裝置瀏覽器上開啟自己的頁面,當點選頁面底部的輸入框時,虛擬
Android音訊實時傳輸與播放(一)
服務端共開放兩個埠,一個udp上行埠用來接收amr音訊流,另一個tcp下行埠用來發送amr音訊流。 我這裡寫的服務端實現了組播的功能,即一個人在錄音,可以同時讓很多人同時聽到。 簡而言之,服務端做的唯一一件事情就是轉發音訊流,囧rz。。。 在這裡,我只貼出一部分程式碼,後
從Android boot.img與recovery.img的解包中瞭解其資料組成
從Android boot.img與recovery.img的解包中瞭解其資料 又到了忙碌的季節,一次要處理N多事情。最近需要從boot.img中取出ramdisk。不同的專案中kernel是一樣的,ramdisk中的資源不一樣,直接取ramdisk與新編譯的kernel打包在一起,方便
ArcGIS for Android 100.3的學習與應用(一) 如何繪製點和線?
平時工作中,我們接觸到的地圖類開發平臺有很多,最常用的有高德,百度,騰訊地圖。而且它們都有自己的開發者平臺和文件供我們使用。基本能滿足我們的業務需求。 由於公司裡的專案會涉及一些地圖資料統計和展示方面的需求,同時也會發布一些地圖服務,所以選擇了使用在地圖方面比較牛逼的ArcGIS。 把平時遇
Android回收AnimationDrawable動畫的每一幀的圖片資源,釋放記憶體資源
/** * 回收每一幀的圖片,釋放記憶體資源 * 取出AnimationDrawable中的每一幀逐個回收,並且設定Callback為null */ private static void tryRecycleAnimationDrawable(AnimationDra
Android 創建與解析XML(一)—— 概述
四種 stream 大小 ora rda roc default 關系 建立 Android 是最常用的智能手機平臺,XML 是數據交換的標準媒介,Android 中可以使用標準的XML生成器、解析器、轉換器 API,對 XML 進行解析和轉換。 XML,相關有DOM
Android ArcGIS的學習與應用(一) 如何繪製點和線?
平時工作中,我們接觸到的地圖類開發平臺有很多,最常用的有高德,百度,騰訊地圖。而且它們都有自己的開發者平臺和文件供我們使用。基本能滿足我們的業務需求。 由於公司裡的專案會涉及一些地圖資料統計和展示方面的需求,同時也會發布一些地圖服務,所以選擇了使用在地圖方面比較
Android觸控式螢幕事件派發機制詳解與原始碼分析一(View篇)
【工匠若水 http://blog.csdn.net/yanbober】 Notice:閱讀完該篇之後如果想繼續深入閱讀Android觸控式螢幕事件派發機制詳解與原始碼分析下一篇請點選《Android觸控式螢幕事件派發機制詳解與原始碼分析二(ViewGroup篇)》檢視。 1
【Android UI設計與開發】第06期:底部選單欄(一)使用TabActivity實現底部選單欄
轉載請註明出處:http://blog.csdn.net/yangyu20121224/article/details/8989063 從這一篇文章開始,我們將進入到一個應用程式主介面UI的開發和設計中了,底部選單欄在Android的應用開發當
Android開發學習資源之(一)
1.Android效能優化(包括記憶體優化)一系列文章 http://androidperformance.com/categories/Android/http://www.csdn.net/article/2015-04-29/2824583-android-perfo
android中熱修復與外掛化(一)
簡介 目前android技術最前沿莫屬熱修復與外掛化的技術點,當下用得最多的就是阿里的Andfix,和微信的Tinker框架,針對原始碼的實現,再次做個記錄。 熱修復給我們解決的問題 剛上線的APP應用,由於測試的疏忽,發現了一個嚴重的bug
Android Studio中so庫的建立與使用、jar庫(jar呼叫so庫)的建立與使用(一)
工程下載https://download.csdn.net/download/cnicfhnui/10422621一、Android Studio 建立so庫,呼叫so庫第一步先下載NDK開發包,下載地址:https://developer.android.google.cn
【Android】多語言適配:語言、名稱、與資源對應關係
語言碼_國家碼 -> 語言選擇裡的顯示語言 -> 英文下的語言(國家) -> 簡體中文下的語言(國家) af -> Afrikaans -> Afrikaans -> 南非荷蘭文 af_N
Android開發中佈局與元件(一)—— 螢幕尺寸單位dp,px,sp的探究
在Android開發中,常用的尺寸單位有 dp , px , sp 。當然還有其他的單位如 pt , mm 等,不過這些都是不常用,所以我們重點來探究一下 dp , px , sp 這三個常用的單位。 px 英文 pixel 的縮寫,即畫素。無論螢幕密度為多少,一個畫素單位對應
Android面試題-與效能優化相關面試題一
本文配套視訊 配套視訊、 配套視訊 配套視訊 原始碼分析相關面試題 與XMPP相關面試題 與效能優化相關面試題 與登入相關面試題 與開發相關面試題 與人事相關面試題 9-記憶體洩漏和記憶體溢位分別是
Android Rom定製與修改學習(一)
最近ZUK慘遭聯想拋棄,從而使得ZUK系列全線大降價,於是將服役了三年的榮耀6換下了,入手ZUK2 PRO,機器在硬體方面都挺讓人滿意,只是聯想採用了一塊AMOLED屏,相比較於IPS而言,A屏顏色實在過於飽和,外加ZUK自帶ZUI也可能不再更新,於是便萌生了在