שינוי הערך של משאבי האפליקציה בזמן הריצה

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

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

משאבים בשכבת-על

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

הגדרת המניפסט

חבילה נחשבת לחבילת RRO אם היא מכילה תג <overlay> בתור צאצא של התג <manifest>.

  • הערך של מאפיין החובה android:targetPackage מציין את השם של החבילה שה-RRO מתכוון ליצור שכבת-על.

  • הערך של המאפיין האופציונלי android:targetName מציין את השם של את קבוצת המשאבים הניתנת לשכבת-על של חבילת היעד שה-RRO מתכוון בשכבת-על. אם היעד לא מגדיר קבוצת משאבים שניתן שכבת-על, לא יכול להיות קיים.

הקוד הבא מציג שכבת-על לדוגמה AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.overlay">
    <application android:hasCode="false" />
    <overlay android:targetPackage="com.example.target"
                   android:targetName="OverlayableResources"/>
</manifest>

שכבות-על לא יכולות להוסיף קוד כשכבת-על, ולכן הן לא יכולות לכלול קובצי DEX. בנוסף, מאפיין android:hasCode של <application> במניפסט צריך להיות מוגדר ל-false.

הגדרה של מפת המשאבים

ב-Android מגרסה 11 ואילך, המנגנון המומלץ עבור ההגדרה של מפת המשאבים בשכבת-על היא ליצור קובץ בres/xml של חבילת שכבת-העל, מספורים את משאבי היעד שאמורים להיות כשכבת-על ואת הערכים החלופיים שלהם, ואז להגדיר את הערך מאפיין android:resourcesMap של תג המניפסט <overlay> לקובץ עזר לקובץ מיפוי המשאבים.

הקוד הבא מציג קובץ res/xml/overlays.xml לדוגמה.

<?xml version="1.0" encoding="utf-8"?>
<overlay xmlns:android="http://schemas.android.com/apk/res/android" >
    <!-- Overlays string/config1 and string/config2 with the same resource. -->
    <item target="string/config1" value="@string/overlay1" />
    <item target="string/config2" value="@string/overlay1" />

    <!-- Overlays string/config3 with the string "yes". -->
    <item target="string/config3" value="@android:string/yes" />

    <!-- Overlays string/config4 with the string "Hardcoded string". -->
    <item target="string/config4" value="Hardcoded string" />

    <!-- Overlays integer/config5 with the integer "42". -->
    <item target="integer/config5" value="42" />
</overlay>

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

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.overlay">
    <application android:hasCode="false" />
    <overlay android:targetPackage="com.example.target"
                   android:targetName="OverlayableResources"
                   android:resourcesMap="@xml/overlays"/>
</manifest>

הרכבת החבילה

במכשירי Android בגרסה 11 ואילך יש תמיכה בכלל build של Sog שכבות-על שמונעות מהכלי 2 (AAPT2) לאריזת נכסים של Android לנסות הגדרות של ביטול כפילויות של משאבים עם אותו ערך (--no-resource-deduping) ומהסרת משאבים ללא ברירת מחדל הגדרות אישיות (--no-resource-removal). הקוד הבא מציג דוגמה קובץ Android.bp.

runtime_resource_overlay {
    name: "ExampleOverlay",
    sdk_version: "current",
}

טיפול במשאבים

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

לדוגמה, אם שכבת-על מגדירה ערך להגדרה drawable-en והיעד מגדיר את הערך של drawable-en-port, drawable-en-port יש התאמה טובה יותר, כך שהערך של הגדרת היעד drawable-en-port נבחר בזמן הריצה. כדי ליצור שכבת-על לכל drawable-en התצורות, שכבת-העל חייבים להגדיר ערך לכל הגדרת drawable-en שהיעד מגדיר.

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

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

  • ב-Android מגרסה 10 ומטה, שכבות-על וחבילות יעד חולקות את אותו משאב מרחב מזהה, שעלולות לגרום להתנגשויות ולהתנהגות לא צפויה כשהם ינסו להפנות למשאבים שלהם באמצעות התחביר @type/name.

הפעלה/השבתה של שכבות-על

שימוש ב-API של OverlayManager כדי להפעיל ולהשבית שכבות-על שניתנות לשינוי (אחזור ממשק ה-API באמצעות Context#getSystemService(Context.OVERLAY_SERVICE)). שכבת-על יכולה להיות מופעלת רק על ידי החבילה שאליה היא מטרגטת או על ידי חבילה עם הרשאת android.permission.CHANGE_OVERLAY_PACKAGES. כששכבת-על היא מופעלת או מושבתת, אירועי שינוי של הגדרות אישיות יועברו לחבילת היעד להפעיל מחדש את פעילויות היעד.

הגבלת משאבים שניתנים לשכבת-על

ב-Android מגרסה 10 ואילך, תג ה-XML מסוג <overlayable> חושף קבוצת משאבים ש-RRO יכולים ליצור שכבת-על. בדוגמה הבאה קובץ res/values/overlayable.xml, string/foo ו-integer/bar הם משאבים משמש לסיווג המכשיר. ליצירת שכבות-על חייב להתמקד במפורש באוסף משאבים שניתן לשכבת-על לפי שם.

<!-- The collection of resources for theming the appearance of the device -->
<overlayable name="ThemeResources">
       <policy type="public">
               <item type="string" name="foo/" />
               <item type="integer" name="bar/" />
       </policy>
       ...
</overlayable>

ל-APK אפשר להגדיר כמה תגי <overlayable>, אבל לכל תג צריך להיות בתוך החבילה. לדוגמה:

  • אוקיי, שתי חבילות שונות מגדירות את <overlayable name="foo">.

  • לא מתאים ל-APK יחיד לכלול שתי חסימות של <overlayable name="foo">.

הקוד הבא מציג דוגמה לשכבת-על בקובץ AndroidManifest.xml חדש.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
       package="com.my.theme.overlay">
       <application android:hasCode="false" />
       <!-- This overlay will override the ThemeResources resources -->
       <overlay android:targetPackage="android" android:targetName="ThemeResources">
</manifest>

כשאפליקציה מגדירה תג <overlayable>, שכבות-על שמטרגטות את האפליקציה הזו:

  • יש לציין את targetName.

  • אפשר להגדיר שכבת-על רק למשאבים שרשומים בתג <overlayable>.

  • ניתן לטרגט רק שם אחד של <overlayable>.

לא ניתן להפעיל שכבת-על שמטרגטת חבילה שחושפת שכבת-על משאבים, אבל לא משתמש ב-android:targetName כדי לטרגט תג <overlayable>.

הגבלת המדיניות

שימוש בתג <policy> כדי לאכוף הגבלות על משאבים שניתן להוסיף שכבת-על. המאפיין type מציין אילו כללי מדיניות שכבת-על צריכה למלא כדי לשנות מברירת המחדל את המשאבים הכלולים. הסוגים הנתמכים כוללים את אלה.

  • public כל שכבת-על יכולה לעקוף את המשאב.
  • system כל שכבת-על במחיצת המערכת יכולה לעקוף את המשאבים.
  • vendor כל שכבת-על במחיצת הספק יכולה לבטל את המשאבים.
  • product כל שכבת-על במחיצת המוצרים יכולה לבטל את המשאבים.
  • oem כל שכבת-על במחיצת ה-OEM יכולה לעקוף את המשאבים.
  • odm כל שכבת-על במחיצת ה-odm יכולה לעקוף את המשאבים.
  • signature כל שכבת-על עם חתימה זהה לזו של APK היעד יכולה לשנות את המשאבים.
  • actor כל שכבת-על עם אותה חתימה כמו זו של ה-APK של השחקן יכולה לשנות את המשאבים. המשתמש מוצהר בתג named-actor במערכת הגדרה
  • config_signature כל שכבת-על שחתומה עם אותה חתימה כמו ה-APK overlay-config יכול לעקוף את המשאבים. הגדרת שכבת-העל היא הוצהרה בתג overlay-config-signature בהגדרות המערכת.

הקוד הבא מציג תג <policy> לדוגמה קובץ res/values/overlayable.xml.

<overlayable name="ThemeResources">
   <policy type="vendor" >
       <item type="string" name="foo" />
   </policy>
   <policy type="product|signature"  >
       <item type="string" name="bar" />
       <item type="string" name="baz" />
   </policy>
</overlayable>

כדי לציין כמה כללי מדיניות, צריך להשתמש בקווים אנכיים (|) בתור תווים מפרידים. אם מציינים כמה כללי מדיניות, שכבת-על צריכה למלא רק תנאי אחד כדי לשנות את המשאבים המפורטים בתג <policy>.

הגדרת שכבות-על

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

  • מכשירים עם Android מגרסה 11 ואילך יכולים להשתמש קובץ OverlayConfig (config.xml) במקום מאפייני המניפסט. שימוש ב קובץ שכבת-על הוא השיטה המומלצת ליצירת שכבות-על.

  • בכל המכשירים אפשר להשתמש במאפייני מניפסט (android:isStatic וגם android:priority) כדי להגדיר תקנות RRO סטטיות.

שימוש ב-OverlayConfig

ב-Android מגרסה 11 ואילך, אפשר להשתמש ב-OverlayConfig כדי להגדיר את יכולת השינוי, מצב ברירת המחדל והעדיפות של שכבות-על. כדי להגדיר שכבת-על, ליצור או לשנות את הקובץ שנמצא בכתובת partition/overlay/config/config.xml, כאשר partition היא המחיצה של שכבת-על להגדרה. כדי להגדיר שכבת-על, הספרייה overlay/ של המחיצה שבה מוגדרת שכבת-העל. הקוד הבא מציג דוגמה product/overlay/config/config.xml.

<config>
    <merge path="OEM-common-rros-config.xml" />
    <overlay package="com.oem.overlay.device" mutable="false" enabled="true" />
    <overlay package="com.oem.green.theme" enabled="true" />
</config>"

לתג <overlay> נדרש מאפיין package שמציין איזו שכבת-על החבילה נמצאת בתהליך הגדרה. המאפיין האופציונלי enabled קובע אם או לא, שכבת-העל מופעלת כברירת מחדל (ברירת המחדל היא false). הערכים האופציונליים המאפיין mutable קובע אם שכבת-העל ניתנת לשינוי ויכולה לכלול המצב המופעל שלו השתנה באופן פרוגרמטי בזמן הריצה (ברירת המחדל היא true). שכבות-על שלא מופיעות בקובץ תצורה ניתנות לשינוי ומושבתות על ידי כברירת מחדל.

קדימות של שכבת-על

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

  • system
  • vendor
  • odm
  • oem
  • product
  • system_ext

מיזוג קבצים

השימוש בתגי <merge> מאפשר למזג קובצי תצורה אחרים את המיקום שצוין בקובץ התצורה. מאפיין path של התג מייצג את נתיב הקובץ למיזוג ביחס לספרייה שמכילה קובצי תצורה של שכבות-על.

שימוש במאפייני מניפסט או ברכיבי RRO סטטיים

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

  • android:isStatic כשהערך של המאפיין הבוליאני הזה מוגדר ל-true, שכבת-העל מופעלת כברירת מחדל ואי אפשר לשנות אותה, ולכן שכבת-העל מהשבתה.

  • android:priority הערך של המאפיין המספרי הזה (שמשפיע רק על שכבות-על סטטיות) מגדיר את הקדימות של שכבת-העל כאשר שכבות-על מטרגטות אותו ערך של משאב. מספר גבוה יותר מצביע על ערך גבוה יותר בעדיפות גבוהה.

הקוד הבא מציג דוגמה ל-AndroidManifest.xml.

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.overlay">
    <application android:hasCode="false" />
    <overlay android:targetPackage="com.example.target"
                   android:isStatic="true"
                   android:priority="5"/>
</manifest>

שינויים ב-Android 11

ב-Android מגרסה 11 ואילך, אם קובץ תצורה ב-partition/overlay/config/config.xml, שכבות-על מוגדרות באמצעות לקובץ הזה ול-android:isStatic ול-android:priority אין השפעה על שכבות-על שנמצאות במחיצה. הגדרת קובץ תצורה של שכבת-על בכל אוכפת הקדימות של מחיצות שכבת-על.

כמו כן, מערכת Android מגרסה 11 ואילך מסירה את האפשרות כדי להשתמש בשכבות-על סטטיות כדי להשפיע על הערכים של המשאבים שנקראים במהלך החבילה בתהליך ההתקנה. בתרחיש לדוגמה נפוץ של שימוש בשכבות-על סטטיות כדי לשנות את בערך של בוליאני שמגדיר את המצב שמופעל של הרכיב, השתמש ב- תג SystemConfig אחד (<component-override>) (חדש ב-Android 11).

שכבות-על של ניפוי באגים

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

adb shell cmd overlay

ב-OverlayManagerService נעשה שימוש ב-idmap2 כדי למפות מזהי משאבים ביעד חבילה למזהי משאבים בחבילת שכבת-העל. מיפויי המזהים שנוצרו מאוחסנים בתיקייה /data/resource-cache/. אם שכבת-העל לא פועלת כראוי, מחפשים את קובץ idmap התואם לשכבת-העל שלך ב-/data/resource-cache/, ואז מריצים את הפקודה הבאה.

adb shell idmap2 dump --idmap-path [file]

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

[target res id] - > [overlay res id] [resource name]
0x01040151 -> 0x01050001 string/config_dozeComponent
0x01040152 -> 0x01050002 string/config_dozeDoubleTapSensorType
0x01040153 -> 0x01050003 string/config_dozeLongPressSensorType