Öğe teslimini entegre etme (Kotlin ve Java)

Java kodunuzdan uygulamanızın öğe paketlerine erişmek için bu kılavuzdaki adımları kullanın.

Kotlin ve Java için geliştirme

Play Asset Delivery'yi projenizin Android App Bundle'ına eklemek için aşağıdaki adımları uygulayın. Bu adımları gerçekleştirmek için Android Studio'yu kullanmanız gerekmez.

  1. Projenizin build.gradle dosyasındaki Android Gradle eklentisinin sürümünü 4.0.0 veya üzeri bir sürüme güncelleyin.

  2. Projenizin en üst düzey dizininde, öğe paketi için bir dizin oluşturun. Bu dizin adı, öğe paketi adı olarak kullanılır. Öğe paketi adları harfle başlamalıdır ve yalnızca harf, sayı ve alt çizgi içerebilir.

  3. Öğe paketi dizininde bir build.gradle dosyası oluşturun ve aşağıdaki kodu ekleyin. Öğe paketinin adını ve yalnızca bir yayınlama türünü belirttiğinizden emin olun:

    Modern

    // 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. Projenin uygulama build.gradle dosyasına, projenizdeki her öğe paketinin adını aşağıda gösterildiği gibi ekleyin:

    Modern

    // 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. Tüm öğe paketlerini, aşağıda gösterildiği gibi projenin settings.gradle dosyasına ekleyin:

    Modern

    // 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. Öğe paketi dizininde şu alt dizini oluşturun: src/main/assets.

  7. Öğeleri src/main/assets dizinine yerleştirin. Burada alt dizinler de oluşturabilirsiniz. Uygulamanızın dizin yapısı artık aşağıdaki gibi görünmelidir:

    • build.gradle
    • settings.gradle
    • app/
    • asset-pack-name/build.gradle
    • asset-pack-name/src/main/assets/your-asset-directories
  8. Android App Bundle'ı Gradle ile oluşturun. Oluşturulan uygulama paketinde, kök düzeyindeki dizin artık aşağıdakileri içermektedir:

    • asset-pack-name/manifest/AndroidManifest.xml: Öğe paketinin tanımlayıcısını ve yayınlama modunu yapılandırır
    • asset-pack-name/assets/your-asset-directories: Öğe paketinin bir parçası olarak yayınlanan tüm öğeleri içeren dizin

    Gradle, her öğe paketi için manifest dosyasını oluşturur ve sizin için assets/ dizinini oluşturur.

  9. (İsteğe bağlı) Hızlı takip ve isteğe bağlı yayınlama özelliklerini kullanmayı planlıyorsanız Play Öğe Yayınlama Kitaplığı'nı dahil edin

    Modern

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

    Kotlin

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

  10. (İsteğe bağlı) Uygulama paketinizi farklı doku sıkıştırma biçimlerini destekleyecek şekilde yapılandırın.

Play Asset Delivery API ile entegrasyon

Play Asset Delivery Java API, öğe paketleri isteğinde bulunmak, indirmeleri yönetmek ve öğelere erişmek için AssetPackManager sınıfını sunar. Önce projenize Play Öğe Yayınlama Kitaplığı'nı eklediğinizden emin olun.

Bu API'yi, erişmek istediğiniz öğe paketinin teslimat türüne göre uygularsınız. Bu adımlar aşağıdaki akış şemasında gösterilmiştir.

Java programlama dili için öğe paketi akış diyagramı

Şekil 1. Öğe paketlerine erişime ilişkin akış diyagramı

Yükleme sırasında teslim

install-time olarak yapılandırılan öğe paketleri, uygulama başlatıldığında hemen kullanılabilir. Bu modda yayınlanan öğelere erişmek için Java AssetManager API'yi kullanın:

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

Hızlı takip ve isteğe bağlı teslimat

Aşağıdaki bölümlerde varlık paketlerini indirmeden önce nasıl bilgi edinileceği, indirme işlemini başlatmak için API'nin nasıl çağırılacağı ve indirilen paketlere nasıl erişileceği gösterilmektedir. Bu bölümler fast-follow ve on-demand öğe paketleri için geçerlidir.

Durumu denetle

Her öğe paketi, uygulamanın dahili depolamasında ayrı bir klasörde saklanır. Bir öğe paketinin kök klasörünü belirlemek için getPackLocation() yöntemini kullanın. Bu yöntem aşağıdaki değerleri döndürür:

Döndürülen değer Durum
Geçerli bir AssetPackLocation nesnesi Öğe paketi kök klasörü, assetsPath() adresinden anında erişim için hazır
null Bilinmeyen öğe paketi veya öğeler kullanılamıyor

Öğe paketleri hakkında indirme bilgilerini alın

Uygulamalar, öğe paketini getirmeden önce indirme boyutunu açıklamak zorundadır. İndirme boyutunu ve paketin zaten indirilip indirilmediğini belirlemek için requestPackStates() veya getPackStates() yöntemini kullanın.

Kotlin

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

Java

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

requestPackStates(), AssetPackStates nesnesi döndüren bir askıya alma işlevidir. getPackStates() ise Task<AssetPackStates> döndüren eşzamansız bir yöntemdir. Bir AssetPackStates nesnesinin packStates() yöntemi Map<String, AssetPackState> döndürür. Bu harita, istenen her bir öğe paketinin durumunu ve adlarıyla belirlenen şekilde içerir:

Kotlin

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

Java

Map<String, AssetPackState> AssetPackStates#packStates()

Son istek aşağıdakilerle gösterilir:

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

Aşağıdaki AssetPackState yöntemleri, öğe paketinin boyutunu, o ana kadar indirilen miktar (istenirse) ve uygulamaya zaten aktarılan tutarı sağlar:

Bir öğe paketinin durumunu almak için status() yöntemini kullanın. Bu yöntem, durumu AssetPackStatus sınıfında sabit bir alana karşılık gelen bir tam sayı olarak döndürür. Henüz yüklenmemiş bir öğe paketi AssetPackStatus.NOT_INSTALLED durumundadır.

Bir istek başarısız olursa döndürülen değeri AssetPackErrorCode sınıfındaki sabit bir alana karşılık gelen errorCode() yöntemini kullanın.

Yükle

Bir öğe paketini ilk kez indirmek veya tamamlamak için öğe paketinin güncellenmesini istemek amacıyla requestFetch() veya fetch() yöntemini kullanın:

Kotlin

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

Java

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

Bu yöntem, paket listesini ve ilk indirme durumlarını ve boyutlarını içeren bir AssetPackStates nesnesi döndürür. requestFetch() veya fetch() aracılığıyla istenen bir öğe paketi zaten indiriliyorsa indirme durumu döndürülür ve ek indirme işlemi başlatılmaz.

İndirme durumlarını izleme

Öğe paketlerinin yükleme ilerlemesini izlemek için bir AssetPackStateUpdatedListener uygulamanız gerekir. Bağımsız öğe paketlerinin durumunun izlenmesini desteklemek için durum güncellemelerinin paket başına dökümü verilir. İsteğiniz için diğer tüm indirme işlemleri tamamlanmadan kullanılabilir öğe paketlerini kullanmaya başlayabilirsiniz.

Kotlin

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

Java

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

Büyük boyutlu indirmeler

İndirme boyutu 150 MB'tan büyükse ve kullanıcı kablosuz ağa bağlı değilse indirme işlemi, kullanıcı mobil veri bağlantısı kullanarak devam etmek için açıkça izin verene kadar başlamaz. Benzer şekilde, indirme boyutu büyükse ve kullanıcı kablosuz bağlantıyı kaybederse indirme işlemi duraklatılır ve mobil veri bağlantısı kullanarak devam etmek için açık izin gerekir. Duraklatılmış bir paketin durumu WAITING_FOR_WIFI şeklindedir. Kullanıcıdan izin istemek üzere kullanıcı arayüzü akışını tetiklemek için requestCellularDataConfirmation() veya showCellularDataConfirmation() yöntemini kullanın.

Uygulama bu yöntemi çağırmıyorsa indirme işleminin duraklatılacağını ve yalnızca kullanıcı tekrar kablosuz ağa bağlandığında otomatik olarak devam edeceğini unutmayın.

Aşağıda, dinleyici kullanımına ilişkin bir örnek verilmiştir:

Kotlin

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 -> {
      if (!waitForWifiConfirmationShown) {
        coroutineScope.launch {
          val resultCode =
            assetPackManager.requestCellularDataConfirmation(this@MainActivity)
          if (resultCode == RESULT_OK) {
            Log.d(TAG, "Confirmation dialog has been accepted.")
          } else if (resultCode == RESULT_CANCELED) {
            Log.d(TAG, "Confirmation dialog has been denied by the user.")
          }
        }
        waitForWifiConfirmationShown = true
      }
    }
    AssetPackStatus.NOT_INSTALLED -> {
      // Asset pack is not downloaded yet.
    }
    AssetPackStatus.UNKNOWN -> {
      Log.wtf(TAG, "Asset pack status unknown")
    }
  }
}

Java

assetPackStateUpdateListener = new AssetPackStateUpdateListener() {
    @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:
          if (!waitForWifiConfirmationShown) {
            assetPackManager.showCellularDataConfirmation(MainActivity.this)
              .addOnSuccessListener(new OnSuccessListener<Integer> () {
                @Override
                public void onSuccess(Integer resultCode) {
                  if (resultCode == RESULT_OK) {
                    Log.d(TAG, "Confirmation dialog has been accepted.");
                  } else if (resultCode == RESULT_CANCELED) {
                    Log.d(TAG, "Confirmation dialog has been denied by the user.");
                  }
                }
              });
            waitForWifiConfirmationShown = true;
          }
          break;

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

Alternatif olarak, mevcut indirmelerin durumunu almak için getPackStates() yöntemini kullanabilirsiniz. AssetPackStates sayfasında indirme ilerleme durumu, indirme durumu ve hata kodları yer alır.

Öğe paketlerine erişme

İndirme isteği COMPLETED durumuna ulaştıktan sonra dosya sistemi çağrılarını kullanarak bir öğe paketine erişebilirsiniz. Öğe paketinin kök klasörünü almak için getPackLocation() yöntemini kullanın.

Öğeler, öğe paketi kök dizinindeki assets dizininde depolanır. assets dizininin yolunu, assetsPath() kolaylık yöntemini kullanarak alabilirsiniz. Belirli bir öğenin yolunu almak için aşağıdaki yöntemi kullanın:

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

Diğer Play Asset Delivery API yöntemleri

Aşağıda, uygulamanızda kullanmak isteyebileceğiniz bazı ek API yöntemleri verilmiştir.

İsteği iptal et

Etkin bir öğe paketi isteğini iptal etmek için cancel() aracını kullanın. Bu isteğin, yapılabilecek en iyi işlem olduğunu unutmayın.

Öğe paketini kaldırma

Bir öğe paketinin kaldırılmasını planlamak için requestRemovePack() veya removePack() aracını kullanın.

Birden fazla öğe paketinin konumlarını alma

Birden fazla öğe paketinin durumunu toplu olarak sorgulamak için getPackLocations() aracını kullanın. Bu sorgu, öğe paketlerinin ve konumlarının haritasını döndürür. getPackLocations() tarafından döndürülen haritada şu anda indirilen ve güncel olan her paket için bir giriş bulunur.

Sonraki adım

Yerel olarak ve Google Play'den Play Asset Delivery'yi test edin.