پوشش منابع زمان اجرا (RRO)

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

  • برای دو بسته مختلف برای تعریف <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 . هر گونه پوشش روی پارتیشن محصول می تواند منابع را لغو کند.
  • signature . هر پوششی که با امضای مشابه APK هدف امضا شده باشد، می‌تواند منابع را لغو کند.

کد زیر نمونه ای از تگ <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 از مکانیسم‌های مختلفی برای پیکربندی تغییرپذیری، وضعیت پیش‌فرض و اولویت پوشش‌ها بسته به نسخه نسخه اندروید پشتیبانی می‌کند.

  • دستگاه‌های دارای 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
  • oem
  • odm
  • 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