دمج عرض مواد العرض (Kotlin وJava)

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

إنشاء تطبيقات لـ Kotlin وJava

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

  1. عدِّل إصدار المكوّن الإضافي لنظام Gradle المتوافق مع Android في ملف build.gradle الخاص بمشروعك إلى 4.0.0 أو إصدار أحدث.

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

  3. في دليل حزمة مواد العرض، أنشِئ ملف build.gradle وأضِف الرمز التالي. احرص على تحديد اسم حزمة مواد العرض ونوع تسليم واحد فقط:

    رائع

    // In the asset pack's build.gradle file:
    plugins {
      id 'com.android.asset-pack'
    }
    
    assetPack {
        packName = "asset-pack-name" // Directory name for the asset pack
        dynamicDelivery {
            deliveryType = "[ install-time | fast-follow | on-demand ]"
        }
    }
    

    Kotlin

    // In the asset pack's build.gradle.kts file:
    plugins {
      id("com.android.asset-pack")
    }
    
    assetPack {
      packName.set("asset-pack-name") // Directory name for the asset pack
      dynamicDelivery {
        deliveryType.set("[ install-time | fast-follow | on-demand ]")
      }
    }
    
  4. في ملف build.gradle الخاص بتطبيق المشروع، أضِف اسم كل حزمة مواد عرض في مشروعك على النحو الموضّح أدناه:

    رائع

    // In the app build.gradle file:
    android {
        ...
        assetPacks = [":asset-pack-name", ":asset-pack2-name"]
    }
    

    Kotlin

    // In the app build.gradle.kts file:
    android {
        ...
        assetPacks += listOf(":asset-pack-name", ":asset-pack2-name")
    }
    
  5. في ملف settings.gradle الخاص بالمشروع، أدرِج كل حِزم مواد العرض في مشروعك كما هو موضّح أدناه:

    رائع

    // In the settings.gradle file:
    include ':app'
    include ':asset-pack-name'
    include ':asset-pack2-name'
    

    Kotlin

    // In the settings.gradle.kts file:
    include(":app")
    include(":asset-pack-name")
    include(":asset-pack2-name")
    
  6. في دليل حزمة مواد العرض، أنشِئ الدليل الفرعي التالي: src/main/assets.

  7. ضَع مواد العرض في دليل src/main/assets. يمكنك إنشاء أدلة فرعية هنا أيضًا. يُفترض أن تبدو بنية الدليل لتطبيقك الآن على النحو التالي:

    • build.gradle
    • settings.gradle
    • app/
    • asset-pack-name/build.gradle
    • asset-pack-name/src/main/assets/your-asset-directories
  8. إنشاء "مجموعة حزمات تطبيق Android" باستخدام Gradle في حِزمة التطبيق التي تم إنشاؤها، يتضمّن دليل المستوى الجذر الآن ما يلي:

    • asset-pack-name/manifest/AndroidManifest.xml: يضبط هذا الخيار معرّف حزمة مواد العرض ووضع العرض.
    • asset-pack-name/assets/your-asset-directories: الدليل الذي يحتوي على كل مواد العرض المقدّمة كجزء من حزمة مواد العرض

    تُنشئ أداة Gradle البيان لكل حزمة مواد عرض وتُخرج دليل assets/ لك.

  9. (اختياري) يمكنك تضمين مكتبة عرض المواد في Play إذا كنت تريد استخدام ميزة التقديم السريع والعرض عند الطلب.

    رائع

    implementation "com.google.android.play:asset-delivery:2.2.2"
    // For Kotlin use asset-delivery-ktx
    implementation "com.google.android.play:asset-delivery-ktx:2.2.2"
    

    Kotlin

    implementation("com.google.android.play:asset-delivery:2.2.2")
    // For Kotlin use core-ktx
    implementation("com.google.android.play:asset-delivery-ktx:2.2.2")
    

  10. (اختياري) يمكنك ضبط حِزمة التطبيق للتوافق مع تنسيقات ضغط الهيئة المختلفة.

الدمج مع واجهة برمجة التطبيقات Play Asset Delivery API

توفّر واجهة برمجة التطبيقات لعرض مواد العرض في Play فئة AssetPackManager لطلب حِزم مواد العرض وإدارة عمليات التنزيل والوصول إلى مواد العرض. احرص على إضافة مكتبة عرض المواد في Play إلى مشروعك أولاً.

يتم تنفيذ واجهة برمجة التطبيقات هذه وفقًا لنوع عرض حزمة مواد العرض التي تريد الوصول إليها. يتم عرض هذه الخطوات في المخطط الانسيابي التالي.

مخطط تدفق حزمة مواد العرض للغة البرمجة Java

الشكل 1. مخطط انسيابي للوصول إلى حِزم مواد العرض

التسليم في وقت التثبيت

تتوفّر حِزم مواد العرض التي تم ضبطها لتكون install-time على الفور عند تشغيل التطبيق. استخدِم واجهة برمجة تطبيقات AssetManager في Java للوصول إلى مواد العرض المعروضة في هذا الوضع:

Kotlin

import android.content.res.AssetManager
...
val context: Context = createPackageContext("com.example.app", 0)
val assetManager: AssetManager = context.assets
val stream: InputStream = assetManager.open("asset-name")

Java

import android.content.res.AssetManager;
...
Context context = createPackageContext("com.example.app", 0);
AssetManager assetManager = context.getAssets();
InputStream is = assetManager.open("asset-name");

متابعة سريعة وتوصيل عند الطلب

توضّح الأقسام التالية كيفية الحصول على معلومات حول حِزم مواد العرض قبل تنزيلها، وكيفية استدعاء واجهة برمجة التطبيقات لبدء التنزيل، وكيفية الوصول إلى الحِزم التي تم تنزيلها. تنطبق هذه الأقسام على حِزمتَي مواد العرض fast-follow وon-demand.

فحص الحالة

يتم تخزين كل حزمة مواد عرض في مجلد منفصل على وحدة التخزين الداخلية للتطبيق. استخدِم الطريقة getPackLocation() لتحديد المجلد الجذر لحزمة مواد العرض. تُرجع هذه الطريقة القيم التالية:

القيمة المعروضة الحالة
عنصر AssetPackLocation صالح المجلد الجذر في حزمة مواد العرض جاهز للوصول إليه فورًا على الرابط assetsPath().
null لا تتوفّر حزمة مواد عرض أو مواد عرض غير معروفة.

الحصول على معلومات تنزيل حِزم مواد العرض

يجب أن تفصح التطبيقات عن حجم الملف الذي يتم تنزيله قبل استرجاع حزمة مواد العرض. استخدِم الطريقة requestPackStates() أو getPackStates() لتحديد حجم الملف الذي تريد تنزيله وما إذا كان سبق تنزيل الحزمة.

Kotlin

suspend fun requestPackStates(packNames: List<String>): AssetPackStates

Java

Task<AssetPackStates> getPackStates(List<String> packNames)

requestPackStates() هي دالة تعليق تعرض كائن AssetPackStates، بينما تمثّل getPackStates() طريقة غير متزامنة تعرض Task<AssetPackStates>. تعرض الطريقة packStates() لكائن AssetPackStates رمز Map<String, AssetPackState>. تحتوي هذه الخريطة على حالة كل حزمة مواد عرض مطلوبة باسمها حسب اسمها:

Kotlin

AssetPackStates#packStates(): Map<String, AssetPackState>

Java

Map<String, AssetPackState> AssetPackStates#packStates()

يظهر الطلب النهائي في ما يلي:

Kotlin

const val assetPackName = "assetPackName"
coroutineScope.launch {
  try {
    val assetPackStates: AssetPackStates =
      manager.requestPackStates(listOf(assetPackName))
    val assetPackState: AssetPackState =
      assetPackStates.packStates()[assetPackName]
  } catch (e: RuntimeExecutionException) {
    Log.d("MainActivity", e.message)
  }
}

Java

final String assetPackName = "myasset";

assetPackManager
    .getPackStates(Collections.singletonList(assetPackName))
    .addOnCompleteListener(new OnCompleteListener<AssetPackStates>() {
        @Override
        public void onComplete(Task<AssetPackStates> task) {
            AssetPackStates assetPackStates;
            try {
                assetPackStates = task.getResult();
                AssetPackState assetPackState =
                    assetPackStates.packStates().get(assetPackName);
            } catch (RuntimeExecutionException e) {
                Log.d("MainActivity", e.getMessage());
                return;
            })

توفّر طرق AssetPackState التالية حجم حزمة مواد العرض والمبلغ الذي تم تنزيله حتى الآن (إذا طلب ذلك) والمبلغ الذي سبق نقله إلى التطبيق:

للحصول على حالة حزمة مواد عرض، استخدِم الطريقة status() التي تعرض الحالة كعدد صحيح يقابل حقلاً ثابتًا في الفئة AssetPackStatus. إنّ حِزمة مواد العرض غير المثبَّتة بعد تتضمّن الحالة AssetPackStatus.NOT_INSTALLED.

إذا تعذّر تنفيذ أحد الطلبات، استخدِم الطريقة errorCode() التي تتوافق قيمتها المعروضة مع حقل ثابت في الفئة AssetPackErrorCode.

تثبيت

استخدِم الطريقة requestFetch() أو fetch() لتنزيل حزمة مواد عرض للمرة الأولى، أو اطلب تعديل حزمة مواد عرض لإكمالها:

Kotlin

suspend fun AssetPackManager.requestFetch(packs: List<String>): AssetPackStates

Java

Task<AssetPackStates> fetch(List<String> packNames)

تعرض هذه الطريقة كائن AssetPackStates يحتوي على قائمة بالحُزم وحالات التنزيل وأحجامها الأولية. إذا كان قد سبق تنزيل حزمة مواد عرض مطلوبة عبر requestFetch() أو fetch()، سيتم عرض حالة التنزيل بدون بدء تنزيل إضافي.

تتبُّع حالات التنزيل

يجب تنفيذ AssetPackStateUpdatedListener لتتبُّع مستوى تقدُّم تثبيت حِزم مواد العرض. يتم تقسيم تحديثات الحالة حسب كل حزمة لدعم تتبّع حالة حِزم مواد العرض الفردية. يمكنك البدء في استخدام حِزم مواد العرض المتاحة قبل اكتمال جميع عمليات التنزيل الأخرى لطلبك.

Kotlin

fun registerListener(listener: AssetPackStateUpdatedListener)
fun unregisterListener(listener: AssetPackStateUpdatedListener)

Java

void registerListener(AssetPackStateUpdatedListener listener)
void unregisterListener(AssetPackStateUpdatedListener listener)

عمليات تنزيل كبيرة الحجم

إذا كان حجم التنزيل أكبر من 200 ميغابايت ولم يكن المستخدم متصلاً بشبكة Wi-Fi، لن يبدأ التنزيل إلى أن يمنح المستخدم موافقته صراحةً على مواصلة عملية التنزيل باستخدام اتصال بيانات الجوّال. وبالمثل، إذا كان حجم التنزيل كبيرًا وفقدان المستخدم شبكة Wi-Fi، يتم إيقاف التنزيل مؤقتًا ويجب الحصول على موافقة صريحة للمتابعة باستخدام اتصال بيانات الجوّال. حالة الحزمة المتوقفة مؤقتًا هي WAITING_FOR_WIFI. لبدء مسار واجهة المستخدم لطلب الموافقة من المستخدم، استخدِم الطريقة showConfirmationDialog().

يُرجى ملاحظة أنّه إذا لم يستدعي التطبيق هذه الطريقة، سيتم إيقاف التنزيل مؤقتًا وسيتم استئنافه تلقائيًا فقط عند معاودة اتصال المستخدم بشبكة Wi-Fi.

تأكيد من المستخدم مطلوب

إذا كانت الحزمة بالحالة REQUIRES_USER_CONFIRMATION، لن تتم عملية التنزيل إلا بعد قبول المستخدم لمربّع الحوار الذي يظهر مع العلامة showConfirmationDialog(). يمكن أن تحدث هذه الحالة إذا لم يتعرّف Play على التطبيق، على سبيل المثال، إذا تم تثبيت التطبيق من متجر خارجي. يُرجى العِلم أنّ طلب الرقم showConfirmationDialog() في هذه الحالة سيؤدي إلى تحديث التطبيق. بعد التحديث، سيكون عليك طلب الأصول مرة أخرى.

فيما يلي مثال على تنفيذ مستمع:

Kotlin

private val activityResultLauncher = registerForActivityResult(
    ActivityResultContracts.StartIntentSenderForResult()
) { result ->
    if (result.resultCode == RESULT_OK) {
        Log.d(TAG, "Confirmation dialog has been accepted.")
    } else if (result.resultCode == RESULT_CANCELED) {
        Log.d(TAG, "Confirmation dialog has been denied by the user.")
    }
}

assetPackManager.registerListener { assetPackState ->
  when(assetPackState.status()) {
    AssetPackStatus.PENDING -> {
      Log.i(TAG, "Pending")
    }
    AssetPackStatus.DOWNLOADING -> {
      val downloaded = assetPackState.bytesDownloaded()
      val totalSize = assetPackState.totalBytesToDownload()
      val percent = 100.0 * downloaded / totalSize

      Log.i(TAG, "PercentDone=" + String.format("%.2f", percent))
    }
    AssetPackStatus.TRANSFERRING -> {
      // 100% downloaded and assets are being transferred.
      // Notify user to wait until transfer is complete.
    }
    AssetPackStatus.COMPLETED -> {
      // Asset pack is ready to use. Start the game.
    }
    AssetPackStatus.FAILED -> {
      // Request failed. Notify user.
      Log.e(TAG, assetPackState.errorCode())
    }
    AssetPackStatus.CANCELED -> {
      // Request canceled. Notify user.
    }
    AssetPackStatus.WAITING_FOR_WIFI,
    AssetPackStatus.REQUIRES_USER_CONFIRMATION -> {
      if (!confirmationDialogShown) {
        assetPackManager.showConfirmationDialog(activityResultLauncher);
        confirmationDialogShown = true
      }
    }
    AssetPackStatus.NOT_INSTALLED -> {
      // Asset pack is not downloaded yet.
    }
    AssetPackStatus.UNKNOWN -> {
      Log.wtf(TAG, "Asset pack status unknown")
    }
  }
}

Java

assetPackStateUpdateListener = new AssetPackStateUpdateListener() {
    private final ActivityResultLauncher<IntentSenderRequest> activityResultLauncher =
      registerForActivityResult(
          new ActivityResultContracts.StartIntentSenderForResult(),
          new ActivityResultCallback<ActivityResult>() {
            @Override
            public void onActivityResult(ActivityResult result) {
              if (result.getResultCode() == RESULT_OK) {
                Log.d(TAG, "Confirmation dialog has been accepted.");
              } else if (result.getResultCode() == RESULT_CANCELED) {
                Log.d(TAG, "Confirmation dialog has been denied by the user.");
              }
            }
          });

    @Override
    public void onStateUpdate(AssetPackState assetPackState) {
      switch (assetPackState.status()) {
        case AssetPackStatus.PENDING:
          Log.i(TAG, "Pending");
          break;

        case AssetPackStatus.DOWNLOADING:
          long downloaded = assetPackState.bytesDownloaded();
          long totalSize = assetPackState.totalBytesToDownload();
          double percent = 100.0 * downloaded / totalSize;

          Log.i(TAG, "PercentDone=" + String.format("%.2f", percent));
          break;

        case AssetPackStatus.TRANSFERRING:
          // 100% downloaded and assets are being transferred.
          // Notify user to wait until transfer is complete.
          break;

        case AssetPackStatus.COMPLETED:
          // Asset pack is ready to use. Start the game.
          break;

        case AssetPackStatus.FAILED:
          // Request failed. Notify user.
          Log.e(TAG, assetPackState.errorCode());
          break;

        case AssetPackStatus.CANCELED:
          // Request canceled. Notify user.
          break;

        case AssetPackStatus.WAITING_FOR_WIFI:
        case AssetPackStatus.REQUIRES_USER_CONFIRMATION:
          if (!confirmationDialogShown) {
            assetPackManager.showConfirmationDialog(activityResultLauncher);
            confirmationDialogShown = true;
          }
          break;

        case AssetPackStatus.NOT_INSTALLED:
          // Asset pack is not downloaded yet.
          break;
        case AssetPackStatus.UNKNOWN:
          Log.wtf(TAG, "Asset pack status unknown")
          break;
      }
    }
}

ويمكنك بدلاً من ذلك استخدام الطريقة getPackStates() للاطّلاع على حالة عمليات التنزيل الحالية. AssetPackStates تحتوي على مستوى تقدّم عملية التنزيل وحالة عملية التنزيل وأيّ رموز أخطاء متعلّقة بالأخطاء.

الوصول إلى حِزم مواد العرض

يمكنك الوصول إلى حزمة مواد عرض باستخدام طلبات نظام الملفات بعد وصول طلب التنزيل إلى الحالة COMPLETED. استخدِم الطريقة getPackLocation() للحصول على المجلد الجذر لحزمة مواد العرض.

يتم تخزين مواد العرض في الدليل assets ضمن الدليل الجذري لحزمة مواد العرض. يمكنك الحصول على المسار إلى دليل assets باستخدام طريقة الراحة assetsPath(). اتّبِع الطريقة التالية للحصول على المسار الذي يؤدي إلى مادة عرض معيّنة:

Kotlin

private fun getAbsoluteAssetPath(assetPack: String, relativeAssetPath: String): String? {
    val assetPackPath: AssetPackLocation =
      assetPackManager.getPackLocation(assetPack)
      // asset pack is not ready
      ?: return null

    val assetsFolderPath = assetPackPath.assetsPath()
    // equivalent to: FilenameUtils.concat(assetPackPath.path(), "assets")
    return FilenameUtils.concat(assetsFolderPath, relativeAssetPath)
}

Java

private String getAbsoluteAssetPath(String assetPack, String relativeAssetPath) {
    AssetPackLocation assetPackPath = assetPackManager.getPackLocation(assetPack);

    if (assetPackPath == null) {
        // asset pack is not ready
        return null;
    }

    String assetsFolderPath = assetPackPath.assetsPath();
    // equivalent to: FilenameUtils.concat(assetPackPath.path(), "assets");
    String assetPath = FilenameUtils.concat(assetsFolderPath, relativeAssetPath);
    return assetPath;
}

طرق أخرى في Play Asset Delivery API

في ما يلي بعض الطرق الإضافية لواجهة برمجة التطبيقات التي قد تريد استخدامها في تطبيقك.

إلغاء الطلب

استخدِم cancel() لإلغاء طلب حزمة مواد عرض نشط. يُرجى العِلم بأنّ هذا الطلب هو أفضل عملية جهد.

إزالة حزمة مواد عرض

استخدِم requestRemovePack() أو removePack() لتحديد موعد لإزالة حزمة مواد عرض.

الحصول على مواقع جغرافية لحِزم مواد عرض متعدّدة

استخدِم getPackLocations() للاستعلام عن حالة حِزم مواد عرض متعدّدة بشكل مجمّع، ما يؤدي إلى عرض خريطة لحِزم مواد العرض ومواقعها الجغرافية. تحتوي الخريطة التي يعرضها "getPackLocations()" على إدخال لكل حزمة يتم تنزيلها وتحديثها حاليًا.

الخطوة التالية

يمكنك اختبار عرض المواد في Play محليًا ومن Google Play.