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

Çalışma zamanında kaynak eşlemesi (RRO), çalışma zamanında bir hedef paketin kaynak değerlerini değiştiren bir pakettir. Örneğin, sistem görüntüsünde yüklenen bir uygulama, kaynağın değerine göre davranışını değiştirebilir. Farklı bir bölüme yüklenen bir RRO, kaynak değerini derleme sırasında sabit kodlamak yerine uygulamanın 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 olanağını açıp kapatmak için etkinleştirme/devre dışı bırakma durumunu programatik olarak ayarlayabilirsiniz. RRO'lar varsayılan olarak devre dışıdır (ancak statik RRO'lar varsayılan olarak etkindir).

Kaynakları bindirme

Bindirmeler, bindirme paketinde tanımlanan kaynakların hedef pakette tanımlanan kaynaklarla eşlenmesiyle çalışır. Bir uygulama, hedef paketteki bir kaynağın değerini çözmeye çalıştığında bunun yerine hedef kaynağın eşlendiği yer paylaşımı kaynağının değeri döndürülür.

Manifest dosyasını ayarlama

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

  • Gerekli android:targetPackage özelliğinin değeri, RRO'nun yer paylaşımlı olarak kullanmayı amaçladığı paketin adını belirtir.

  • İsteğe bağlı android:targetName özelliğinin değeri, RRO'nun yer paylaşımı yapmayı amaçladığı hedef paketin yer paylaşımına uygun kaynak alt kümesinin adını belirtir. Hedef, üzerine yazılabilir bir kaynak grubu tanımlamıyorsa bu özellik mevcut olmamalıdır.

Aşağıdaki kodda örnek bir yer paylaşımı AndroidManifest.xml gösterilmektedir.

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

Bindirmelerde kod yer paylaşımı yapılamaz, bu nedenle DEX dosyaları bulunamaz. Ayrıca, manifest dosyasında <application> etiketinin android:hasCode özelliği false olarak ayarlanmalıdır.

Kaynak haritasını tanımlama

Android 11 veya sonraki sürümlerde, yer paylaşımı kaynak 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 yerine kullanılacak değerleri numaralandırmak, ardından <overlay> manifest etiketinin android:resourcesMap özelliğinin değerini kaynak eşleme dosyasına referans olacak şekilde ayarlamaktır.

Aşağıdaki kodda örnek bir res/xml/overlays.xml dosyası gösterilmektedir.

<?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 kodda örnek bir yer paylaşımı manifesti gösterilmektedir.

<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 sonraki sürümler, Android Öğe Paketleme Aracı 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ı olmayan kaynakları (--no-resource-removal) kaldırmasını engelleyen yer paylaşımları için Shortg derleme kuralını destekler. Aşağıdaki kodda örnek Android.bp dosyası gösterilmektedir.

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

Kaynakları çözme

Bir hedef kaynak veya yer paylaşımı kaynağında, sorgulanan kaynak için birden fazla yapılandırma tanımlanmışsa kaynak çalışma zamanı, cihaz yapılandırmasıyla en iyi eşleşen yapılandırma değerini döndürür. En iyi eşleşen yapılandırmayı belirlemek için yer paylaşımı kaynak yapılandırmaları grubunu hedef kaynak yapılandırmaları grubuyla birleştirin ve ardından normal kaynak çözümü akışını uygulayın (ayrıntılar için Android en iyi eşleşen kaynağı nasıl bulur? başlıklı makaleyi inceleyin).

Örneğin, bir yer paylaşımı drawable-en yapılandırması 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. Böylece, drawable-en-port hedef yapılandırmasının değeri çalışma zamanında seçilir. Tüm drawable-en yapılandırmalarını yer paylaşımına eklemek için yer paylaşımının, hedefin tanımladığı her drawable-en yapılandırması için bir değer tanımlaması gerekir.

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

  • Android 11 veya sonraki sürümlerde her yer paylaşımının, hedef kaynak kimliği alanıyla veya diğer yer paylaşımı kaynak kimliği alanlarıyla çakışmayan 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 yer paylaşımları ve hedef paketler aynı kaynak kimliği alanını paylaşır. Bu durum, @type/name söz dizimini kullanarak kendi kaynaklarına referans vermeye çalıştıklarında çakışmalara ve beklenmedik davranışlara neden olabilir.

Yer paylaşımlarını etkinleştirme/devre dışı bırakma

Değişebilir yer paylaşımlarını etkinleştirmek ve devre dışı bırakmak için OverlayManager API'yi kullanın (API arayüzünü Context#getSystemService(Context.OVERLAY_SERVICE) kullanarak alın). Yer paylaşımı, yalnızca hedeflediği paket veya android.permission.CHANGE_OVERLAY_PACKAGES iznine sahip bir paket tarafından etkinleştirilebilir. Bir yer paylaşımı etkinleştirildiğinde veya devre dışı bırakıldığında, yapılandırma değişikliği etkinlikleri hedef pakete yayılır ve hedef etkinlikleri 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 yer paylaşımına izin verilen bir kaynak grubunu gösterir. Aşağıdaki örnek res/values/overlayable.xml dosyasında string/foo ve integer/bar, cihazın görünümünde tema oluşturmak için kullanılan kaynaklardır. Bu kaynakların yer paylaşımlı olarak yer alması için bir yer paylaşımı, yer paylaşımlı kaynaklar koleksiyonunu ada göre açıkça hedeflemelidir.

<!-- 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 <overlayable name="foo"> değerini tanımlaması sorun oluşturmaz.

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

Aşağıdaki kodda, AndroidManifest.xml dosyasında yer alan bir yer paylaşımı örneği gösterilmektedir.

<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 <overlayable> etiketi tanımladığında, bu uygulamayı hedefleyen yer paylaşımları:

  • targetName belirtilmelidir.

  • Yalnızca <overlayable> etiketinde listelenen kaynaklarla yer paylaşımlı olabilir.

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

Yerleşik kaynaklar gösteren ancak belirli bir <overlayable> etiketini hedeflemek için android:targetName kullanmayan bir paketi hedefleyen bir yer paylaşımını etkinleştiremezsiniz.

Politikaları kısıtlama

Yerleştirilebilir kaynaklarda kısıtlamaları zorunlu kılmak için <policy> etiketini kullanın. type özelliği, dahil edilen kaynakları geçersiz kılmak için bir yer paylaşımının hangi politikaları karşılaması gerektiğini belirtir. Desteklenen türler şunlardır:

  • public. Herhangi bir yer paylaşımı, kaynağı geçersiz kılabilir.
  • system. Sistem bölümündeki tüm yer paylaşımları kaynakları geçersiz kılabilir.
  • vendor. Tedarikçi firma bölümündeki tüm yer paylaşımları kaynakları geçersiz kılabilir.
  • product. Ürün bölümündeki tüm yer paylaşımları 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 yer paylaşımı, kaynakları geçersiz kılabilir.
  • signature. Hedef APK ile aynı imzaya sahip olan herhangi bir yer paylaşımı, kaynakları geçersiz kılabilir.
  • actor. İşlemi yapan APK ile aynı imzaya sahip olan tüm yer paylaşımları kaynakları geçersiz kılabilir. Oyuncu, sistem yapılandırmasında named-actor etiketinde belirtilir.
  • config_signature. Overlay-config APK'sıyla aynı imzayla imzalanan tüm yer paylaşımları kaynakları geçersiz kılabilir. Yer paylaşımı yapılandırması, sistem yapılandırmasında yer paylaşımı yapılandırması imzası etiketinde tanımlanır.

Aşağıdaki kodda, res/values/overlayable.xml dosyasında bir örnek <policy> etiketi gösterilmektedir.

<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> etiketinde listelenen kaynakları geçersiz kılmak için yalnızca bir politikayı yerine getirmesi gerekir.

Yer paylaşımlarını yapılandırma

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

  • Android 11 veya sonraki sürümleri çalıştıran cihazlar, manifest özellikleri yerine OverlayConfig dosyası (config.xml) kullanabilir. Yer paylaşımları için önerilen yöntem, yer paylaşımı dosyası kullanmaktır.

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

OverlayConfig kullanma

Android 11 veya sonraki sürümlerde yer paylaşımlarının değişkenliğini, varsayılan durumunu ve önceliğini yapılandırmak için OverlayConfig kullanabilirsiniz. Yer paylaşımını 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 yer paylaşımının bölümüdür. Bir yer paylaşımının yapılandırılabilmesi için, yer paylaşımının yapılandırıldığı bölümün overlay/ dizininde bulunması gerekir. Aşağıdaki kodda bir product/overlay/config/config.xml örneği gösterilmektedir.

<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 özelliği gerektirir. İsteğe bağlı enabled özelliği, yer paylaşımının varsayılan olarak etkinleştirilip etkinleştirilmeyeceğini kontrol eder (varsayılan olarak false şeklindedir). İsteğe bağlı mutable özelliği, yer paylaşımının değiştirilip değişemeyeceğini kontrol eder ve etkin durumunun çalışma zamanında programatik olarak değiştirilmesini sağlar (varsayılan değer true). Bir yapılandırma dosyasında listelenmeyen yer paylaşımları değişebilir ve varsayılan olarak devre dışı bırakılır.

Yer paylaşımı önceliği

Birden fazla yer paylaşımı aynı kaynakları geçersiz kıldığında yer paylaşımlarının sırası önemlidir. Bir yer paylaşımının önceliği, kendi yapılandırmasından önce gelen yapılandırmalara sahip yer paylaşımlarından daha yüksektir. Farklı bölümlerdeki yer paylaşımlarının öncelik sırası (en düşükten en yükseğ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ında birleştirilmesine olanak tanır. Etiketin path özelliği, yer paylaşımlı yapılandırma dosyalarını içeren dizine göre birleştirilecek dosyanın yolunu temsil eder.

Manifest özelliklerini/statik RRO'ları kullanma

Android 10 veya önceki sürümlerde yer paylaşımının değişmezliği ve önceliği aşağıdaki manifest özellikleri kullanılarak yapılandırılır.

  • android:isStatic. Bu boole özelliğinin değeri true olarak ayarlandığında, yer paylaşımı varsayılan olarak etkinleştirilir ve sabittir. Bu da yer paylaşımının devre dışı bırakılmasını engeller.

  • android:priority. Bu sayısal özelliğin değeri (yalnızca statik yer paylaşımlarını etkiler), birden fazla statik yer paylaşımı aynı kaynak değerini hedeflediğinde yer paylaşımının önceliğini yapılandırır. Sayı ne kadar yüksek olursa öncelik de o kadar yüksektir.

Aşağıdaki kodda bir örnek AndroidManifest.xml gösterilmektedir.

<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 bulunursa yer paylaşımları bu dosya kullanılarak yapılandırılır ve android:isStatic ile android:priority öğesinin bölümdeki yer paylaşımları üzerinde bir etkisi yoktur. Herhangi bir bölümde yer paylaşımlı yapılandırma dosyası tanımlamak, yer paylaşımlı bölüm önceliğini zorunlu kılar.

Ayrıca Android 11 veya sonraki sürümlerde, paket yükleme sırasında okunan kaynakların değerlerini etkilemek için statik yer paylaşımları kullanma özelliği kaldırılmıştır. Bileşenin etkin durumunu yapılandıran boole değerini değiştirmek amacıyla statik yer paylaşımları kullanmanın yaygın kullanım alanı için <component-override> SystemConfig etiketini (Android 11'de yeni sunulan) kullanın.

Hata ayıklama yer paylaşımları

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

adb shell cmd overlay

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