ضبط ميزة التسليم عند الطلب

تتيح لك وحدات الميزات فصل بعض الميزات والموارد. من الوحدة الأساسية في تطبيقك وتضمينها في حِزمة التطبيق. من خلال عرض الميزات في Play، يمكن للمستخدمين مثلاً تنزيل تلك الميزات وتثبيتها المكونات عند الطلب بعد تثبيت حزمة APK الأساسية لتطبيقك.

على سبيل المثال، ضع في اعتبارك تطبيقًا للمراسلة النصية يتضمن وظيفة التي تلتقط وترسل رسائل مصوّرة، ولكن فقط نسبة صغيرة من المستخدمين إرسال رسائل مصورة. قد يكون من المنطقي تضمين رسائل مصورة وحدة الميزات القابلة للتنزيل. بهذه الطريقة، يتم تنزيل التطبيق أصغر لجميع المستخدمين وفقط هؤلاء المستخدمين الذين يرسلون رسائل صور وتنزيل هذا المكون الإضافي.

يُرجى العِلم أنّ هذا النوع من التقسيم إلى وحدات يتطلّب المزيد من الجهد وقد يتطلّب بإعادة هيكلة التعليمات البرمجية الحالية لتطبيقك، لذا فكّر بعناية في أي من الاستفادة القصوى من ميزات التطبيق من التوافر للمستخدمين عند الطلب. للتعرّف بشكل أفضل على حالات الاستخدام والإرشادات المتعلّقة بالميزات المتاحة عند الطلب، اطّلِع على أفضل ممارسات تجربة المستخدم للتسليم عند الطلب.

إذا أردت تقسيم ميزات التطبيق تدريجيًا إلى وحدات مع مرور الوقت، بدون تفعيل خيارات التوصيل المتقدّمة، مثل التوصيل عند الطلب، ضبط التسليم في وقت التثبيت

تساعدك هذه الصفحة في إضافة وحدة ميزات إلى مشروع تطبيقك وتهيئته للتسليم عند الطلب. قبل أن تبدأ، تأكد من باستخدام الإصدار 3.5 من "استوديو Android" أو الإصدارات الأحدث والإصدار 3.5.0 من المكوّن الإضافي لنظام Gradle المتوافق مع Android أو أعلى.

إعداد وحدة جديدة للتسليم عند الطلب

تتمثل أسهل طريقة لإنشاء وحدة ميزات جديدة في استخدام الإصدار 3.5 من "استوديو Android" أو إصدار أحدث لأنّ وحدات الميزات على وحدة التطبيق الأساسية، يمكنك إضافتها فقط إلى الوحدات ومشروعات التطبيقات.

لإضافة وحدة ميزة إلى مشروع تطبيقك باستخدام "استوديو Android"، يُرجى اتّباع الخطوات التالية: والمتابعة على النحو التالي:

  1. افتح مشروع تطبيقك في بيئة التطوير المتكاملة (IDE)، إذا لم يسبق لك إجراء ذلك.
  2. حدد ملف > جديد > وحدة جديدة من شريط القوائم.
  3. في مربّع الحوار إنشاء وحدة جديدة، اختَر وحدة الميزات الديناميكية وانقر على التالي.
  4. في قسم تهيئة الوحدة الجديدة، أكمل التالي:
    1. اختَر وحدة التطبيق الأساسية لمشروع تطبيقك من. القائمة المنسدلة.
    2. حدِّد اسم الوحدة. يستخدم IDE هذا الاسم لتحديد باعتبارها مشروعًا فرعيًا من Gradle في ملف إعدادات Gradle عندما تريد إنشاء حزمة تطبيقك، فإن Gradle يستخدم العنصر الأخير من المشروع الفرعي لإدخال السمة <manifest split> في بيان وحدة الميزات.
    3. حدِّد اسم الحزمة للوحدة. "استوديو Android" بشكل تلقائي اسم حزمة يضم اسم الحزمة الجذر الوحدة الأساسية واسم الوحدة الذي حددته في الخطوة السابقة.
    4. اختَر الحد الأدنى لمستوى واجهة برمجة التطبيقات الذي تريد أن تتيحه الوحدة. يجب أن تتطابق هذه القيمة مع قيمة الوحدة الأساسية.
  5. انقر على التالي.
  6. في قسم خيارات تنزيل الوحدة، أكمل ما يلي:

    1. حدِّد عنوان الوحدة باستخدام ما يصل إلى 50 حرفًا. النظام الأساسي هذا العنوان لتحديد الوحدة للمستخدمين، على سبيل المثال، وتأكيد ما إذا كان المستخدم يريد تنزيل الوحدة أم لا. لهذا الغرض السبب، يجب أن تتضمّن الوحدة الأساسية في تطبيقك عنوان الوحدة مورد السلسلة، والذي الترجمة. عند إنشاء الوحدة باستخدام "استوديو Android"، يتمكن بيئة التطوير المتكاملة (IDE) من تضيف مورد السلسلة إلى الوحدة الأساسية من أجلك وتُدخل الإدخال التالي في بيان وحدة الميزات:

      <dist:module
          ...
          dist:title="@string/feature_title">
      </dist:module>
      
    2. في القائمة المنسدلة ضمن تضمين وقت التثبيت، اختَر عدم تضمين الوحدة أثناء التثبيت. يضيف "استوديو Android" التالية في بيان الوحدة ليعكس اختيارك:

      <dist:module ... >
        <dist:delivery>
            <dist:on-demand/>
        </dist:delivery>
      </dist:module>
      
    3. ضع علامة في المربّع بجانب دمج إذا كنت تريد إتاحة هذه الوحدة. للأجهزة التي تعمل بنظام التشغيل Android 4.4 (المستوى 20 لواجهة برمجة التطبيقات) والإصدارات الأقدم والمضمّنة في حِزم APK متعددة. يعني هذا أنّه يمكنك تفعيل السلوك عند الطلب لهذه الوحدة. وإيقاف الدمج لحذفه من الأجهزة غير المتوافقة تنزيل حِزم APK مجزّأة وتثبيتها يضيف "استوديو Android" التالية في بيان الوحدة ليعكس اختيارك:

      <dist:module ...>
          <dist:fusing dist:include="true | false" />
      </dist:module>
      
  7. انقر على إنهاء.

بعد انتهاء "استوديو 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 المثبَّتة التي تنتمي إلى تطبيقك. لمزيد من المعلومات، يُرجى قراءة إدارة تحديثات التطبيقات

للوصول إلى رمز الوحدة ومواردها، يحتاج التطبيق إلى تفعيل SegmentCompat تجدر الإشارة إلى أنّ SegmentCompat لا مطلوبة لتطبيقات 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 تم رفض الطلب نظرًا لوجود طلب واحد على الأقل طلب يتم تنزيله حاليًا. التحقّق ممّا إذا كانت هناك أيّ طلبات لا تزال قيد التنزيل، على النحو الموضّح في النموذج أعلاه.
الوحدة_غير متوفرة يتعذَّر على Google Play العثور على الوحدة المطلوبة استنادًا إلى الوحدة المطلوبة على الإصدار الحالي المثبَّت من التطبيق والجهاز وحساب المستخدم في Google Play الحساب. وإذا لم يتمكّن المستخدم من الوصول إلى الوحدة، عليك إبلاغه بذلك.
طلب_غير صالح تلقّى Google Play الطلب، ولكن لم يتم قبوله. غير صالح. التحقق من أن المعلومات المضمنة في الطلب كاملة ودقيقة.
الجلسة التي لم يتم العثور عليها لم يتم العثور على جلسة لرقم تعريف جلسة معيّن. في حال كنت تحاول مراقبة حالة طلب باستخدام معرّف الجلسة، تأكّد من أنّ رقم تعريف الجلسة صحيح.
واجهة برمجة التطبيقات_غير متوفرة مكتبة عرض الميزات في Play غير متاحة على الجهاز الحالي. أي أنّ الجهاز لا يمكنه تنزيل المحتوى وتثبيته. ميزات عند الطلب. بالنسبة إلى الأجهزة التي تعمل بالإصدار 4.4 من نظام التشغيل Android (المستوى 20 من واجهة برمجة التطبيقات) أو الإصدارات الأقدم، عليك: تضمين وحدات الميزات أثناء التثبيت باستخدام سمة dist:fusing في البيان. لمزيد من المعلومات، يمكنك الاطّلاع على بيان وحدة الميزات.
خطأ_الشبكة تعذَّرت تلبية الطلب لخطأ في الشبكة. طلب إنشاء اتصال بالشبكة من المستخدم أو الانتقال إلى شبكة مختلفة.
تم رفض منح الإذن بالوصول يتعذّر على التطبيق تسجيل الطلب بسبب عدم توفّر أذونات كافية. يحدث هذا عادةً عندما يعمل التطبيق في الخلفية. حاوِل إجراء الطلب عندما يعود التطبيق إلى المقدّمة.
INCOMPATIBLE_WITH_EXISTING_SESSION يحتوي الطلب على وحدة واحدة أو أكثر سبق أن تم استخدامها طلبها ولكن لم يتم تثبيتها بعد. يمكنك إما إنشاء طلب جديد لا يتضمن الوحدات التي طلبَ التطبيق ذلك من قبل، أو يمكنك انتظار جميع الوحدات المطلوبة حاليًا لإتمام التثبيت قبل إعادة محاولة الطلب.

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

SERVICE_DIED توقف الخدمة المسؤولة عن التعامل مع الطلب. يُرجى إعادة محاولة إرسال الطلب.

يتلقّى SplitInstallStateUpdatedListener SplitInstallSessionState مع رمز الخطأ هذا، الحالة FAILED ومعرّف الجلسة -1.

سعة التخزين غير متوفرة لا تتوفّر مساحة تخزين مجانية كافية على الجهاز لتثبيت الميزة واحدة. يجب إبلاغ المستخدم بأنّه لا تتوفّر لديه مساحة تخزين كافية لتثبيت هذه الإضافة. الجديدة.
SPLITCOMPAT_VERIFICATION_ERROR، وSPLITCOMPAT_EMULATION_ERROR، وSPLITCOMPAT_COPY_ERROR تعذّر على spCompat تحميل وحدة الميزات. من المفترض أن يتم حل هذه الأخطاء تلقائيًا بعد التطبيق التالي إعادة التشغيل.
متجر Play لم يتم العثور عليه تطبيق "متجر Play" غير مثبّت على الجهاز. إبلاغ المستخدم بضرورة تنزيل تطبيق "متجر Play" الجديدة.
APP_NOT_OWNED لم يتم تثبيت التطبيق من خلال Google Play ولا يمكن تثبيت الميزة تم تنزيله. لا يمكن أن يحدث هذا الخطأ إلا لعمليات التثبيت المؤجلة. إذا أردت أن يكتسب المستخدم التطبيق على Google Play، استخدم startInstall() التي يمكنها الحصول على البيانات اللازمة تأكيد المستخدم.
INTERNAL_ERROR حدث خطأ داخلي في "متجر 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) أو أعلى، عليك استخدام splitInstallHelper من أجل تحديث مكونات التطبيق باستخدام الوحدة الجديدة.

فشل تعذَّرت تلبية الطلب قبل تحميل الوحدة التي تم تثبيتها على الجهاز. اطلب من المستخدم إعادة محاولة الطلب أو إلغائه.
جارٍ الإلغاء يجري إلغاء الطلب على الجهاز. لمزيد من المعلومات، انتقِل إلى القسم الخاص بكيفية إلغاء طلب تثبيت التطبيق.
تم إلغاؤها تم إلغاء الطلب.

الحصول على تأكيد من المستخدم

في بعض الحالات، قد يطلب Google Play تأكيدًا من المستخدم قبل تنفيذ طلب تنزيل البيانات. على سبيل المثال، إذا لم تثبّت Google تطبيقك. التشغيل أو ما إذا كنت تحاول إجراء تنزيل كبير الحجم عبر بيانات الجوّال. في مثل هذه الحالات، حالة تقريرَي الطلب 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 العقد. يُرجى الاطّلاع على واجهات برمجة تطبيقات نتائج الأنشطة.

يتم تعديل حالة الطلب استنادًا إلى ردّ المستخدم:

  • إذا قبل المستخدم رسالة التأكيد، تتغير حالة الطلب إلى 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);

وحدات الوصول

للوصول إلى الرمز والموارد من الوحدة النمطية التي تم تنزيلها بعد تنزيلها، يحتاج تطبيقك إلى تفعيل مكتبة divCompat لكل من تطبيقك ولكل نشاط في وحدات الميزات الخاصة بتطبيقك عمليات التنزيل.

مع ذلك، تجدر الإشارة إلى أنّ المنصة تخضع لما يلي: القيود المفروضة على الوصول إلى محتويات وحدة ما، لبعض الوقت (أيام، في بعض الحالات) بعد تنزيل الوحدة:

  • لا يمكن للنظام الأساسي تطبيق أي إدخالات جديدة في البيان تقدّمها الوحدة.
  • لا يمكن للنظام الأساسي الوصول إلى موارد الوحدة لمكونات واجهة مستخدم النظام، مثل الإشعارات. إذا كنت بحاجة إلى استخدام هذه الموارد على الفور، بما في ذلك الموارد في الوحدة الأساسية في تطبيقك

تفعيل SegmentCompat

لكي يتمكّن التطبيق من الوصول إلى رمز الوصول والموارد من الوحدة التي تم تنزيلها، يُرجى اتّباع الخطوات التالية: يجب تفعيل SegmentCompat باستخدام طريقة واحدة فقط كما هو موضَّح في الأقسام التالية.

بعد تفعيل SegmentCompat للتطبيق، عليك أيضًا تفعيل splitCompat. لكل نشاط في وحدات الميزات التي التي يريد التطبيق الوصول إليها.

تعريف SegmentCompatApplication في البيان

إنّ أبسط طريقة لتفعيل splitCompat هي بتعريف SplitCompatApplication. باعتبارها الفئة الفرعية Application في في بيان تطبيقك، كما هو موضّح أدناه:

<application
    ...
    android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
</application>

بعد تثبيت التطبيق على جهاز، يمكنك الوصول إلى الرمز والموارد من يتم تنزيل وحدات الميزات تلقائيًا.

استدعاء splitCompat في وقت التشغيل

يمكنك أيضًا تفعيل splitCompat في أنشطة أو خدمات معينة أثناء التشغيل. يجب تفعيل SegmentCompat بهذه الطريقة لبدء الأنشطة المضمّنة في وحدات الميزات. ولإجراء ذلك، يمكنك إلغاء attachBaseContext كما هو موضّح أدناه.

إذا كان لديك فئة تطبيق مخصّصة، جعله يمدّد SplitCompatApplication لتفعيل سبلCompat للتطبيق على النحو الموضَّح أدناه:

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);
    }
}

تفعيل spCompat للأنشطة المتعلّقة بالوحدات

بعد تفعيل SegmentCompat للتطبيق الأساسي، عليك تفعيل 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 هي اسم حزمة التطبيق والمعلمة الثانية هي اسم فئة النشاط الكامل.

عندما يكون لديك نشاط في وحدة ميزات نزّلتها عند الطلب، يجب تفعيل SegmentCompat في النشاط

بدء خدمة محدّدة في وحدة من الميزات

يمكنك تشغيل الخدمات المحددة في وحدات الميزات باستخدام 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 الأساسية، بمجرد تثبيت الوحدة الاختيارية.

رمز الدخول من وحدة مختلفة

الوصول إلى الرمز الأساسي من وحدة معيّنة

يمكن استخدام الرمز المتوفّر داخل الوحدة الأساسية مباشرةً بواسطة وحدات أخرى. لست مضطرًا إلى القيام بأي شيء خاص؛ ما عليك سوى استيراد الفصول الدراسية التي تحتاجها واستخدامها.

رمز وحدة الوصول من وحدة أخرى

لا يمكن الوصول الثابت إلى كائن أو فئة داخل وحدة من خلال الوحدة مباشرة، ولكن يمكن الوصول إليها بشكل غير مباشر باستخدام الانعكاس.

يجب أن تكون حذرًا بشأن عدد مرات حدوث ذلك، وذلك بسبب تكاليف الأداء للانعكاس. بالنسبة إلى حالات الاستخدام المعقدة، استخدم أطر عمل حقن التبعية مثل أداة السحب 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()) أو أعِد تثبيت سبلCompat عليه بعد انتهاء وحدة الميزات التثبيت.

تحميل رمز برمجي أصلي في تطبيق باستخدام ميزة التسليم عند الطلب

نقترح استخدام ReLinker لتحميل جميع مكتباتك الأصلية عند استخدام التسليم عند الطلب لوحدات الميزات. يصلح ReLinker لمشكلة في تحميل المكتبات الأصلية بعد تثبيت الجديدة. يمكنك الحصول على مزيد من المعلومات حول ReLinker في نصائح حول خطة JNI لنظام التشغيل Android

تحميل رمز أصلي من وحدة اختيارية

بعد تثبيت التقسيم، ننصحك بتحميل الرمز الأصلي من خلال 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 الفوري على Android 8.0 (المستوى 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 وسبل أمامك على المستوى 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 اختبار قدرة تطبيقك على تنفيذ التالي، بدون الاتصال بـ "متجر Play":

توضّح هذه الصفحة كيفية نشر حِزم APK المجزّأة لتطبيقك على جهاز الاختبار كي يتمكّن من أنّ ميزة "عرض الميزات في Play" تستخدم تلقائيًا حِزم APK هذه لمحاكاة طلب وتنزيل وتثبيت وحدات من "متجر Play"

على الرغم من أنك لست بحاجة إلى إجراء أي تغييرات على منطق تطبيقك، يجب عليك استيفاء المتطلبات التالية:

  • تنزيل أحدث إصدار من bundletool وتثبيته. تحتاج إلى bundletool لإنشاء مجموعة جديدة من حِزم APK القابلة للتثبيت من خلال تطبيقك. حُزم.

إنشاء مجموعة من حِزم APK

أنشئ حِزم APK المجزّأة لتطبيقك، إذا لم يسبق لك إجراء ذلك، على النحو التالي:

  1. يمكنك إنشاء حِزمة تطبيق لتطبيقك باستخدام إحدى الطرق التالية:
  2. استخدام bundletool لإنشاء مجموعة من حِزم APK لجميع الأجهزة باستخدام الأمر التالي:

    bundletool build-apks --local-testing
      --bundle my_app.aab
      --output my_app.apks
    

تتضمّن العلامة --local-testing بيانات وصفية في حِزم APK الخاصة بك أن يتيح لمكتبة عرض الميزات في Play معرفة كيفية استخدام حِزم APK المجزّأة على الجهاز لاختبار حزمة APK. تثبيت وحدات الميزات بدون الاتصال بـ "متجر Play".

نشر تطبيقك على الجهاز

بعد إنشاء مجموعة من حِزم APK باستخدام العلامة --local-testing، استخدام "bundletool" لتثبيت الإصدار الأساسي من تطبيقك ونقل بيانات إضافية حِزم APK إلى مساحة التخزين المحلية على جهازك. يمكنك تنفيذ كلا الإجراءين باستخدام الأمر التالي:

bundletool install-apks --apks my_app.apks

والآن، عند بدء تشغيل التطبيق وإكمال مسار المستخدم لتنزيل التطبيق وتثبيته وحدة ميزة، تستخدم مكتبة عرض الميزات في Play حِزم APK التي bundletool تم نقله إلى مساحة التخزين المحلية للجهاز.

محاكاة خطأ في الشبكة

لمحاكاة عمليات تثبيت الوحدات من "متجر 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);