Çalışma zamanında bir uygulamanın kaynaklarının değerini 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, bir kaynağın değerine bağlı olarak davranışını değiştirebilir. Oluşturma zamanında kaynak değerini sabit kodlamak yerine, farklı bir bölüme yüklenen bir RRO, çalışma zamanında uygulamanın kaynaklarının değerlerini 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 programlı olarak ayarlayabilirsiniz. RRO'lar varsayılan olarak devre dışıdır (ancak, statik RRO'lar varsayılan olarak etkindir).

Yer paylaşımlı 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 çözmeye çalıştığında, bunun yerine hedef kaynağın eşlendiği kaplama kaynağının değeri döndürülür.

bildirimi ayarlama

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

  • Gerekli android:targetPackage özniteliğ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 yer paylaşımlı kaynak altkümesinin adını belirtir. Hedef, yer paylaşımlı bir kaynak kümesi tanımlamıyorsa, bu öznitelik mevcut olmamalıdır.

Aşağıdaki kod, örnek bir AndroidManifest.xml kaplamasını 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"/>
</manifest>

Yer paylaşımları kodu kaplayamaz, dolayısıyla DEX dosyalarına sahip olamazlar. Ek olarak, bildirimdeki <application > etiketinin android:hasCode özniteliği false olarak ayarlanmalıdır.

Kaynak haritasını tanımlama

Android 11 veya sonraki sürümlerde, kaplama kaynakları eşlemesini tanımlamak için önerilen mekanizma, kaplama paketinin res/xml dizininde bir dosya oluşturmak, üzerine bindirilmesi gereken hedef kaynakları ve bunların değiştirme değerlerini numaralandırmak ve ardından değerini ayarlamaktır. <overlay> manifest etiketinin android:resourcesMap özniteliği, kaynak eşleme dosyasına bir referanstır.

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

<?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 bindirme 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şturma

Android 11 veya üstü, Android Asset Packaging Tool 2'nin (AAPT2) aynı değere sahip ( --no-resource-deduping ) kaynakların yapılandırmalarını tekilleştirme girişiminde bulunmasını ve varsayılan yapılandırmalar olmadan ( --no-resource-removal ) kaynakları kaldırmasını engelleyen kaplamalar için bir Soong oluşturma 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ı çözme

Bir hedef kaynak veya kaplama kaynağı, sorgulanan kaynak için tanımlanmış birden çok yapılandırmaya sahipse, kaynakların çalışma zamanı, cihaz yapılandırmasının yapılandırmasıyla en iyi eşleşen yapılandırmanın değerini döndürür. Hangi konfigürasyonun en iyi eşleşen konfigürasyon olduğunu belirlemek için yer paylaşımlı kaynak konfigürasyonları setini hedef kaynak konfigürasyonları setiyle birleştirin ve ardından normal kaynak çözümleme akışını izleyin (ayrıntılar için Android en iyi eşleşen kaynağı nasıl bulur bölümüne bakın).

Örneğin, bir bindirme, drawable-en -en-port için bir değer tanımlıyorsa ve hedef, drawable-en-port için bir değer tanımlıyorsa, drawable-en-port daha iyi bir eşleşmeye sahip olur, bu nedenle, drawable-en-port hedef yapılandırmasının değeri şu şekilde olur: çalışma zamanında seçilir. Tüm drawable-en konfigürasyonlarını kaplamak için, kaplamanın, hedefin tanımladığı her drawable-en konfigürasyonu için bir değer tanımlaması gerekir.

Bindirmeler, Android sürümleri arasında farklı davranışlarla kendi kaynaklarına başvurabilir.

  • Android 11 veya sonraki sürümlerde, her yer paylaşımının, hedef kaynak kimliği alanı 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 başvuran kaplamalar beklendiği gibi çalışır.

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

Bindirmeleri 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). Kaplama, yalnızca hedeflediği paket tarafından veya android.permission.CHANGE_OVERLAY_PACKAGES iznine sahip bir paket tarafından etkinleştirilebilir. Bir kaplama 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.

Yer paylaşımlı kaynakları kısıtlama

Android 10 veya sonraki sürümlerde, <overlayable> XML etiketi, RRO'ların kaplamasına izin verilen bir dizi kaynağı gösterir. Aşağıdaki örnek res/values/overlayable.xml dosyasında, string/foo ve integer/bar , aygıtın görünümünü temalandırmak için kullanılan kaynaklardır; bu kaynakları kaplamak için, bir kaplamanın yer paylaşımlı 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 çok <overlayable> etiketi tanımlayabilir, ancak her etiketin paket içinde benzersiz bir adı olmalıdır. Örneğin, şu:

  • Her ikisinin de <overlayable name="foo"> tanımlaması için iki farklı paket için uygundur.

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

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, o uygulamayı hedefleyen bindirmeler:

  • targetName belirtilmelidir.

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

  • 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 yer paylaşımını etkinleştiremezsiniz.

Kısıtlama politikaları

Yer paylaşımlı kaynaklar üzerinde kısıtlamalar uygulamak için <policy> etiketini kullanın. type özniteliği, yer paylaşımının dahil edilen kaynakları geçersiz kılmak için hangi ilkeleri yerine getirmesi gerektiğini belirtir. Desteklenen türler aşağıdakileri içerir.

  • public Herhangi bir yer paylaşımı, kaynağı geçersiz kılabilir.
  • system . Sistem bölümündeki herhangi bir yerleşim, kaynakları geçersiz kılabilir.
  • vendor Satıcı bölümündeki herhangi bir katman, kaynakları geçersiz kılabilir.
  • product Ürün bölümündeki herhangi bir yerleşim, kaynakları geçersiz kılabilir.
  • oem OEM bölümündeki herhangi bir yer paylaşımı, kaynakları geçersiz kılabilir.
  • odm odm bölümündeki herhangi bir katman, kaynakları geçersiz kılabilir.
  • signature Hedef APK ile aynı imzayla imzalanan herhangi bir kaplama, kaynakları geçersiz kılabilir.
  • actor Aktör APK'sı ile aynı imzayla imzalanmış herhangi bir bindirme, kaynakları geçersiz kılabilir. Aktör, sistem yapılandırmasında adlı aktör etiketinde bildirilir.
  • config_signature overlay-config apk ile aynı imzayla imzalanan herhangi bir kaplama, kaynakları geçersiz kılabilir. overlay-config, system config içindeki 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 ilke belirtmek için ayırıcı karakterler olarak dikey çubuklar (|) kullanın. Birden çok ilke belirtildiğinde, bir kaplamanın <policy> etiketinde listelenen kaynakları geçersiz kılmak için yalnızca bir ilkeyi yerine getirmesi gerekir.

Bindirmeleri yapılandırma

Android, Android yayın sürümüne bağlı olarak bindirmelerin 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 öznitelikleri yerine bir OverlayConfig dosyası ( config.xml ) kullanabilir. Bindirmeler için önerilen yöntem bir kaplama dosyası kullanmaktır.

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

OverlayConfig'i Kullanma

Android 11 veya sonraki sürümlerde, bindirmelerin değişkenliğ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 bulunan dosyayı oluşturun veya değiştirin; burada partition , kaplamanın yapılandırılacak bölümüdür. Yapılandırılması için, kaplamanın yapılandırıldığı bölümün overlay/ dizininde bir kaplama bulunmalıdır. Aşağıdaki kod, bir örnek 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 kaplama paketinin yapılandırıldığını gösteren bir package özniteliği gerektirir. İsteğe bağlı enabled özellik kaplamanın varsayılan olarak etkinleştirilip etkinleştirilmediğini denetler (varsayılan değer false ). İsteğe bağlı mutable özniteliği, yer paylaşımının değişken olup olmadığını ve etkin durumunun çalışma zamanında programlı olarak değiştirilip değiştirilemeyeceğini kontrol eder (varsayılan değer true ). Yapılandırma dosyasında listelenmeyen bindirmeler değiştirilebilir ve varsayılan olarak devre dışıdır.

Bindirme önceliği

Birden çok kaplama aynı kaynakları geçersiz kıldığında, kaplamaların sırası önemlidir. Kaplama, kendi konfigürasyonundan önce gelen konfigürasyonlara sahip kaplamalardan daha yüksek önceliğe sahiptir. Farklı bölümlerdeki bindirmelerin ö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ştirme

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

Bildirim özelliklerini kullanma (statik RRO'lar)

Android 10 veya önceki sürümlerde yer paylaşımı değişmezliği ve öncelik, aşağıdaki bildirim öznitelikleri kullanılarak yapılandırılır.

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

  • android:priority . Bu sayısal özniteliğ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, 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, partition/overlay/config/config.xml konumunda bir yapılandırma dosyası 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 kaplama yapılandırma dosyası tanımlamak, kaplama bölümü önceliğini zorlar.

Ek olarak, Android 11 veya üstü, paket kurulumu sırasında okunan kaynakların değerlerini etkilemek için statik yer paylaşımları kullanma özelliğini kaldırır. Bileşen etkin durumunu yapılandıran boolean'ların değerini değiştirmek üzere statik bindirmeleri kullanmanın yaygın kullanım durumu için, <component-override> SystemConfig etiketini kullanın (Android 11'de yeni).

Yer paylaşımlarında hata ayıklama

Yer paylaşımlarını manuel olarak etkinleştirmek, devre dışı bırakmak ve dökümü yapmak için aşağıdaki yer paylaşımı yöneticisi kabuk komutunu kullanın.

adb shell cmd overlay

OverlayManagerService , hedef paketteki kaynak kimliklerini kaplama paketindeki kaynak kimlikleriyle eşlemek için idmap2 kullanır. Oluşturulan kimlik eşlemeleri /data/resource-cache/ içinde depolanır. Katmanınız düzgün çalışmıyorsa, /data/resource-cache/ içinde yer paylaşımınız için karşılık gelen idmap dosyasını 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