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

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

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

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

همپوشانی‌ها با نگاشت منابع تعریف‌شده در بسته‌ی overlay به منابع تعریف‌شده در بسته‌ی target کار می‌کنند. وقتی یک برنامه سعی می‌کند مقدار یک منبع را در بسته‌ی target تشخیص دهد، مقدار منبع overlay که منبع target به آن نگاشت شده است، به جای آن بازگردانده می‌شود.

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

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

  • مقدار ویژگی مورد نیاز 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 تنظیم شود.

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

در اندروید ۱۱ یا بالاتر، مکانیزم توصیه‌شده برای تعریف نقشه منابع overlay، ایجاد یک فایل در دایرکتوری res/xml از پکیج overlay، شمارش منابع هدفی که باید overlay شوند و مقادیر جایگزینی آنها، و سپس تنظیم مقدار ویژگی android:resourcesMap از تگ manifest <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>

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

ساخت بسته

اندروید ۱۱ یا بالاتر از یک قانون ساخت Soong برای overlayها پشتیبانی می‌کند که مانع از تلاش ابزار بسته‌بندی دارایی‌های اندروید ۲ (AAPT2) برای حذف پیکربندی‌های منابع با مقدار یکسان ( --no-resource-deduping ) و حذف منابع بدون پیکربندی‌های پیش‌فرض ( --no-resource-removal ) می‌شود. کد زیر نمونه‌ای از یک فایل Android.bp را نشان می‌دهد.

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

حل منابع

اگر یک منبع هدف یا منبع پوششی، پیکربندی‌های متعددی برای منبع مورد جستجو تعریف کرده باشد، زمان اجرای منابع، مقدار پیکربندی‌ای را برمی‌گرداند که به بهترین وجه با پیکربندی پیکربندی دستگاه مطابقت دارد. برای تعیین اینکه کدام پیکربندی بهترین پیکربندی منطبق است، مجموعه پیکربندی‌های منبع پوششی را در مجموعه پیکربندی‌های منبع هدف ادغام کنید و سپس جریان معمول تفکیک منبع را دنبال کنید (برای جزئیات بیشتر، به « چگونه اندروید بهترین منبع منطبق را پیدا می‌کند » مراجعه کنید).

برای مثال، اگر یک overlay مقداری را برای پیکربندی drawable-en تعریف کند و target مقداری را برای drawable-en-port تعریف کند، drawable-en-port تطابق بهتری دارد، بنابراین مقدار پیکربندی target یعنی drawable-en-port در زمان اجرا انتخاب می‌شود. برای همپوشانی همه پیکربندی‌های drawable-en ، overlay باید برای هر پیکربندی drawable-en که target تعریف می‌کند، مقداری تعریف کند.

همپوشانی‌ها می‌توانند به منابع خود ارجاع دهند، که رفتارهای متفاوتی بین نسخه‌های اندروید دارد.

  • در اندروید ۱۱ یا بالاتر، هر overlay فضای شناسه منبع رزرو شده خود را دارد که با فضای شناسه منبع هدف یا سایر فضاهای شناسه منبع overlay همپوشانی ندارد، بنابراین overlayهایی که به منابع خود ارجاع می‌دهند، همانطور که انتظار می‌رود کار می‌کنند.

  • در اندروید ۱۰ یا پایین‌تر، overlayها و بسته‌های هدف، فضای شناسه منبع یکسانی را به اشتراک می‌گذارند که می‌تواند باعث تصادم و رفتار غیرمنتظره هنگام تلاش برای ارجاع به منابع خود با استفاده از سینتکس @type/name شود.

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

پوشش‌ها می‌توانند به صورت دستی و از طریق برنامه‌نویسی فعال/غیرفعال شوند.

غیرفعال کردن یا فعال کردن دستی پوشش‌ها

برای فعال کردن و تأیید دستی RRO، دستور زیر را اجرا کنید:

adb shell cmd overlay enable --user current com.example.carrro
adb shell cmd overlay list --user current | grep -i com.example com.example.carrro

این دستور RRO را برای کاربر سیستم ( userId = 0 ) که مالک SystemUI است، فعال می‌کند. این دستور روی برنامه‌هایی که توسط کاربر پیش‌زمینه ( userId = 10 ) اجرا می‌شوند، تأثیری ندارد. برای فعال کردن RRO برای کاربر پیش‌زمینه، از پارامتر -–user 10 استفاده کنید:

adb shell cmd overlay enable --user 10 com.example.carrro

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

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

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

در اندروید ۱۰ یا بالاتر، تگ XML <overlayable> مجموعه‌ای از منابع را که 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"> داشته باشد، درست نیست.

کد زیر نمونه‌ای از یک overlay را در فایل 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> را تعریف می‌کند، overlayها آن برنامه را هدف قرار می‌دهند:

  • باید targetName مشخص کنید.

  • فقط می‌تواند منابع فهرست‌شده در تگ <overlayable> را همپوشانی کند.

  • می‌تواند فقط یک نام <overlayable> را هدف قرار دهد.

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

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

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

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

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

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

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

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

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

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

در اندروید ۱۱ یا بالاتر، می‌توانید از OverlayConfig برای پیکربندی تغییرپذیری، حالت پیش‌فرض و اولویت overlayها استفاده کنید. برای پیکربندی یک overlay، فایل واقع در partition/overlay/config/config.xml را ایجاد یا تغییر دهید، که در آن partition پارتیشنی است که قرار است overlay پیکربندی شود. برای پیکربندی، یک overlay باید در دایرکتوری overlay/ پارتیشنی که 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 نیاز دارد که نشان می‌دهد کدام بسته overlay در حال پیکربندی است. ویژگی اختیاری enabled کنترل می‌کند که آیا overlay به طور پیش‌فرض فعال است یا خیر (پیش‌فرض false است). ویژگی اختیاری mutable کنترل می‌کند که آیا overlay قابل تغییر است یا خیر و آیا می‌توان وضعیت فعال بودن آن را در زمان اجرا به صورت برنامه‌نویسی تغییر داد یا خیر (پیش‌فرض true است). overlayهایی که در یک فایل پیکربندی فهرست نشده‌اند، قابل تغییر و به طور پیش‌فرض غیرفعال هستند.

اولویت همپوشانی

وقتی چندین overlay منابع یکسانی را نادیده می‌گیرند، ترتیب overlayها مهم است. یک overlay نسبت به overlayهایی که پیکربندی‌هایشان مقدم بر پیکربندی خودشان است، اولویت بیشتری دارد. ترتیب اولویت overlayها در پارتیشن‌های مختلف (از کمترین اولویت به بیشترین اولویت) به شرح زیر است.

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

ادغام فایل‌ها

استفاده از تگ‌های <merge> امکان ادغام سایر فایل‌های پیکربندی را در موقعیت مشخص‌شده در فایل پیکربندی فراهم می‌کند. ویژگی path این تگ، مسیر فایلی را که باید ادغام شود، نسبت به دایرکتوری حاوی فایل‌های پیکربندی پوششی نشان می‌دهد.

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

در اندروید ۱۰ یا پایین‌تر، تغییرناپذیری و اولویت overlay با استفاده از ویژگی‌های manifest زیر پیکربندی می‌شوند.

  • android:isStatic . وقتی مقدار این ویژگی بولی روی true تنظیم شود، overlay به طور پیش‌فرض فعال و تغییرناپذیر می‌شود، که از غیرفعال شدن overlay جلوگیری می‌کند.

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

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

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

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

اشکال‌زدایی پوشش‌ها

برای فعال، غیرفعال و حذف دستی overlayها، از دستور shell manager زیر استفاده کنید.

adb shell cmd overlay

استفاده از enable بدون مشخص کردن کاربر، کاربر فعلی، یعنی کاربر سیستم ( userId = 0 ) که مالک رابط کاربری سیستم است را تحت تأثیر قرار می‌دهد. این امر بر کاربر پیش‌زمینه ( userId = 10 ) که مالک برنامه‌ها است، تأثیری ندارد. برای فعال کردن RRO برای کاربر پیش‌زمینه، از پارامتر –-user 10 استفاده کنید:

adb shell cmd overlay enable --user 10 com.example.carrro

OverlayManagerService از idmap2 برای نگاشت شناسه‌های منابع در بسته‌ی هدف به شناسه‌های منابع در بسته‌ی overlay استفاده می‌کند. نگاشت‌های شناسه‌ی تولید شده در /data/resource-cache/ ذخیره می‌شوند. اگر overlay شما به درستی کار نمی‌کند، فایل idmap مربوطه را برای overlay خود در /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