تغيير قيمة موارد التطبيق في وقت التشغيل

تراكب الموارد في وقت التشغيل (RRO) هو حزمة تغيّر قيم الموارد لحزمة مستهدَفة في وقت التشغيل. على سبيل المثال، قد يغيّر تطبيق مثبَّت على صورة النظام سلوكه استنادًا إلى قيمة أحد الموارد. بدلاً من الترميز الثابت لقيمة المورد في وقت الإنشاء، يمكن أن يغيّر RRO مثبَّت على قسم مختلف قيم موارد التطبيق في وقت التشغيل.

يمكن تفعيل أو إيقاف RRO. يمكنك ضبط حالة التفعيل/الإيقاف برمجيًا لتبديل قدرة حزمة RRO على تغيير قيم الموارد. تكون حِزم RRO غير مفعَّلة تلقائيًا (ومع ذلك، تكون حِزم RRO الثابتة مفعَّلة تلقائيًا).

موارد التراكب

تعمل التراكبات من خلال ربط الموارد المحدّدة في حزمة التراكب بالموارد المحدّدة في الحزمة المستهدَفة. عندما يحاول تطبيق تحديد قيمة أحد الموارد في الحزمة المستهدَفة، يتم عرض قيمة المورد المتراكب الذي يتم ربط المورد المستهدَف به بدلاً من ذلك.

إعداد ملف البيان

تُعدّ الحزمة حزمة 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.

تحديد خريطة الموارد

في نظام التشغيل Android 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 Asset Packaging Tool 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.

تفعيل التراكبات أو إيقافها

يمكن تفعيل/إيقاف التراكبات يدويًا وبرمجيًا.

إيقاف التراكبات أو تفعيلها يدويًا

لتفعيل 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

تفعيل التراكبات أو إيقافها آليًا

استخدِم واجهة برمجة التطبيقات OverlayManager لتفعيل وإيقاف التراكبات القابلة للتغيير (استرجِع واجهة برمجة التطبيقات باستخدام Context#getSystemService(Context.OVERLAY_SERVICE)). ولا يمكن تفعيل التراكب إلا من خلال الحزمة التي يستهدفها أو من خلال حزمة لديها إذن android.permission.CHANGE_OVERLAY_PACKAGES. عند تفعيل أو إيقاف تراكب، تنتقل أحداث تغيير الإعدادات إلى الحزمة المستهدَفة، ويتم إعادة تشغيل الأنشطة المستهدَفة.

حظر الموارد التي يمكن عرضها كطبقة

في الإصدار 10 من نظام التشغيل Android أو الإصدارات الأحدث، تعرض علامة 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">.

يعرض الرمز التالي مثالاً على تراكب في ملف 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 في ملف system config.
  • 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 آليات مختلفة لضبط إمكانية التغيير والحالة التلقائية والأولوية الخاصة بالتراكبات، وذلك حسب إصدار Android.

  • يمكن للأجهزة التي تعمل بالإصدار 11 من نظام التشغيل Android أو الإصدارات الأحدث استخدام ملف OverlayConfig (config.xml) بدلاً من سمات ملف البيان. يُنصح باستخدام ملف تراكب لإنشاء تراكبات.

  • يمكن لجميع الأجهزة استخدام سمات البيان (android:isStatic وandroid:priority) لضبط عمليات RRO الثابتة.

استخدام OverlayConfig

في الإصدار 11 من نظام التشغيل Android أو الإصدارات الأحدث، يمكنك استخدام 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 الخاصة بالعلامة مسار الملف الذي سيتم دمجه بالنسبة إلى الدليل الذي يحتوي على ملفات إعدادات التراكب.

استخدام سمات ملف البيان/عمليات تراكب الموارد الثابتة فقط

في الإصدار 10 من نظام التشغيل Android أو الإصدارات الأقدم، يتم ضبط ثبات التراكب وأولويته باستخدام سمات البيان التالية.

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

تراكبات تصحيح الأخطاء

لتفعيل الطبقات المتراكبة وإيقافها وإفراغها يدويًا، استخدِم أمر shell التالي الخاص بأداة إدارة الطبقات المتراكبة.

adb shell cmd overlay

يؤثر استخدام enable بدون تحديد مستخدم في المستخدم الحالي، أي مستخدم النظام (userId = 0) الذي يملك واجهة مستخدم النظام. ولا يؤثّر ذلك في المستخدم النشط (userId = 10) الذي يملك التطبيقات. لتفعيل RRO للمستخدم الذي يعمل في المقدّمة، استخدِم المَعلمة –-user 10:

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

يستخدم 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