จัดการไฟล์ Manifest

หน้านี้อธิบายวิธีการทำงานของการผสานไฟล์ Manifest และวิธีใช้ค่ากำหนดการผสานเพื่อแก้ไขข้อขัดแย้งในการผสาน ดูข้อมูลเบื้องต้นเกี่ยวกับไฟล์ Manifest ของแอปได้ที่ภาพรวมของไฟล์ Manifest ของแอป

ผสานไฟล์ Manifest หลายไฟล์

ไฟล์ APK หรือ Android App Bundle อาจมีไฟล์ AndroidManifest.xml เพียงไฟล์เดียว แต่โปรเจ็กต์ Android Studio อาจมีไฟล์ Manifest หลายไฟล์ที่มาจากชุดแหล่งที่มาหลัก ตัวแปรการสร้าง และไลบรารีที่นําเข้า เมื่อสร้างแอป บิลด์ Gradle จะผสานไฟล์ Manifest ทั้งหมดเข้าเป็นไฟล์ Manifest ไฟล์เดียวที่รวมอยู่ในแอป

เครื่องมือผสานไฟล์ Manifest จะรวมองค์ประกอบ XML ทั้งหมดจากแต่ละไฟล์โดยทำตามวิธีการแบบเฮuristic ในการผสานและปฏิบัติตามค่ากําหนดการผสานที่คุณกําหนดไว้ด้วยแอตทริบิวต์ XML พิเศษ

เคล็ดลับ: ใช้มุมมองไฟล์ Manifest ที่ผสานที่อธิบายไว้ในส่วนถัดไปเพื่อดูตัวอย่างผลลัพธ์ของไฟล์ Manifest ที่ผสานและค้นหาข้อผิดพลาดที่ขัดแย้งกัน

ผสานลําดับความสําคัญ

เครื่องมือผสานจะรวมไฟล์ Manifest ทั้งหมดเข้าเป็นไฟล์เดียวตามลําดับ โดยอิงตามลําดับความสําคัญของไฟล์ Manifest แต่ละไฟล์ ตัวอย่างเช่น หากคุณมีไฟล์ Manifest 3 ไฟล์ ระบบจะผสานไฟล์ Manifest ที่มีลําดับความสําคัญต่ำสุดเข้ากับไฟล์ Manifest ที่มีลําดับความสําคัญถัดไป แล้วผสานไฟล์ Manifest ดังกล่าวเข้ากับไฟล์ Manifest ที่มีลําดับความสําคัญสูงสุดดังที่แสดงในรูปที่ 1

รูปที่ 1 กระบวนการผสานไฟล์ Manifest 3 ไฟล์จากลําดับความสําคัญต่ำสุดไปสูงสุด

ไฟล์ Manifest พื้นฐานมี 3 ประเภทที่อาจผสานรวมกันได้ โดยลำดับความสำคัญของการผสานมีดังนี้ (ลำดับความสำคัญสูงสุดก่อน)

  1. ไฟล์ Manifest สำหรับตัวแปรบิลด์

    หากมีชุดแหล่งที่มาหลายชุดสำหรับตัวแปร ลําดับความสําคัญของไฟล์ Manifest จะเป็นไปตามลำดับต่อไปนี้

    • ไฟล์ Manifest ตัวแปรการสร้าง (เช่น src/demoDebug/)
    • ไฟล์ Manifest ประเภทบิลด์ (เช่น src/debug/)
    • ไฟล์ Manifest ของเวอร์ชันผลิตภัณฑ์ (เช่น src/demo/)

      หากคุณใช้มิติข้อมูล Flavor ลำดับความสำคัญของไฟล์ Manifest จะสอดคล้องกับลําดับที่แต่ละมิติข้อมูลแสดงในพร็อพเพอร์ตี้ flavorDimensions (รายการแรกมีลําดับความสําคัญสูงสุด)

  2. ไฟล์ Manifest หลักสําหรับโมดูลแอป
  3. ไฟล์ Manifest จากไลบรารีที่รวมไว้

    หากคุณมีไลบรารีหลายรายการ ลําดับความสําคัญของไฟล์ Manifest จะตรงกับลําดับที่ปรากฏในบล็อก Gradledependencies

เช่น ระบบจะผสานไฟล์ Manifest ของไลบรารีเข้ากับไฟล์ Manifest หลัก จากนั้นจะผสานไฟล์ Manifest หลักเข้ากับไฟล์ Manifest ของตัวแปรบิลด์ โปรดทราบว่าลำดับความสำคัญเหล่านี้เป็นลำดับความสำคัญการผสานเดียวกันสำหรับชุดแหล่งที่มาทั้งหมด ตามที่อธิบายไว้ในสร้างด้วยชุดแหล่งที่มา

สำคัญ: การกําหนดค่าบิลด์จากไฟล์ build.gradle จะลบล้างแอตทริบิวต์ที่เกี่ยวข้องในไฟล์ Manifest ที่ผสาน เช่น minSdk จากไฟล์ build.gradle หรือ build.gradle.kts จะลบล้างแอตทริบิวต์ที่ตรงกันในองค์ประกอบ <uses-sdk> ไฟล์ Manifest โปรดละองค์ประกอบ <uses-sdk> ออกและกำหนดพร็อพเพอร์ตี้เหล่านี้ในไฟล์ build.gradle เท่านั้นเพื่อไม่ให้เกิดความสับสน โปรดดูรายละเอียดเพิ่มเติมที่หัวข้อกำหนดค่าบิลด์

การประเมินจากสิ่งต่างๆ เพื่อแก้ไขข้อขัดแย้งในการผสาน

เครื่องมือผสานสามารถจับคู่องค์ประกอบ XML ทั้งหมดจากไฟล์ Manifest หนึ่งกับองค์ประกอบที่เกี่ยวข้องในไฟล์ Manifest อื่นได้อย่างเป็นตรรกะ โปรดดูรายละเอียดเกี่ยวกับวิธีการทำงานของการจับคู่ที่หัวข้อลําดับความสําคัญของการผสานในส่วนก่อนหน้า

หากองค์ประกอบจากไฟล์ Manifest ที่มีลำดับความสำคัญต่ำกว่าไม่ตรงกับองค์ประกอบใดๆ ในไฟล์ Manifest ที่มีลำดับความสำคัญสูงกว่า ระบบจะเพิ่มองค์ประกอบนั้นลงในไฟล์ Manifest ที่ผสาน อย่างไรก็ตาม หากมีองค์ประกอบที่ตรงกัน เครื่องมือผสานจะพยายามรวมแอตทริบิวต์ทั้งหมดจากแต่ละรายการไว้ในองค์ประกอบเดียวกัน หากเครื่องมือพบว่าไฟล์ Manifest ทั้ง 2 ไฟล์มีแอตทริบิวต์เดียวกันซึ่งมีค่าต่างกัน ก็จะเกิดความขัดแย้งในการผสาน

ตารางที่ 1 แสดงผลลัพธ์ที่เป็นไปได้เมื่อเครื่องมือผสานพยายามรวมแอตทริบิวต์ทั้งหมดไว้ในองค์ประกอบเดียวกัน

ตารางที่ 1 ลักษณะการผสานเริ่มต้นสำหรับค่าแอตทริบิวต์

แอตทริบิวต์ที่มีลําดับความสําคัญสูง แอตทริบิวต์ที่มีลําดับความสําคัญต่ำ ผลลัพธ์ที่ผสานรวมของแอตทริบิวต์
ไม่มีคุณค่า ไม่มีคุณค่า ไม่มีค่า (ใช้ค่าเริ่มต้น)
ค่า ข ค่า ข
ค่า ก ไม่มีคุณค่า ค่า ก
ค่า ก ค่า ก
ค่า ข ข้อผิดพลาดที่ขัดแย้งกัน - คุณต้องเพิ่มเครื่องหมายการผสานกฎ

อย่างไรก็ตาม เครื่องมือผสานจะทำงานต่างออกไปในบางสถานการณ์เพื่อหลีกเลี่ยงข้อขัดแย้งในการผสาน ดังนี้

  • ระบบจะไม่ผสานแอตทริบิวต์ในองค์ประกอบ <manifest> เข้าด้วยกัน แต่จะนํามาใช้เฉพาะแอตทริบิวต์จากไฟล์ Manifest ที่มีลําดับความสําคัญสูงสุด
  • แอตทริบิวต์ android:required ในองค์ประกอบ <uses-feature> และ <uses-library> ใช้การผสาน OR หากมีข้อขัดแย้ง ระบบจะใช้ "true" และรวมฟีเจอร์หรือไลบรารีที่ไฟล์ Manifest รายการใดรายการหนึ่งกำหนดไว้เสมอ
  • แอตทริบิวต์ในองค์ประกอบ <uses-sdk> จะใช้ค่าจากไฟล์ Manifest ที่มีลําดับความสําคัญสูงกว่าเสมอ ยกเว้นในสถานการณ์ต่อไปนี้
    • เมื่อไฟล์ Manifest ที่มีลำดับความสำคัญต่ำกว่ามีค่า minSdk สูงกว่า ระบบจะแสดงข้อผิดพลาด เว้นแต่คุณจะใช้กฎการผสาน overrideLibrary
    • เมื่อไฟล์ Manifest ที่มีลำดับความสำคัญต่ำกว่ามีค่า targetSdkVersion ที่ต่ำกว่า เครื่องมือผสานจะใช้ค่าจากไฟล์ Manifest ที่มีลำดับความสำคัญสูงกว่า และจะเพิ่มสิทธิ์ของระบบที่จำเป็นเพื่อให้ไลบรารีที่นำเข้าทํางานต่อไปอย่างถูกต้อง (สําหรับกรณีที่ Android เวอร์ชันที่สูงกว่ามีการจํากัดสิทธิ์มากขึ้น) ดูข้อมูลเพิ่มเติมเกี่ยวกับลักษณะการทำงานนี้ได้ในส่วนสิทธิ์ของระบบโดยนัย
  • ระบบจะไม่จับคู่องค์ประกอบ <intent-filter> ระหว่างไฟล์ Manifest ระบบจะถือว่าแต่ละรายการไม่ซ้ำกันและจะเพิ่มลงในองค์ประกอบหลักทั่วไปในไฟล์ Manifest ที่ผสาน

สำหรับความขัดแย้งอื่นๆ ทั้งหมดระหว่างแอตทริบิวต์ คุณจะได้รับข้อผิดพลาดและต้องบอกวิธีแก้ปัญหาให้เครื่องมือผสานทราบด้วยการเพิ่มแอตทริบิวต์พิเศษในไฟล์ Manifest ที่มีลำดับความสำคัญสูงกว่า ดูส่วนต่อไปนี้เกี่ยวกับเครื่องหมายกฎการผสาน

อย่าใช้ค่าแอตทริบิวต์เริ่มต้น เนื่องจากระบบจะรวมแอตทริบิวต์ที่ไม่ซ้ำทั้งหมดไว้ในองค์ประกอบเดียวกัน จึงอาจทำให้เกิดผลลัพธ์ที่ไม่คาดคิดหากไฟล์ Manifest ที่มีลำดับความสำคัญสูงกว่านั้นใช้ค่าเริ่มต้นของแอตทริบิวต์โดยไม่ได้ประกาศ ตัวอย่างเช่น หากไฟล์ Manifest ที่มีลำดับความสำคัญสูงกว่าไม่ได้ประกาศแอตทริบิวต์ android:launchMode ระบบจะใช้ค่าเริ่มต้นของ "standard" แต่หากไฟล์ Manifest ที่มีลำดับความสำคัญต่ำกว่าประกาศแอตทริบิวต์นี้ด้วยค่าอื่น ระบบจะใช้ค่านั้นกับไฟล์ Manifest ที่ผสาน ซึ่งจะลบล้างค่าเริ่มต้น คุณควรกำหนดแอตทริบิวต์แต่ละรายการอย่างชัดแจ้งตามที่คุณต้องการ ค่าเริ่มต้นสำหรับแต่ละแอตทริบิวต์จะระบุไว้ในข้อมูลอ้างอิงไฟล์ Manifest

ผสานเครื่องหมายกฎ

เครื่องหมายกฎการผสานคือแอตทริบิวต์ XML ที่คุณสามารถใช้เพื่อแสดงค่ากำหนดเกี่ยวกับวิธีแก้ไขข้อขัดแย้งในการผสานหรือนำองค์ประกอบและแอตทริบิวต์ที่ไม่ต้องการออก คุณสามารถใช้เครื่องหมายกับทั้งองค์ประกอบหรือเฉพาะแอตทริบิวต์ที่ต้องการในองค์ประกอบก็ได้

เมื่อผสานไฟล์ Manifest 2 ไฟล์ เครื่องมือผสานจะมองหาเครื่องหมายเหล่านี้ในไฟล์ Manifest ที่มีลําดับความสําคัญสูงกว่า

เครื่องหมายทั้งหมดอยู่ในเนมสเปซ tools ของ Android คุณจึงต้องประกาศเนมสเปซนี้ในองค์ประกอบ <manifest> ก่อน ดังที่แสดงที่นี่

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

เครื่องหมายโหนด

หากต้องการใช้กฎการผสานกับองค์ประกอบ XML ทั้งหมด (กับแอตทริบิวต์ทั้งหมดในองค์ประกอบไฟล์ Manifest หนึ่งๆ และกับแท็กย่อยทั้งหมดขององค์ประกอบนั้น) ให้ใช้แอตทริบิวต์ต่อไปนี้

tools:node="merge"
ผสานแอตทริบิวต์ทั้งหมดในแท็กนี้และองค์ประกอบที่ฝังอยู่ทั้งหมดเมื่อไม่มีความขัดแย้งโดยใช้การผสาน heuristics ของความขัดแย้ง ลักษณะการทำงานนี้เป็นลักษณะเริ่มต้นขององค์ประกอบ

ไฟล์ Manifest สำคัญน้อย

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

ไฟล์ Manifest สำคัญสูง

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge">
</activity>

ผลลัพธ์ของไฟล์ Manifest ที่ผสาน:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
tools:node="merge-only-attributes"
ผสานแอตทริบิวต์ในแท็กนี้เท่านั้น อย่าผสานองค์ประกอบที่ฝังอยู่

ไฟล์ Manifest สำคัญน้อย

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <data android:type="image/*" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

ไฟล์ Manifest สำคัญสูง

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge-only-attributes">
</activity>

ผลลัพธ์ของไฟล์ Manifest ที่ผสาน:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
</activity>
tools:node="remove"
นําองค์ประกอบนี้ออกจากไฟล์ Manifest ที่ผสาน ใช้เมื่อคุณพบองค์ประกอบในไฟล์ Manifest ที่ผสานซึ่งไม่จําเป็นซึ่งมาจากไฟล์ Manifest ที่มีลําดับความสําคัญต่ำกว่าซึ่งอยู่นอกเหนือการควบคุมของคุณ (เช่น ไลบรารีที่นําเข้า)

ไฟล์ Manifest สำคัญน้อย

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

ไฟล์ Manifest สำคัญสูง

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      tools:node="remove"/>
</activity-alias>

ผลลัพธ์ของไฟล์ Manifest ที่ผสาน:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>
tools:node="removeAll"
คล้ายกับ tools:node="remove" แต่จะนำองค์ประกอบทั้งหมดที่ตรงกับประเภทองค์ประกอบนี้ออก (ภายในองค์ประกอบหลักเดียวกัน)

ไฟล์ Manifest สำคัญน้อย

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

ไฟล์ Manifest สำคัญสูง

<activity-alias android:name="com.example.alias">
  <meta-data tools:node="removeAll"/>
</activity-alias>

ผลลัพธ์ของไฟล์ Manifest ที่ผสาน:

<activity-alias android:name="com.example.alias">
</activity-alias>
tools:node="replace"
แทนที่องค์ประกอบที่มีลำดับความสำคัญต่ำกว่าโดยสมบูรณ์ กล่าวคือ หากมีองค์ประกอบที่ตรงกันในไฟล์ Manifest ที่มีลำดับความสำคัญต่ำกว่า ให้ละเว้นองค์ประกอบนั้นและใช้องค์ประกอบนี้ตามที่ปรากฏในไฟล์ Manifest นี้

ไฟล์ Manifest สำคัญน้อย

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

ไฟล์ Manifest สำคัญสูง

<activity-alias android:name="com.example.alias"
    tools:node="replace">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>

ผลลัพธ์ของไฟล์ Manifest ที่ผสาน:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>
tools:node="strict"
สร้างการสร้างที่ไม่สําเร็จทุกครั้งที่องค์ประกอบนี้ในไฟล์ Manifest ที่มีลําดับความสําคัญต่ำกว่าไม่ตรงกับองค์ประกอบในไฟล์ Manifest ที่มีลําดับความสําคัญสูงกว่า (เว้นแต่จะมีการแก้ไขโดยเครื่องหมายกฎการผสานอื่นๆ) ซึ่งจะลบล้างheuristics ของข้อขัดแย้งในการผสาน เช่น หากไฟล์ Manifest ที่มีลําดับความสําคัญต่ำกว่ามีแอตทริบิวต์เพิ่มเติม การสร้างจะล้มเหลว (ในขณะที่ลักษณะการทํางานเริ่มต้นจะเพิ่มแอตทริบิวต์เพิ่มเติมลงในไฟล์ Manifest ที่ผสาน)

ไฟล์ Manifest สำคัญน้อย

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

ไฟล์ Manifest สำคัญสูง

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="strict">
</activity>

การดำเนินการนี้จะทำให้เกิดข้อผิดพลาดในการผสานไฟล์ Manifest องค์ประกอบไฟล์ Manifest 2 รายการต้องเหมือนกันทุกประการในโหมดที่เข้มงวด คุณต้องใส่เครื่องหมายกฎการผสานอื่นๆ เพื่อแก้ไขความแตกต่างเหล่านี้ (หากไม่มี tools:node="strict" ไฟล์ 2 ไฟล์นี้จะผสานเข้าด้วยกันได้โดยไม่มีข้อผิดพลาด ดังที่แสดงในตัวอย่างสำหรับ tools:node="merge")

เครื่องหมายแอตทริบิวต์

หากต้องการใช้กฎการผสานกับแอตทริบิวต์ที่เฉพาะเจาะจงในแท็กไฟล์ Manifest เท่านั้น ให้ใช้แอตทริบิวต์ต่อไปนี้ แอตทริบิวต์แต่ละรายการยอมรับชื่อแอตทริบิวต์อย่างน้อย 1 ชื่อ (รวมถึงเนมสเปซของแอตทริบิวต์) โดยคั่นด้วยคอมมา

tools:remove="attr, ..."
นำแอตทริบิวต์ที่ระบุออกจากไฟล์ Manifest ที่ผสาน ใช้เมื่อไฟล์ Manifest ที่มีความสําคัญต่ำกว่ามีแอตทริบิวต์เหล่านี้ และคุณต้องการตรวจสอบว่าแอตทริบิวต์ดังกล่าวจะไม่รวมอยู่ในไฟล์ Manifest ที่ผสาน

ไฟล์ Manifest สำคัญน้อย

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

ไฟล์ Manifest สำคัญสูง

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

ผลลัพธ์ของไฟล์ Manifest ที่ผสาน:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait">
tools:replace="attr, ..."
แทนที่แอตทริบิวต์ที่ระบุในไฟล์ Manifest ลำดับความสำคัญต่ำกว่าด้วยแอตทริบิวต์จากไฟล์ Manifest นี้ กล่าวคือ ให้เก็บค่าของไฟล์ Manifest ที่มีลำดับความสำคัญสูงกว่าไว้เสมอ

ไฟล์ Manifest สำคัญน้อย

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:windowSoftInputMode="stateUnchanged">

ไฟล์ Manifest สำคัญสูง

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported">

ผลลัพธ์ของไฟล์ Manifest ที่ผสาน:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
tools:strict="attr, ..."
สร้างการสร้างที่ไม่สําเร็จทุกครั้งที่แอตทริบิวต์เหล่านี้ในไฟล์ Manifest ที่มีลําดับความสําคัญต่ำกว่าไม่ตรงกับแอตทริบิวต์ในไฟล์ Manifest ที่มีลําดับความสําคัญสูงกว่า ลักษณะการทำงานนี้เป็นลักษณะการทำงานเริ่มต้นสำหรับแอตทริบิวต์ทั้งหมด ยกเว้นแอตทริบิวต์ที่มีลักษณะการทำงานพิเศษตามที่อธิบายไว้ในheuristics ของข้อขัดแย้งในการผสาน

ไฟล์ Manifest สำคัญน้อย

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="landscape">
</activity>

ไฟล์ Manifest สำคัญสูง

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:strict="android:screenOrientation">
</activity>

การดำเนินการนี้จะทำให้เกิดข้อผิดพลาดในการผสานไฟล์ Manifest คุณต้องใส่เครื่องหมายกฎการผสานอื่นๆ เพื่อแก้ไขข้อขัดแย้ง นี่คือลักษณะการทำงานเริ่มต้น ดังนั้นผลลัพธ์เดียวกันจะเกิดขึ้นเมื่อเพิ่ม tools:strict="screenOrientation" อย่างชัดเจน

นอกจากนี้ คุณยังใช้เครื่องหมายหลายรายการกับองค์ประกอบเดียวได้ ดังที่แสดงในตัวอย่างต่อไปนี้

ไฟล์ Manifest สำคัญน้อย

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:allowTaskReparenting="true"
    android:windowSoftInputMode="stateUnchanged">

ไฟล์ Manifest สำคัญสูง

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported"
    tools:remove="android:windowSoftInputMode">

ผลลัพธ์ของไฟล์ Manifest ที่ผสาน:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:allowTaskReparenting="true"
    android:screenOrientation="portrait">

ตัวเลือกเครื่องหมาย

หากต้องการใช้เครื่องหมายกฎการผสานกับไลบรารีที่นำเข้าบางรายการเท่านั้น ให้เพิ่มแอตทริบิวต์ tools:selector พร้อมชื่อแพ็กเกจไลบรารี

ตัวอย่างเช่น เมื่อใช้ไฟล์ Manifest ต่อไปนี้ ระบบจะใช้กฎการผสาน remove เฉพาะในกรณีที่ไฟล์ Manifest ที่มีลําดับความสําคัญต่ำกว่ามาจากไลบรารี com.example.lib1

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

หากไฟล์ Manifest ที่มีลําดับความสําคัญต่ำกว่ามาจากแหล่งที่มาอื่น ระบบจะไม่สนใจกฎการผสานremove

หมายเหตุ: หากคุณใช้แอตทริบิวต์นี้กับเครื่องหมายแอตทริบิวต์ใดเครื่องหมายหนึ่ง แอตทริบิวต์ดังกล่าวจะมีผลกับแอตทริบิวต์ทั้งหมดที่ระบุไว้ในเครื่องหมาย

ลบล้าง <uses-sdk> สำหรับไลบรารีที่นำเข้า

โดยค่าเริ่มต้น เมื่อนําเข้าคลังที่มีค่า minSdk สูงกว่าไฟล์ Manifest หลัก ระบบจะแสดงข้อผิดพลาดและนําเข้าคลังไม่ได้

หากต้องการให้เครื่องมือผสานละเว้นข้อขัดแย้งนี้และนําเข้าคลังโดยเก็บค่า minSdk ที่ต่ำกว่าของแอปไว้ ให้เพิ่มแอตทริบิวต์ overrideLibrary ลงในแท็ก <uses-sdk> ค่าแอตทริบิวต์อาจเป็นชื่อแพ็กเกจไลบรารีอย่างน้อย 1 ชื่อ (คั่นด้วยคอมมา) ซึ่งระบุไลบรารีที่สามารถลบล้าง minSdk ของไฟล์ Manifest หลัก

ตัวอย่างเช่น หากไฟล์ Manifest หลักของแอปใช้ overrideLibrary ดังนี้

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.app"
          xmlns:tools="http://schemas.android.com/tools">
  <uses-sdk tools:overrideLibrary="com.example.lib1, com.example.lib2"/>
...

จากนั้นจะผสานไฟล์ Manifest ต่อไปนี้ได้โดยไม่มีข้อผิดพลาดเกี่ยวกับแท็ก <uses-sdk> และไฟล์ Manifest ที่ผสานจะเก็บ minSdk="2" จากไฟล์ Manifest ของแอปไว้

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.lib1">
   <uses-sdk android:minSdk="4" />
...

สิทธิ์ของระบบโดยนัย

API ของ Android บางรายการที่แอปเคยเข้าถึงได้อย่างอิสระได้ถูกจำกัดโดยสิทธิ์ของระบบใน Android เวอร์ชันล่าสุด

Android เวอร์ชันล่าสุดอนุญาตให้แอปเข้าถึง API เหล่านี้ต่อไปได้หากไม่มีสิทธิ์ หากตั้งค่า targetSdkVersion เป็นค่าที่ต่ำกว่าเวอร์ชันที่มีการเพิ่มข้อจำกัด เพื่อหลีกเลี่ยงไม่ให้แอปที่คาดหวังว่าจะเข้าถึง API เหล่านี้ใช้งานไม่ได้ ลักษณะการทํางานนี้จะให้สิทธิ์โดยนัยแก่แอปในการอนุญาตให้เข้าถึง API ไฟล์ Manifest ที่ผสานซึ่งมีค่าสำหรับ targetSdkVersion แตกต่างกันอาจได้รับผลกระทบ

หากไฟล์ Manifest ที่มีลำดับความสำคัญต่ำกว่ามีค่า targetSdkVersion ต่ำกว่าซึ่งให้สิทธิ์โดยนัย และไฟล์ Manifest ที่มีลำดับความสำคัญสูงกว่าไม่มีสิทธิ์โดยนัยเดียวกัน (เนื่องจาก targetSdkVersion ของไฟล์ Manifest นั้นเท่ากับหรือสูงกว่าเวอร์ชันที่มีการเพิ่มข้อจำกัด) เครื่องมือผสานจะเพิ่มสิทธิ์ของระบบลงในไฟล์ Manifest ที่ผสานโดยชัดแจ้ง

ตัวอย่างเช่น หากแอปตั้งค่า targetSdkVersion เป็น 4 ขึ้นไปและนําเข้าไลบรารีที่มีการตั้งค่า targetSdkVersion เป็น 3 หรือต่ำกว่า เครื่องมือผสานจะเพิ่มสิทธิ์ WRITE_EXTERNAL_STORAGE ลงในไฟล์ Manifest ที่ผสาน

ตารางที่ 2 แสดงสิทธิ์ที่เป็นไปได้ทั้งหมดซึ่งสามารถเพิ่มลงในไฟล์ Manifest ที่ผสาน

ตารางที่ 2 รายการสิทธิ์ที่เครื่องมือผสานอาจเพิ่มลงในไฟล์ Manifest ที่ผสาน

ประกาศไฟล์ Manifest ที่มีลําดับความสําคัญต่ำกว่า สิทธิ์ที่เพิ่มลงในไฟล์ Manifest ที่ผสาน
targetSdkVersion เท่ากับหรือน้อยกว่า 3 WRITE_EXTERNAL_STORAGE, READ_PHONE_STATE
targetSdkVersion มีอายุ 15 ปีหรือต่ำกว่าและใช้ READ_CONTACTS READ_CALL_LOG
targetSdkVersion มีอายุ 15 ปีหรือต่ำกว่าและใช้ WRITE_CONTACTS WRITE_CALL_LOG

ตรวจสอบไฟล์ Manifest ที่ผสานรวมและค้นหาข้อขัดแย้ง

คุณดูตัวอย่างลักษณะของไฟล์ Manifest ที่ผสานได้ก่อนที่จะสร้างแอป หากต้องการดูตัวอย่าง ให้ทําดังนี้

  1. เปิดไฟล์ AndroidManifest.xml ใน Android Studio
  2. คลิกแท็บไฟล์ Manifest ที่ผสานที่ด้านล่างของตัวแก้ไข

มุมมองไฟล์ Manifest ที่ผสานจะแสดงผลลัพธ์ของไฟล์ Manifest ที่ผสานทางด้านซ้าย และข้อมูลเกี่ยวกับไฟล์ Manifest ที่ผสานแต่ละไฟล์ทางด้านขวา ดังที่แสดงในรูปที่ 2

องค์ประกอบที่ผสานมาจากไฟล์ Manifest ที่มีลําดับความสําคัญต่ำกว่าจะไฮไลต์ด้วยสีที่ต่างกันทางด้านซ้าย ระบุคีย์สำหรับแต่ละสีในส่วนแหล่งที่มาของไฟล์ Manifest

รูปที่ 2 มุมมองไฟล์ Manifest ที่ผสานแล้ว

ไฟล์ Manifest ที่อยู่ในบิลด์แต่ไม่ได้มีส่วนประกอบหรือแอตทริบิวต์จะแสดงอยู่ในส่วนไฟล์ Manifest อื่นๆ

หากต้องการดูข้อมูลเกี่ยวกับแหล่งที่มาขององค์ประกอบ ให้คลิกองค์ประกอบนั้นในแผงด้านซ้าย แล้วรายละเอียดจะปรากฏในส่วนบันทึกการผสาน

หากเกิดข้อขัดแย้ง ข้อขัดแย้งดังกล่าวจะปรากฏในส่วนข้อผิดพลาดในการผสานพร้อมคําแนะนําเกี่ยวกับวิธีแก้ไขข้อขัดแย้งโดยใช้เครื่องหมายกฎการผสาน

ระบบจะพิมพ์ข้อผิดพลาดในหน้าต่างบันทึกเหตุการณ์ด้วย หากต้องการดู ให้เลือกดู > หน้าต่างเครื่องมือ > บันทึกเหตุการณ์

หากต้องการดูบันทึกที่สมบูรณ์ของผังการตัดสินใจการผสาน ให้ค้นหาไฟล์บันทึกในไดเรกทอรี build/outputs/logs/ ของโมดูลซึ่งมีชื่อว่า manifest-merger-buildVariant-report.txt

ผสานนโยบาย

เครื่องมือผสานไฟล์ Manifest สามารถจับคู่องค์ประกอบ XML ทั้งหมดจากไฟล์ Manifest ไฟล์หนึ่งกับองค์ประกอบที่เกี่ยวข้องในไฟล์อื่นได้อย่างมีเหตุผล การผสานจะจับคู่แต่ละองค์ประกอบโดยใช้คีย์การจับคู่ ซึ่งอาจเป็นค่าแอตทริบิวต์ที่ไม่ซ้ำกัน (เช่น android:name) หรือความเฉพาะตัวตามธรรมชาติของแท็กเอง (เช่น มีองค์ประกอบ <supports-screen> ได้เพียงรายการเดียว)

หากไฟล์ Manifest 2 ไฟล์มีองค์ประกอบ XML เดียวกัน เครื่องมือจะผสานองค์ประกอบ 2 รายการเข้าด้วยกันโดยใช้นโยบายการผสานอย่างใดอย่างหนึ่งต่อไปนี้

รวม
รวมแอตทริบิวต์ทั้งหมดที่ไม่ขัดแย้งไว้ในแท็กเดียวกันและผสานองค์ประกอบย่อยตามนโยบายการผสานที่เกี่ยวข้อง หากแอตทริบิวต์ใดขัดแย้งกัน ให้ผสานแอตทริบิวต์เหล่านั้นเข้าด้วยกันด้วยเครื่องหมายกฎการผสาน
ผสานรายการย่อยเท่านั้น
อย่ารวมหรือผสานแอตทริบิวต์ (เก็บเฉพาะแอตทริบิวต์ที่ระบุโดยไฟล์ Manifest ที่มีลำดับความสำคัญสูงสุด) และผสานองค์ประกอบย่อยตามนโยบายการผสาน
Keep
ปล่อยองค์ประกอบไว้ตามเดิมและเพิ่มลงในองค์ประกอบหลักทั่วไปในไฟล์ที่ผสาน ใช้เฉพาะในกรณีที่ยอมรับการประกาศองค์ประกอบเดียวกันหลายรายการ

ตารางที่ 3 แสดงรายการประเภทองค์ประกอบแต่ละประเภท ประเภทนโยบายการผสานที่ใช้ และคำที่ใช้เพื่อระบุการจับคู่องค์ประกอบระหว่างไฟล์ Manifest 2 รายการ

ตารางที่ 3 นโยบายการผสานองค์ประกอบไฟล์ Manifest และคียกํากับ

ธาตุ นโยบายการผสาน คีย์การจับคู่
<action> รวม แอตทริบิวต์ android:name
<activity> รวม แอตทริบิวต์ android:name
<application> รวม โดยจะมีเพียง 1 รายการต่อ <manifest>
<category> รวม แอตทริบิวต์ android:name
<data> รวม โดยจะมีเพียง 1 รายการต่อ <intent-filter>
<grant-uri-permission> รวม โดยจะมีเพียง 1 รายการต่อ <provider>
<instrumentation> รวม แอตทริบิวต์ android:name
<intent-filter> Keep ไม่ตรงกัน ระบบอนุญาตให้มีการประกาศหลายรายการภายในองค์ประกอบหลัก
<manifest> ผสานรายการย่อยเท่านั้น โดยจะมีเพียง 1 รายการต่อไฟล์
<meta-data> รวม แอตทริบิวต์ android:name
<path-permission> รวม โดยจะมีเพียง 1 รายการต่อ <provider>
<permission-group> รวม แอตทริบิวต์ android:name
<permission> รวม แอตทริบิวต์ android:name
<permission-tree> รวม แอตทริบิวต์ android:name
<provider> รวม แอตทริบิวต์ android:name
<receiver> รวม แอตทริบิวต์ android:name
<screen> รวม แอตทริบิวต์ android:screenSize
<service> รวม แอตทริบิวต์ android:name
<supports-gl-texture> รวม แอตทริบิวต์ android:name
<supports-screen> รวม โดยจะมีเพียง 1 รายการต่อ <manifest>
<uses-configuration> รวม โดยจะมีเพียง 1 รายการต่อ <manifest>
<uses-feature> รวม แอตทริบิวต์ android:name (หากไม่มี ให้ใช้แอตทริบิวต์ android:glEsVersion)
<uses-library> รวม แอตทริบิวต์ android:name
<uses-permission> รวม แอตทริบิวต์ android:name
<uses-sdk> รวม โดยจะมีเพียง 1 รายการต่อ <manifest>
องค์ประกอบที่กำหนดเอง รวม ไม่ตรงกัน เครื่องมือผสานไม่รู้จักรายการเหล่านี้และจะรวมไว้ในไฟล์ Manifest ที่ผสานเสมอ

แทรกตัวแปรบิวด์เข้าไปในไฟล์ Manifest

หากต้องการแทรกตัวแปรลงในไฟล์ AndroidManifest.xml ที่กําหนดไว้ในไฟล์ build.gradle ให้ใช้พร็อพเพอร์ตี้ manifestPlaceholders พร็อพเพอร์ตี้นี้ใช้แผนที่ของคู่คีย์-ค่า ดังที่แสดงที่นี่

Groovy

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
    }
    ...
}

Kotlin

android {
    defaultConfig {
        manifestPlaceholders["hostName"] = "www.example.com"
    }
    ...
}

จากนั้นคุณสามารถแทรกตัวยึดตําแหน่งในไฟล์ Manifest เป็นค่าแอตทริบิวต์ได้ ดังนี้

<intent-filter ... >
    <data android:scheme="https" android:host="${hostName}" ... />
    ...
</intent-filter>

โดยค่าเริ่มต้น เครื่องมือสร้างจะระบุรหัสแอปพลิเคชันของแอปในตัวยึดตําแหน่ง ${applicationId} ด้วย ค่านี้จะตรงกับรหัสแอปพลิเคชันสุดท้ายของบิลด์ปัจจุบันเสมอ รวมถึงการเปลี่ยนแปลงตามตัวแปรของบิลด์ ซึ่งมีประโยชน์เมื่อคุณต้องการใช้เนมสเปซที่ไม่ซ้ำกันสำหรับตัวระบุ เช่น การดําเนินการของ Intent แม้แต่ระหว่างตัวแปรของบิลด์

เช่น หากไฟล์ build.gradle มีลักษณะดังนี้

Groovy

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    flavorDimensions "type"
    productFlavors {
        free {
            applicationIdSuffix ".free"
            dimension "type"
        }
        pro {
            applicationIdSuffix ".pro"
            dimension "type"
        }
    }
}

Kotlin

android {
    defaultConfig {
        applicationId = "com.example.myapp"
    }
    flavorDimensions += "type"
    productFlavors {
        create("free") {
            applicationIdSuffix = ".free"
            dimension = "type"
        }
        create("pro") {
            applicationIdSuffix = ".pro"
            dimension = "type"
        }
    }
}

จากนั้นแทรกรหัสแอปพลิเคชันในไฟล์ Manifest ดังนี้

<intent-filter ... >
    <action android:name="${applicationId}.TRANSMOGRIFY" />
    ...
</intent-filter>

และผลลัพธ์ของไฟล์ Manifest เมื่อคุณสร้างผลิตภัณฑ์ "ฟรี" มีดังนี้

<intent-filter ... >
   <action android:name="com.example.myapp.free.TRANSMOGRIFY" />
    ...
</intent-filter>

ดูข้อมูลเพิ่มเติมได้ที่หัวข้อตั้งค่ารหัสแอปพลิเคชัน