שכבת-על של משאבים בסביבת זמן ריצה (RRO) היא חבילה שמשנה את ערכי המשאבים של חבילת יעד בסביבת זמן ריצה. לדוגמה, אפליקציה שמותקנת בקובץ האימג' של המערכת עשויה לשנות את ההתנהגות שלה על סמך הערך של משאב. במקום להטמיע את ערך המשאב בזמן ה-build, קובץ RRO שמותקן במחיצה אחרת יכול לשנות את הערכים של משאבי האפליקציה בזמן הריצה.
אפשר להפעיל או להשבית את ה-RRO. אפשר להגדיר באופן פרוגרמטי את המצב מופעל/מושבת כדי להחליף את היכולת של RRO לשנות את ערכי המשאבים. קובצי RRO מושבתים כברירת מחדל (עם זאת, קובצי RRO סטטיים מופעלים כברירת מחדל).
משאבי שכבת-על
שכבות-על פועלות על ידי מיפוי משאבים שמוגדרים בחבילת שכבת-העל למשאבים שמוגדרים בחבילת היעד. כשאפליקציה מנסה לפתור את הערך של משאב בחבילת היעד, במקום זאת מוחזר הערך של משאב שכבת-העל שאליו משאב היעד ממופה.
הגדרת המניפסט
חבילה נחשבת לחבילת 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 של Soong לשכבות-על, שמנע מ-Android Asset Packaging Tool 2 (AAPT2) לנסות למחוק כפילויות של הגדרות של משאבים עם אותו ערך (--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
.
הפעלה/השבתה של שכבות-על
אפשר להפעיל או להשבית שכבות-על באופן ידני וגם באופן פרוגרמטי.
השבתה או הפעלה ידנית של שכבות-על
כדי להפעיל ולבדוק באופן ידני RRO, מריצים את הפקודה:
adb shell cmd overlay enable --user current com.example.carrro
adb shell cmd overlay list --user current | grep -i com.example com.example.carrro
הפעולה הזו מפעילה את ה-RRO למשתמש המערכת (userId = 0
) שבבעלותו SystemUI.
ההוראה הזו לא משפיעה על אפליקציות שהמשתמש בחזית הפעיל (userId = 10
). כדי להפעיל את RRO למשתמש בחזית, משתמשים בפרמטר -–user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
הפעלה או השבתה של שכבות-על באופן פרוגרמטי
משתמשים ב-OverlayManager
API כדי להפעיל ולהשבית שכבות-על שניתן לשנות (אחזור ממשק ה-API באמצעות Context#getSystemService(Context.OVERLAY_SERVICE)
). אפשר להפעיל שכבת-על רק באמצעות החבילה שהיא מטרגטת או באמצעות חבילת עם ההרשאה android.permission.CHANGE_OVERLAY_PACKAGES
. כששכבת-על מופעלת או מושבתת, אירועי שינוי בתצורה מועברים לחבילת היעד והפעילויות של היעד מופעלות מחדש.
הגבלת משאבים שאפשר להוסיף שכבה עליהם
ב-Android 10 ואילך, תג ה-XML <overlayable>
חושף קבוצה של משאבים ש-RROs יכולים להציג בשכבה עליונה. בקובץ 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">
.אסור לכלול שני בלוקים של
<overlayable name="foo">
ב-APK יחיד.
הקוד הבא מציג דוגמה לשכבת-על בקובץ 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
. כל שכבת-על במחיצה של יצרן הציוד המקורי יכולה לשנות את המשאבים.odm
. כל שכבת-על במחיצה של ODM יכולה לשנות את המשאבים.signature
. כל שכבת-על חתומה באותה חתימה כמו חבילת ה-APK היעד יכולה לשנות את המשאבים.actor
. כל שכבת-על חתומה באותה חתימה כמו חבילת ה-APK של הגורם יכולה לשנות את המשאבים. השחקן מוגדר בתג named-actor בקובץ system.config.config_signature
. כל שכבת-על חתומה באותה חתימה כמו קובץ ה-APK של overlay-config יכולה לשנות את המשאבים. ההגדרה של 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
) כדי להגדיר RROs סטטיים.
שימוש ב-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 ואילך אין אפשרות להשתמש בשכבות-על סטטיות כדי להשפיע על הערכים של המשאבים שנקראו במהלך התקנת החבילה. בתרחיש לדוגמה הנפוץ של שימוש בשכבות-על סטטיות כדי לשנות את הערך של משתני בוליאני שמגדירים את מצב ההפעלה של רכיבים, צריך להשתמש בתג <component-override>
SystemConfig
(חדש ב-Android 11).
שכבות-על של ניפוי באגים
כדי להפעיל, להשבית ולשמור ידנית שכבות-על, משתמשים בפקודה הבאה של מעטפת מנהל שכבות-העל.
adb shell cmd overlay
שימוש ב-enable
בלי לציין משתמש משפיע על המשתמש הנוכחי, כלומר משתמש המערכת (userId = 0
), שבבעלותו ממשק המשתמש של המערכת. הפעולה הזו לא משפיעה על המשתמש בחזית (userId = 10
), שבבעלותו האפליקציות. כדי להפעיל את RRO למשתמש בחזית, משתמשים בפרמטר –-user 10
:
adb shell cmd overlay enable --user 10 com.example.carrro
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