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

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

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

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

  1. อัปเดตเวอร์ชันของปลั๊กอิน Android Gradle ในไฟล์ build.gradle ของโปรเจ็กต์เป็น 4.0.0 ขึ้นไป

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

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

    ดึงดูด

    // 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 ของแอปของโปรเจ็กต์ ให้เพิ่มชื่อ Asset Pack ทั้งหมดในโปรเจ็กต์ตามที่แสดงด้านล่าง

    Groovy

    // 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 ของโปรเจ็กต์ ให้รวมแพ็กเนื้อหาทั้งหมดในโปรเจ็กต์ดังที่แสดงด้านล่าง

    Groovy

    // 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. ในไดเรกทอรี Asset Pack ให้สร้างไดเรกทอรีย่อยต่อไปนี้ 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 หากคุณวางแผนที่จะใช้การส่งแบบติดตามอย่างรวดเร็วและแบบออนดีมานด์

    ดึงดูด

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

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

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

คุณใช้ API นี้ตามประเภทการนำส่งของ Asset Pack ที่ต้องการเข้าถึง ขั้นตอนเหล่านี้แสดงอยู่ในแผนภาพต่อไปนี้

แผนภาพขั้นตอนการสร้างแพ็กเนื้อหาสำหรับภาษาโปรแกรม Java

รูปที่ 1 แผนภาพขั้นตอนในการเข้าถึงชุดชิ้นงาน

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

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

นำส่งตามคำสั่งซื้ออย่างรวดเร็ว

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

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

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

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

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

แอปจะต้องเปิดเผยขนาดของการดาวน์โหลดก่อนดึงข้อมูล 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> แผนที่นี้มีสถานะของ Asset Pack แต่ละรายการที่ขอ ซึ่งเรียงโดยชื่อ:

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, จำนวนที่ดาวน์โหลดจนถึงตอนนี้ (หากขอ) และจำนวนที่โอนไปยังแอปแล้ว

หากต้องการดูสถานะของ Asset Pack ให้ใช้เมธอด status() ซึ่งจะแสดงสถานะเป็นจำนวนเต็มที่สอดคล้องกับช่องคงที่ในคลาส AssetPackStatus Asset Pack ที่ยังไม่ได้ติดตั้งมีสถานะ AssetPackStatus.NOT_INSTALLED

หากคำขอไม่สำเร็จ ให้ใช้เมธอด errorCode() ซึ่งค่าผลลัพธ์ตรงกับช่องคงที่ในคลาส AssetPackErrorCode

ติดตั้ง

ใช้เมธอด requestFetch() หรือ fetch() เพื่อดาวน์โหลด Asset Pack เป็นครั้งแรก หรือส่งคำขอให้อัปเดต Asset Pack ให้เสร็จสมบูรณ์ วิธีการมีดังนี้

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() เพื่อรับโฟลเดอร์รูทของ Asset Pack

ระบบจะเก็บเนื้อหาไว้ในไดเรกทอรี 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