Mengubah nilai resource aplikasi saat runtime

Overlay resource runtime (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 meng-hardcode nilai resource pada waktu build, RRO yang diinstal pada partisi lain dapat mengubah nilai resource aplikasi saat runtime.

RRO dapat diaktifkan atau dinonaktifkan. Anda dapat menyetel status aktif/nonaktif secara terprogram untuk mengalihkan kemampuan RRO dalam mengubah nilai resource. RRO dinonaktifkan secara default (namun, 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 menyelesaikan 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 dari 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 di-overlay dari paket target yang ingin di-overlay oleh RRO. Jika target tidak menentukan set resource yang dapat di-overlay, 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 menutupi 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 dengan membuat file di direktori res/xml paket overlay, mencantumkan resource target yang harus di-overlay dan nilai penggantinya, 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>

Membangun 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",
}

Mengatasi masalah 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 perangkat. Untuk menentukan konfigurasi mana yang paling cocok, gabungkan kumpulan konfigurasi resource overlay ke dalam kumpulan konfigurasi resource target, lalu ikuti alur penyelesaian resource reguler (untuk 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 di 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 rendah, paket target dan overlay berbagi ruang ID resource yang sama, yang dapat menyebabkan konflik dan perilaku yang tidak terduga saat mencoba mereferensikan resource 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

Hal ini 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 diteruskan ke paket target dan aktivitas target diluncurkan ulang.

Membatasi resource yang dapat di-overlay

Di Android 10 atau yang lebih tinggi, tag XML <overlayable> mengekspos serangkaian resource yang diizinkan untuk di-overlay oleh RRO. Dalam contoh file res/values/overlayable.xml berikut, string/foo dan integer/bar adalah resource yang digunakan untuk membuat tema tampilan perangkat; untuk menempatkan resource ini di atas, overlay harus secara eksplisit menargetkan kumpulan resource yang dapat di-overlay 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,

  • OK untuk dua paket berbeda yang keduanya 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 menargetkan aplikasi tersebut:

  • Harus menentukan targetName.

  • Dapat melapisi hanya 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.

Membatasi kebijakan

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

  • public. Overlay apa pun dapat menggantikan resource.
  • system. Overlay apa pun pada partisi sistem dapat menggantikan resource.
  • vendor. Overlay apa pun di partisi vendor dapat menggantikan resource.
  • product. Overlay apa pun pada partisi produk dapat menggantikan resource.
  • oem. Overlay apa pun pada partisi oem dapat menggantikan resource.
  • odm. Overlay apa pun pada partisi odm dapat menggantikan resource.
  • signature. Setiap overlay yang ditandatangani dengan tanda tangan yang sama dengan APK target dapat menggantikan resource.
  • actor. Overlay yang ditandatangani dengan tanda tangan yang sama dengan APK aktor dapat menggantikan resource. Aktor dideklarasikan dalam tag named-actor di konfigurasi sistem.
  • config_signature. Overlay apa pun yang ditandatangani dengan tanda tangan yang sama seperti APK overlay-config dapat menggantikan resource. overlay-config 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 menggantikan resource yang tercantum dalam tag <policy>.

Mengonfigurasi overlay

Android mendukung berbagai mekanisme untuk mengonfigurasi kemampuan berubah, 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) sebagai pengganti 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 tinggi, Anda dapat menggunakan OverlayConfig untuk mengonfigurasi kemampuan berubah, status default, dan prioritas overlay. Untuk mengonfigurasi overlay, buat atau ubah file yang berada 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 dan dapat mengubah status aktifnya 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 menggantikan resource yang sama, urutan overlay menjadi penting. Overlay memiliki prioritas yang lebih tinggi daripada overlay dengan konfigurasi yang mendahului konfigurasinya sendiri. Urutan prioritas overlay di partisi yang berbeda (dari prioritas terkecil hingga terbesar) 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 dari tag mewakili jalur file yang akan digabungkan relatif terhadap direktori yang berisi file konfigurasi overlay.

Menggunakan atribut manifes/RRO statis

Di Android 10 atau yang lebih rendah, keabadian 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 preseden 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 berupa penggunaan overlay statis untuk mengubah nilai boolean yang mengonfigurasi status aktif komponen, gunakan tag <component-override> SystemConfig (baru di Android 11).

Overlay debug

Untuk mengaktifkan, menonaktifkan, dan melakukan dump overlay secara manual, gunakan perintah shell overlay manager 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 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