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

تراكب الموارد في وقت التشغيل (RRO) هو حزمة تغيّر قيم الموارد لحزمة مستهدَفة في وقت التشغيل. على سبيل المثال، قد يغيّر تطبيق مثبَّت على ملف ‎system image سلوكه استنادًا إلى قيمة أحد الموارد. بدلاً من ترميز قيمة المورد بشكلٍ ثابت في وقت الإنشاء، يمكن أن يؤدي تثبيت حزمة 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.

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

في الإصدار 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>

إنشاء الحزمة

يتوافق نظام التشغيل 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 من 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) الذي يملك SystemUI. لا تؤثّر هذه التعليمات في التطبيقات التي يبدأها المستخدم المرئي (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> مجموعة من الموارد التي يُسمح لتطبيقات 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. يمكن لأيّ تراكب على قسم الشركة المصنّعة للجهاز إلغاء الموارد.
  • odm. يمكن لأيّ تراكب على قسم odm إلغاء الموارد.
  • signature. يمكن أن تُلغي أي طبقة أساسية موقَّعة بالتوقيع نفسه المستخدَم في حزمة APK المستهدَفة الموارد.
  • actor. يمكن أن تؤدي أي طبقة مثبّتة موقَّعة بالتوقيع نفسه لحزمة APK الخاصة بالممثّل إلى إلغاء الموارد. يتمّ الإعلان عن الفاعل في علامة named-actor في system config.
  • config_signature. يمكن لأي عنصر مصغّر موقَّع بالتوقيع نفسه لحزمة APK 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 هو قسم الصورة المركّبة المطلوب ضبطه. لكي يتم ضبط الصورة المتراكبة، يجب أن تكون موجودة في الدليل 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).

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

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

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