Mengubah nilai resource aplikasi saat runtime

Overlay resource runtime (RRO) adalah paket yang mengubah nilai resource paket target pada saat runtime. Misalnya, aplikasi yang diinstal di sistem gambar dapat mengubah perilakunya berdasarkan nilai resource. Bukan melakukan hardcode nilai resource pada waktu build, RRO yang diinstal pada dapat mengubah nilai resource aplikasi saat runtime.

RRO dapat diaktifkan atau dinonaktifkan. Anda dapat menetapkan secara terprogram aktifkan/nonaktifkan status untuk mengubah kemampuan RRO dalam mengubah nilai resource. RRO dinonaktifkan secara default (tetapi, RRO statis diaktifkan oleh default).

Resource overlay

Overlay berfungsi dengan memetakan sumber daya yang ditetapkan dalam paket overlay ke sumber daya yang ditentukan dalam paket target. Saat aplikasi mencoba me-resolve nilai resource dalam paket target, nilai resource overlay target dipetakan ke resource yang akan ditampilkan.

Menyiapkan manifes

Paket dianggap sebagai paket RRO jika berisi tag <overlay> sebagai turunan tag <manifest>.

  • Nilai atribut android:targetPackage yang diperlukan menentukan nama dari paket yang ingin dilapiskan oleh RRO.

  • Nilai atribut android:targetName opsional menentukan nama subset resource yang dapat di-overlay dari paket target, yang dimaksudkan untuk menjadi overlay. Jika target tidak menentukan rangkaian resource yang bisa di-overlay, ini tidak boleh ada.

Kode berikut menunjukkan contoh overlay 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>

Overlay tidak bisa menempatkan kode, sehingga tidak bisa memiliki file DEX. Selain itu, Atribut android:hasCode dari <application> dalam manifes harus ditetapkan ke false.

Menentukan peta resource

Di Android 11 atau lebih tinggi, mekanisme yang direkomendasikan untuk menentukan peta resource overlay adalah membuat file di res/xml paket overlay, menghitung sumber daya target yang harus iklan overlay dan nilai penggantinya, lalu tetapkan nilai Atribut android:resourcesMap dari tag manifes <overlay> ke referensi ke file pemetaan resource.

Kode berikut menunjukkan contoh file 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>

Kode berikut menunjukkan contoh manifes 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>

Membangun paket

Android 11 atau yang lebih baru mendukung aturan build Soong untuk overlay yang mencegah Android Asset Packaging Tool 2 (AAPT2) mencoba konfigurasi penghapusan duplikat resource dengan nilai yang sama (--no-resource-deduping) dan dari menghapus resource tanpa default konfigurasi (--no-resource-removal). Kode berikut menampilkan contoh File Android.bp.

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

Menyelesaikan resource

Jika resource target atau resource overlay memiliki beberapa konfigurasi yang ditetapkan untuk resource yang dikueri, runtime resource akan menampilkan nilai konfigurasi yang paling sesuai dengan konfigurasi konfigurasi perangkat. Untuk menentukan konfigurasi mana yang paling cocok, gabungkan set konfigurasi resource overlay ke dalam kumpulan resource target dan kemudian mengikuti alur resolusi resource reguler (untuk lihat detailnya, lihat Cara Android menemukan aplikasi yang paling cocok resource).

Misalnya, jika overlay menentukan nilai untuk konfigurasi drawable-en dan target menentukan nilai untuk drawable-en-port, drawable-en-port lebih cocok, jadi nilai konfigurasi target drawable-en-port dipilih saat runtime. Untuk menempatkan semua konfigurasi drawable-en, overlay harus menentukan nilai untuk setiap konfigurasi drawable-en yang ditetapkan target.

Overlay dapat mereferensikan resource-nya sendiri, dengan perilaku yang berbeda di antara Rilis Android.

  • Di Android 11 atau yang lebih baru, setiap overlay memiliki ruang ID resource yang dicadangkan yang tidak tumpang-tindih dengan ruang ID resource target atau ruang ID aset overlay lainnya, sehingga overlay merujuk pada sumber dayanya sendiri bekerja seperti yang diharapkan.

  • Di Android 10 atau yang lebih rendah, overlay dan paket target memiliki resource yang sama ruang ID, yang dapat menyebabkan tumbukan dan perilaku tak terduga saat mencoba untuk mereferensikan resource-nya sendiri menggunakan sintaksis @type/name.

Mengaktifkan/menonaktifkan overlay

Gunakan OverlayManager API untuk mengaktifkan dan menonaktifkan overlay yang dapat diubah (ambil antarmuka API menggunakan Context#getSystemService(Context.OVERLAY_SERVICE)). Channel {i>overlay <i}hanya dapat diaktifkan oleh paket yang ditargetkannya atau oleh paket dengan android.permission.CHANGE_OVERLAY_PACKAGES. Bila sebuah overlay adalah diaktifkan atau dinonaktifkan, peristiwa perubahan konfigurasi akan disebarkan ke paket target dan aktivitas target diluncurkan kembali.

Membatasi resource yang dapat ditempatkan

Di Android 10 atau yang lebih tinggi, tag XML <overlayable> mengekspos kumpulan resource sehingga RRO dapat ditempatkan. Pada contoh berikut File res/values/overlayable.xml, string/foo, dan integer/bar adalah resource digunakan untuk menerapkan tema tampilan perangkat; untuk menempatkan sumber daya ini, sebuah overlay harus secara eksplisit menargetkan kumpulan resource yang dapat ditempatkan berdasarkan nama.

<!-- 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 dapat menentukan beberapa tag <overlayable>, tetapi setiap tag harus memiliki dalam paket. Misalnya:

  • Oke untuk dua paket yang berbeda untuk menentukan <overlayable name="foo">.

  • Tidak disarankan untuk satu APK memiliki dua blok <overlayable name="foo">.

Kode berikut menunjukkan contoh overlay di 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>

Saat aplikasi menentukan tag <overlayable>, overlay yang menargetkan aplikasi tersebut:

  • Harus menentukan targetName.

  • Hanya dapat menempatkan resource yang tercantum dalam tag <overlayable>.

  • Hanya dapat menargetkan satu nama <overlayable>.

Anda tidak dapat mengaktifkan overlay yang menargetkan paket yang mengekspos iklan overlay resource, tetapi tidak menggunakan android:targetName untuk menargetkan tag <overlayable>.

Batasi kebijakan

Gunakan tag <policy> untuk menerapkan batasan pada resource yang dapat ditempatkan. Tujuan Atribut type menentukan kebijakan mana yang harus dipenuhi overlay untuk mengganti sumber daya yang disertakan. Jenis yang didukung mencakup hal berikut.

  • public. Overlay apa pun dapat menggantikan resource.
  • system. Overlay pada partisi sistem dapat mengganti resource.
  • vendor. Setiap overlay di partisi vendor dapat menggantikan resource.
  • product. Overlay apa pun di partisi produk dapat mengganti resource.
  • oem. Overlay pada partisi oem dapat mengganti resource.
  • odm. Overlay pada partisi odm dapat mengganti resource.
  • signature. Setiap overlay yang ditandatangani dengan tanda tangan yang sama seperti APK target dapat mengganti resource.
  • actor. Setiap overlay yang ditandatangani dengan tanda tangan yang sama dengan APK actor dapat mengganti resource. Pelaku dideklarasikan dalam tag Name-actor di sistem konfigurasi.
  • config_signature. Overlay apa pun yang ditandatangani dengan tanda tangan yang sama dengan apk overlay-config dapat mengganti resource. Overlay-config adalah dideklarasikan dalam tag overlay-config-signature dalam konfigurasi sistem.

Kode berikut menunjukkan contoh tag <policy> di bagian File 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>

Untuk menentukan beberapa kebijakan, gunakan garis vertikal (|) sebagai karakter pemisah. Jika beberapa kebijakan ditentukan, sebuah overlay hanya perlu memenuhi satu kebijakan untuk mengganti resource yang tercantum dalam tag <policy>.

Mengonfigurasi overlay

Android mendukung berbagai mekanisme untuk mengonfigurasi mutabilitas, setelan default status, dan prioritas overlay, bergantung pada versi rilis Android.

  • Perangkat yang menjalankan Android 11 atau yang lebih baru dapat menggunakan File OverlayConfig (config.xml), bukan atribut manifes. Menggunakan adalah metode yang disarankan untuk overlay.

  • Semua perangkat dapat menggunakan atribut manifes (android:isStatic dan android:priority) untuk mengonfigurasi RRO statis.

Menggunakan OverlayConfig

Di Android 11 atau yang lebih baru, Anda dapat menggunakan OverlayConfig untuk mengonfigurasi mutabilitas, status default, dan prioritas overlay. Untuk mengonfigurasi {i>overlay<i}, membuat atau mengubah file yang berada di partition/overlay/config/config.xml, dengan partition adalah partisi dari untuk dikonfigurasi. Agar dikonfigurasi, overlay harus berada dalam Direktori overlay/ partisi tempat overlay dikonfigurasi. Tujuan kode berikut menunjukkan contoh 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>"

Tag <overlay> memerlukan atribut package yang menunjukkan overlay mana sedang dikonfigurasi. Atribut enabled opsional mengontrol apakah atau tidak overlay diaktifkan secara default (default-nya adalah false). Opsi Atribut mutable mengontrol apakah overlay dapat berubah dan dapat memiliki status aktifnya berubah secara terprogram saat runtime (default-nya adalah true). Overlay yang tidak tercantum dalam file konfigurasi dapat diubah dan dinonaktifkan oleh secara default.

Prioritas overlay

Jika beberapa overlay mengganti aset yang sama, urutan overlay akan sangatlah penting. Overlay memiliki prioritas lebih besar daripada overlay dengan konfigurasi sebelum konfigurasinya sendiri. Urutan prioritas overlay di berbagai partisi (dari prioritas terkecil hingga terbesar) adalah sebagai berikut.

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

Gabungkan file

Penggunaan tag <merge> memungkinkan file konfigurasi lainnya digabungkan di posisi yang ditentukan ke dalam file konfigurasi. Atribut path tag mewakili jalur file yang akan digabungkan secara relatif terhadap direktori yang berisi file konfigurasi overlay.

Menggunakan atribut manifes/RRO statis

Di Android 10 atau yang lebih rendah, ketetapan dan prioritas overlay dikonfigurasi menggunakan atribut manifes berikut.

  • android:isStatic. Jika nilai atribut boolean ini ditetapkan ke true, overlay diaktifkan secara default dan tidak dapat diubah, sehingga mencegah overlay agar tidak dinonaktifkan.

  • android:priority. Nilai atribut numerik ini (yang hanya memengaruhi overlay statis) mengonfigurasi prioritas overlay ketika beberapa overlay menargetkan nilai resource yang sama. Angka yang lebih tinggi menunjukkan prioritas tinggi.

Kode berikut menunjukkan contoh 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>

Perubahan di Android 11

Di Android 11 atau yang lebih tinggi, jika file konfigurasi adalah yang terletak di partition/overlay/config/config.xml, overlay dikonfigurasi menggunakan file tersebut serta android:isStatic dan android:priority tidak berpengaruh pada overlay yang terletak di partisi. Menetapkan file konfigurasi overlay dalam menerapkan prioritas partisi overlay.

Selain itu, Android 11 atau yang lebih baru menghapus kemampuan menggunakan overlay statis untuk memengaruhi nilai resource yang dibaca selama paket penginstalan. Untuk kasus penggunaan umum penggunaan overlay statis nilai boolean yang mengonfigurasi status aktif komponen, gunakan metode Tag SystemConfig <component-override> (baru di Android 11.)

Overlay debug

Untuk mengaktifkan, menonaktifkan, dan membuang overlay secara manual, gunakan overlay berikut menggunakan perintah manager shell.

adb shell cmd overlay

OverlayManagerService menggunakan idmap2 untuk memetakan ID resource di target ke ID sumber daya dalam paket overlay. Pemetaan ID yang dihasilkan disimpan di /data/resource-cache/. Jika overlay Anda tidak berfungsi dengan benar, cari file idmap yang sesuai untuk overlay Anda di /data/resource-cache/, lalu jalankan perintah berikut.

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

Perintah ini mencetak pemetaan resource seperti yang ditunjukkan di bawah ini.

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