تتيح لك وحدات الميزات فصل ميزات وموارد معيّنة عن الوحدة الأساسية لتطبيقك وتضمينها في حزمة التطبيق. من خلال ميزة "عرض الميزات في Play"، يمكن للمستخدمين، على سبيل المثال، تنزيل هذه المكوّنات وتثبيتها لاحقًا عند الطلب بعد تثبيت حزمة APK الأساسية لتطبيقك.
على سبيل المثال، لنفترض أنّ هناك تطبيقًا للرسائل النصية يتضمّن وظيفة لالتقاط رسائل الصور وإرسالها، ولكن نسبة صغيرة فقط من المستخدمين ترسل رسائل الصور. قد يكون من المنطقي تضمين رسائل الصور كوحدة ميزات قابلة للتنزيل. بهذه الطريقة، يكون حجم التطبيق عند تنزيله لأول مرة أصغر لجميع المستخدمين، ولن يحتاج إلى تنزيل هذا المكوّن الإضافي سوى المستخدمين الذين يرسلون رسائل مصوّرة.
يُرجى العِلم أنّ هذا النوع من التقسيم يتطلّب المزيد من الجهد وربما إعادة هيكلة الرمز الحالي لتطبيقك، لذا عليك التفكير بعناية في ميزات تطبيقك التي ستستفيد أكثر من توفّرها للمستخدمين عند الطلب. لفهم حالات الاستخدام الأمثل والإرشادات الخاصة بالميزات عند الطلب بشكل أفضل، يُرجى الاطّلاع على أفضل الممارسات المتعلّقة بتجربة المستخدم للتسليم عند الطلب.
إذا أردت تقسيم ميزات التطبيق تدريجيًا بمرور الوقت بدون تفعيل خيارات العرض المتقدّمة، مثل العرض عند الطلب، يمكنك بدلاً من ذلك ضبط العرض في وقت التثبيت.
تساعدك هذه الصفحة في إضافة وحدة ميزات إلى مشروع تطبيقك وضبطها لتسليمها عند الطلب. قبل البدء، تأكَّد من استخدام الإصدار 3.5 من "استوديو Android" أو إصدار أحدث والإصدار 3.5.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android أو إصدار أحدث.
ضبط وحدة جديدة للتسليم عند الطلب
أسهل طريقة لإنشاء وحدة ميزات جديدة هي استخدام الإصدار 3.5 من "استوديو Android" أو إصدار أحدث. بما أنّ وحدات الميزات تعتمد بطبيعتها على وحدة التطبيق الأساسية، يمكنك إضافتها فقط إلى مشاريع التطبيقات الحالية.
لإضافة وحدة ميزات إلى مشروع تطبيقك باستخدام "استوديو Android"، اتّبِع الخطوات التالية:
- افتح مشروع تطبيقك في بيئة التطوير المتكاملة (IDE) إذا لم يسبق لك ذلك.
- انقر على ملف (File) > جديد (New) > وحدة جديدة (New Module) من شريط القوائم.
- في مربّع الحوار إنشاء وحدة جديدة، اختَر وحدة الميزات الديناميكية وانقر على التالي.
- في قسم ضبط الوحدة الجديدة، أكمِل ما يلي:
- اختَر وحدة التطبيق الأساسية لمشروع تطبيقك من القائمة المنسدلة.
- حدِّد اسم الوحدة. تستخدم بيئة التطوير المتكاملة هذا الاسم لتحديد الوحدة كمشروع فرعي في Gradle في ملف إعدادات Gradle. عند إنشاء حِزمة تطبيقك، يستخدم Gradle العنصر الأخير من اسم المشروع الفرعي لإدخال السمة
<manifest split>في ملف بيان وحدة الميزات. - حدِّد اسم حزمة الوحدة. يقترح استوديو Android تلقائيًا اسم حزمة يجمع بين اسم الحزمة الجذر للوحدة الأساسية واسم الوحدة الذي حدّدته في الخطوة السابقة.
- اختَر الحدّ الأدنى لمستوى واجهة برمجة التطبيقات الذي تريد أن تتوافق معه الوحدة. يجب أن تتطابق هذه القيمة مع قيمة الوحدة الأساسية.
- انقر على التالي.
في قسم خيارات تنزيل الوحدات، أكمِل ما يلي:
حدِّد عنوان الوحدة باستخدام ما يصل إلى 50 حرفًا. تستخدم المنصة هذا العنوان لتعريف المستخدمين بالوحدة، على سبيل المثال، عند تأكيد ما إذا كان المستخدم يريد تنزيل الوحدة. لهذا السبب، يجب أن تتضمّن الوحدة الأساسية في تطبيقك عنوان الوحدة على شكل مصدر السلاسل النصية يمكنك ترجمته. عند إنشاء الوحدة باستخدام "استوديو Android"، تضيف بيئة التطوير المتكاملة (IDE) مصدر السلاسل النصية إلى الوحدة الأساسية وتُدخل الإدخال التالي في بيان وحدة الميزات:
<dist:module ... dist:title="@string/feature_title"> </dist:module>في القائمة المنسدلة ضمن التضمين في وقت التثبيت، اختَر عدم تضمين الوحدة في وقت التثبيت. يُدخل "استوديو Android" ما يلي في ملف بيان الوحدة ليعكس اختيارك:
<dist:module ... > <dist:delivery> <dist:on-demand/> </dist:delivery> </dist:module>ضَع علامة في المربّع بجانب دمج إذا أردت أن تكون هذه الوحدة متاحة للأجهزة التي تعمل بنظام التشغيل Android 4.4 (مستوى واجهة برمجة التطبيقات 20) والإصدارات الأقدم والمضمّنة في حِزم APK المتعددة. وهذا يعني أنّه يمكنك تفعيل سلوك "عند الطلب" لهذه الوحدة وإيقاف الدمج لحذفها من الأجهزة التي لا تتيح تنزيل حِزم APK المجزّأة وتثبيتها. يُدخل "استوديو Android" ما يلي في ملف بيان الوحدة ليعكس اختيارك:
<dist:module ...> <dist:fusing dist:include="true | false" /> </dist:module>
انقر على إنهاء.
بعد أن ينتهي "استوديو Android" من إنشاء الوحدة، يمكنك فحص محتواها بنفسك من لوحة المشروع (انقر على عرض > نوافذ الأدوات > المشروع من شريط القوائم). يجب أن يكون الرمز التلقائي والموارد والتنظيم مشابهًا لتلك الموجودة في وحدة التطبيق العادية.
بعد ذلك، عليك تنفيذ وظيفة التثبيت عند الطلب باستخدام مكتبة "عرض الميزات في Play".
تضمين مكتبة "عرض الميزات في Play" في مشروعك
قبل البدء، عليك أولاً إضافة مكتبة "عرض الميزات في Play" إلى مشروعك.
طلب وحدة عند الطلب
عندما يحتاج تطبيقك إلى استخدام وحدة ميزات، يمكنه طلبها أثناء تشغيله في المقدّمة من خلال الفئة SplitInstallManager. عند تقديم طلب، يحتاج تطبيقك إلى تحديد اسم الوحدة على النحو المحدّد في العنصر split في بيان الوحدة المستهدفة. عند إنشاء وحدة ميزات باستخدام "استوديو Android"، يستخدم نظام الإصدار اسم الوحدة الذي تقدّمه لإدخال هذه السمة في ملف بيان الوحدة في وقت التجميع.
لمزيد من المعلومات، يُرجى الاطّلاع على
ملفات بيان وحدات الميزات.
على سبيل المثال، لنفترض أنّ هناك تطبيقًا يحتوي على وحدة عند الطلب لالتقاط رسائل مصوّرة وإرسالها باستخدام كاميرا الجهاز، وتحدّد هذه الوحدة عند الطلب split="pictureMessages" في ملف البيان الخاص بها. يستخدم النموذج التالي SplitInstallManager لطلب الوحدة pictureMessages (بالإضافة إلى وحدة أخرى لبعض فلاتر العروض الترويجية):
Kotlin
// Creates an instance of SplitInstallManager. val splitInstallManager = SplitInstallManagerFactory.create(context) // Creates a request to install a module. val request = SplitInstallRequest .newBuilder() // You can download multiple on demand modules per // request by invoking the following method for each // module you want to install. .addModule("pictureMessages") .addModule("promotionalFilters") .build() splitInstallManager // Submits the request to install the module through the // asynchronous startInstall() task. Your app needs to be // in the foreground to submit the request. .startInstall(request) // You should also be able to gracefully handle // request state changes and errors. To learn more, go to // the section about how to Monitor the request state. .addOnSuccessListener { sessionId -> ... } .addOnFailureListener { exception -> ... }
Java
// Creates an instance of SplitInstallManager. SplitInstallManager splitInstallManager = SplitInstallManagerFactory.create(context); // Creates a request to install a module. SplitInstallRequest request = SplitInstallRequest .newBuilder() // You can download multiple on demand modules per // request by invoking the following method for each // module you want to install. .addModule("pictureMessages") .addModule("promotionalFilters") .build(); splitInstallManager // Submits the request to install the module through the // asynchronous startInstall() task. Your app needs to be // in the foreground to submit the request. .startInstall(request) // You should also be able to gracefully handle // request state changes and errors. To learn more, go to // the section about how to Monitor the request state. .addOnSuccessListener(sessionId -> { ... }) .addOnFailureListener(exception -> { ... });
عندما يطلب تطبيقك وحدة عند الطلب، تستخدم مكتبة "عرض الميزات في Play" استراتيجية "التشغيل والنسيان". أي أنّه يرسل طلب تنزيل الوحدة إلى المنصة، ولكنه لا يراقب ما إذا كان التثبيت قد تم بنجاح. للمضي قدمًا في تجربة المستخدم بعد التثبيت أو معالجة الأخطاء بشكل سلس، تأكَّد من مراقبة حالة الطلب.
ملاحظة: يمكنك طلب وحدة ميزات سبق تثبيتها على الجهاز. تعتبر واجهة برمجة التطبيقات الطلب مكتملاً على الفور إذا اكتشفت أنّ الوحدة مثبّتة بالفعل. بالإضافة إلى ذلك، بعد تثبيت وحدة معيّنة، يحرص Google Play على تحديثها تلقائيًا. أي أنّه عند تحميل إصدار جديد من حزمة تطبيقك، تعمل المنصة على تحديث جميع حِزم APK المثبَّتة التي تنتمي إلى تطبيقك. لمزيد من المعلومات، يُرجى الاطّلاع على إدارة تحديثات التطبيقات.
للوصول إلى الرمز البرمجي للوحدة ومواردها، يحتاج تطبيقك إلى تفعيل SplitCompat. يُرجى العِلم أنّ SplitCompat غير مطلوب لتطبيقات Android الفورية.
تأجيل تثبيت الوحدات عند الطلب
إذا لم يكن تطبيقك بحاجة إلى تنزيل وحدة عند الطلب وتثبيتها على الفور، يمكنك تأجيل التثبيت إلى أن يصبح التطبيق في الخلفية. على سبيل المثال، إذا أردت تحميل بعض المواد الترويجية مسبقًا لإطلاق تطبيقك في وقت لاحق.
يمكنك تحديد وحدة لتنزيلها لاحقًا باستخدام الطريقة
deferredInstall()
، كما هو موضّح أدناه. وعلى عكس
SplitInstallManager.startInstall()،
لا يحتاج تطبيقك إلى أن يكون في المقدّمة لبدء طلب
التثبيت المؤجَّل.
Kotlin
// Requests an on demand module to be downloaded when the app enters // the background. You can specify more than one module at a time. splitInstallManager.deferredInstall(listOf("promotionalFilters"))
Java
// Requests an on demand module to be downloaded when the app enters // the background. You can specify more than one module at a time. splitInstallManager.deferredInstall(Arrays.asList("promotionalFilters"));
يتم تنفيذ طلبات عمليات التثبيت المؤجَّلة على أساس بذل أقصى جهد ممكن، ولا يمكنك تتبُّع
مدى تقدّمها. لذلك، قبل محاولة الوصول إلى وحدة حدّدتها للتثبيت المؤجَّل، عليك
التحقّق من تثبيت الوحدة. إذا كنت
بحاجة إلى أن تكون الوحدة متاحة على الفور، استخدِم
SplitInstallManager.startInstall() لطلبها، كما هو موضّح في القسم
السابق.
مراقبة حالة الطلب
لتتمكّن من تعديل شريط التقدّم أو إرسال طلب بعد التثبيت أو معالجة خطأ في الطلب بشكل سلس، عليك الاستماع إلى تعديلات الحالة من مهمة SplitInstallManager.startInstall() غير المتزامنة.
قبل أن تتمكّن من بدء تلقّي آخر المعلومات عن طلب التثبيت، عليك تسجيل
مستمع والحصول على رقم تعريف الجلسة للطلب، كما هو موضّح أدناه.
Kotlin
// Initializes a variable to later track the session ID for a given request. var mySessionId = 0 // Creates a listener for request status updates. val listener = SplitInstallStateUpdatedListener { state -> if (state.sessionId() == mySessionId) { // Read the status of the request to handle the state update. } } // Registers the listener. splitInstallManager.registerListener(listener) ... splitInstallManager .startInstall(request) // When the platform accepts your request to download // an on demand module, it binds it to the following session ID. // You use this ID to track further status updates for the request. .addOnSuccessListener { sessionId -> mySessionId = sessionId } // You should also add the following listener to handle any errors // processing the request. .addOnFailureListener { exception -> // Handle request errors. } // When your app no longer requires further updates, unregister the listener. splitInstallManager.unregisterListener(listener)
Java
// Initializes a variable to later track the session ID for a given request. int mySessionId = 0; // Creates a listener for request status updates. SplitInstallStateUpdatedListener listener = state -> { if (state.sessionId() == mySessionId) { // Read the status of the request to handle the state update. } }; // Registers the listener. splitInstallManager.registerListener(listener); ... splitInstallManager .startInstall(request) // When the platform accepts your request to download // an on demand module, it binds it to the following session ID. // You use this ID to track further status updates for the request. .addOnSuccessListener(sessionId -> { mySessionId = sessionId; }) // You should also add the following listener to handle any errors // processing the request. .addOnFailureListener(exception -> { // Handle request errors. }); // When your app no longer requires further updates, unregister the listener. splitInstallManager.unregisterListener(listener);
التعامل مع أخطاء الطلبات
يُرجى العِلم أنّ تثبيت وحدات الميزات عند الطلب قد يتعذّر أحيانًا، تمامًا مثلما يتعذّر تثبيت التطبيقات في بعض الأحيان. قد يرجع سبب تعذُّر التثبيت إلى مشاكل مثل انخفاض مساحة التخزين على الجهاز أو عدم الاتصال بالشبكة أو عدم تسجيل المستخدم الدخول إلى "متجر Google Play". للحصول على اقتراحات حول كيفية التعامل مع هذه المواقف بشكل سلس من منظور المستخدم، يمكنك الاطّلاع على إرشادات تجربة المستخدم للتسليم عند الطلب.
من ناحية الرمز البرمجي، يجب معالجة حالات تعذُّر تنزيل وحدة أو تثبيتها
باستخدام addOnFailureListener()، كما هو موضّح أدناه:
Kotlin
splitInstallManager .startInstall(request) .addOnFailureListener { exception -> when ((exception as SplitInstallException).errorCode) { SplitInstallErrorCode.NETWORK_ERROR -> { // Display a message that requests the user to establish a // network connection. } SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED -> checkForActiveDownloads() ... } } fun checkForActiveDownloads() { splitInstallManager // Returns a SplitInstallSessionState object for each active session as a List. .sessionStates .addOnCompleteListener { task -> if (task.isSuccessful) { // Check for active sessions. for (state in task.result) { if (state.status() == SplitInstallSessionStatus.DOWNLOADING) { // Cancel the request, or request a deferred installation. } } } } }
Java
splitInstallManager .startInstall(request) .addOnFailureListener(exception -> { switch (((SplitInstallException) exception).getErrorCode()) { case SplitInstallErrorCode.NETWORK_ERROR: // Display a message that requests the user to establish a // network connection. break; case SplitInstallErrorCode.ACTIVE_SESSIONS_LIMIT_EXCEEDED: checkForActiveDownloads(); ... }); void checkForActiveDownloads() { splitInstallManager // Returns a SplitInstallSessionState object for each active session as a List. .getSessionStates() .addOnCompleteListener( task -> { if (task.isSuccessful()) { // Check for active sessions. for (SplitInstallSessionState state : task.getResult()) { if (state.status() == SplitInstallSessionStatus.DOWNLOADING) { // Cancel the request, or request a deferred installation. } } } }); }
يوضّح الجدول أدناه حالات الخطأ التي قد يحتاج تطبيقك إلى معالجتها:
| رمز الخطأ | الوصف | الإجراء المُقترَح |
|---|---|---|
| ACTIVE_SESSIONS_LIMIT_EXCEEDED | تم رفض الطلب لأنّ هناك طلبًا واحدًا على الأقل قيد التنزيل حاليًا. | تحقَّق ممّا إذا كانت هناك أي طلبات لا تزال قيد التنزيل، كما هو موضّح في النموذج أعلاه. |
| MODULE_UNAVAILABLE | يتعذّر على Google Play العثور على الوحدة المطلوبة استنادًا إلى الإصدار الحالي المثبَّت من التطبيق والجهاز وحساب المستخدم على Google Play. | إذا لم يكن لدى المستخدم إذن بالوصول إلى الوحدة، أبلِغه بذلك. |
| INVALID_REQUEST | تلقّى Google Play الطلب، ولكنّه غير صالح. | تأكَّد من أنّ المعلومات الواردة في الطلب كاملة ودقيقة. |
| SESSION_NOT_FOUND | لم يتم العثور على جلسة لمعرّف جلسة معيّن. | إذا كنت تحاول مراقبة حالة طلب باستخدام معرّف الجلسة، تأكَّد من صحة معرّف الجلسة. |
| API_NOT_AVAILABLE | مكتبة "عرض الميزات في Play" غير متاحة على الجهاز الحالي. أي أنّ الجهاز لا يمكنه تنزيل الميزات وتثبيتها عند الطلب. | بالنسبة إلى الأجهزة التي تعمل بنظام التشغيل Android 4.4 (مستوى واجهة برمجة التطبيقات 20) أو الإصدارات الأقدم، يجب تضمين وحدات الميزات في وقت التثبيت باستخدام السمة dist:fusing في ملف البيان. لمزيد من المعلومات، يمكنك الاطّلاع على ملف بيان وحدة الميزات.
|
| NETWORK_ERROR | تعذَّر تنفيذ الطلب بسبب خطأ في الشبكة. | اطلب من المستخدم إنشاء اتصال بالشبكة أو التبديل إلى شبكة أخرى. |
| ACCESS_DENIED | يتعذّر على التطبيق تسجيل الطلب بسبب عدم توفّر أذونات كافية. | يحدث هذا عادةً عندما يكون التطبيق في الخلفية. حاوِل إرسال الطلب عندما يعود التطبيق إلى المقدّمة. |
| INCOMPATIBLE_WITH_EXISTING_SESSION | يحتوي الطلب على وحدة واحدة أو أكثر سبق طلبها ولكن لم يتم تثبيتها بعد. | يمكنك إنشاء طلب جديد لا يتضمّن الوحدات التي سبق لتطبيقك طلبها، أو الانتظار حتى تنتهي عملية تثبيت جميع الوحدات المطلوبة حاليًا قبل إعادة محاولة الطلب.
يُرجى العِلم أنّ طلب وحدة سبق تثبيتها لا يؤدي إلى حدوث خطأ. |
| SERVICE_DIED | توقّفت الخدمة المسؤولة عن معالجة الطلب. | أعِد محاولة إرسال الطلب.
يتلقّى " |
| INSUFFICIENT_STORAGE | لا تتوفّر مساحة تخزين كافية على الجهاز لتثبيت وحدة الميزات. | أبلِغ المستخدم بأنّه لا تتوفّر لديه مساحة تخزين كافية لتثبيت هذه الميزة. |
| SPLITCOMPAT_VERIFICATION_ERROR, SPLITCOMPAT_EMULATION_ERROR, SPLITCOMPAT_COPY_ERROR | تعذَّر على SplitCompat تحميل وحدة الميزات. | من المفترض أن يتم حلّ هذه الأخطاء تلقائيًا بعد إعادة تشغيل التطبيق في المرة التالية. |
| PLAY_STORE_NOT_FOUND | تطبيق "متجر Play" غير مثبّت على الجهاز. | يجب إعلام المستخدم بأنّ تطبيق "متجر Google Play" مطلوب لتنزيل هذه الميزة. |
| APP_NOT_OWNED | لم يتم تثبيت التطبيق من خلال Google Play ولا يمكن تنزيل الميزة. يمكن أن يحدث هذا الخطأ فقط في عمليات التثبيت المؤجَّلة. | إذا أردت أن يحصل المستخدم على التطبيق من Google Play، استخدِم
startInstall() الذي يمكنه الحصول على
تأكيد المستخدم اللازم. |
| INTERNAL_ERROR | حدث خطأ داخلي في "متجر Google Play". | أعِد محاولة إرسال الطلب. |
إذا طلب مستخدم تنزيل وحدة عند الطلب وحدث خطأ، ننصحك بعرض مربّع حوار يوفّر خيارَين للمستخدم: إعادة المحاولة (الذي يحاول تنفيذ الطلب مرة أخرى) وإلغاء (الذي يتجاهل الطلب). للحصول على دعم إضافي، عليك أيضًا توفير رابط المساعدة الذي يوجّه المستخدمين إلى مركز مساعدة Google Play.
التعامل مع تعديلات الحالة
بعد تسجيل مستمع وتسجيل معرّف الجلسة لطلبك،
استخدِم StateUpdatedListener.onStateUpdate()
للتعامل مع تغييرات الحالة، كما هو موضّح أدناه.
Kotlin
override fun onStateUpdate(state : SplitInstallSessionState) { if (state.status() == SplitInstallSessionStatus.FAILED && state.errorCode() == SplitInstallErrorCode.SERVICE_DIED) { // Retry the request. return } if (state.sessionId() == mySessionId) { when (state.status()) { SplitInstallSessionStatus.DOWNLOADING -> { val totalBytes = state.totalBytesToDownload() val progress = state.bytesDownloaded() // Update progress bar. } SplitInstallSessionStatus.INSTALLED -> { // After a module is installed, you can start accessing its content or // fire an intent to start an activity in the installed module. // For other use cases, see access code and resources from installed modules. // If the request is an on demand module for an Android Instant App // running on Android 8.0 (API level 26) or higher, you need to // update the app context using the SplitInstallHelper API. } } } }
Java
@Override public void onStateUpdate(SplitInstallSessionState state) { if (state.status() == SplitInstallSessionStatus.FAILED && state.errorCode() == SplitInstallErrorCode.SERVICE_DIES) { // Retry the request. return; } if (state.sessionId() == mySessionId) { switch (state.status()) { case SplitInstallSessionStatus.DOWNLOADING: int totalBytes = state.totalBytesToDownload(); int progress = state.bytesDownloaded(); // Update progress bar. break; case SplitInstallSessionStatus.INSTALLED: // After a module is installed, you can start accessing its content or // fire an intent to start an activity in the installed module. // For other use cases, see access code and resources from installed modules. // If the request is an on demand module for an Android Instant App // running on Android 8.0 (API level 26) or higher, you need to // update the app context using the SplitInstallHelper API. } } }
يتم توضيح الحالات المحتملة لطلب التثبيت في الجدول أدناه.
| حالة الطلب | الوصف | الإجراء المُقترَح |
|---|---|---|
| في انتظار المراجعة | تم قبول الطلب ومن المفترض أن تبدأ عملية التنزيل قريبًا. | ابدأ بتهيئة مكوّنات واجهة المستخدم، مثل شريط التقدم، لإعلام المستخدم بحالة عملية التنزيل. |
| REQUIRES_USER_CONFIRMATION | تتطلّب عملية التنزيل تأكيدًا من المستخدم. تظهر هذه الحالة عادةً إذا لم يتم تثبيت التطبيق من خلال Google Play. | اطلب من المستخدم تأكيد تنزيل الميزة من خلال Google Play. لمزيد من المعلومات، انتقِل إلى القسم حول كيفية الحصول على تأكيد من المستخدم. |
| التنزيل | عملية التنزيل قيد التقدم. | إذا كنت توفّر شريط تقدّم لعملية التنزيل، استخدِم الطريقتَين SplitInstallSessionState.bytesDownloaded() وSplitInstallSessionState.totalBytesToDownload() لتعديل واجهة المستخدم (اطّلِع على عيّنة التعليمات البرمجية أعلى هذا الجدول). |
| تم التنزيل | نزّل الجهاز الوحدة ولكن لم يبدأ التثبيت بعد. | يجب أن تفعّل التطبيقات SplitCompat للوصول إلى الوحدات التي تم تنزيلها وتجنُّب ظهور هذه الحالة. هذا الإجراء مطلوب للوصول إلى الرموز البرمجية والموارد الخاصة بوحدة الميزات. |
| جارٍ التثبيت | يعمل الجهاز حاليًا على تثبيت الوحدة. | تعديل شريط التقدم وعادةً ما تكون هذه الحالة قصيرة. |
| تم التثبيت | تم تثبيت الوحدة على الجهاز. | الوصول إلى الرمز والمورد في الوحدة
لمواصلة تجربة المستخدم
إذا كانت الوحدة مخصّصة لتطبيق Android فوري يعمل بنظام التشغيل Android 8.0 (المستوى 26 من واجهة برمجة التطبيقات) أو إصدار أحدث، عليك استخدام |
| تعذّر إجراء الاختبار. | تعذّر تنفيذ الطلب قبل تثبيت الوحدة على الجهاز. | اطلب من المستخدم إعادة محاولة إرسال الطلب أو إلغائه. |
| جارٍ الإلغاء | الجهاز في طور إلغاء الطلب. | لمزيد من المعلومات، انتقِل إلى القسم حول كيفية إلغاء طلب تثبيت. |
| تم إلغاؤها | تم إلغاء الطلب. |
الحصول على تأكيد المستخدم
في بعض الحالات، قد يطلب Google Play تأكيدًا من المستخدم قبل تلبية طلب التنزيل. على سبيل المثال، إذا لم يتم تثبيت تطبيقك من خلال Google Play أو إذا كنت تحاول تنزيل ملف كبير باستخدام بيانات الجوّال. في هذه الحالات،
تكون حالة طلب التقارير REQUIRES_USER_CONFIRMATION، ويحتاج تطبيقك
إلى الحصول على تأكيد من المستخدم قبل أن يتمكّن الجهاز من تنزيل
الوحدات في الطلب وتثبيتها. للحصول على التأكيد، يجب أن يطلب تطبيقك من المستخدم ما يلي:
Kotlin
override fun onSessionStateUpdate(state: SplitInstallSessionState) { if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { // Displays a confirmation for the user to confirm the request. splitInstallManager.startConfirmationDialogForResult( state, // an activity result launcher registered via registerForActivityResult activityResultLauncher) } ... }
Java
@Override void onSessionStateUpdate(SplitInstallSessionState state) { if (state.status() == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) { // Displays a confirmation for the user to confirm the request. splitInstallManager.startConfirmationDialogForResult( state, // an activity result launcher registered via registerForActivityResult activityResultLauncher); } ... }
يمكنك تسجيل مشغّل نتائج النشاط باستخدام عقد
ActivityResultContracts.StartIntentSenderForResult
المضمّن. يُرجى الاطّلاع على واجهات برمجة التطبيقات Activity Result.
يتم تعديل حالة الطلب استنادًا إلى ردّ المستخدم:
- إذا وافق المستخدم على التأكيد، ستتغيّر حالة الطلب إلى
PENDINGوستتم متابعة عملية التنزيل. - إذا رفض المستخدم التأكيد، تتغيّر حالة الطلب إلى
CANCELED. - إذا لم يحدّد المستخدم خيارًا قبل إغلاق مربّع الحوار،
ستبقى حالة الطلب
REQUIRES_USER_CONFIRMATION. يمكن لتطبيقك أن يطلب من المستخدم مرة أخرى إكمال الطلب.
لتلقّي معاودة اتصال تتضمّن ردّ المستخدم، يمكنك إلغاء ActivityResultCallback كما هو موضّح أدناه.
Kotlin
registerForActivityResult(StartIntentSenderForResult()) { result: ActivityResult -> { // Handle the user's decision. For example, if the user selects "Cancel", // you may want to disable certain functionality that depends on the module. } }
Java
registerForActivityResult( new ActivityResultContracts.StartIntentSenderForResult(), new ActivityResultCallback<ActivityResult>() { @Override public void onActivityResult(ActivityResult result) { // Handle the user's decision. For example, if the user selects "Cancel", // you may want to disable certain functionality that depends on the module. } });
إلغاء طلب تثبيت
إذا كان تطبيقك بحاجة إلى إلغاء طلب قبل تثبيته، يمكنه استدعاء الإجراء cancelInstall() باستخدام رقم تعريف جلسة الطلب، كما هو موضّح أدناه.
Kotlin
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId)
Java
splitInstallManager // Cancels the request for the given session ID. .cancelInstall(mySessionId);
وحدات الوصول
للوصول إلى الرموز والموارد من وحدة تم تنزيلها، يجب أن يفعّل تطبيقك مكتبة SplitCompat لكل من تطبيقك وكل نشاط في وحدات الميزات التي يتم تنزيلها من خلال تطبيقك.
ومع ذلك، يجب ملاحظة أن النظام الأساسي يواجه القيود التالية للوصول إلى محتويات الوحدة، لبعض الوقت (أيام، في بعض الحالات) بعد تنزيل الوحدة:
- لا يمكن للمنصة تطبيق أي إدخالات جديدة في ملف البيان يقدّمها المكوّن الإضافي.
- لا يمكن للمنصة الوصول إلى موارد الوحدة لعناصر واجهة المستخدم في النظام، مثل الإشعارات. إذا كنت بحاجة إلى استخدام هذه الموارد على الفور، ننصحك بتضمينها في الوحدة الأساسية لتطبيقك.
تفعيل SplitCompat
لكي يتمكّن تطبيقك من الوصول إلى الرموز البرمجية والموارد من وحدة تم تنزيلها، عليك تفعيل SplitCompat باستخدام طريقة واحدة فقط من الطرق الموضّحة في الأقسام التالية.
بعد تفعيل SplitCompat لتطبيقك، عليك أيضًا تفعيل SplitCompat لكل نشاط في وحدات الميزات التي تريد أن يتمكّن تطبيقك من الوصول إليها.
تعريف SplitCompatApplication في ملف البيان
أبسط طريقة لتفعيل SplitCompat هي تعريف SplitCompatApplication
كفئة فرعية من Application في
ملف بيان تطبيقك، كما هو موضّح أدناه:
<application
...
android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>
بعد تثبيت التطبيق على جهاز، يمكنك الوصول إلى الرموز البرمجية والموارد من وحدات الميزات التي تم تنزيلها تلقائيًا.
استدعاء SplitCompat في وقت التشغيل
يمكنك أيضًا تفعيل SplitCompat في أنشطة أو خدمات معيّنة في وقت التشغيل.
يجب تفعيل SplitCompat بهذه الطريقة لتشغيل الأنشطة المضمّنة في وحدات الميزات. لإجراء ذلك، يمكنك إلغاء attachBaseContext كما هو موضّح أدناه.
إذا كانت لديك فئة تطبيق مخصّصة،
يمكنك جعلها تمدّد
SplitCompatApplication
لتفعيل SplitCompat لتطبيقك، كما هو موضّح أدناه:
Kotlin
class MyApplication : SplitCompatApplication() { ... }
Java
public class MyApplication extends SplitCompatApplication { ... }
تتجاوز السمة SplitCompatApplication السمة ContextWrapper.attachBaseContext()
لتشمل SplitCompat.install(Context applicationContext). إذا كنت لا تريد أن تمتد فئة Application
إلى SplitCompatApplication، يمكنك تجاوز طريقة attachBaseContext()
يدويًا، على النحو التالي:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of future on demand modules using SplitCompat. SplitCompat.install(this); }
إذا كانت الوحدة عند الطلب متوافقة مع كل من التطبيقات الفورية والتطبيقات المثبّتة، يمكنك استدعاء SplitCompat بشكل مشروط على النحو التالي:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this) } }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); if (!InstantApps.isInstantApp(this)) { SplitCompat.install(this); } }
تفعيل SplitCompat لأنشطة الوحدات
بعد تفعيل SplitCompat لتطبيقك الأساسي، عليك تفعيل SplitCompat لكل نشاط ينزّله تطبيقك في وحدة ميزات. لإجراء ذلك،
استخدِم طريقة SplitCompat.installActivity() على النحو التالي:
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); // Emulates installation of on demand modules using SplitCompat. SplitCompat.installActivity(this); }
الوصول إلى المكوّنات المحدّدة في وحدات الميزات
بدء نشاط محدّد في وحدة ميزات
يمكنك تشغيل الأنشطة المحدّدة في وحدات الميزات باستخدام
startActivity()
بعد تفعيل SplitCompat.
Kotlin
startActivity(Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...))
Java
startActivity(new Intent() .setClassName("com.package", "com.package.module.MyActivity") .setFlags(...));
المَعلمة الأولى في setClassName هي اسم حزمة التطبيق، والمَعلمة الثانية هي اسم الفئة الكامل للنشاط.
عندما يكون لديك نشاط في وحدة ميزات نزّلتها عند الطلب، يجب تفعيل SplitCompat في النشاط.
بدء خدمة محدّدة في وحدة ميزات
يمكنك تشغيل الخدمات المحدّدة في وحدات الميزات باستخدام
startService()
بعد تفعيل SplitCompat.
Kotlin
startService(Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...))
Java
startService(new Intent() .setClassName("com.package", "com.package.module.MyService") .setFlags(...));
تصدير مكوّن محدّد في وحدة ميزات
يجب عدم تضمين مكوّنات Android التي تم تصديرها داخل الوحدات الاختيارية.
يدمج نظام التصميم إدخالات ملفات البيان المدمجة لجميع الوحدات في الوحدة الأساسية، وإذا كانت الوحدة الاختيارية تحتوي على مكوّن تم تصديره، سيكون من الممكن الوصول إليه حتى قبل تثبيت الوحدة، ويمكن أن يتسبب ذلك في حدوث تعطُّل بسبب عدم توفّر الرمز البرمجي عند استدعائه من تطبيق آخر.
لا يمثّل ذلك مشكلة للمكوّنات الداخلية، لأنّ التطبيق وحده هو الذي يصل إليها، وبالتالي يمكن للتطبيق التحقّق من تثبيت الوحدة قبل الوصول إلى المكوّن.
إذا كنت بحاجة إلى مكوّن يتم تصديره، وتريد أن يكون محتواه في وحدة اختيارية، ننصحك بتنفيذ نمط الخادم الوكيل.
يمكنك إجراء ذلك عن طريق إضافة مكوّن مصدَّر بالوكالة في القاعدة،
وعند الوصول إليه، يمكن للمكوّن الوكيل التحقّق من توفّر الوحدة التي
تحتوي على المحتوى. إذا كانت الوحدة متوفّرة، يمكن لمكوّن الخادم الوكيل بدء المكوّن الداخلي من الوحدة من خلال Intent، مع نقل الغرض من تطبيق المتصل. إذا لم تكن الوحدة متوفّرة، يمكن للمكوّن تنزيل الوحدة أو عرض رسالة خطأ مناسبة لتطبيق المتصل.
الوصول إلى الرموز البرمجية والموارد من الوحدات المثبَّتة
إذا فعّلت SplitCompat لسياق تطبيقك الأساسي والأنشطة في وحدة الميزات، يمكنك استخدام الرمز والموارد من وحدة الميزات كما لو كانت جزءًا من حزمة APK الأساسية، بعد تثبيت الوحدة الاختيارية.
رمز الدخول من وحدة مختلفة
الوصول إلى الرمز الأساسي من وحدة
يمكن استخدام الرمز البرمجي داخل الوحدة الأساسية مباشرةً من خلال الوحدات الأخرى. لست بحاجة إلى اتخاذ أي إجراء خاص، ما عليك سوى استيراد الفئات التي تحتاجها واستخدامها.
الوصول إلى رمز وحدة من وحدة أخرى
لا يمكن الوصول إلى كائن أو فئة داخل وحدة بشكل ثابت من وحدة أخرى مباشرة، ولكن يمكن الوصول إليها بشكل غير مباشر، باستخدام الانعكاس.
يجب أن تكون حذرًا من عدد مرات حدوث ذلك، بسبب تكاليف الأداء للانعكاس. بالنسبة إلى حالات الاستخدام المعقّدة، يمكنك استخدام أُطر عمل حقن التبعية مثل Dagger 2 لضمان استدعاء انعكاس واحد لكل دورة حياة تطبيق.
لتبسيط التفاعلات مع العنصر بعد إنشاء مثيل له، ننصحك بتحديد واجهة في الوحدة الأساسية وتنفيذها في وحدة الميزات. على سبيل المثال:
Kotlin
// In the base module interface MyInterface { fun hello(): String } // In the feature module object MyInterfaceImpl : MyInterface { override fun hello() = "Hello" } // In the base module, where we want to access the feature module code val stringFromModule = (Class.forName("com.package.module.MyInterfaceImpl") .kotlin.objectInstance as MyInterface).hello();
Java
// In the base module public interface MyInterface { String hello(); } // In the feature module public class MyInterfaceImpl implements MyInterface { @Override public String hello() { return "Hello"; } } // In the base module, where we want to access the feature module code String stringFromModule = ((MyInterface) Class.forName("com.package.module.MyInterfaceImpl").getConstructor().newInstance()).hello();
الوصول إلى الموارد ومواد العرض من وحدة مختلفة
بعد تثبيت وحدة، يمكنك الوصول إلى الموارد ومواد العرض داخل الوحدة بالطريقة العادية، مع مراعاة التحذيرين التاليين:
- إذا كنت تصل إلى مورد من وحدة مختلفة، فلن تتمكن الوحدة من الوصول إلى معرّف المورد، على الرغم من أنه لا يزال من الممكن الوصول إلى المورد بالاسم. يُرجى العِلم أنّ الحزمة التي يجب استخدامها للإشارة إلى المورد هي حزمة الوحدة التي تم تحديد المورد فيها.
- إذا أردت الوصول إلى مواد العرض أو الموارد المتوفّرة في وحدة تم تثبيتها حديثًا من وحدة أخرى مثبَّتة في تطبيقك، عليك إجراء ذلك باستخدام سياق التطبيق. لن يتم بعد تعديل سياق المكوّن الذي يحاول الوصول إلى الموارد. بدلاً من ذلك، يمكنك إعادة إنشاء هذا المكوّن (على سبيل المثال، استدعاء Activity.recreate()) أو إعادة تثبيت SplitCompat عليه بعد تثبيت وحدة الميزات.
تحميل الرموز البرمجية الأصلية في تطبيق باستخدام ميزة "التسليم عند الطلب"
ننصحك باستخدام ReLinker لتحميل جميع المكتبات المجمّعة من رموز برمجية أصلية عند استخدام ميزة "العرض عند الطلب" لوحدات الميزات. تعمل ReLinker على حلّ مشكلة تحميل المكتبات المجمّعة من رموز برمجية أصلية بعد تثبيت وحدة الميزات. يمكنك معرفة المزيد من المعلومات عن ReLinker في نصائح Android JNI.
تحميل الرموز البرمجية الأصلية من وحدة اختيارية
بعد تثبيت ملف APK مجزّأ، ننصح بتحميل رموزه البرمجية الأصلية من خلال ReLinker. بالنسبة إلى التطبيقات الفورية، يجب استخدام هذه الطريقة الخاصة.
إذا كنت تستخدم System.loadLibrary() لتحميل الرموز البرمجية الأصلية وكانت مكتبتك المجمّعة من رموز برمجية أصلية تعتمد على مكتبة أخرى في الوحدة، عليك تحميل تلك المكتبة الأخرى يدويًا أولاً.
إذا كنت تستخدم ReLinker، تكون العملية المكافئة هي
Relinker.recursively().loadLibrary().
إذا كنت تستخدم dlopen() في الرموز البرمجية الأصلية لتحميل مكتبة محدّدة في وحدة اختيارية، لن يعمل ذلك مع مسارات المكتبة النسبية.
أفضل حل هو استرداد المسار المطلق للمكتبة من رمز Java البرمجي
عبر ClassLoader.findLibrary() ثم استخدامه في طلب dlopen().
يجب تنفيذ ذلك قبل إدخال الرموز البرمجية الأصلية أو استخدام طلب JNI من الرموز البرمجية الأصلية إلى Java.
الوصول إلى "تطبيقات Android الفورية" المثبَّتة
بعد أن تظهر وحدة تطبيق Android الفوري على أنّها INSTALLED، يمكنك الوصول إلى الرمز البرمجي والموارد الخاصة بها باستخدام سياق تطبيق تم تحديثه. إنّ السياق الذي ينشئه تطبيقك قبل تثبيت وحدة (على سبيل المثال، وحدة مخزَّنة في متغيّر) لا يحتوي على محتوى الوحدة الجديدة. ولكن يمكن الحصول على سياق جديد باستخدام
createPackageContext مثلاً.
Kotlin
// Generate a new context as soon as a request for a new module // reports as INSTALLED. override fun onStateUpdate(state: SplitInstallSessionState ) { if (state.sessionId() == mySessionId) { when (state.status()) { ... SplitInstallSessionStatus.INSTALLED -> { val newContext = context.createPackageContext(context.packageName, 0) // If you use AssetManager to access your app’s raw asset files, you’ll need // to generate a new AssetManager instance from the updated context. val am = newContext.assets } } } }
Java
// Generate a new context as soon as a request for a new module // reports as INSTALLED. @Override public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { ... case SplitInstallSessionStatus.INSTALLED: Context newContext = context.createPackageContext(context.getPackageName(), 0); // If you use AssetManager to access your app’s raw asset files, you’ll need // to generate a new AssetManager instance from the updated context. AssetManager am = newContext.getAssets(); } } }
تطبيقات Android الفورية على الإصدار 8.0 من نظام التشغيل Android والإصدارات الأحدث
عند طلب وحدة عند الطلب لتطبيق Android فوري على الإصدار 8.0 من نظام التشغيل Android (مستوى واجهة برمجة التطبيقات 26) والإصدارات الأحدث، بعد أن يبلّغ طلب التثبيت عن الحالة INSTALLED، عليك تحديث التطبيق بسياق الوحدة الجديدة من خلال طلب SplitInstallHelper.updateAppInfo(Context context).
وإلا، لن يكون التطبيق على علم بعد برمز الوحدة
ومواردها. بعد تعديل البيانات الوصفية للتطبيق، عليك تحميل محتوى الوحدة أثناء حدث سلسلة التعليمات الرئيسي التالي من خلال استدعاء Handler جديد، كما هو موضّح أدناه:
Kotlin
override fun onStateUpdate(state: SplitInstallSessionState ) { if (state.sessionId() == mySessionId) { when (state.status()) { ... SplitInstallSessionStatus.INSTALLED -> { // You need to perform the following only for Android Instant Apps // running on Android 8.0 (API level 26) and higher. if (BuildCompat.isAtLeastO()) { // Updates the app’s context with the code and resources of the // installed module. SplitInstallHelper.updateAppInfo(context) Handler().post { // Loads contents from the module using AssetManager val am = context.assets ... } } } } } }
Java
@Override public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { ... case SplitInstallSessionStatus.INSTALLED: // You need to perform the following only for Android Instant Apps // running on Android 8.0 (API level 26) and higher. if (BuildCompat.isAtLeastO()) { // Updates the app’s context with the code and resources of the // installed module. SplitInstallHelper.updateAppInfo(context); new Handler().post(new Runnable() { @Override public void run() { // Loads contents from the module using AssetManager AssetManager am = context.getAssets(); ... } }); } } } }
تحميل مكتبات C/C++
إذا أردت تحميل مكتبات C/C++ من وحدة سبق للجهاز تنزيلها في تطبيق فوري، استخدِم SplitInstallHelper.loadLibrary(Context context, String libName)، كما هو موضّح أدناه:
Kotlin
override fun onStateUpdate(state: SplitInstallSessionState) { if (state.sessionId() == mySessionId) { when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Updates the app’s context as soon as a module is installed. val newContext = context.createPackageContext(context.packageName, 0) // To load C/C++ libraries from an installed module, use the following API // instead of System.load(). SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”) ... } } } }
Java
public void onStateUpdate(SplitInstallSessionState state) { if (state.sessionId() == mySessionId) { switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Updates the app’s context as soon as a module is installed. Context newContext = context.createPackageContext(context.getPackageName(), 0); // To load C/C++ libraries from an installed module, use the following API // instead of System.load(). SplitInstallHelper.loadLibrary(newContext, “my-cpp-lib”); ... } } }
القيود المعروفة
- لا يمكن استخدام Android WebView في نشاط يصل إلى الموارد أو مواد العرض من وحدة اختيارية. ويرجع ذلك إلى عدم التوافق بين WebView وSplitCompat في المستوى 28 من واجهة برمجة التطبيقات لنظام التشغيل Android والإصدارات الأقدم.
- لا يمكنك تخزين عناصر
ApplicationInfoفي Android أو محتواها أو العناصر التي تتضمّنها مؤقتًا داخل تطبيقك. يجب دائمًا جلب هذه العناصر حسب الحاجة من سياق التطبيق. قد يؤدي تخزين هذه العناصر مؤقتًا إلى تعطُّل التطبيق عند تثبيت وحدة ميزات.
إدارة الوحدات المثبَّتة
للتحقّق من وحدات الميزات المثبَّتة حاليًا على الجهاز،
يمكنك استدعاء
SplitInstallManager.getInstalledModules()،
التي تعرض Set<String> لأسماء الوحدات المثبَّتة، كما هو موضّح
أدناه.
Kotlin
val installedModules: Set<String> = splitInstallManager.installedModules
Java
Set<String> installedModules = splitInstallManager.getInstalledModules();
إلغاء تثبيت الوحدات
يمكنك أن تطلب من الجهاز إلغاء تثبيت الوحدات من خلال استدعاء
SplitInstallManager.deferredUninstall(List<String> moduleNames)،
كما هو موضّح أدناه.
Kotlin
// Specifies two feature modules for deferred uninstall. splitInstallManager.deferredUninstall(listOf("pictureMessages", "promotionalFilters"))
Java
// Specifies two feature modules for deferred uninstall. splitInstallManager.deferredUninstall(Arrays.asList("pictureMessages", "promotionalFilters"));
لا يتم إلغاء تثبيت الوحدات على الفور. أي أنّ الجهاز يلغي تثبيتها في الخلفية حسب الحاجة لتوفير مساحة تخزين.
يمكنك التأكّد من أنّ الجهاز قد حذف وحدة من خلال استدعاء SplitInstallManager.getInstalledModules() وفحص النتيجة، كما هو موضّح في القسم السابق.
تنزيل مراجع لغوية إضافية
باستخدام حِزم التطبيقات، لا تنزّل الأجهزة سوى الرموز البرمجية والموارد التي تحتاجها لتشغيل تطبيقك. لذلك، بالنسبة إلى موارد اللغة، لا ينزّل جهاز المستخدم سوى موارد لغة تطبيقك التي تتطابق مع لغة واحدة أو أكثر من اللغات المحدّدة حاليًا في إعدادات الجهاز.
إذا أردت أن يتمكّن تطبيقك من الوصول إلى مَراجع لغوية إضافية، مثلاً لتنفيذ أداة اختيار اللغة داخل التطبيق، يمكنك استخدام مكتبة "عرض الميزات في Play" لتنزيلها عند الطلب. تشبه هذه العملية عملية تنزيل وحدة ميزات، كما هو موضّح أدناه.
Kotlin
// Captures the user’s preferred language and persists it // through the app’s SharedPreferences. sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply() ... // Creates a request to download and install additional language resources. val request = SplitInstallRequest.newBuilder() // Uses the addLanguage() method to include French language resources in the request. // Note that country codes are ignored. That is, if your app // includes resources for “fr-FR” and “fr-CA”, resources for both // country codes are downloaded when requesting resources for "fr". .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) .build() // Submits the request to install the additional language resources. splitInstallManager.startInstall(request)
Java
// Captures the user’s preferred language and persists it // through the app’s SharedPreferences. sharedPrefs.edit().putString(LANGUAGE_SELECTION, "fr").apply(); ... // Creates a request to download and install additional language resources. SplitInstallRequest request = SplitInstallRequest.newBuilder() // Uses the addLanguage() method to include French language resources in the request. // Note that country codes are ignored. That is, if your app // includes resources for “fr-FR” and “fr-CA”, resources for both // country codes are downloaded when requesting resources for "fr". .addLanguage(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) .build(); // Submits the request to install the additional language resources. splitInstallManager.startInstall(request);
تتم معالجة الطلب كما لو كان طلبًا لوحدة ميزات. وهذا يعني أنّه يمكنك مراقبة حالة الطلب كالمعتاد.
إذا كان تطبيقك لا يتطلّب موارد اللغة الإضافية على الفور، يمكنك تأجيل التثبيت إلى حين تشغيل التطبيق في الخلفية، كما هو موضّح أدناه.
Kotlin
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageInstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
الوصول إلى مراجع اللغات التي تم تنزيلها
للوصول إلى موارد اللغة التي تم تنزيلها، يحتاج تطبيقك إلى تشغيل طريقة
SplitCompat.installActivity() ضمن طريقة attachBaseContext()
لكل نشاط يتطلب الوصول إلى هذه الموارد، كما هو موضّح أدناه.
Kotlin
override fun attachBaseContext(base: Context) { super.attachBaseContext(base) SplitCompat.installActivity(this) }
Java
@Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); SplitCompat.installActivity(this); }
لكل نشاط تريد فيه استخدام موارد اللغة التي نزّلها تطبيقك،
عدِّل السياق الأساسي واضبط لغة جديدة من خلال
Configuration:
Kotlin
override fun attachBaseContext(base: Context) { val configuration = Configuration() configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))) val context = base.createConfigurationContext(configuration) super.attachBaseContext(context) SplitCompat.install(this) }
Java
@Override protected void attachBaseContext(Context base) { Configuration configuration = new Configuration(); configuration.setLocale(Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION))); Context context = base.createConfigurationContext(configuration); super.attachBaseContext(context); SplitCompat.install(this); }
لكي تسري هذه التغييرات، عليك إعادة إنشاء نشاطك
بعد تثبيت اللغة الجديدة وتجهيزها للاستخدام. يمكنك استخدام طريقة Activity#recreate().
Kotlin
when (state.status()) { SplitInstallSessionStatus.INSTALLED -> { // Recreates the activity to load resources for the new language // preference. activity.recreate() } ... }
Java
switch (state.status()) { case SplitInstallSessionStatus.INSTALLED: // Recreates the activity to load resources for the new language // preference. activity.recreate(); ... }
إلغاء تثبيت موارد اللغات الإضافية
على غرار وحدات الميزات، يمكنك إلغاء تثبيت الموارد الإضافية في أي وقت. قبل طلب إلغاء التثبيت، قد تحتاج أولاً إلى تحديد اللغات المثبّتة حاليًا، على النحو التالي.
Kotlin
val installedLanguages: Set<String> = splitInstallManager.installedLanguages
Java
Set<String> installedLanguages = splitInstallManager.getInstalledLanguages();
يمكنك بعد ذلك تحديد اللغات التي تريد إلغاء تثبيتها باستخدام الطريقة
deferredLanguageUninstall()، كما هو موضّح أدناه.
Kotlin
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)))
Java
splitInstallManager.deferredLanguageUninstall( Locale.forLanguageTag(sharedPrefs.getString(LANGUAGE_SELECTION)));
اختبار عمليات تثبيت الوحدات على الجهاز
تتيح لك مكتبة "عرض الميزات في Play" اختبار قدرة تطبيقك على تنفيذ ما يلي محليًا بدون الاتصال بـ "متجر Google Play":
- طلب تثبيت الوحدات ومراقبتها
- التعامل مع أخطاء التثبيت
- استخدِم
SplitCompatللوصول إلى الوحدات.
توضّح هذه الصفحة كيفية نشر حِزم APK المجزّأة لتطبيقك على جهاز الاختبار لكي تستخدم ميزة "عرض الميزات في Play" حِزم APK هذه تلقائيًا لمحاكاة طلب الوحدات وتنزيلها وتثبيتها من "متجر Google Play".
على الرغم من أنّه ليس عليك إجراء أي تغييرات على منطق تطبيقك، يجب استيفاء المتطلبات التالية:
- نزِّل أحدث إصدار من
bundletoolوثبِّته. يجب استخدامbundletoolلإنشاء مجموعة جديدة من حِزم APK القابلة للتثبيت من حِزمة تطبيقك.
إنشاء مجموعة من ملفات APK
إذا لم يسبق لك إنشاء حِزم APK المجزّأة لتطبيقك، يمكنك إنشاؤها على النحو التالي:
- أنشئ حزمة تطبيق لتطبيقك باستخدام إحدى الطرق التالية:
- استخدِم "استوديو Android" والمكوّن الإضافي المتوافق مع Android لنظام Gradle من أجل إنشاء مجموعة حزمات تطبيق Android وتوقيعها.
- إنشاء حِزمة تطبيق من سطر الأوامر
استخدِم
bundletoolلإنشاء مجموعة من حِزم APK لجميع إعدادات الأجهزة باستخدام الأمر التالي:bundletool build-apks --local-testing --bundle my_app.aab --output my_app.apks
تتضمّن العلامة --local-testing بيانات وصفية في ملفات البيان الخاصة بحِزم APK، والتي تتيح لمكتبة "عرض الميزات في Play" معرفة كيفية استخدام حِزم APK المجزّأة المحلية لاختبار تثبيت وحدات الميزات، بدون الاتصال بـ "متجر Google Play".
نشر تطبيقك على الجهاز
بعد إنشاء مجموعة من حِزم APK باستخدام العلامة --local-testing،
استخدِم bundletool لتثبيت الإصدار الأساسي من تطبيقك ونقل حِزم APK
الإضافية إلى مساحة التخزين المحلية على جهازك. يمكنك تنفيذ كلا الإجراءَين باستخدام الأمر التالي:
bundletool install-apks --apks my_app.apks
الآن، عند بدء تشغيل تطبيقك وإكمال مسار المستخدم لتنزيل وحدة ميزات وتثبيتها، تستخدم مكتبة "عرض الميزات في Play" حِزم APK التي تم نقلها من خلال bundletool إلى مساحة التخزين المحلية على الجهاز.
محاكاة خطأ في الشبكة
لمحاكاة عمليات تثبيت الوحدات من "متجر Google Play"، تستخدم مكتبة "عرض الميزات في Play" بديلاً لـ SplitInstallManager، يُسمى FakeSplitInstallManager، لطلب الوحدة. عند استخدام bundletool مع العلامة --local-testing
لإنشاء مجموعة من حِزم APK ونشرها على جهاز الاختبار، فإنّها
تتضمّن بيانات وصفية تطلب من مكتبة "عرض الميزات في Play" تبديل
طلبات البيانات من واجهة برمجة التطبيقات في تطبيقك تلقائيًا لاستدعاء FakeSplitInstallManager بدلاً من
SplitInstallManager.
يتضمّن FakeSplitInstallManager علامة منطقية يمكنك تفعيلها لمحاكاة خطأ في الشبكة في المرة التالية التي يطلب فيها تطبيقك تثبيت وحدة. للوصول إلى FakeSplitInstallManager في اختباراتك، يمكنك الحصول على مثيل له باستخدام FakeSplitInstallManagerFactory، كما هو موضّح أدناه:
Kotlin
// Creates an instance of FakeSplitInstallManager with the app's context. val fakeSplitInstallManager = FakeSplitInstallManagerFactory.create(context) // Tells Play Feature Delivery Library to force the next module request to // result in a network error. fakeSplitInstallManager.setShouldNetworkError(true)
Java
// Creates an instance of FakeSplitInstallManager with the app's context. FakeSplitInstallManager fakeSplitInstallManager = FakeSplitInstallManagerFactory.create(context); // Tells Play Feature Delivery Library to force the next module request to // result in a network error. fakeSplitInstallManager.setShouldNetworkError(true);