Bir uygulamanın kaynaklarının değerini çalışma zamanında değiştirme

Çalışma zamanı kaynak kaplaması (RRO), çalışma zamanında bir hedef paketin kaynak değerlerini değiştiren bir pakettir. Örneğin, sistem görüntüsüne yüklenen bir uygulama, kaynağın değerine bağlı olarak davranışını değiştirebilir. Kaynak değerini derleme sırasında sabit kodlamak yerine, farklı bir bölüme yüklenen bir RRO, uygulama kaynaklarının değerlerini çalışma zamanında değiştirebilir.

RRO'lar etkinleştirilebilir veya devre dışı bırakılabilir. Bir RRO'nun kaynak değerlerini değiştirme yeteneğini değiştirmek için etkinleştirme/devre dışı bırakma durumunu program aracılığıyla ayarlayabilirsiniz. RRO'lar varsayılan olarak devre dışıdır (ancak statik RRO'lar varsayılan olarak etkindir).

Yer paylaşımı kaynakları

Kaplamalar, kaplama paketinde tanımlanan kaynakları hedef pakette tanımlanan kaynaklarla eşleyerek çalışır. Bir uygulama hedef paketteki bir kaynağın değerini çözümlemeye çalıştığında bunun yerine hedef kaynağın eşlendiği yer paylaşımlı kaynağın değeri döndürülür.

Manifest'i ayarlama

Bir paket, <manifest> etiketinin alt öğesi olarak <overlay> etiketini içeriyorsa RRO paketi olarak kabul edilir.

  • Gerekli android:targetPackage özelliğinin değeri, RRO'nun kaplamayı amaçladığı paketin adını belirtir.

  • İsteğe bağlı android:targetName özniteliğinin değeri, RRO'nun kaplamayı amaçladığı hedef paketin kaplanabilir kaynak alt kümesinin adını belirtir. Hedef, yerleştirilebilir bir kaynak kümesini tanımlamıyorsa bu özniteliğin mevcut olmaması gerekir.

Aşağıdaki kod AndroidManifest.xml örneğini göstermektedir.

<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>

Kaplamalar kodu kaplayamaz, dolayısıyla DEX dosyalarına sahip olamazlar. Ayrıca manifestteki <application > etiketinin android:hasCode özelliğinin false olarak ayarlanması gerekir.

Kaynak haritasını tanımlayın

Android 11 veya sonraki sürümlerde, yer paylaşımı kaynakları haritasını tanımlamak için önerilen mekanizma, yer paylaşımı paketinin res/xml dizininde bir dosya oluşturmak, yer paylaşımı yapılması gereken hedef kaynakları ve bunların değiştirilme değerlerini numaralandırmak, ardından değerini ayarlamaktır. <overlay> manifest etiketinin android:resourcesMap niteliğini, kaynak eşleme dosyasına yapılan bir referansa yönlendirir.

Aşağıdaki kod örnek bir res/xml/overlays.xml dosyasını gösterir.

<?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>

Aşağıdaki kod örnek bir yer paylaşımı bildirimini gösterir.

<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>

Paketi oluştur

Android 11 veya üzeri, Android Asset Packaging Tool 2'nin (AAPT2) aynı değere ( --no-resource-deduping ) sahip kaynakların yapılandırmalarını tekilleştirmeye çalışmasını ve varsayılan yapılandırmalar olmadan kaynakları kaldırmasını engelleyen kaplamalar için Soong derleme kuralını destekler ( --no-resource-removal ). Aşağıdaki kod örnek bir Android.bp dosyasını gösterir.

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

Kaynakları çözümleyin

Bir hedef kaynak veya katman kaynağının, sorgulanan kaynak için tanımlanmış birden fazla konfigürasyonu varsa, kaynak çalışma zamanı, cihaz konfigürasyonunun konfigürasyonuyla en iyi eşleşen konfigürasyonun değerini döndürür. Hangi yapılandırmanın en iyi eşleşen yapılandırma olduğunu belirlemek için, yer paylaşımlı kaynak yapılandırmaları kümesini hedef kaynak yapılandırmaları kümesiyle birleştirin ve ardından normal kaynak çözümleme akışını izleyin (ayrıntılar için Android'in en iyi eşleşen kaynağı nasıl bulduğu bölümüne bakın).

Örneğin, bir yer paylaşımı drawable-en drawable-en-port için bir değer tanımlıyorsa, drawable-en-port daha iyi bir eşleşmeye sahip olur, dolayısıyla drawable-en-port hedef konfigürasyonunun değeri şöyle olur: çalışma zamanında seçilir. Tüm drawable-en konfigürasyonları kaplamak için kaplamanın, hedefin tanımladığı her drawable-en konfigürasyon için bir değer tanımlaması gerekir.

Kaplamalar, Android sürümleri arasında farklı davranışlarla kendi kaynaklarına referans verebilir.

  • Android 11 veya sonraki sürümlerde, her bir yer paylaşımının, hedef kaynak kimliği alanıyla veya diğer yer paylaşımı kaynak kimliği alanlarıyla örtüşmeyen kendi ayrılmış kaynak kimliği alanı vardır; bu nedenle, kendi kaynaklarına referans veren yer paylaşımları beklendiği gibi çalışır.

  • Android 10 veya önceki sürümlerde, kaplamalar ve hedef paketler aynı kaynak kimlik alanını paylaşır; bu da @type/name sözdizimini kullanarak kendi kaynaklarına başvurmaya çalıştıklarında çarpışmalara ve beklenmeyen davranışlara neden olabilir.

Kaplamaları etkinleştirme/devre dışı bırakma

Değişken kaplamaları etkinleştirmek ve devre dışı bırakmak için OverlayManager API'sini kullanın ( Context#getSystemService(Context.OVERLAY_SERVICE) kullanarak API arayüzünü alın). Bir yer paylaşımı yalnızca hedeflediği paket veya android.permission.CHANGE_OVERLAY_PACKAGES iznine sahip bir paket tarafından etkinleştirilebilir. Bir katman etkinleştirildiğinde veya devre dışı bırakıldığında, yapılandırma değişikliği olayları hedef pakete yayılır ve hedef etkinlikler yeniden başlatılır.

Yerleştirilebilir kaynakları kısıtla

Android 10 veya üzeri sürümlerde <overlayable> XML etiketi, RRO'ların yer paylaşımına izin verdiği bir dizi kaynağı ortaya çıkarır. Aşağıdaki örnekte res/values/overlayable.xml dosyası, string/foo ve integer/bar cihazın görünümünü temalandırmak için kullanılan kaynaklardır; Bu kaynakların yer paylaşımı için bir yer paylaşımının, yer paylaşımı yapılabilir kaynakların koleksiyonunu ada göre açıkça hedeflemesi gerekir.

<!-- 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>

Bir APK birden fazla <overlayable> etiketi tanımlayabilir, ancak her etiketin paket içinde benzersiz bir adı olmalıdır. Örneğin:

  • İki farklı paketin her ikisinin de <overlayable name="foo"> tanımlaması tamamdır.

  • Tek bir APK'nın iki <overlayable name="foo"> bloğuna sahip olması uygun değildir.

Aşağıdaki kod, AndroidManifest.xml dosyasındaki bir kaplama örneğini gösterir.

<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>

Bir uygulama bir <overlayable> etiketi tanımladığında, bu uygulamayı hedefleyen yer paylaşımları:

  • targetName belirtilmelidir.

  • Yalnızca <overlayable> etiketi içinde listelenen kaynaklar kaplanabilir.

  • Yalnızca bir <overlayable> adı hedefleyebilir.

Bindirilebilir kaynakları açığa çıkaran ancak belirli bir <overlayable> etiketini hedeflemek için android:targetName kullanmayan bir paketi hedefleyen bir kaplamayı etkinleştiremezsiniz.

Politikaları kısıtla

Yerleştirilebilir kaynaklara kısıtlamalar uygulamak için <policy> etiketini kullanın. type özelliği, bir yer paylaşımının dahil edilen kaynakları geçersiz kılmak için hangi politikaları yerine getirmesi gerektiğini belirtir. Desteklenen türler aşağıdakileri içerir.

  • public . Herhangi bir kaplama, kaynağı geçersiz kılabilir.
  • system . Sistem bölümündeki herhangi bir yer paylaşımı, kaynakları geçersiz kılabilir.
  • vendor . Satıcı bölümündeki herhangi bir yer paylaşımı, kaynakları geçersiz kılabilir.
  • product . Ürün bölümündeki herhangi bir kaplama, kaynakları geçersiz kılabilir.
  • oem . OEM bölümündeki herhangi bir kaplama, kaynakları geçersiz kılabilir.
  • odm . ODM bölümündeki herhangi bir kaplama, kaynakları geçersiz kılabilir.
  • signature . Hedef APK ile aynı imzayla imzalanan herhangi bir yer paylaşımı, kaynakları geçersiz kılabilir.
  • actor . Aktör APK'sıyla aynı imzayla imzalanan herhangi bir yer paylaşımı, kaynakları geçersiz kılabilir. Aktör, sistem yapılandırmasındaki adlandırılmış aktör etiketinde bildirildi.
  • config_signature . overlay-config apk ile aynı imzayla imzalanan herhangi bir kaplama, kaynakları geçersiz kılabilir. overlay-config, sistem yapılandırmasındaki overlay-config-signature etiketinde bildirilir.

Aşağıdaki kod res/values/overlayable.xml dosyasındaki örnek bir <policy> etiketini gösterir.

<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>

Birden çok politika belirtmek için ayırıcı karakterler olarak dikey çubukları (|) kullanın. Birden fazla politika belirtildiğinde, bir yer paylaşımının <policy> etiketi içinde listelenen kaynakları geçersiz kılmak için yalnızca bir politikayı yerine getirmesi gerekir.

Kaplamaları yapılandırma

Android, Android sürüm sürümüne bağlı olarak katmanların değişebilirliğini, varsayılan durumunu ve önceliğini yapılandırmak için farklı mekanizmaları destekler.

  • Android 11 veya üstünü çalıştıran cihazlar, manifest nitelikleri yerine OverlayConfig dosyasını ( config.xml ) kullanabilir. Kaplama dosyası kullanmak kaplamalar için önerilen yöntemdir.

  • Tüm cihazlar, statik RRO'ları yapılandırmak için bildirim niteliklerini ( android:isStatic ve android:priority ) kullanabilir.

OverlayConfig'i kullan

Android 11 veya sonraki sürümlerde, katmanların değiştirilebilirliğini, varsayılan durumunu ve önceliğini yapılandırmak için OverlayConfig kullanabilirsiniz. Bir kaplamayı yapılandırmak için, partition/overlay/config/config.xml konumunda bulunan dosyayı oluşturun veya değiştirin; burada partition yapılandırılacak kaplamanın bölümüdür. Yapılandırılabilmesi için bir kaplamanın, kaplamanın yapılandırıldığı bölümün overlay/ dizininde bulunması gerekir. Aşağıdaki kod örnek bir product/overlay/config/config.xml gösterir.

<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> etiketi, hangi yer paylaşımı paketinin yapılandırıldığını belirten bir package niteliği gerektirir. İsteğe bağlı enabled özelliği, kaplamanın varsayılan olarak etkin olup olmadığını kontrol eder (varsayılan, false ). İsteğe bağlı mutable özelliği, kaplamanın değiştirilebilir olup olmadığını ve etkin durumunun çalışma zamanında program aracılığıyla değiştirilip değiştirilemeyeceğini kontrol eder (varsayılan true ). Bir yapılandırma dosyasında listelenmeyen katmanlar değiştirilebilir ve varsayılan olarak devre dışıdır.

Yer paylaşımı önceliği

Birden fazla katman aynı kaynakları geçersiz kıldığında katmanların sırası önemlidir. Bir yer paylaşımı, kendi konfigürasyonundan önce gelen konfigürasyonlara sahip yer paylaşımlarından daha büyük önceliğe sahiptir. Farklı bölümlerdeki katmanların öncelik sırası (en küçükten en büyüğe doğru) aşağıdaki gibidir.

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

Dosyaları birleştir

<merge> etiketlerinin kullanılması, diğer yapılandırma dosyalarının belirtilen konumda yapılandırma dosyasıyla birleştirilmesine olanak tanır. Etiketin path niteliği, yer paylaşımı yapılandırma dosyalarını içeren dizine göre birleştirilecek dosyanın yolunu temsil eder.

Bildiri niteliklerini/statik RRO'ları kullan

Android 10 veya daha düşük sürümlerde yer paylaşımının değişmezliği ve öncelik, aşağıdaki manifest nitelikleri kullanılarak yapılandırılır.

  • android:isStatic . Bu boole özelliğinin değeri true olarak ayarlandığında, kaplama varsayılan olarak etkinleştirilir ve değiştirilemez; bu da kaplamanın devre dışı bırakılmasını engeller.

  • android:priority . Bu sayısal özelliğin değeri (yalnızca statik kaplamaları etkiler), birden fazla statik kaplama aynı kaynak değerini hedeflediğinde kaplamanın önceliğini yapılandırır. Daha yüksek bir sayı, daha yüksek bir önceliği gösterir.

Aşağıdaki kod bir AndroidManifest.xml örneğini gösterir.

<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'deki değişiklikler

Android 11 veya sonraki sürümlerde, bir yapılandırma dosyası partition/overlay/config/config.xml konumunda bulunuyorsa kaplamalar bu dosya kullanılarak yapılandırılır ve android:isStatic ve android:priority bölümde bulunan kaplamalar üzerinde bir etkisi yoktur. Herhangi bir bölümde bir yer paylaşımı yapılandırma dosyasının tanımlanması, yer paylaşımı bölümünün önceliğini zorunlu kılar.

Ayrıca Android 11 veya üzeri, paket kurulumu sırasında okunan kaynakların değerlerini etkilemek için statik katmanlar kullanma özelliğini ortadan kaldırır. Bileşenin etkin durumunu yapılandıran boolean'ların değerini değiştirmek amacıyla statik katmanların kullanılması şeklindeki yaygın kullanım durumu için <component-override> SystemConfig etiketini kullanın (Android 11'de yeni).

Kaplamalarda hata ayıklama

Kaplamaları manuel olarak etkinleştirmek, devre dışı bırakmak ve boşaltmak için aşağıdaki kaplama yöneticisi kabuk komutunu kullanın.

adb shell cmd overlay

OverlayManagerService hedef paketteki kaynak kimliklerini yer paylaşımı paketindeki kaynak kimlikleriyle eşleştirmek için idmap2 kullanır. Oluşturulan kimlik eşlemeleri /data/resource-cache/ konumunda saklanır. Kaplamanız düzgün çalışmıyorsa, kaplamanız için karşılık gelen idmap dosyasını /data/resource-cache/ içinde bulun ve ardından aşağıdaki komutu çalıştırın.

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

Bu komut, aşağıda gösterildiği gibi kaynakların eşlemesini yazdırır.

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