การซ้อนทับทรัพยากรรันไทม์ (RRO) คือแพ็กเกจที่เปลี่ยนค่าทรัพยากรของแพ็กเกจเป้าหมายในรันไทม์ ตัวอย่างเช่น แอปที่ติดตั้งในอิมเมจระบบอาจเปลี่ยนลักษณะการทำงานตามค่าของทรัพยากร แทนที่จะฮาร์ดโค้ดค่าทรัพยากรในเวลาบิลด์ RRO ที่ติดตั้งในพาร์ติชันอื่นจะเปลี่ยนค่าทรัพยากรของแอปในรันไทม์ได้
คุณเปิดหรือปิดใช้ RRO ได้ คุณสามารถตั้งค่าสถานะเปิด/ปิดใช้แบบเป็นโปรแกรมเพื่อสลับความสามารถของ RRO ในการเปลี่ยนค่าทรัพยากรได้ RROs จะปิดใช้อยู่โดยค่าเริ่มต้น (แต่ RRO แบบคงที่ จะเปิดใช้อยู่โดย ค่าเริ่มต้น)
ทรัพยากรการซ้อนทับ
การซ้อนทับทำงานโดยการจับคู่ทรัพยากรที่กำหนดไว้ในแพ็กเกจการซ้อนทับกับทรัพยากรที่กำหนดไว้ในแพ็กเกจเป้าหมาย เมื่อแอปพยายามแก้ปัญหาค่าทรัพยากรในแพ็กเกจเป้าหมาย ระบบจะแสดงค่าทรัพยากรการซ้อนทับที่จับคู่กับทรัพยากรเป้าหมายแทน
ตั้งค่าไฟล์ Manifest
ระบบจะถือว่าแพ็กเกจเป็นแพ็กเกจ 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> ในไฟล์ Manifest ต้อง
ตั้งค่าเป็น false
กำหนดการจับคู่ทรัพยากร
ใน Android 11 ขึ้นไป กลไกที่แนะนำสำหรับการ
กำหนดการจับคู่ทรัพยากรการซ้อนทับคือการสร้างไฟล์ในไดเรกทอรี res/xml
ของแพ็กเกจการซ้อนทับ แสดงรายการทรัพยากรเป้าหมายที่ควร
ซ้อนทับและค่าการแทนที่ จากนั้นตั้งค่าแอตทริบิวต์
android:resourcesMap ของแท็ก <overlay> ในไฟล์ Manifest เป็นการอ้างอิง
ไฟล์การจับคู่ทรัพยากร
โค้ดต่อไปนี้แสดงตัวอย่างไฟล์ 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 ของการซ้อนทับ
<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> ได้หลายรายการ แต่แต่ละแท็กต้องมีชื่อที่ไม่ซ้ำกัน
ภายในแพ็กเกจ ตัวอย่างเช่น
แพ็กเกจ 2 รายการที่แตกต่างกันกำหนด
<overlayable name="foo">ได้APK รายการเดียวมีบล็อก
<overlayable name="foo">2 บล็อกไม่ได้
โค้ดต่อไปนี้แสดงตัวอย่างการซ้อนทับในไฟล์ 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 จะประกาศในแท็ก 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) แทนแอตทริบิวต์ไฟล์ Manifest ได้ การใช้ไฟล์การซ้อนทับเป็นวิธีที่แนะนำสำหรับการซ้อนทับอุปกรณ์ทั้งหมดสามารถใช้แอตทริบิวต์ไฟล์ Manifest (
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) การซ้อนทับที่ไม่ได้แสดงในไฟล์การกำหนดค่าจะเปลี่ยนแปลงได้และปิดใช้อยู่โดยค่าเริ่มต้น
ลำดับความสำคัญของการซ้อนทับ
เมื่อการซ้อนทับหลายรายการลบล้างทรัพยากรเดียวกัน ลำดับของการซ้อนทับจึงมีความสำคัญ การซ้อนทับจะมีลำดับความสำคัญสูงกว่าการซ้อนทับที่มีการกำหนดค่าก่อนการกำหนดค่าของตัวเอง ลำดับความสำคัญของการซ้อนทับในพาร์ติชันต่างๆ (จากลำดับความสำคัญน้อยที่สุดไปมากที่สุด) มีดังนี้
systemvendorodmoemproductsystem_ext
ผสานไฟล์
การใช้แท็ก <merge> จะช่วยให้ผสานไฟล์การกำหนดค่าอื่นๆ เข้ากับไฟล์การกำหนดค่าในตำแหน่งที่
ระบุได้ แอตทริบิวต์ path ของแท็กจะแสดงเส้นทางของไฟล์ที่จะผสานเทียบกับไดเรกทอรีที่มีไฟล์การกำหนดค่าการซ้อนทับ
ใช้แอตทริบิวต์ไฟล์ Manifest/RRO แบบคงที่
ใน Android 10 ลงไป คุณจะกำหนดค่าการเปลี่ยนแปลงไม่ได้และลำดับความสำคัญของการซ้อนทับได้โดยใช้แอตทริบิวต์ไฟล์ Manifest ต่อไปนี้
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)
แก้ปัญหาการซ้อนทับ
หากต้องการเปิด ปิด และดัมพ์การซ้อนทับด้วยตนเอง ให้ใช้คำสั่งเชลล์ของ Overlay Manager ต่อไปนี้
adb shell cmd overlayการใช้ enable โดยไม่ระบุผู้ใช้จะส่งผลต่อผู้ใช้ปัจจุบัน นั่นคือผู้ใช้ระบบ (userId = 0) ที่เป็นเจ้าของ UI ของระบบ การดำเนินการนี้จะไม่ส่งผลต่อผู้ใช้เบื้องหน้า (userId = 10) ที่เป็นเจ้าของแอป หากต้องการเปิดใช้ RRO สำหรับผู้ใช้เบื้องหน้า ให้ใช้พารามิเตอร์ –-user 10
adb shell cmd overlay enable --user 10 com.example.carrroOverlayManagerService ใช้ 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