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

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

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

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

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

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

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

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

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

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

  1. קובץ מניפסט של גרסת build

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

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

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

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

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

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

חשוב: הגדרות ה-build מהקובץ build.gradle מבטלות את כל המאפיינים התואמים בקובץ המניפסט הממוזג. לדוגמה, הערך של minSdk בקובץ build.gradle או בקובץ build.gradle.kts מבטל את הערך של המאפיין התואם ברכיב המניפסט <uses-sdk>. כדי למנוע בלבול, מומלץ להשמיט את הרכיב <uses-sdk> ולהגדיר את המאפיינים האלה רק בקובץ build.gradle. פרטים נוספים זמינים במאמר הגדרת ה-build.

שיטות ניתוח להיוריסטיקה של מיזוג קונפליקטים

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

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

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

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

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

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

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

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

אל תסתמכו על ערכי ברירת המחדל של המאפיינים. מכיוון שכל המאפיינים הייחודיים משולבים באותו רכיב, הדבר עלול לגרום לתוצאות בלתי צפויות אם המניפסט בעדיפות גבוהה יותר תלוי בפועל בערך ברירת המחדל של מאפיין מסוים בלי להצהיר עליו. לדוגמה, אם המניפסט עם העדיפות הגבוהה יותר לא מצהיר על המאפיין android:launchMode, נעשה שימוש בערך ברירת המחדל "standard". לעומת זאת, אם המניפסט עם העדיפות הנמוכה יותר מצהיר על המאפיין הזה עם ערך שונה, הערך הזה יחול על המניפסט הממוזג ויבטל את ערך ברירת המחדל. צריך להגדיר בבירור את כל המאפיינים כפי שרוצים שהם יהיו. ערכי ברירת המחדל של כל מאפיין מתועדים בחומר העזר של המניפסט.

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

סימן של כלל מיזוג הוא מאפיין 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="merge-only-attributes"
ממזגים מאפיינים בתג הזה בלבד, ולא ממזגים אלמנטים בתצוגת עץ.

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

<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="merge-only-attributes">
</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. פותחים את הקובץ AndroidManifest.xml ב-Android Studio.
  2. לוחצים על הכרטיסייה Merged Manifest (מאניפסט משולב) בתחתית הכלי.

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

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

איור 2. תצוגת המניפסט הממוזג.

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

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

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

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

כדי לראות יומן מלא של עץ ההחלטות למיזוג, תוכלו למצוא את קובץ היומן בתיקייה 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. המאפיין הזה מקבל מפה של צמדי מפתח/ערך, כפי שמוצג כאן:

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

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

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

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

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

GroovyKotlin
android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    flavorDimensions "type"
    productFlavors {
        free {
            applicationIdSuffix ".free"
            dimension "type"
        }
        pro {
            applicationIdSuffix ".pro"
            dimension "type"
        }
    }
}
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>

התוצאה של המניפסט כשמפתחים את גרסת המוצר 'חינם' היא:

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

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