रनटाइम के दौरान किसी ऐप्लिकेशन के संसाधनों की वैल्यू बदलना

रनटाइम रिसॉर्स ओवरले (आरआरओ) एक ऐसा पैकेज है जो रनटाइम पर टारगेट पैकेज के रिसॉर्स की वैल्यू बदलता है. उदाहरण के लिए, सिस्टम इमेज पर इंस्टॉल किया गया कोई ऐप्लिकेशन, किसी संसाधन की वैल्यू के आधार पर अपना व्यवहार बदल सकता है. बिल्ड के समय रिसॉर्स की वैल्यू को हार्डकोड करने के बजाय, किसी दूसरे पार्टीशन पर इंस्टॉल किया गया RRO, रनटाइम के दौरान ऐप्लिकेशन के संसाधनों की वैल्यू बदल सकता है.

आरआरओ को चालू या बंद किया जा सकता है. प्रोग्राम के ज़रिए, चालू/बंद करने की स्थिति को सेट किया जा सकता है, ताकि संसाधन की वैल्यू बदलने के लिए RRO की क्षमता को टॉगल किया जा सके. आरआरओ डिफ़ॉल्ट रूप से बंद होते हैं. हालांकि, स्टैटिक आरआरओ डिफ़ॉल्ट रूप से चालू होते हैं.

ओवरले से जुड़े संसाधन

ओवरले, ओवरले पैकेज में तय किए गए रिसॉर्स को टारगेट पैकेज में तय किए गए रिसॉर्स से मैप करके काम करते हैं. जब कोई ऐप्लिकेशन टारगेट पैकेज में किसी संसाधन की वैल्यू को हल करने की कोशिश करता है, तो टारगेट संसाधन को जिस ओवरले संसाधन पर मैप किया गया है उसकी वैल्यू दिखती है.

मेनिफ़ेस्ट सेट अप करना

किसी पैकेज को आरआरओ पैकेज तब माना जाता है, जब उसमें <manifest> टैग के चाइल्ड के तौर पर <overlay> टैग शामिल हो.

  • ज़रूरी android:targetPackage एट्रिब्यूट की वैल्यू से उस पैकेज का नाम पता चलता है जिसे RRO ओवरले करना चाहता है.

  • वैकल्पिक android:targetName एट्रिब्यूट की वैल्यू से, टारगेट किए गए उस पैकेज के रिसॉर्स के ओवरले का नाम पता चलता है जिसे RRO, ओवरले करना चाहता है. अगर टारगेट, संसाधनों का वह सेट नहीं है जिसे ओवरले किया जा सकता है, तो यह एट्रिब्यूट मौजूद नहीं होना चाहिए.

यहां दिया गया कोड, ओवरले का एक उदाहरण दिखाता है 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>

ओवरले, कोड को ओवरले नहीं कर सकते. इसलिए, इनमें DEX फ़ाइलें नहीं हो सकतीं. इसके अलावा, मेनिफ़ेस्ट में <application> टैग के android:hasCode एट्रिब्यूट को false पर सेट करना ज़रूरी है.

संसाधनों वाले मैप को तय करना

Android 11 या इसके बाद के वर्शन में, ओवरले संसाधनों के मैप को तय करने के लिए, ओवरले पैकेज की res/xml डायरेक्ट्री में एक फ़ाइल बनाएं. इसके बाद, उन टारगेट संसाधनों की सूची बनाएं जिन्हें ओवरले किया जाना चाहिए और उनकी बदली गई वैल्यू. इसके बाद, <overlay> मेनिफ़ेस्ट टैग के android:resourcesMap एट्रिब्यूट की वैल्यू को, संसाधन मैपिंग फ़ाइल के रेफ़रंस पर सेट करें.

यहां दिया गया कोड, 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>

नीचे दिया गया कोड, ओवरले मेनिफ़ेस्ट का एक उदाहरण दिखाता है.

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

पैकेज बनाना

Android 11 या इसके बाद के वर्शन में, ओवरले के लिए Soong बिल्ड नियम काम करता है. यह नियम, Android एसेट पैकेजिंग टूल 2 (AAPT2) को एक ही वैल्यू (--no-resource-deduping) वाले संसाधनों के कॉन्फ़िगरेशन को डुप्लीकेट करने से रोकता है. साथ ही, डिफ़ॉल्ट कॉन्फ़िगरेशन (--no-resource-removal) के बिना संसाधनों को हटाने से भी रोकता है. नीचे दिए गए कोड में, Android.bp फ़ाइल का उदाहरण दिया गया है.

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

संसाधनों को हल करना

अगर किसी टारगेट रिसॉर्स या ओवरले रिसॉर्स में, क्वेरी किए गए संसाधन के लिए एक से ज़्यादा कॉन्फ़िगरेशन तय किए गए हैं, तो रिसॉर्स का रनटाइम उस कॉन्फ़िगरेशन की वैल्यू दिखाता है जो डिवाइस कॉन्फ़िगरेशन के कॉन्फ़िगरेशन से सबसे अच्छी तरह मेल खाता है. यह तय करने के लिए कि कौनसा कॉन्फ़िगरेशन सबसे ज़्यादा मैच करता है, ओवरले रिसॉर्स कॉन्फ़िगरेशन के सेट को टारगेट रिसॉर्स कॉन्फ़िगरेशन के सेट में मर्ज करें. इसके बाद, रिसॉर्स रिज़ॉल्यूशन के सामान्य फ़्लो का पालन करें. ज़्यादा जानकारी के लिए, Android सबसे ज़्यादा मैच करने वाला रिसॉर्स कैसे ढूंढता है लेख पढ़ें.

उदाहरण के लिए, अगर कोई ओवरले drawable-en कॉन्फ़िगरेशन के लिए कोई वैल्यू तय करता है और टारगेट drawable-en-port के लिए कोई वैल्यू तय करता है, तो drawable-en-port का बेहतर मैच होता है. इसलिए, टारगेट कॉन्फ़िगरेशन drawable-en-port की वैल्यू, रनटाइम पर चुनी जाती है. सभी drawable-en कॉन्फ़िगरेशन को ओवरले करने के लिए, ओवरले को टारगेट किए गए हर drawable-en कॉन्फ़िगरेशन के लिए एक वैल्यू तय करनी होगी.

ओवरले अपने खुद के संसाधनों का रेफ़रंस दे सकते हैं. इसमें, Android की रिलीज़ का तरीका अलग-अलग होता है.

  • Android 11 या उसके बाद के वर्शन में, हर ओवरले का अपना रिज़र्व किया गया रिसॉर्स आईडी स्पेस होता है. यह टारगेट रिसॉर्स आईडी स्पेस या अन्य ओवरले रिसॉर्स आईडी स्पेस को ओवरलैप नहीं करता. इसलिए, अपने रिसॉर्स का रेफ़रंस देने वाले ओवरले उम्मीद के मुताबिक काम करते हैं.

  • Android 10 या उससे पहले के वर्शन में, ओवरले और टारगेट पैकेज एक ही रिसॉर्स आईडी स्पेस शेयर करते हैं. इस वजह से, जब वे @type/name सिंटैक्स का इस्तेमाल करके अपने रिसॉर्स का रेफ़रंस देने की कोशिश करते हैं, तब टकराव और अनचाहा व्यवहार हो सकता है.

ओवरले चालू/बंद करें

बदलाव किए जा सकने वाले ओवरले को चालू और बंद करने के लिए, OverlayManager एपीआई का इस्तेमाल करें. इसके लिए, Context#getSystemService(Context.OVERLAY_SERVICE) का इस्तेमाल करके एपीआई इंटरफ़ेस को फिर से पाएं. किसी ओवरले को सिर्फ़ वह पैकेज चालू कर सकता है जिसे वह टारगेट करता है या android.permission.CHANGE_OVERLAY_PACKAGES अनुमति वाला पैकेज. जब कोई ओवरले चालू या बंद किया जाता है, तो कॉन्फ़िगरेशन में बदलाव करने वाले इवेंट, टारगेट पैकेज पर लागू होते हैं और टारगेट की गई गतिविधियां फिर से शुरू हो जाती हैं.

ओवरले किए जा सकने वाले संसाधनों पर पाबंदी लगाएं

Android 10 या उसके बाद के वर्शन में, <overlayable> एक्सएमएल टैग ऐसे संसाधनों का सेट दिखाता है जिन्हें आरआरओ, ओवरले कर सकते हैं. नीचे दिए गए उदाहरण में res/values/overlayable.xml फ़ाइल, string/foo और integer/bar ऐसे संसाधन हैं जिनका इस्तेमाल डिवाइस के लुक की थीम तय करने के लिए किया गया है. इन संसाधनों को ओवरले करने के लिए, एक ओवरले को साफ़ तौर पर, ओवरले किए जा सकने वाले रिसॉर्स के कलेक्शन को नाम से टारगेट करना होगा.

<!-- 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 में कई <overlayable> टैग तय किए जा सकते हैं. हालांकि, पैकेज में हर टैग का नाम अलग होना चाहिए. उदाहरण के लिए, यह:

  • दो अलग-अलग पैकेज के लिए ठीक है, ताकि दोनों <overlayable name="foo"> को तय कर सकें.

  • किसी एक APK के लिए दो <overlayable name="foo"> ब्लॉक होना ठीक नहीं है.

नीचे दिया गया कोड, 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>

जब कोई ऐप्लिकेशन <overlayable> टैग तय करता है, तो उस ऐप्लिकेशन को टारगेट करने वाले ओवरले:

  • targetName की वैल्यू देना ज़रूरी है.

  • सिर्फ़ <overlayable> टैग में मौजूद संसाधनों को ही ओवरले किया जा सकता है.

  • सिर्फ़ एक <overlayable> नाम को टारगेट किया जा सकता है.

किसी ऐसे पैकेज को टारगेट करने वाले ओवरले को चालू नहीं किया जा सकता जो ओवरले किए जा सकने वाले संसाधनों को दिखाता है, लेकिन किसी खास <overlayable> टैग को टारगेट करने के लिए android:targetName का इस्तेमाल नहीं करता.

नीतियों पर पाबंदी लगाएं

ओवरले किए जा सकने वाले संसाधनों पर पाबंदियां लागू करने के लिए, <policy> टैग का इस्तेमाल करें. type एट्रिब्यूट से पता चलता है कि शामिल किए गए संसाधनों को बदलने के लिए, ओवरले को किन नीतियों को पूरा करना होगा. इन टाइप की फ़ाइलें इस्तेमाल की जा सकती हैं.

  • public. कोई भी ओवरले, रिसॉर्स को बदल सकता है.
  • system. सिस्टम पार्टीशन पर मौजूद कोई भी ओवरले, रिसॉर्स को बदल सकता है.
  • vendor. वेंडर पार्टीशन पर कोई भी ओवरले, संसाधनों को बदल सकता है.
  • product. प्रॉडक्ट विभाजन पर मौजूद कोई भी ओवरले, संसाधनों को बदल सकता है.
  • oem. OEM पार्टीशन पर मौजूद कोई भी ओवरले, संसाधनों को बदल सकता है.
  • odm. ओडीएम पार्टीशन पर कोई भी ओवरले होने पर संसाधनों को बदला जा सकता है.
  • signature. टारगेट APK जैसे हस्ताक्षर से साइन किया गया कोई भी ओवरले, संसाधनों को बदल सकता है.
  • actor. actor APK के हस्ताक्षर से हस्ताक्षर किया गया कोई भी ओवरले, संसाधनों को बदल सकता है. सिस्टम कॉन्फ़िगरेशन में, कलाकार का नाम named-actor टैग में बताया गया है.
  • config_signature. overlay-config APK के साथ उसी हस्ताक्षर वाले किसी भी ओवरले से, संसाधनों को बदला जा सकता है. ओवरले-कॉन्फ़िगरेशन का एलान, सिस्टम कॉन्फ़िगरेशन में overlay-config-signature टैग में किया जाता है.

नीचे दिया गया कोड, res/values/overlayable.xml फ़ाइल में <policy> टैग का उदाहरण दिखाता है.

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

एक से ज़्यादा नीतियों की जानकारी देने के लिए, वर्टिकल बार (|) का इस्तेमाल सेपरेटर वर्णों के तौर पर करें. एक से ज़्यादा नीतियां तय करने पर, <policy> टैग में दिए गए संसाधनों को बदलने के लिए, ओवरले को सिर्फ़ एक नीति का पालन करना होगा.

ओवरले कॉन्फ़िगर करना

Android, Android रिलीज़ वर्शन के आधार पर ओवरले की म्यूटेबिलिटी, डिफ़ॉल्ट स्थिति, और प्राथमिकता कॉन्फ़िगर करने के अलग-अलग तरीकों के साथ काम करता है.

  • Android 11 या इसके बाद के वर्शन वाले डिवाइसों में, मेनिफ़ेस्ट एट्रिब्यूट के बजाय OverlayConfig फ़ाइल (config.xml) का इस्तेमाल किया जा सकता है. ओवरले फ़ाइल के लिए, ओवरले फ़ाइल का इस्तेमाल करने का सुझाव दिया जाता है.

  • स्टैटिक आरआरओ को कॉन्फ़िगर करने के लिए, सभी डिवाइस मेनिफ़ेस्ट एट्रिब्यूट (android:isStatic और android:priority) का इस्तेमाल कर सकते हैं.

ओवरले कॉन्फ़िगरेशन का इस्तेमाल करें

Android 11 या इसके बाद के वर्शन में, OverlayConfig का इस्तेमाल करके ओवरले की बदलाव करने की सुविधा, डिफ़ॉल्ट स्थिति, और प्राथमिकता को कॉन्फ़िगर किया जा सकता है. किसी ओवरले को कॉन्फ़िगर करने के लिए, partition/overlay/config/config.xml पर मौजूद फ़ाइल बनाएं या उसमें बदलाव करें. यहां partition, ओवरले का वह सेगमेंट है जिसे कॉन्फ़िगर करना है. कॉन्फ़िगर करने के लिए, ओवरले को उस सेगमेंट की overlay/ डायरेक्ट्री में ही रखना चाहिए जिसमें ओवरले को कॉन्फ़िगर किया गया है. यहां दिया गया कोड, 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>"

<overlay> टैग के लिए package एट्रिब्यूट की ज़रूरत होती है. इससे पता चलता है कि किस ओवरले पैकेज को कॉन्फ़िगर किया जा रहा है. ज़रूरी नहीं enabled एट्रिब्यूट यह कंट्रोल करता है कि ओवरले डिफ़ॉल्ट रूप से चालू है या नहीं (डिफ़ॉल्ट रूप से false). ज़रूरी नहीं mutable एट्रिब्यूट यह कंट्रोल करता है कि ओवरले में बदलाव किया जा सकता है या नहीं और क्या रनटाइम के दौरान, प्रोग्राम के हिसाब से इसकी चालू स्थिति में बदलाव किया जा सकता है (डिफ़ॉल्ट रूप से true). कॉन्फ़िगरेशन फ़ाइल में शामिल नहीं किए गए ओवरले में बदलाव किया जा सकता है और वे डिफ़ॉल्ट रूप से बंद होते हैं.

ओवरले की प्राथमिकता

जब एक ही रिसॉर्स पर कई ओवरले लागू होते हैं, तो ओवरले का क्रम ज़रूरी हो जाता है. किसी ओवरले को, अपने कॉन्फ़िगरेशन से पहले कॉन्फ़िगर किए गए ओवरले के मुकाबले ज़्यादा प्राथमिकता दी जाती है. अलग-अलग पार्टीशन में ओवरले के प्राथमिकता का क्रम (सबसे कम से सबसे ज़्यादा प्राथमिकता) नीचे दिया गया है.

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

फ़ाइलें मर्ज करें

<merge> टैग का इस्तेमाल करके, कॉन्फ़िगरेशन फ़ाइल में तय की गई जगह पर अन्य कॉन्फ़िगरेशन फ़ाइलों को मर्ज किया जा सकता है. टैग का path एट्रिब्यूट, ओवरले कॉन्फ़िगरेशन फ़ाइलों वाली डायरेक्ट्री के हिसाब से, मर्ज की जाने वाली फ़ाइल का पाथ दिखाता है.

मेनिफ़ेस्ट एट्रिब्यूट/स्टैटिक आरआरओ का इस्तेमाल करना

Android 10 या उससे पहले के वर्शन में, ओवरले में बदलाव न होने की सेटिंग और प्राथमिकता को इन मेनिफ़ेस्ट एट्रिब्यूट का इस्तेमाल करके कॉन्फ़िगर किया जाता है.

  • android:isStatic. जब इस बूलियन एट्रिब्यूट की वैल्यू true पर सेट की जाती है, तो ओवरले डिफ़ॉल्ट रूप से चालू हो जाता है और इसे बदला नहीं जा सकता. इससे ओवरले को बंद होने से रोका जाता है.

  • android:priority. जब एक से ज़्यादा स्टैटिक ओवरले एक ही संसाधन की वैल्यू को टारगेट करते हैं, तो इस अंकों वाले एट्रिब्यूट की वैल्यू (जो सिर्फ़ स्टैटिक ओवरले पर असर डालती है) से ओवरले की प्राथमिकता कॉन्फ़िगर होती है. बड़ी संख्या का मतलब है कि वरीयता ज़्यादा है.

नीचे दिया गया कोड, 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>

Android 11 में हुए बदलाव

Android 11 या उसके बाद के वर्शन में, अगर कोई कॉन्फ़िगरेशन फ़ाइल partition/overlay/config/config.xml में मौजूद है, तो ओवरले उस फ़ाइल का इस्तेमाल करके कॉन्फ़िगर किए जाते हैं. साथ ही, android:isStatic और android:priority का, सेगमेंट में मौजूद ओवरले पर कोई असर नहीं पड़ता. किसी भी पार्टीशन में ओवरले कॉन्फ़िगरेशन फ़ाइल तय करने से ओवरले पार्टीशन की प्राथमिकता लागू होती है.

इसके अलावा, Android 11 या उसके बाद के वर्शन में, पैकेज इंस्टॉल करने के दौरान पढ़े जाने वाले रिसॉर्स की वैल्यू पर असर डालने के लिए, स्टैटिक ओवरले का इस्तेमाल नहीं किया जा सकता. कॉम्पोनेंट के चालू होने की स्थिति को कॉन्फ़िगर करने वाले बूलियन की वैल्यू बदलने के लिए, स्टैटिक ओवरले का इस्तेमाल करने के सामान्य इस्तेमाल के उदाहरण के लिए, <component-override> SystemConfig टैग (Android 11 में नया) इस्तेमाल करें.

ओवरले डीबग करें

ओवरले को मैन्युअल तरीके से चालू, बंद, और डंप करने के लिए, इस ओवरले मैनेजर शेल कमांड का इस्तेमाल करें.

adb shell cmd overlay

OverlayManagerService, idmap2 का इस्तेमाल करके टारगेट पैकेज के रिसॉर्स आईडी को ओवरले पैकेज के रिसॉर्स आईडी से मैप करता है. जनरेट की गई आईडी मैपिंग, /data/resource-cache/ में सेव की जाती हैं. अगर आपका ओवरले सही से काम नहीं कर रहा है, तो /data/resource-cache/ में अपने ओवरले के लिए मिलती-जुलती idmap फ़ाइल ढूंढें. इसके बाद, नीचे दिया गया निर्देश चलाएं.

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

यह कमांड, संसाधनों की मैपिंग को नीचे दिखाए गए तरीके से प्रिंट करता है.

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