1. 程式人生 > >Android重疊包與資源合併一見

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種來源:

  1. 主資源,和main sourceSet相關聯,大多位於src/main/res
  2. Variant重疊包,來自Build Type和Flavor(s).
  3. 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.imgrecovery.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也可能不再更新,於是便萌生了在