مقدار منابع یک برنامه را در زمان اجرا تغییر دهید

پوشش منبع زمان اجرا (RRO) بسته ای است که مقادیر منابع بسته هدف را در زمان اجرا تغییر می دهد. به عنوان مثال، یک برنامه نصب شده روی تصویر سیستم ممکن است رفتار خود را بر اساس مقدار یک منبع تغییر دهد. به جای اینکه مقدار منبع را در زمان ساخت کدگذاری کند، یک RRO نصب شده روی یک پارتیشن متفاوت می تواند مقادیر منابع برنامه را در زمان اجرا تغییر دهد.

RRO ها را می توان فعال یا غیرفعال کرد. شما می توانید به صورت برنامه نویسی حالت فعال/غیرفعال را برای تغییر توانایی RRO برای تغییر مقادیر منابع تنظیم کنید. RRO ها به طور پیش فرض غیرفعال هستند (با این حال، RRO های ثابت به طور پیش فرض فعال هستند).

منابع همپوشانی

همپوشانی ها با نگاشت منابع تعریف شده در بسته همپوشانی به منابع تعریف شده در بسته هدف کار می کنند. هنگامی که یک برنامه سعی می کند مقدار یک منبع را در بسته هدف حل کند، به جای آن، مقدار منبع پوششی که منبع هدف به آن نگاشت شده است، برمی گردد.

مانیفست را تنظیم کنید

یک بسته اگر حاوی یک تگ <overlay> به عنوان فرزند تگ <manifest> باشد، یک بسته RRO در نظر گرفته می شود.

  • مقدار ویژگی 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 داشته باشند. علاوه بر این، ویژگی android:hasCode تگ <application > در مانیفست باید روی false تنظیم شود.

نقشه منابع را تعریف کنید

در اندروید 11 یا بالاتر، مکانیسم توصیه شده برای تعریف نقشه منابع همپوشانی این است که یک فایل در دایرکتوری res/xml بسته همپوشانی ایجاد کنید، منابع هدفی را که باید روی هم قرار گیرند و مقادیر جایگزین آنها را برشمردید، سپس مقدار android:resourcesMap ویژگی تگ مانیفست <overlay> به یک مرجع به فایل نقشه برداری منبع.

کد زیر نمونه ای از فایل 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 برای پوشش‌ها پشتیبانی می‌کند که از تلاش برای حذف پیکربندی منابع با همان مقدار ( --no-resource-deduping ) و حذف منابع بدون تنظیمات پیش‌فرض ( --no-resource-removal جلوگیری می‌کند. --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 11 یا بالاتر، هر همپوشانی فضای شناسه منبع رزرو شده خود را دارد که با فضای شناسه منبع هدف یا دیگر فضاهای شناسه منبع همپوشانی همپوشانی ندارد، بنابراین همپوشانی‌هایی که به منابع خود ارجاع می‌دهند همانطور که انتظار می‌رود کار می‌کنند.

  • در Android 10 یا پایین‌تر، همپوشانی‌ها و بسته‌های هدف از فضای شناسه منبع یکسانی استفاده می‌کنند، که می‌تواند باعث برخورد و رفتار غیرمنتظره‌ای شود که آنها سعی می‌کنند با استفاده از نحو @type/name به منابع خود ارجاع دهند.

فعال/غیرفعال کردن همپوشانی ها

از OverlayManager API برای فعال و غیرفعال کردن همپوشانی های قابل تغییر استفاده کنید (واسط API را با استفاده از Context#getSystemService(Context.OVERLAY_SERVICE) بازیابی کنید). یک پوشش را فقط می‌توان توسط بسته‌ای که هدفش قرار می‌دهد یا بسته‌ای با مجوز android.permission.CHANGE_OVERLAY_PACKAGES فعال کرد. هنگامی که یک پوشش فعال یا غیرفعال می شود، رویدادهای تغییر پیکربندی به بسته هدف منتشر می شود و فعالیت های هدف مجدداً راه اندازی می شود.

منابع قابل همپوشانی را محدود کنید

در Android 10 یا بالاتر، تگ <overlayable> XML مجموعه‌ای از منابع را نشان می‌دهد که RROها مجاز به همپوشانی هستند. در مثال زیر فایل 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> تعریف کند، اما هر تگ باید یک نام منحصر به فرد در بسته داشته باشد. مثلاً این است:

  • OK برای دو بسته مختلف برای تعریف <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> را هدف قرار دهد.

نمی‌توانید پوششی را فعال کنید که بسته‌ای را هدف قرار می‌دهد که منابع قابل همپوشانی را نشان می‌دهد، اما از android:targetName برای هدف‌گیری یک برچسب <overlayable> خاص استفاده نمی‌کند.

سیاست ها را محدود کنید

از تگ <policy> برای اعمال محدودیت در منابع قابل همپوشانی استفاده کنید. ویژگی type مشخص می‌کند که یک همپوشانی باید چه سیاست‌هایی را برای نادیده گرفتن منابع موجود انجام دهد. انواع پشتیبانی شده شامل موارد زیر است.

  • public . هر پوششی می تواند منبع را لغو کند.
  • system . هر گونه پوشش روی پارتیشن سیستم می تواند منابع را لغو کند.
  • vendor . هر گونه پوشش روی پارتیشن فروشنده می تواند منابع را لغو کند.
  • product . هر گونه پوشش روی پارتیشن محصول می تواند منابع را لغو کند.
  • oem . هر گونه پوشش روی پارتیشن oem می تواند منابع را لغو کند.
  • odm . هر گونه پوشش روی پارتیشن odm می تواند منابع را لغو کند.
  • signature . هر پوششی که با امضای مشابه APK هدف امضا شود، می‌تواند منابع را لغو کند.
  • actor . هر پوششی که با همان امضای APK بازیگر امضا شده باشد، می‌تواند منابع را لغو کند. بازیگر در تگ named-actor در پیکربندی سیستم اعلان می شود.
  • config_signature . هر پوششی که با امضای مشابه apk overlay-config امضا شود، می‌تواند منابع را لغو کند. overlay-config در تگ overlay-config-signature در پیکربندی سیستم اعلام شده است.

کد زیر نمونه ای از تگ <policy> را در فایل 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>

برای تعیین چندین خط مشی، از نوارهای عمودی (|) به عنوان کاراکترهای جداکننده استفاده کنید. هنگامی که چندین خط مشی مشخص می شود، یک پوشش باید تنها یک خط مشی را اجرا کند تا منابع فهرست شده در برچسب <policy> را لغو کند.

همپوشانی ها را پیکربندی کنید

اندروید از مکانیسم‌های مختلفی برای پیکربندی تغییرپذیری، وضعیت پیش‌فرض و اولویت پوشش‌ها بسته به نسخه نسخه اندروید پشتیبانی می‌کند.

  • دستگاه‌های دارای Android 11 یا بالاتر می‌توانند از فایل OverlayConfig ( config.xml ) به جای ویژگی‌های مانیفست استفاده کنند. استفاده از فایل همپوشانی روش توصیه شده برای همپوشانی است.

  • همه دستگاه‌ها می‌توانند از ویژگی‌های مانیفست ( android:isStatic و android:priority ) برای پیکربندی RRO‌های استاتیک استفاده کنند.

از OverlayConfig استفاده کنید

در اندروید 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 تگ نشان دهنده مسیر فایل برای ادغام نسبت به دایرکتوری حاوی فایل های پیکربندی همپوشانی است.

از ویژگی‌های مانیفست/RRO استاتیک استفاده کنید

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

تغییرات اندروید 11

در Android 11 یا بالاتر، اگر یک فایل پیکربندی در partition/overlay/config/config.xml قرار داشته باشد، همپوشانی‌ها با استفاده از آن فایل پیکربندی می‌شوند و android:isStatic و android:priority روی هم‌پوشانی‌های واقع در پارتیشن تأثیری ندارند. تعریف یک فایل پیکربندی همپوشانی در هر پارتیشن، اولویت پارتیشن همپوشانی را اعمال می کند.

علاوه بر این، اندروید 11 یا بالاتر، امکان استفاده از همپوشانی استاتیک برای تأثیرگذاری بر مقادیر منابع خوانده شده در حین نصب بسته را حذف می کند. برای استفاده رایج از استفاده از همپوشانی های ایستا برای تغییر مقدار بولی ها که حالت فعال مولفه را پیکربندی می کنند، از تگ <component-override> SystemConfig (جدید در Android 11) استفاده کنید.

اشکال زدایی همپوشانی ها

برای فعال کردن، غیرفعال کردن و حذف هم‌پوشانی‌ها به صورت دستی، از دستور پوسته مدیر پوشش زیر استفاده کنید.

adb shell cmd overlay

OverlayManagerService از idmap2 برای نگاشت شناسه های منبع در بسته هدف به شناسه های منبع در بسته همپوشانی استفاده می کند. نگاشت شناسه های تولید شده در /data/resource-cache/ ذخیره می شوند. اگر همپوشانی شما به درستی کار نمی کند، فایل idmap مربوطه را برای پوشش خود در /data/resource-cache/ پیدا کنید، سپس دستور زیر را اجرا کنید.

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