חבילה של שכבת-על בזמן ריצה (RRO) היא חבילה שמשנה את ערכי המשאבים של חבילת יעד בזמן ריצה. לדוגמה, אפליקציה שמותקנת בתמונת המערכת עשויה לשנות את ההתנהגות שלה על סמך הערך של משאב. במקום להגדיר את ערך המשאב כקבוע בזמן הבנייה, אפשר להשתמש ב-RRO שמותקן במחיצה אחרת כדי לשנות את ערכי המשאבים של האפליקציה בזמן הריצה.
אפשר להפעיל או להשבית את ה-RRO. אפשר להגדיר באופן פרוגרמטי את מצב ההפעלה או ההשבתה כדי להחליף את היכולת של RRO לשנות ערכי משאבים. האפשרות RROs מושבתת כברירת מחדל (אבל 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 ואילך תומך בכלל בנייה של 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>
חושף קבוצה של משאבים שניתן להשתמש בהם ב-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 בקובץ 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
) כדי להגדיר 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 ואילך הוסרה האפשרות להשתמש בשכבות-על סטטיות כדי להשפיע על ערכי המשאבים שנקראים במהלך התקנת החבילה. במקרה השימוש הנפוץ של שימוש בשכבות-על סטטיות כדי לשנות את הערך של בוליאנים שמגדירים את המצב המופעל של רכיב, צריך להשתמש בתג <component-override>
SystemConfig
(חדש ב-Android 11).
שכבות-על של ניפוי באגים
כדי להפעיל, להשבית ולבצע dump של שכבות-על באופן ידני, משתמשים בפקודת ה-shell של מנהל שכבות-העל הבאה.
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