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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

כל הסמנים שייכים למרחב השמות של Android tools, לכן צריך להצהיר עליו קודם מרחב השמות הזה ברכיב <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" />
...

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

חלק מממשקי ה-API של Android, שפעם היו נגישים בצורה חופשית, הפכו מוגבל על ידי הרשאות המערכת ב- הגרסאות האחרונות של 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. לוחצים על הכרטיסייה מניפסט ממוזג בתחתית העורך.

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

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

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

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

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

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

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

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

ותוצאת המניפסט כאשר טעם המוצר הוא:

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

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