การซ้อนทับทรัพยากรรันไทม์ (RRO) คือแพ็คเกจที่เปลี่ยนค่าทรัพยากรของแพ็คเกจเป้าหมายขณะรันไทม์ ตัวอย่างเช่น แอปที่ติดตั้งบนอิมเมจระบบอาจเปลี่ยนลักษณะการทำงานตามมูลค่าของทรัพยากร แทนที่จะฮาร์ดโค้ดค่าทรัพยากร ณ เวลาที่สร้าง 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
> ในไฟล์ Manifest จะต้องตั้งค่าเป็น 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 หรือสูงกว่า แต่ละโอเวอร์เลย์จะมีพื้นที่ ID ทรัพยากรที่สงวนไว้ของตัวเอง ซึ่งไม่ทับซ้อนกับพื้นที่ ID ทรัพยากรเป้าหมายหรือช่องว่าง ID ทรัพยากรที่ซ้อนทับอื่นๆ ดังนั้นการซ้อนทับที่อ้างอิงถึงทรัพยากรของตนเองจึงทำงานได้ตามที่คาดไว้
ใน Android 10 หรือต่ำกว่า แพ็คเกจซ้อนทับและเป้าหมายใช้พื้นที่ ID ทรัพยากรเดียวกัน ซึ่งอาจทำให้เกิดการชนกันและพฤติกรรมที่ไม่คาดคิดเมื่อแพ็คเกจพยายามอ้างอิงทรัพยากรของตนเองโดยใช้ไวยากรณ์
@type/name
การเปิด/ปิดการวางซ้อน
ใช้ 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 ของนักแสดง สามารถแทนที่ทรัพยากรได้ นักแสดงได้รับการประกาศในแท็ก ชื่อนักแสดง ในการกำหนดค่าระบบ -
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 หรือสูงกว่าจะลบความสามารถในการใช้การวางซ้อนแบบคงที่เพื่อส่งผลต่อค่าของทรัพยากรที่อ่านระหว่างการติดตั้งแพ็คเกจ สำหรับกรณีการใช้งานทั่วไปของการใช้การวางซ้อนแบบคงที่เพื่อเปลี่ยนค่าบูลีนที่กำหนดค่าสถานะเปิดใช้งานส่วนประกอบ ให้ใช้แท็ก SystemConfig
<component-override>
(ใหม่ใน Android 11)
การดีบักการซ้อนทับ
หากต้องการเปิดใช้งาน ปิดใช้งาน และดัมพ์โอเวอร์เลย์ด้วยตนเอง ให้ใช้คำสั่งเชลล์ตัวจัดการโอเวอร์เลย์ต่อไปนี้
adb shell cmd overlay
OverlayManagerService
ใช้ idmap2
เพื่อจับคู่รหัสทรัพยากรในแพ็คเกจเป้าหมายกับรหัสทรัพยากรในแพ็คเกจซ้อนทับ การแมป ID ที่สร้างขึ้นจะถูกเก็บไว้ใน /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