ผสานรวมการส่งเนื้อหา (Kotlin และ Java)

ทำตามขั้นตอนในคู่มือนี้เพื่อเข้าถึง Asset Pack ของแอปจากโค้ด Java

บิลด์สำหรับ Kotlin และ Java

ทำตามขั้นตอนต่อไปนี้เพื่อสร้างการส่งเนื้อหา Play ลงใน App Bundle ของ Android ในโปรเจ็กต์ คุณไม่จำเป็นต้องใช้ Android Studio เพื่อทําตามขั้นตอนเหล่านี้

  1. อัปเดตเวอร์ชันของปลั๊กอิน Android Gradle ในโปรเจ็กต์ build.gradle ไฟล์ไปยัง 4.0.0 หรือใหม่กว่า

  2. ในไดเรกทอรีระดับบนสุดของโปรเจ็กต์ ให้สร้างไดเรกทอรีสำหรับแพ็กเกจชิ้นงาน ระบบจะใช้ชื่อไดเรกทอรีนี้เป็นชื่อแพ็กเนื้อหา ชื่อแพ็กเนื้อหาต้องขึ้นต้นด้วยตัวอักษรและมีได้เฉพาะตัวอักษร ตัวเลข และขีดล่างเท่านั้น

  3. ในไดเรกทอรี Asset Pack ให้สร้างไฟล์ build.gradle แล้วเพิ่มเมธอด โค้ดต่อไปนี้ อย่าลืมระบุชื่อ Asset Pack และระบุเพียงชื่อเดียว ประเภทการนำส่ง:

    Groovy

    // 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. เพิ่มชื่อ Asset Pack ทั้งหมดในไฟล์ 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 App Bundle ด้วย Gradle ใน App Bundle ที่สร้างขึ้น ตอนนี้ไดเรกทอรีระดับรูทได้รวม ดังต่อไปนี้:

    • asset-pack-name/manifest/AndroidManifest.xml: กำหนดค่าตัวระบุและโหมดการนำส่งของ Asset Pack
    • asset-pack-name/assets/your-asset-directories: ไดเรกทอรีที่มีการนำส่งเนื้อหาทั้งหมดซึ่งเป็นส่วนหนึ่งของ Asset Pack

    Gradle สร้างไฟล์ Manifest สำหรับ Asset Pack แต่ละรายการและเอาต์พุต assets/ ไดเรกทอรีให้กับคุณ

  9. (ไม่บังคับ) ใส่ไลบรารีการนำส่งเนื้อหา Play หากคุณวางแผนที่จะใช้การนำส่งเนื้อหาที่รวดเร็วและแบบออนดีมานด์

    Groovy

    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"

    Kotlin

    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. (ไม่บังคับ) กำหนดค่า App Bundle ให้รองรับรูปแบบการบีบอัดพื้นผิวที่แตกต่างกัน

ผสานรวมกับ Play Asset Delivery API

Play Asset Delivery Java API มีคลาส AssetPackManager สำหรับขอ Asset Pack, จัดการการดาวน์โหลด และเข้าถึงเนื้อหา อย่าลืมเพิ่มไลบรารี Play Asset Delivery ลงในโปรเจ็กต์ก่อน

คุณใช้ API นี้ตามประเภทการนำส่งของ Asset Pack ที่ต้องการเข้าถึง ขั้นตอนเหล่านี้จะแสดงในโฟลว์ชาร์ตต่อไปนี้

แผนภาพโฟลว์ของ Asset Pack สำหรับภาษาการเขียนโปรแกรม Java

รูปที่ 1 แผนภาพสำหรับการเข้าถึง Asset Pack

การนำส่งเมื่อติดตั้ง

Asset Pack ที่กำหนดค่าเป็น install-time จะพร้อมใช้งานในแอปทันที เปิดใช้งาน ใช้ Java AssetManager API เพื่อเข้าถึงเนื้อหาที่แสดงในโหมดนี้

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

การแสดงโฆษณาตามอย่างรวดเร็วและแบบออนดีมานด์

ส่วนต่อไปนี้แสดงวิธีรับข้อมูลเกี่ยวกับ Asset Pack ก่อนวันที่ การดาวน์โหลดแอปพลิเคชัน วิธีเรียก API เพื่อเริ่มต้นการดาวน์โหลด และวิธีการ เข้าถึงแพ็กที่ดาวน์โหลดได้ ส่วนเหล่านี้ใช้กับ fast-follow และ Asset Pack on-demand

ตรวจสอบสถานะ

Asset Pack แต่ละรายการจะเก็บไว้ในโฟลเดอร์แยกกันในที่จัดเก็บข้อมูลภายในของแอป ใช้เมนู getPackLocation() ในการกำหนดโฟลเดอร์รูทของ Asset Pack เมธอดนี้จะแสดงผลค่าต่อไปนี้

ผลลัพธ์ สถานะ
ออบเจ็กต์ AssetPackLocation ที่ถูกต้อง โฟลเดอร์รูทของ Asset Pack พร้อมให้เข้าถึงได้ทันทีที่ assetsPath()
null แพ็กเกจชิ้นงานหรือชิ้นงานที่ไม่ทราบไม่พร้อมใช้งาน

ดูข้อมูลการดาวน์โหลดเกี่ยวกับ Asset Pack

แอปต้องเปิดเผยขนาดของการดาวน์โหลดก่อนดึงข้อมูลเนื้อหา แพ็ก ใช้วิธี 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 วิธีการระบุขนาดของ Asset Pack จำนวนการดาวน์โหลดจนถึงตอนนี้ (หาก ) และจำนวนเงินที่โอนไปยังแอปแล้ว

หากต้องการดูสถานะของแพ็กเกจชิ้นงาน ให้ใช้เมธอด 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 เพื่อติดตามความคืบหน้าในการติดตั้งเนื้อหา แพ็ก การอัปเดตสถานะจะแจกแจงตามแพ็กเกจเพื่อรองรับการติดตามสถานะของ Asset Pack แต่ละรายการ คุณเริ่มใช้ชุดชิ้นงานที่พร้อมใช้งานได้ก่อนที่จะดาวน์โหลดรายการอื่นๆ ทั้งหมดตามคำขอเสร็จสมบูรณ์

Kotlin

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

Java

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

การดาวน์โหลดขนาดใหญ่

หากการดาวน์โหลดมีขนาดใหญ่กว่า 200 MB และผู้ใช้ไม่ได้ใช้ Wi-Fi ระบบจะดาวน์โหลด จะไม่เริ่มต้นจนกว่าผู้ใช้จะให้ความยินยอมอย่างชัดแจ้งในการดำเนินการต่อ ดาวน์โหลดโดยใช้การเชื่อมต่ออินเทอร์เน็ตมือถือ ในทํานองเดียวกัน หากการดาวน์โหลดมีขนาดใหญ่และผู้ใช้ไม่มี Wi-Fi การดาวน์โหลดจะหยุดชั่วคราวและต้องมีการให้ความยินยอมอย่างชัดเจนเพื่อดำเนินการต่อโดยใช้การเชื่อมต่ออินเทอร์เน็ตมือถือ แพ็กที่หยุดชั่วคราวมีสถานะ WAITING_FOR_WIFI หากต้องการทริกเกอร์ขั้นตอน UI เพื่อแจ้งให้ผู้ใช้ให้ความยินยอม ให้ใช้เมธอด showConfirmationDialog()

โปรดทราบว่าหากแอปไม่ได้เรียกใช้เมธอดนี้ การดาวน์โหลดจะหยุดชั่วคราวและจะกลับมาดำเนินการต่อโดยอัตโนมัติเมื่อผู้ใช้กลับมาเชื่อมต่อ Wi-Fi อีกครั้งเท่านั้น

ต้องมีการยืนยันผู้ใช้

หากแพ็กมีสถานะ REQUIRES_USER_CONFIRMATION ระบบจะไม่ดาวน์โหลด ดำเนินการจนกว่าผู้ใช้จะยอมรับกล่องโต้ตอบที่ปรากฏพร้อมกับ showConfirmationDialog() สถานะนี้อาจเกิดขึ้นเมื่อ Play ไม่รู้จักแอปดังกล่าว ตัวอย่างเช่น หาก ที่แอปโหลดจากแหล่งที่ไม่รู้จัก โปรดทราบว่าการโทร showConfirmationDialog() ในกรณีนี้ จะทำให้มีการอัปเดตแอป หลังจากการอัปเดต คุณจะต้อง เพื่อขอเนื้อหาอีกครั้ง

ต่อไปนี้คือตัวอย่างการใช้งาน Listener

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 มีสถานะการดาวน์โหลด สถานะการดาวน์โหลด และรหัสข้อผิดพลาดที่บ่งบอกถึงความล้มเหลว

เข้าถึง Asset Pack

คุณสามารถเข้าถึง Asset Pack ได้โดยใช้การเรียกระบบไฟล์หลังจากคำขอดาวน์โหลด ถึง COMPLETED ใช้วิธี getPackLocation() เพื่อรับโฟลเดอร์รูทของแพ็กเกจชิ้นงาน

เนื้อหาจัดเก็บอยู่ในไดเรกทอรี assets ภายในรูทของ Asset Pack ไดเรกทอรี คุณดูเส้นทางไปยังไดเรกทอรี 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

เมธอด API เพิ่มเติมบางส่วนที่คุณอาจต้องการใช้ในแอปมีดังนี้

ยกเลิกคำขอ

ใช้ cancel() เพื่อยกเลิกคำขอ Asset Pack ที่ใช้งานอยู่ โปรดทราบว่าคำขอนี้เป็นวิธีที่ดีที่สุด การดำเนินการ

นําแพ็กชิ้นงานออก

ใช้ requestRemovePack() หรือ removePack()เพื่อกำหนดเวลาการนำ Asset Pack ออก

รับสถานที่ตั้งของ Asset Pack หลายรายการ

ใช้ getPackLocations() เพื่อค้นหาสถานะของ Asset Pack หลายรายการพร้อมกัน ซึ่งจะแสดงแผนที่ของ Asset Pack และตำแหน่งของอุปกรณ์ก็ได้ แผนที่แสดงผลโดย getPackLocations() จะมีรายการสำหรับแต่ละแพ็กเก็ตที่ดาวน์โหลดและอัปเดตแล้วในปัจจุบัน

ขั้นตอนถัดไป

ทดสอบ Play Asset Delivery ในพื้นที่และจาก Google Play