Mengubah nilai resource aplikasi saat runtime

Runtime resource overlay (RRO) adalah paket yang mengubah nilai resource paket target saat runtime. Misalnya, aplikasi yang diinstal pada image sistem dapat mengubah perilakunya berdasarkan nilai resource. Daripada melakukan hardcoding nilai resource pada waktu build, RRO yang diinstal di partisi lain dapat mengubah nilai resource aplikasi saat runtime.

RRO dapat diaktifkan atau dinonaktifkan. Anda dapat menetapkan status enable/disable secara terprogram untuk mengalihkan kemampuan RRO guna mengubah nilai resource. RRO dinonaktifkan secara default (tetapi, RRO statis diaktifkan secara default).

Resource overlay

Overlay berfungsi dengan memetakan resource yang ditentukan dalam paket overlay ke resource yang ditentukan dalam paket target. Saat aplikasi mencoba me-resolve nilai resource dalam paket target, nilai resource overlay yang dipetakan ke resource target 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 paket yang ingin di-overlay oleh RRO.

  • Nilai atribut android:targetName opsional menentukan nama subset resource yang dapat ditempatkan dari paket target yang ingin ditempatkan oleh RRO. Jika target tidak menentukan kumpulan resource yang dapat ditempatkan, atribut 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 dapat menempatkan kode, sehingga tidak dapat memiliki file DEX. Selain itu, atribut android:hasCode dari tag <application> dalam manifes harus ditetapkan ke false.

Menentukan peta resource

Di Android 11 atau yang lebih tinggi, mekanisme yang direkomendasikan untuk menentukan peta resource overlay adalah membuat file di direktori res/xml paket overlay, menghitung resource target yang harus ditumpangkan dan nilai penggantiannya, lalu menetapkan 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>

Mem-build paket

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

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

Me-resolve resource

Jika resource target atau resource overlay memiliki beberapa konfigurasi yang ditentukan untuk resource yang dikueri, runtime resource akan menampilkan nilai konfigurasi yang paling cocok dengan konfigurasi konfigurasi perangkat. Untuk menentukan konfigurasi mana yang merupakan konfigurasi yang paling cocok, gabungkan kumpulan konfigurasi resource overlay ke dalam kumpulan konfigurasi resource target, lalu ikuti alur resolusi resource reguler (untuk mengetahui detailnya, lihat Cara Android menemukan resource yang paling cocok).

Misalnya, jika overlay menentukan nilai untuk konfigurasi drawable-en dan target menentukan nilai untuk drawable-en-port, drawable-en-port memiliki kecocokan yang lebih baik sehingga 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 ditentukan target.

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

  • Di Android 11 atau yang lebih tinggi, setiap overlay memiliki ruang ID resource yang dicadangkan sendiri yang tidak tumpang-tindih dengan ruang ID resource target atau ruang ID resource overlay lainnya, sehingga overlay yang mereferensikan resourcenya sendiri berfungsi seperti yang diharapkan.

  • Di Android 10 atau yang lebih lama, overlay dan paket target berbagi ruang ID resource yang sama, yang dapat menyebabkan konflik dan perilaku yang tidak terduga saat mencoba mereferensikan resource-nya sendiri menggunakan sintaksis @type/name.

Mengaktifkan/menonaktifkan overlay

Overlay dapat diaktifkan/dinonaktifkan secara manual dan terprogram.

Menonaktifkan atau mengaktifkan overlay secara manual

Untuk mengaktifkan dan memverifikasi RRO secara manual, jalankan:

adb shell cmd overlay enable --user current com.example.carrro
adb shell cmd overlay list --user current | grep -i com.example com.example.carrro

Tindakan ini akan mengaktifkan RRO untuk pengguna sistem (userId = 0) yang memiliki SystemUI. Petunjuk ini tidak memengaruhi aplikasi yang dimulai oleh pengguna latar depan (userId = 10). Untuk mengaktifkan RRO bagi pengguna latar depan, gunakan parameter -–user 10:

adb shell cmd overlay enable --user 10 com.example.carrro

Mengaktifkan atau menonaktifkan overlay secara terprogram

Gunakan OverlayManager API untuk mengaktifkan dan menonaktifkan overlay yang dapat diubah (ambil antarmuka API menggunakan Context#getSystemService(Context.OVERLAY_SERVICE)). Overlay hanya dapat diaktifkan oleh paket yang ditargetkannya atau oleh paket dengan izin android.permission.CHANGE_OVERLAY_PACKAGES. Saat overlay diaktifkan atau dinonaktifkan, peristiwa perubahan konfigurasi akan diterapkan ke paket target dan aktivitas target akan diluncurkan ulang.

Membatasi resource yang dapat ditempatkan

Di Android 10 atau yang lebih baru, tag XML <overlayable> mengekspos kumpulan resource yang diizinkan untuk ditempatkan oleh RRO. Dalam contoh file res/values/overlayable.xml berikut, string/foo dan integer/bar adalah resource yang digunakan untuk tema tampilan perangkat; untuk menempatkan resource ini, 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 nama unik dalam paket. Misalnya, nilainya adalah:

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

  • Tidak boleh ada dua blok <overlayable name="foo"> dalam satu APK.

Kode berikut menunjukkan contoh overlay dalam file 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 resource yang dapat di-overlay, tetapi tidak menggunakan android:targetName untuk menargetkan tag <overlayable> tertentu.

Kebijakan pembatasan

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

  • public. Overlay apa pun dapat mengganti resource.
  • system. Setiap overlay pada partisi sistem dapat mengganti resource.
  • vendor. Setiap overlay pada partisi vendor dapat mengganti resource.
  • product. Setiap overlay pada partisi produk dapat mengganti resource.
  • oem. Setiap overlay pada partisi OEM dapat mengganti resource.
  • odm. Setiap overlay pada partisi odm dapat mengganti resource.
  • signature. Setiap overlay yang ditandatangani dengan tanda tangan yang sama dengan APK target dapat mengganti resource.
  • actor. Setiap overlay yang ditandatangani dengan tanda tangan yang sama dengan APK aktor dapat mengganti resource. Aktor dideklarasikan dalam tag named-actor dalam konfigurasi sistem.
  • config_signature. Setiap overlay yang ditandatangani dengan tanda tangan yang sama dengan apk overlay-config dapat mengganti resource. Konfigurasi overlay dideklarasikan dalam tag overlay-config-signature di konfigurasi sistem.

Kode berikut menunjukkan contoh tag <policy> dalam 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, overlay hanya perlu memenuhi satu kebijakan untuk mengganti resource yang tercantum dalam tag <policy>.

Mengonfigurasi overlay

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

  • Perangkat yang menjalankan Android 11 atau yang lebih tinggi dapat menggunakan file OverlayConfig (config.xml), bukan atribut manifes. Menggunakan file overlay adalah metode yang direkomendasikan 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 overlay, buat atau ubah file yang terletak di partition/overlay/config/config.xml, dengan partition adalah partisi overlay yang akan dikonfigurasi. Agar dapat dikonfigurasi, overlay harus berada di direktori overlay/ partisi tempat overlay dikonfigurasi. 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 paket overlay yang sedang dikonfigurasi. Atribut enabled opsional mengontrol apakah overlay diaktifkan secara default atau tidak (defaultnya adalah false). Atribut mutable opsional mengontrol apakah overlay dapat diubah atau tidak dan dapat mengubah status pengaktifannya secara terprogram saat runtime (defaultnya adalah true). Overlay yang tidak tercantum dalam file konfigurasi dapat diubah dan dinonaktifkan secara default.

Prioritas overlay

Jika beberapa overlay mengganti resource yang sama, urutan overlay sangat penting. Overlay memiliki prioritas yang lebih besar daripada overlay dengan konfigurasi yang mendahului konfigurasinya sendiri. Urutan prioritas overlay dalam berbagai partisi (dari prioritas paling kecil hingga paling besar) adalah sebagai berikut.

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

Menggabungkan file

Penggunaan tag <merge> memungkinkan file konfigurasi lain digabungkan pada 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 lama, ketidakmutlakan 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 dinonaktifkan.

  • android:priority. Nilai atribut numerik ini (yang hanya memengaruhi overlay statis) mengonfigurasi prioritas overlay saat beberapa overlay statis menargetkan nilai resource yang sama. Angka yang lebih tinggi menunjukkan precedence yang lebih 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 berada di partition/overlay/config/config.xml, overlay dikonfigurasi menggunakan file tersebut dan android:isStatic serta android:priority tidak berpengaruh pada overlay yang berada di partisi. Menentukan file konfigurasi overlay di partisi mana pun akan menerapkan prioritas partisi overlay.

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

Overlay debug

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

adb shell cmd overlay

Menggunakan enable tanpa menentukan pengguna akan memengaruhi pengguna saat ini, yaitu pengguna sistem (userId = 0), yang memiliki UI Sistem. Hal ini tidak memengaruhi pengguna latar depan (userId = 10), yang memiliki aplikasi. Untuk mengaktifkan RRO bagi pengguna latar depan, gunakan parameter –-user 10:

adb shell cmd overlay enable --user 10 com.example.carrro

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

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

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

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