ادغام کردن ارائه دارایی (Kotlin و Java)

از مراحل این راهنما برای دسترسی به بسته‌های دارایی برنامه‌تان از کد Java استفاده کنید.

ساختن برای Kotlin و Java

از مراحل زیر برای ساختن «ارائه دارایی‌های Play» در Android App Bundle پروژه‌تان استفاده کنید. برای انجام این مراحل، نیازی به استفاده از Android Studio ندارید.

  1. نسخه افزایه Android Gradle را در فایل 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 ]"
        }
    }

    کاتلین

    // 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"]
    }

    کاتلین

    // 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'

    کاتلین

    // 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 Asset Delivery را اضافه کنید

    شیک

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

    کاتلین

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

  10. (اختیاری) دسته برنامه‌تان را برای پشتیبانی از قالب‌های فشرده‌سازی بافت مختلف پیکربندی کنید.

ادغام کردن با Play Asset Delivery API

Play Asset Delivery Java API کلاس AssetPackManager را برای درخواست بسته‌های دارایی، مدیریت بارگیری‌ها، و دسترسی به دارایی‌ها ارائه می‌دهد. حتماً ابتدا کتابخانه «ارائه دارایی‌های Play» را به پروژه‌تان اضافه کنید.

این API را براساس نوع توزیع بسته دارایی که می‌خواهید به آن دسترسی داشته باشید پیاده‌سازی می‌کنید. این مراحل در روندنمای زیر نشان داده شده است.

نمودار جریان بسته دارایی برای زبان برنامه‌نویسی Java

شکل ۱. نمودار جریان برای دسترسی به بسته‌های دارایی

تحویل در زمان نصب

بسته‌های دارایی پیکربندی‌شده به‌عنوان install-time بلافاصله در راه‌اندازی برنامه دردسترس هستند. از Java AssetManager API برای دسترسی به دارایی‌های ارائه‌شده در این حالت استفاده کنید:

کاتلین

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")

جاوا

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() برای تعیین اندازه بارگیری و اینکه آیا بسته درحال بارگیری است یا نه استفاده کنید.

کاتلین

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

جاوا

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

‫requestPackStates() یک تابع تعلیق است که یک شیء AssetPackStates را برمی‌گرداند، درحالی‌که getPackStates() یک روش ناهمگام است که یک Task<AssetPackStates> را برمی‌گرداند. روش packStates() شیء AssetPackStates، Map<String, AssetPackState> را برمی‌گرداند. این نقشه حاوی وضعیت هر بسته دارایی درخواست‌شده است که با نام آن کلید شده است:

کاتلین

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

جاوا

Map<String, AssetPackState> AssetPackStates#packStates()

درخواست نهایی به‌صورت زیر نشان داده می‌شود:

کاتلین

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

جاوا

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() برای بارگیری بسته دارایی برای اولین‌بار استفاده کنید یا برای تکمیل به‌روزرسانی بسته دارایی تماس بگیرید:

کاتلین

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

جاوا

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

این روش یک شیء AssetPackStates برمی‌گرداند که حاوی فهرستی از بسته‌ها و وضعیت‌ها و اندازه‌های بارگیری اولیه آن‌ها است. اگر بسته دارایی درخواست‌شده ازطریق requestFetch() یا fetch() قبلاً بارگیری شده باشد، وضعیت بارگیری برگردانده می‌شود و بارگیری دیگری شروع نمی‌شود.

پایش وضعیت بارگیری

باید AssetPackStateUpdatedListener را برای پیگیری پیشرفت نصب بسته‌های دارایی پیاده‌سازی کنید. به‌روزرسانی‌های وضعیت برای هر بسته تفکیک شده است تا از ردیابی وضعیت بسته‌های دارایی تکی پشتیبانی شود. می‌توانید استفاده از بسته‌های دارایی دردسترس را قبل‌از تکمیل شدن همه بارگیری‌های دیگر برای درخواستتان شروع کنید.

کاتلین

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

جاوا

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

بارگیری‌های بزرگ

اگر حجم بارگیری بیشتر از ۲۰۰ مگابایت باشد و کاربر به Wi-Fi متصل نباشد، بارگیری شروع نمی‌شود تا زمانی که کاربر صریحاً رضایت خود را برای ادامه بارگیری بااستفاده از اتصال داده تلفن همراه اعلام کند. به‌طور مشابه، اگر حجم بارگیری زیاد باشد و کاربر اتصال Wi-Fi را ازدست بدهد، بارگیری موقتاً متوقف می‌شود و برای ادامه دادن بااستفاده از اتصال داده تلفن همراه، رضایت صریح لازم است. بسته موقتاً متوقف‌شده دارای وضعیت WAITING_FOR_WIFI است. برای راه‌اندازی جریان واسط کاربر برای درخواست رضایت از کاربر، از روش showConfirmationDialog() استفاده کنید.

توجه داشته باشید که اگر برنامه این روش را فراخوانی نکند، بارگیری موقتاً متوقف می‌شود و فقط زمانی‌که کاربر دوباره به اتصال Wi-Fi برگردد به‌طور خودکار ازسر گرفته می‌شود.

تأیید کاربر لازم است

اگر بسته‌ای وضعیت REQUIRES_USER_CONFIRMATION داشته باشد، بارگیری ادامه نخواهد یافت تا زمانی که کاربر کادر گفتگویی را که با showConfirmationDialog() نشان داده می‌شود بپذیرد. این وضعیت زمانی رخ می‌دهد که برنامه توسط Play شناسایی نشود—برای مثال، اگر برنامه از منبع جانبی بارگیری شده باشد. توجه داشته باشید که فراخوانی showConfirmationDialog() در این مورد باعث به‌روزرسانی برنامه می‌شود. پس‌از به‌روزرسانی، باید دوباره دارایی‌ها را درخواست کنید.

در زیر نمونه‌ای از پیاده‌سازی شنونده آورده شده است:

کاتلین

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

جاوا

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() دریافت کنید. از روش زیر برای دریافت مسیر دارایی خاصی استفاده کنید:

کاتلین

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

جاوا

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 آزمایش کنید.