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

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

يمكن تفعيل تراكبات الموارد في وقت التشغيل أو إيقافها. يمكنك ضبط حالة التفعيل أو الإيقاف آليًا لتبديل قدرة تراكب الموارد في وقت التشغيل على تغيير قيم الموارد. تكون تراكبات الموارد في وقت التشغيل غير مفعَّلة تلقائيًا (ولكن يتم تفعيل تراكبات الموارد في وقت التشغيل الثابتة تلقائيًا ).

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

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

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

تُعتبَر الحزمة حزمة تراكب موارد في وقت التشغيل إذا كانت تحتوي على علامة <overlay> كعنصر فرعي من العلامة <manifest>

  • تحدّد قيمة السمة android:targetPackage المطلوبة اسم الحزمة التي ينوي تراكب الموارد في وقت التشغيل تراكبها.

  • تحدّد قيمة السمة android:targetName الاختيارية اسم مجموعة فرعية من الموارد القابلة للتراكب في الحزمة المستهدَفة التي ينوي تراكب الموارد في وقت التشغيل تراكبها. إذا لم يحدّد الهدف مجموعة موارد قابلة للتراكب، يجب ألا تكون هذه السمة موجودة.

يعرض الرمز التالي مثالاً على تراكب 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> في ملف البيان على set to false.

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

في الإصدار 11 من نظام Android أو الإصدارات الأحدث، الآلية المقترَحة لـ تحديد خريطة موارد التراكب هي إنشاء ملف في دليل 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>

إنشاء الحزمة

يتوافق الإصدار 11 من نظام Android أو الإصدارات الأحدث مع قاعدة إنشاء Soong للتراكبات التي تمنع أداة تجميع الموارد في Android‏ (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 من نظام Android أو الإصدارات الأقدم، تتشارك التراكبات والحِزم المستهدَفة مساحة معرّفات الموارد نفسها، ما قد يؤدي إلى حدوث تعارضات وسلوك غير متوقّع عندما تحاول الإشارة إلى مواردها الخاصة باستخدام البنية @type/name.

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

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

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

لتفعيل تراكب الموارد في وقت التشغيل والتحقّق منه يدويًا، نفِّذ ما يلي:

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

يؤدي هذا إلى تفعيل تراكب الموارد في وقت التشغيل لمستخدم النظام (userId = 0) الذي يملك واجهة مستخدم النظام. لا يؤثّر هذا التعليم في التطبيقات التي يبدأها المستخدم في المقدّمة (userId = 10). لتفعيل تراكب الموارد في وقت التشغيل للمستخدم في المقدّمة، استخدِم المَعلمة -–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> مجموعة من الموارد التي يُسمح لتراكبات الموارد في وقت التشغيل بتراكبها. في المثال التالي لملف 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: يمكن لأي تراكب على قسم الشركة المصنّعة للمعدات الأصلية تجاوز الموارد.
  • 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 آليات مختلفة لضبط قابلية التغيير والحالة التلقائية والأولوية للتراكبات استنادًا إلى نسخة إصدار Android.

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

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

استخدام OverlayConfig

في الإصدار 11 من نظام Android أو الإصدارات الأحدث، يمكنك استخدام OverlayConfig لضبط قابلية التغيير والحالة التلقائية والأولوية للتراكبات. لضبط تراكب، أنشِئ الملف الموجود في partition/overlay/config/config.xml أو عدِّله، حيث partition هو قسم التراك101}ب الذي سيتم ضبطه. لكي يتم ضبط التراكب، يجب أن يكون موجودًا في الدليل 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>

التغييرات في الإصدار 11 من نظام Android

في الإصدار 11 من نظام Android أو الإصدارات الأحدث، إذا كان ملف الإعداد موجودًا في partition/overlay/config/config.xml، يتم ضبط التراكبات باستخدام هذا الملف ولا تؤثّر android:isStatic وandroid:priority في التراكبات الموجودة في القسم. يفرض تحديد ملف إعداد تراكب في أي قسم أولوية قسم التراكب.

بالإضافة إلى ذلك، يزيل الإصدار 11 من نظام Android أو الإصدارات الأحدث إمكانية استخدام التراكبات الثابتة للتأثير في قيم الموارد التي تتم قراءتها أثناء تثبيت الحزمة. في حالة الاستخدام الشائعة للتراكبات الثابتة لتغيير الـ قيمة للقيم المنطقية التي تضبط حالة تفعيل المكوّن، استخدِم الـ <component-override> SystemConfig علامة (الجديدة في نظام Android 11).

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

لتفعيل التراكبات وإيقافها وعرضها يدويًا، استخدِم أمر shell التالي لمدير التراكب:

adb shell cmd overlay

يؤثّر استخدام enable بدون تحديد مستخدم في المستخدم الحالي، أي مستخدم النظام (userId = 0) الذي يملك واجهة مستخدم النظام. لا يؤثّر هذا في المستخدم في المقدّمة (userId = 10) الذي يملك التطبيقات. لتفعيل تراكب الموارد في وقت التشغيل للمستخدم في المقدّمة، استخدِم المَعلمة –-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