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

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

يمكن تمكين أو تعطيل RROs. يمكنك تعيين حالة التمكين / التعطيل برمجيًا لتبديل قدرة RRO على تغيير قيم الموارد. يتم تعطيل RROs بشكل افتراضي (ومع ذلك ، يتم تمكين RROs ثابت بشكل افتراضي).

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

تعمل التراكبات عن طريق تعيين الموارد المحددة في حزمة التراكب إلى الموارد المحددة في الحزمة الهدف. عندما يحاول أحد التطبيقات حل قيمة مورد في الحزمة الهدف ، يتم إرجاع قيمة مورد التراكب الذي تم تعيين المورد الهدف إليه بدلاً من ذلك.

إعداد البيان

تعتبر الحزمة حزمة 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 syntax.

تمكين / تعطيل التراكبات

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

تقييد الموارد القابلة للتراكب

في Android 10 أو إصدار أحدث ، تعرض علامة XML <overlayable> مجموعة من الموارد التي يُسمح لـ RROs بتراكبها. في المثال التالي ملف 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 للممثل تجاوز الموارد. تم الإعلان عن الممثل في علامة فاعل مسمى في تكوين النظام.
  • config_signature . يمكن لأي تراكب موقع بنفس التوقيع مثل overlay-config apk تجاوز الموارد. يتم الإعلان عن التراكب-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.

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

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

باستخدام OverlayConfig

في Android 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
  • odm
  • oem
  • product
  • system_ext

دمج الملفات

يسمح استخدام علامات <merge> ملفات التكوين الأخرى في الموضع المحدد في ملف التكوين. تمثل سمة path للعلامة مسار الملف المراد دمجه بالنسبة إلى الدليل الذي يحتوي على ملفات تكوين التراكب.

استخدام سمات البيان (ثابت RROs)

في 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>

التغييرات في Android 11

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

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

تراكبات التصحيح

لتمكين التراكبات وتعطيلها وتفريغها يدويًا ، استخدم أمر shell manager التالي.

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