Android 合併清單文件 Merge multiple manifest files

Android在打包的時候會合並清單文件,這裏需要知道合併的原理,本文以 

https://developer.android.com/studio/build/manifest-merge  官方文檔爲參考,進行翻譯解讀。同時也爲自己記錄相應的知識點。

 合併優先級

清單文件合併是按照優先級進行合併的,低優先級的清單文件內容合併到高優先級的,假如合併的時候產生了衝突就需要解決衝突,這也是我們這篇文章重點要講述的。而優先級的高低劃分原則是這樣的:

主工程(又區分構建體、渠道、風味) > module(按照依賴關係) > jar 包(aar)。

gradle的相關屬性會覆蓋manifest中的屬性,比如最小sdk,minSdkVersion 屬性會以gradle中的爲準,所以manifest就不要寫該屬性

合併衝突

當低優先級的清單文件屬性合併到高優先級中,假如高優先級中沒有對應的屬性,則直接合並,假如有並且不一樣,這時候就有了衝突,應該去解決,怎麼解決?

規則

High priority attribute Low priority attribute Attribute's merged result
No value No value No value (use default value)
Value B Value B
Value A No value Value A
Value A Value A
Value B Conflict error—you must add a merge rule marker

補充規則:

針對要合併的值不一樣,該如何去合併呢?這時候就要對一些不同屬性的值在不同的情況具體對待?注意manifest中的任何attribute 都可以使用補充規則,

<uses-permission android:name="android.permission.INTERNET"  tools:node="merge"/>
<uses-feature android:name="android.hardware.Sensor" tools:node="remove"/>
<uses-sdk android:targetSdkVersion="Q" tools:node="merge-only-attributes"/>
<permission android:name="xx" tools:node="replace"/>
<uses-permission android:name="android.permission.ACCESS_CHECKIN_PROPERTIES" tools:node="strict"/>
..........

常用的需要合併的屬性值有 
 <uses-sdk> <uses-libray> <uses-feature> <targetSdkVersion> <minSdkVersion>.Android的解決方式是使用標記,合併工具會優先在高優先級的清單文件中尋找這些標記,這一點要記住。另外,在使用標記的時候,需要在根節點manifest中添加 tools 命名空間:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp"
    xmlns:tools="http://schemas.android.com/tools">

節點標記

merge tools:node = "merge/replace/strict/remove/removeAll/merge-only-attribute"

合併規則中很重要的一個規則是節點標記,而merge 是默認行爲,當manifest 各節點屬性沒有聲明節點標記時候,就會使用默認值。現在一一解釋每個值的含義

  • merge  合併該attribute 所有的屬性和子屬性;
  • replace 替換其他的值,使用該清單文件的值(一般而言,都是替換掉低優先級的值)
  • strict    嚴格的意思,就是不同的清單文件,相同屬性的值應該一樣,否則編譯失敗。(一般而言,就是不同的清單文件同一個屬性其值要一樣)
  • remove  刪除某個屬性。
  • removeAll 刪除某個屬性及其嵌套的子屬性。(相當於remove,不過是有些時候刪除很多子屬性時,方便一些)
  • merge-only-attribute :Merge attributes in this tag only; do not merge nested elements 。只合並屬性,不合並嵌套的屬性
主工程app 的testActivity 聲明:
 <activity android:name=".testActivity" tools:node="merge">
            <meta-data android:name="xxx" tools:node="replace"/>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
 </activity>

module 的testActivity 聲明:
 <activity android:name=".testActivity" >
            <meta-data android:name="xxx" tools:node="replace"/>
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
 </activity>

說明:嵌套的含義——針對上面的activity(屬於module)來說,就是activity裏面的attribute——mate ,intent-filter,現在activity的合併標記是 merge,假如這個activity 所在的module、主工程都聲明瞭該activity,顯然在最終的manifest只會有一份 聲明,需要合併(所以說出現在 manifest 的任何屬性都可以運用合併標記)。這時候,我們需要按照規則來合併。

應用場景:

remove:假如主工程中不能使用某個權限,比如說聯繫人權限,但你引用的jar包或者aar使用了該權限,這時候就可以通過remove 標記去掉該權限在不影響使用的情況下。

replace:引用的工程在某個屬性使用了和主工程不同的值,這時候使用replace可以解決衝突;

 

屬性標記

tools:remove = "attr, ..."  tools:replace="attr, ..."  tools:strict="attr, ..."

 

見明知意。也是替換,移除,嚴格,和node中差不多,那爲什麼又搞出一個屬性標記呢?爲啥不直接用node這一個節點標記呢?
官方文檔給出的解釋:

To instead apply a merge rule only to specific attributes in a manifest tag, use the following attributes. Each attribute accepts one or more attribute names (including the attribute namespace), separated by commas.

低優先級

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">

高優先級

<activity android:name="com.example.ActivityOne"     
android:screenOrientation="portrait"   
  tools:remove="android:windowSoftInputMode">

合併之後
<activity android:name="com.example.ActivityOne"    
 android:screenOrientation="portrait">

而其他的一些屬性只有一個確定的子屬性,比如前面提到的 user-feature \ permission 等等,他們都是確定好哪個屬性了,所以就用了node 。

<uses-permission android:name="android.permission.INTERNET" tools:node="merge"/> 
<uses-feature android:name="android.hardware.Sensor" tools:node="remove"/>

選擇標記

應用場景:假如你只想對某個module 、library 實施一些規則,比如說,你引用了一個module, 一個aar ,你只想對aar包作用,這樣你可以用selector 指明作用域(現在好像去掉了這個標記了,已經找不到了)

<permission android:name="permissionOne"
    tools:node="remove"
    tools:selector="com.example.lib1">

<uses-sdk>

場景1:假如依賴的jar 的minSdkVersion 大於主工程的值,這時候爲了保持主工程的最小sdk值,可以使用 

<uses-sdk android:minSdkVersion="15" tools:overrideLibrary="要覆蓋的包名" />

注意:現在manifest 中的minSDK 和targetSdk會被gradle覆蓋,不推薦再寫 ,所以這裏只需要填寫

<uses-sdk  tools:overrideLibrary="要覆蓋的包名" />

使用IDE 的合併工具

合併策略 

合併工具通過尋找唯一的元素 (android:name ="") 或者 唯一的tag 比如<uses-sdk > ,按照如下總的規則去合併:

  1. 合併所有沒有衝突的屬性,若有衝突則按照衝突規則標記來;
  2. 只合並嵌套元素,比如activity 這種。
  3. 保持原來,並進行整和不同的屬性值

下面看英文原文,上面的翻譯不太準確:

 Merge policies

The manifest merger tool can logically match every XML element from one manifest file to a corresponding element in another file. The merger matches each element using a "match key": either a unique attribute value (such as android:name) or the natural uniqueness of the tag itself (for example, there can be only one <supports-screen> element). If two manifests have the same XML element, then the tool merges the two elements together using one of three merge policies:

Merge

Combine all non-conflicting attributes into the same tag and merge child elements according to their respective merging policy. If any attributes conflict with each other, merge them together with the merge rule markers.

Merge children only

Do not combine or merge the attributes (keep only the attributes provided by the highest priority manifest file) and merge child elements according to their merging policy.

Keep

Leave the element "as is" and add it to the common parent element in the merged file. This is used only when it is acceptable for there to be several declarations of the same element.

 Manifest element merge policies and match keys

Element Merge policy Match key
<action> Merge android:name attribute
<activity> Merge android:name attribute
<application> Merge There is only one per <manifest>
<category> Merge android:name attribute
<data> Merge There is only one per <intent-filter>
<grant-uri-permission> Merge There is only one per <provider>
<instrumentation> Merge android:name attribute
<intent-filter> Keep No matching; several declarations within the parent element are allowed
<manifest> Merge children only There is only one per file
<meta-data> Merge android:name attribute
<path-permission> Merge There is only one per <provider>
<permission-group> Merge android:name attribute
<permission> Merge android:name attribute
<permission-tree> Merge android:name attribute
<provider> Merge android:name attribute
<receiver> Merge android:name attribute
<screen> Merge android:screenSize attribute
<service> Merge android:name attribute
<supports-gl-texture> Merge android:name attribute
<supports-screen> Merge There is only one per <manifest>
<uses-configuration> Merge There is only one per <manifest>
<uses-feature> Merge android:name attribute (if not present, then the android:glEsVersion attribute)
<uses-library> Merge android:name attribute
<uses-permission> Merge android:name attribute
<uses-sdk> Merge There is only one per <manifest>
Custom elements Merge No matching; these are unknown to the merger tool so they are always included in the merged manifest
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章