ניהול קובצי מניפסט

בדף הזה מוסבר איך מיזוג מניפסטים פועל ואיך אפשר להחיל העדפות מיזוג כדי לפתור התנגשויות במיזוג. למבוא על קובץ המניפסט של האפליקציה, ראו סקירה כללית על קובץ המניפסט של האפליקציה.

מיזוג של כמה קובצי מניפסט

קובץ ה-APK או ה-Android App Bundle יכול להכיל רק קובץ AndroidManifest.xml אחד, אבל פרויקט Android Studio יכול להכיל כמה קובצי מניפסט שסופקו על ידי קבוצת המקורות הראשית, וריאנטים של build וספריות מיובאות. כשיוצרים את האפליקציה, ה-build של Gradle ממזג את כל קובצי המניפסט לקובץ מניפסט אחד שנארז באפליקציה.

כלי המיזוג של המניפסט משלב את כל רכיבי ה-XML מכל קובץ לפי היוריסטיקות של מיזוג ובהתאם להעדפות המיזוג שהגדרתם באמצעות מאפייני XML מיוחדים.

מיזוג עדיפויות

כלי המיזוג משלב את כל קובצי המניפסט לקובץ אחד באופן רציף, על סמך העדיפות של כל קובץ מניפסט. לדוגמה, אם יש לכם שלושה קובצי מניפסט, המניפסט עם העדיפות הנמוכה ביותר מתמזג עם המניפסט עם העדיפות הבאה בתור, ואז הוא מתמזג עם המניפסט עם העדיפות הגבוהה ביותר, כמו שמוצג באיור 1.

איור 1. תהליך המיזוג של שלושה קובצי מניפסט, מהעדיפות הנמוכה ביותר לעדיפות הגבוהה ביותר.

יש שלושה סוגים בסיסיים של קובצי מניפסט שאפשר למזג זה עם זה, וסדרי העדיפויות שלהם למיזוג הם (העדיפות הגבוהה ביותר קודם):

  1. קובץ מניפסט של וריאנט ה-build

    אם יש לכם כמה קבוצות מקורות לווריאנט, אלה סדרי העדיפויות של המניפסטים שלהן:

    • מניפסט של וריאנט build (למשל src/demoDebug/)
    • מניפסט של סוג ה-build (למשל src/debug/)
    • מניפסט של גרסת המוצר (למשל src/demo/)

      אם אתם משתמשים בקבוצות גרסאות, סדרי העדיפויות של המניפסטים תואמים לסדר שבו כל קבוצה מופיעה במאפיין flavorDimensions (הראשונה היא בעלת העדיפות הגבוהה ביותר).

  2. קובץ המניפסט הראשי של מודול האפליקציה

  3. קובץ מניפסט מספרייה כלולה

    אם יש לכם כמה ספריות, סדרי העדיפויות של המניפסטים שלהן תואמים לסדר שבו הן מופיעות בבלוק dependencies של Gradle.

לדוגמה, מניפסט של ספרייה ממוזג לתוך המניפסט הראשי, ואז המניפסט הראשי ממוזג לתוך המניפסט של וריאנט ה-build. שימו לב שאלה אותן עדיפויות מיזוג לכל קבוצות המקורות, כמו שמתואר במאמר פיתוח באמצעות קבוצות מקורות.

היוריסטיקה של התנגשויות במיזוג

כלי המיזוג יכול להתאים באופן לוגי כל רכיב XML ממניפסט אחד לרכיב תואם במניפסט אחר. לפרטים על אופן ההתאמה, עיינו בקטע הקודם בנושא סדרי עדיפויות במיזוג.

אם רכיב מהמניפסט בעדיפות הנמוכה יותר לא תואם לאף רכיב במניפסט בעדיפות הגבוהה יותר, הוא מתווסף למניפסט שעבר מיזוג. עם זאת, אם יש רכיב תואם, כלי המיזוג מנסה לשלב את כל המאפיינים של כל אחד מהם באותו רכיב. אם הכלי מוצא ששני המניפסטים מכילים את אותו מאפיין עם ערכים שונים, מתרחשת התנגשות במיזוג.

טבלה 1 מתארת את התוצאות האפשריות כשכלי המיזוג מנסה לשלב את כל המאפיינים באותו רכיב.

טבלה 1. התנהגות ברירת המחדל של מיזוג ערכי מאפיינים

מאפיין בעדיפות גבוהה מאפיין בעדיפות נמוכה התוצאה הממוזגת של המאפיין
חסרת חשיבות חסרת חשיבות אין ערך (שימוש בערך ברירת המחדל)
ערך ב' ערך ב'
ערך א' חסרת חשיבות ערך א'
ערך א' ערך א'
ערך ב' שגיאת התנגשות – צריך להוסיף סמן של כלל מיזוג.

עם זאת, יש כמה מצבים שבהם כלי המיזוג פועל באופן שונה כדי למנוע התנגשויות במיזוג:

  • המאפיינים ברכיב <manifest> אף פעם לא מתמזגים. המערכת משתמשת רק במאפיינים מהמניפסט עם העדיפות הגבוהה ביותר.
  • המאפיין android:required ברכיבים <uses-feature> ו-<uses-library> משתמש במיזוג OR. אם יש התנגשות, המערכת מחילה את "true" והתכונה או הספרייה שנדרשות על ידי מניפסט אחד תמיד נכללות.
  • המאפיינים ברכיב <uses-sdk> תמיד משתמשים בערך מהמניפסט בעל העדיפות הגבוהה יותר, חוץ מהמקרים הבאים:
    • כשהערך של minSdk במניפסט בעל העדיפות הנמוכה יותר גבוה יותר, תתרחש שגיאה, אלא אם תפעילו את כלל המיזוג overrideLibrary.
    • אם במניפסט בעל העדיפות הנמוכה יותר יש ערך targetSdkVersion נמוך יותר, כלי המיזוג משתמש בערך מהמניפסט בעל העדיפות הגבוהה יותר, וגם מוסיף את כל הרשאות המערכת שנדרשות כדי להבטיח שהספרייה המיובאת תמשיך לפעול כראוי (במקרים שבהם בגרסת Android הגבוהה יותר יש הגבלות הרשאות מוגברות). למידע נוסף על ההתנהגות הזו, קראו את הקטע בנושא הרשאות מערכת משתמעות.
  • הרכיב <intent-filter> אף פעם לא תואם בין מניפסטים. כל אחד מהם נחשב לייחודי ומתווסף לרכיב ההורה המשותף במניפסט שעבר מיזוג.

בכל שאר ההתנגשויות בין מאפיינים, תתקבל שגיאה ותצטרכו להורות לכלי המיזוג איך לפתור אותה על ידי הוספת מאפיין מיוחד בקובץ המניפסט בעל העדיפות הגבוהה יותר. בקטע הבא מוסבר על סמני כללי מיזוג.

מיזוג סמני כללים

סמן של כלל מיזוג הוא מאפיין XML שמאפשר לכם להגדיר את ההעדפה שלכם לגבי פתרון של התנגשויות במיזוג או הסרה של רכיבים ומאפיינים לא רצויים. אפשר להחיל סמן על רכיב שלם או רק על מאפיינים ספציפיים ברכיב.

כשממזגים שני קובצי מניפסט, כלי המיזוג מחפש את הסמנים האלה בקובץ המניפסט עם העדיפות הגבוהה יותר.

כל הסמנים שייכים למרחב השמות 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 שלם (על כל המאפיינים ברכיב מניפסט נתון ועל כל התגים הצאצאים שלו), משתמשים במאפיינים הבאים:

tools:node="merge"
מיזוג כל המאפיינים בתג הזה וכל הרכיבים המקוננים כשאין התנגשויות, באמצעות היוריסטיקה של התנגשויות במיזוג. זוהי פעולת ברירת המחדל של רכיבים.

מניפסט בעדיפות נמוכה:

<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>

מניפסט בעדיפות גבוהה:

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

תוצאת המניפסט שעבר מיזוג:

<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="mergeOnlyAttributes"
מיזוג מאפיינים בתג הזה בלבד; אין למזג רכיבים בתצוגת עץ.

מניפסט בעדיפות נמוכה:

<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>

מניפסט בעדיפות גבוהה:

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

תוצאת המניפסט שעבר מיזוג:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
</activity>
tools:node="remove"
צריך להסיר את הרכיב הזה מהמניפסט שעבר מיזוג. משתמשים במאפיין הזה כשמגלים במניפסט שעבר מיזוג רכיב שלא צריך, שסופק על ידי קובץ מניפסט בעדיפות נמוכה יותר שלא נמצא בשליטתכם (כמו ספרייה מיובאת).

מניפסט בעדיפות נמוכה:

<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>

מניפסט בעדיפות גבוהה:

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

תוצאת המניפסט שעבר מיזוג:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>
tools:node="removeAll"
דומה ל-tools:node="remove", אבל מסיר את כל הרכיבים שתואמים לסוג הרכיב הזה (בתוך אותו רכיב הורה).

מניפסט בעדיפות נמוכה:

<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>

מניפסט בעדיפות גבוהה:

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

תוצאת המניפסט שעבר מיזוג:

<activity-alias android:name="com.example.alias">
</activity-alias>
tools:node="replace"
להחליף לגמרי את הרכיב בעל העדיפות הנמוכה יותר. כלומר, אם יש רכיב תואם במניפסט בעדיפות נמוכה יותר, המערכת מתעלמת ממנו ומשתמשת ברכיב הזה בדיוק כפי שהוא מופיע במניפסט הזה.

מניפסט בעדיפות נמוכה:

<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>

מניפסט בעדיפות גבוהה:

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

תוצאת המניפסט שעבר מיזוג:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>
tools:node="strict"
יצירת כשל ב-build בכל פעם שהרכיב הזה במניפסט בעדיפות הנמוכה יותר לא תואם בדיוק לרכיב במניפסט בעדיפות הגבוהה יותר (אלא אם הבעיה נפתרה על ידי סמנים אחרים של כללי מיזוג). הפעולה הזו מבטלת את ההיוריסטיקה של התנגשויות המיזוג. לדוגמה, אם המניפסט בעדיפות נמוכה יותר כולל מאפיין נוסף, ה-build נכשל (בעוד שפעולת ברירת המחדל מוסיפה את המאפיין הנוסף למניפסט שעבר מיזוג).

מניפסט בעדיפות נמוכה:

<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>

מניפסט בעדיפות גבוהה:

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

זה גורם לשגיאה במיזוג המניפסט. שני רכיבי המניפסט חייבים להיות זהים לחלוטין במצב קפדני. כדי לפתור את ההבדלים האלה, צריך להחיל סמנים אחרים של כללי מיזוג. (בלי tools:node="strict", שני הקבצים האלה יכולים להתמזג בלי שגיאות, כמו שמוצג בדוגמה של tools:node="merge").

סמני מאפיינים

כדי להחיל כלל מיזוג רק על מאפיינים ספציפיים בתג מניפסט, משתמשים במאפיינים הבאים. כל מאפיין מקבל שם מאפיין אחד או יותר (כולל מרחב השמות של המאפיין), מופרדים בפסיקים.

tools:remove="attr, ..."
צריך להסיר את המאפיינים שצוינו מהמניפסט שעבר מיזוג. משתמשים בו כשקובץ המניפסט בעדיפות נמוכה יותר כולל את המאפיינים האלה, ואתם רוצים לוודא שהם לא ייכנסו למניפסט שעבר מיזוג.

מניפסט בעדיפות נמוכה:

<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">
tools:replace="attr, ..."
החלפת המאפיינים שצוינו במניפסט בעל העדיפות הנמוכה יותר במאפיינים מהמניפסט הזה. במילים אחרות, תמיד צריך לשמור את הערכים של המניפסט בעל העדיפות הגבוהה יותר.

מניפסט בעדיפות נמוכה:

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

מניפסט בעדיפות גבוהה:

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

תוצאת המניפסט שעבר מיזוג:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
tools:strict="attr, ..."
יצירת כשל ב-build בכל פעם שהמאפיינים האלה במניפסט בעדיפות נמוכה יותר לא תואמים בדיוק למאפיינים במניפסט בעדיפות גבוהה יותר. זו פעולת ברירת המחדל לכל המאפיינים, חוץ מאלה עם פעולות מיוחדות, כמו שמתואר בהיוריסטיקה של התנגשויות במיזוג.

מניפסט בעדיפות נמוכה:

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

מניפסט בעדיפות גבוהה:

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

זה גורם לשגיאה במיזוג המניפסט. כדי לפתור את ההתנגשות, צריך להחיל סמנים אחרים של כללי מיזוג. זוהי התנהגות ברירת המחדל, כך שאותה תוצאה מתקבלת גם אם מוסיפים באופן מפורש את tools:strict="screenOrientation".

אפשר גם להחיל כמה סמנים על רכיב אחד, כמו בדוגמה הבאה:

מניפסט בעדיפות נמוכה:

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

מניפסט בעדיפות גבוהה:

<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">

תוצאת המניפסט שעבר מיזוג:

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

בורר הסמנים

אם רוצים להחיל את סמני כללי המיזוג רק על ספרייה מיובאת ספציפית, מוסיפים את המאפיין tools:selector עם שם החבילה של הספרייה.

לדוגמה, במניפסט הבא, כלל המיזוג remove חל רק כשקובץ המניפסט בעדיפות הנמוכה יותר הוא מהספרייה com.example.lib1:

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

אם המניפסט בעדיפות הנמוכה יותר הוא ממקור אחר, המערכת מתעלמת מכלל המיזוג remove.

שינוי של <uses-sdk> בספריות מיובאות

כברירת מחדל, כשמייבאים ספרייה עם ערך minSdk שגבוה יותר מקובץ המניפסט הראשי, מתרחשת שגיאה ואי אפשר לייבא את הספרייה.

כדי שכלי המיזוג יתעלם מההתנגשות הזו וייבא את הספרייה תוך שמירה על הערך הנמוך יותר של minSdk באפליקציה, צריך להוסיף את המאפיין overrideLibrary לתג <uses-sdk>. ערך המאפיין יכול להיות שם אחד או יותר של חבילת ספרייה (מופרדים בפסיקים), שמציין את הספריות שיכולות לשנות את ה-minSdk של המניפסט הראשי.

לדוגמה, אם המניפסט הראשי של האפליקציה מחיל את 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"/>
...

אחרי זה, אפשר למזג את המניפסט הבא בלי שגיאה לגבי התג <uses-sdk>, והמניפסט שעבר מיזוג ישמור את minSdk="2" מקובץ המניפסט של האפליקציה.

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

הרשאות מערכת משתמעות

בגרסאות האחרונות של Android, חלק מממשקי ה-API של Android שהיו נגישים לאפליקציות באופן חופשי, הוגבלו על ידי הרשאות מערכת.

כדי למנוע שיבושים באפליקציות שצריכות גישה לממשקי ה-API האלה, הגרסאות האחרונות של Android מאפשרות לאפליקציות להמשיך לגשת לממשקי ה-API האלה בלי ההרשאה, אם הערך של targetSdkVersion נמוך מהגרסה שבה נוספה ההגבלה. ההתנהגות הזו מעניקה לאפליקציה הרשאה משתמעת לאפשר גישה לממשקי ה-API. יכול להיות שהמניפסטים שעברו מיזוג עם ערכים שונים של targetSdkVersion יושפעו.

אם בקובץ המניפסט בעל העדיפות הנמוכה יותר יש ערך נמוך יותר של targetSdkVersion שמספק לו הרשאה משתמעת, ובמניפסט בעל העדיפות הגבוהה יותר אין את אותה הרשאה משתמעת (כי הערך של targetSdkVersion שלו שווה לגרסה שבה נוספה ההגבלה או גבוה ממנה), כלי המיזוג מוסיף באופן מפורש את הרשאת המערכת למניפסט שעבר מיזוג.

לדוגמה, אם באפליקציה שלכם מוגדר targetSdkVersion ל-4 ומעלה, ואתם מייבאים ספרייה שבה מוגדר targetSdkVersion ל-3 ומטה, כלי המיזוג מוסיף את ההרשאה WRITE_EXTERNAL_STORAGE למניפסט שעבר מיזוג.

בטבלה 2 מפורטות כל ההרשאות האפשריות שאפשר להוסיף למניפסט שעבר מיזוג:

טבלה 2. רשימת ההרשאות שכלי המיזוג עשוי להוסיף למניפסט שעבר מיזוג

הצהרות במניפסט בעדיפות נמוכה יותר הרשאות שנוספו למניפסט שעבר מיזוג
‫targetSdkVersion הוא 3 או פחות WRITE_EXTERNAL_STORAGE, READ_PHONE_STATE
‫targetSdkVersion הוא 15 או פחות ומשתמש ב-READ_CONTACTS READ_CALL_LOG
‫targetSdkVersion הוא 15 או פחות ומשתמש ב-WRITE_CONTACTS WRITE_CALL_LOG

בודקים את המניפסט שעבר מיזוג ומחפשים התנגשויות

עוד לפני שאתם יוצרים את האפליקציה, אתם יכולים לראות תצוגה מקדימה של המניפסט שעבר מיזוג. כדי לראות תצוגה מקדימה, מבצעים את הפעולות הבאות:

  1. ב-Android Studio, פותחים את הקובץ AndroidManifest.xml.
  2. לוחצים על הכרטיסייה Merged Manifest (מניפסט שעבר מיזוג) בתחתית כלי העריכה.

בתצוגה Merged Manifest, התוצאות של המניפסט שעבר מיזוג מופיעות מימין, ומידע על כל קובץ מניפסט שעבר מיזוג מופיע משמאל, כמו שמוצג באיור 2.

הרכיבים שמוזגו מקובצי מניפסט בעדיפות נמוכה יותר מודגשים בצבעים שונים בצד ימין. המקרא של כל צבע מפורט בקטע Manifest Sources.

התצוגה Merged Manifest (מניפסט שעבר מיזוג)
איור 2. התצוגה Merged Manifest (מניפסט שעבר מיזוג).

קובצי מניפסט שהיו חלק מה-build אבל לא תרמו רכיבים או מאפיינים מופיעים בקטע קובצי מניפסט אחרים.

כדי לראות מידע על המקור של רכיב מסוים, לוחצים עליו בחלונית הימנית והפרטים מופיעים בקטע Merging Log.

אם יש התנגשויות, הן מופיעות בקטע Merging Errors עם המלצה איך לפתור את ההתנגשות באמצעות סמנים של כללי מיזוג.

השגיאות מודפסות גם בחלון Event Log (יומן אירועים). כדי לראות אותן, בוחרים באפשרות View > חלון של הכלי > יומן אירועים.

כדי לראות יומן מלא של עץ ההחלטות של המיזוג, אפשר למצוא את קובץ היומן בספרייה build/outputs/logs/ של המודול, בשם manifest-merger-buildVariant-report.txt.

מיזוג כללי מדיניות

כלי המיזוג של המניפסט יכול להתאים באופן לוגי כל רכיב XML מקובץ מניפסט אחד לרכיב תואם בקובץ אחר. המיזוג מתאים כל רכיב באמצעות מפתח התאמה, ערך מאפיין ייחודי (כמו android:name) או הייחודיות הטבעית של התג עצמו (לדוגמה, יכול להיות רק רכיב <supports-screen> אחד).

אם לשני קובצי מניפסט יש את אותו רכיב XML, הכלי ממזג את שני הרכיבים יחד באמצעות אחת משלוש כללי מדיניות המיזוג:

מזג
משלבים את כל המאפיינים שלא מתנגשים באותו תג וממזגים רכיבי צאצא בהתאם למדיניות המיזוג שלהם. אם יש מאפיינים שסותרים אחד את השני, ממזגים אותם באמצעות סמני כללי המיזוג.
מיזוג של הצאצאים בלבד
לא לשלב או למזג את המאפיינים (לשמור רק את המאפיינים שסופקו על ידי קובץ המניפסט בעדיפות הגבוהה ביותר) ולמזג רכיבי צאצא בהתאם למדיניות המיזוג שלהם.
Keep
משאירים את הרכיב כמו שהוא ומוסיפים אותו לרכיב ההורה המשותף בקובץ הממוזג. האפשרות הזו משמשת רק כשמותר שיהיו כמה הצהרות של אותו רכיב.

בטבלה 3 מפורטים כל סוגי הרכיבים, סוג מדיניות המיזוג שבה נעשה שימוש והמפתח שמשמש לקביעת התאמה של רכיב בין שני מניפסטים:

טבלה 3. כללי מדיניות למיזוג רכיבי מניפסט ומפתחות התאמה

רכיב מדיניות המיזוג מפתח התאמה
<action> מזג מאפיין android:name
<activity> מזג מאפיין android:name
<application> מזג יש רק אחד לכל <manifest>.
<category> מזג מאפיין android:name
<data> מזג יש רק אחד לכל <intent-filter>.
<grant-uri-permission> מזג יש רק אחד לכל <provider>.
<instrumentation> מזג מאפיין android:name
<intent-filter> Keep אין התאמה; מותרות כמה הצהרות בתוך רכיב ההורה.
<manifest> מיזוג של הצאצאים בלבד יש רק אחד כזה בכל קובץ.
<meta-data> מזג מאפיין android:name
<path-permission> מזג יש רק אחד לכל <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> מזג יש רק אחד לכל <manifest>.
<uses-configuration> מזג יש רק אחד לכל <manifest>.
<uses-feature> מזג המאפיין android:name (אם הוא לא קיים, אז המאפיין android:glEsVersion)
<uses-library> מזג מאפיין android:name
<uses-permission> מזג מאפיין android:name
<uses-sdk> מזג יש רק אחד לכל <manifest>.
רכיבים בהתאמה אישית מזג אין התאמה. הרכיבים האלה לא מוכרים לכלי המיזוג והם תמיד נכללים במניפסט שעבר מיזוג.

הזרקת משתני build למניפסט

אם אתם צריכים להוסיף לקובץ AndroidManifest.xml משתנים שמוגדרים בקובץ build.gradle, אתם יכולים לעשות את זה באמצעות המאפיין manifestPlaceholders. המאפיין הזה מקבל מפה של צמדי מפתח/ערך, כמו בדוגמה הבאה:

מגניב

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

Kotlin

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

אחר כך אפשר להוסיף את אחד מה-placeholders לקובץ המניפסט כערך מאפיין:

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

כברירת מחדל, כלי ה-build מספקים גם את מזהה האפליקציה בפלייסהולדר ${applicationId}. הערך תמיד תואם למזהה האפליקציה הסופי של ה-build הנוכחי, כולל שינויים שבוצעו על ידי וריאנטים של build. האפשרות הזו שימושית כשרוצים להשתמש במרחב שמות ייחודי למזהים, כמו פעולת Intent, אפילו בין וריאנטים של build.

לדוגמה, אם קובץ ה-build.gradle נראה כך:

מגניב

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"
        }
    }
}

לאחר מכן, אפשר להוסיף את מזהה האפליקציה למניפסט באופן הבא:

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

והתוצאה במניפסט כשיוצרים את גרסת המוצר "free" היא:

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

מידע נוסף זמין במאמר הגדרת מזהה האפליקציה.