Google Play Faturalandırma Kitaplığı'nı uygulamanıza entegre etme

Bu konuda, ürün satmaya başlamak için Google Play Faturalandırma Kitaplığı'nı uygulamanıza nasıl entegre edeceğiniz açıklanmaktadır.

Bu konu, GitHub'daki resmi örnek uygulamaları temel alan kod örnekleri içerir. Örnek uygulamaların tam listesi ve entegrasyon sırasında kullanabileceğiniz diğer kaynaklar için ek kaynaklara göz atın.

Bir satın alma süreci

Tek seferlik bir satın alma veya abonelik için tipik bir satın alma akışı aşağıda verilmiştir.

  1. Kullanıcıya neler satın alabileceğini gösterin.
  2. Kullanıcının satın alma işlemini kabul etmesi için satın alma akışını başlatın.
  3. Satın alma işlemini sunucunuzda doğrulayın.
  4. Kullanıcıya içerik verin.
  5. İçeriğin yayınlanmasını onaylayın. Tüketilebilir ürünler söz konusu olduğunda, kullanıcının öğeyi tekrar satın alabilmesi için satın alma işlemini gerçekleştirin.

Abonelikler iptal edilene kadar otomatik olarak yenilenir. Bir abonelikte aşağıdaki durumlar yaşanabilir:

  • Etkin: Kullanıcı iyi durumda ve aboneliğe erişimi var.
  • İptal edildi: Kullanıcı, işlemi iptal etmiştir ancak sona erme tarihine kadar erişimi devam eder.
  • Ek yayınlanma süresinde: Kullanıcı bir ödeme sorunuyla karşılaşmıştır ancak Google, ödeme yöntemini yeniden denerken hâlâ erişime sahiptir.
  • Beklemede: Kullanıcı bir ödeme sorunuyla karşılaşmıştır ve Google, ödeme yöntemini yeniden denerken artık erişemez.
  • Duraklatıldı: Kullanıcı, erişimini duraklatmıştır ve devam edene kadar erişemez.
  • Süresi doldu: Kullanıcı, aboneliği iptal etmiştir ve aboneliği kaybetti. Kullanıcı, geçerlilik süresi sona erdiğinde kaybetmiş olarak kabul edilir.

Google Play bağlantısını ilk kullanıma hazırlama

Google Play'in faturalandırma sistemiyle entegrasyonun ilk adımı, uygulamanıza Google Play Faturalandırma Kitaplığı'nı eklemek ve bir bağlantı başlatmaktır.

Google Play Faturalandırma Kitaplığı bağımlılığını ekleme

Aşağıdaki gösterildiği gibi uygulamanızın build.gradle dosyasına Google Play Faturalandırma Kitaplığı bağımlılığını ekleyin:

Modern

dependencies {
    def billing_version = "6.1.0"

    implementation "com.android.billingclient:billing:$billing_version"
}

Kotlin

dependencies {
    val billing_version = "6.1.0"

    implementation("com.android.billingclient:billing:$billing_version")
}

Kotlin kullanıyorsanız Google Play Faturalandırma Kitaplığı KTX modülü, Google Play Faturalandırma Kitaplığı'nı kullanırken deyimsel Kotlin yazabilmenizi sağlayan Kotlin uzantıları ve eş yordamlar desteğini içerir. Bu uzantıları projenize dahil etmek için aşağıdaki bağımlılığı uygulamanızın build.gradle dosyasına gösterildiği şekilde ekleyin:

Modern

dependencies {
    def billing_version = "6.1.0"

    implementation "com.android.billingclient:billing-ktx:$billing_version"
}

Kotlin

dependencies {
    val billing_version = "6.1.0"

    implementation("com.android.billingclient:billing-ktx:$billing_version")
}

Bir Faturalandırma İstemcisini Başlatma

Google Play Faturalandırma Kitaplığı'na bağımlılık ekledikten sonra bir BillingClient örneği başlatmanız gerekir. BillingClient, Google Play Faturalandırma Kitaplığı ile uygulamanızın geri kalanı arasındaki iletişim için ana arayüzdür. BillingClient, yaygın faturalandırma işlemleri için hem eşzamanlı hem de eşzamansız olarak çeşitli yöntemler sunar. Tek bir etkinlikte birden fazla PurchasesUpdatedListener geri çağırmasının önüne geçmek için aynı anda etkin bir BillingClient bağlantınızın olması kesinlikle önerilir.

BillingClient oluşturmak için newBuilder() işlevini kullanın. Herhangi bir bağlamı newBuilder() öğesine iletebilirsiniz. BillingClient, bunu uygulama bağlamı almak için kullanır. Diğer bir deyişle, bellek sızıntıları konusunda endişelenmenize gerek yoktur. Satın alma işlemleriyle ilgili güncellemeleri almak için bir PurchasesUpdatedListener referansı ileterek setListener() numarasını da çağırmanız gerekir. Bu dinleyici, uygulamanızdaki tüm satın alma işlemleri için güncelleme alır.

Kotlin

private val purchasesUpdatedListener =
   PurchasesUpdatedListener { billingResult, purchases ->
       // To be implemented in a later section.
   }

private var billingClient = BillingClient.newBuilder(context)
   .setListener(purchasesUpdatedListener)
   .enablePendingPurchases()
   .build()

Java

private PurchasesUpdatedListener purchasesUpdatedListener = new PurchasesUpdatedListener() {
    @Override
    public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
        // To be implemented in a later section.
    }
};

private BillingClient billingClient = BillingClient.newBuilder(context)
    .setListener(purchasesUpdatedListener)
    .enablePendingPurchases()
    .build();

Google Play'e bağlan

BillingClient oluşturduktan sonra, Google Play ile bağlantı kurmanız gerekir.

Google Play'e bağlanmak için startConnection() numaralı telefonu arayın. Bağlantı işlemi eşzamansızdır ve istemcinin kurulumu tamamlanıp istemci başka isteklerde bulunmaya hazır olduğunda geri arama almak için bir BillingClientStateListener uygulamanız gerekir.

Kayıp Google Play bağlantılarını ele almak için yeniden deneme mantığını da uygulamanız gerekir. Yeniden deneme mantığını uygulamak için onBillingServiceDisconnected() geri çağırma yöntemini geçersiz kılın ve BillingClient ürününün, başka isteklerde bulunmadan önce Google Play'e yeniden bağlanmak için startConnection() yöntemini çağırdığından emin olun.

Aşağıdaki örnekte, bağlantının nasıl başlatılacağı ve bağlantının kullanıma hazır olup olmadığı gösterilmektedir:

Kotlin

billingClient.startConnection(object : BillingClientStateListener {
    override fun onBillingSetupFinished(billingResult: BillingResult) {
        if (billingResult.responseCode ==  BillingResponseCode.OK) {
            // The BillingClient is ready. You can query purchases here.
        }
    }
    override fun onBillingServiceDisconnected() {
        // Try to restart the connection on the next request to
        // Google Play by calling the startConnection() method.
    }
})

Java

billingClient.startConnection(new BillingClientStateListener() {
    @Override
    public void onBillingSetupFinished(BillingResult billingResult) {
        if (billingResult.getResponseCode() ==  BillingResponseCode.OK) {
            // The BillingClient is ready. You can query purchases here.
        }
    }
    @Override
    public void onBillingServiceDisconnected() {
        // Try to restart the connection on the next request to
        // Google Play by calling the startConnection() method.
    }
});

Satın alınabilecek ürünleri gösterin

Google Play ile bağlantı kurduktan sonra, kullanılabilir ürünlerinizi sorgulamaya ve bunları kullanıcılarınıza göstermeye hazırsınız.

Ürün ayrıntılarını sorgulamak, yerelleştirilmiş ürün bilgileri döndürdüğünden ürünlerinizi kullanıcılarınıza göstermeden önce önemli bir adımdır. Aboneliklerde ürün ekranınızın tüm Play politikalarına uyduğundan emin olun.

Uygulama içi ürün ayrıntılarını sorgulamak için queryProductDetailsAsync() numaralı telefonu arayın.

Eşzamansız işlemin sonucunu işlemek için ProductDetailsResponseListener arayüzünü uygulayan bir işleyici belirtmeniz de gerekir. Ardından, aşağıdaki örnekte gösterildiği gibi, sorgu tamamlandığında işleyiciyi bilgilendiren onProductDetailsResponse() öğesini geçersiz kılabilirsiniz:

Kotlin

val queryProductDetailsParams =
    QueryProductDetailsParams.newBuilder()
        .setProductList(
            ImmutableList.of(
                Product.newBuilder()
                    .setProductId("product_id_example")
                    .setProductType(ProductType.SUBS)
                    .build()))
        .build()

billingClient.queryProductDetailsAsync(queryProductDetailsParams) {
    billingResult,
    productDetailsList ->
      // check billingResult
      // process returned productDetailsList
}
)

Java

QueryProductDetailsParams queryProductDetailsParams =
    QueryProductDetailsParams.newBuilder()
        .setProductList(
            ImmutableList.of(
                Product.newBuilder()
                    .setProductId("product_id_example")
                    .setProductType(ProductType.SUBS)
                    .build()))
        .build();

billingClient.queryProductDetailsAsync(
    queryProductDetailsParams,
    new ProductDetailsResponseListener() {
        public void onProductDetailsResponse(BillingResult billingResult,
                List<ProductDetails> productDetailsList) {
            // check billingResult
            // process returned productDetailsList
        }
    }
)

Ürün ayrıntılarını sorgularken, Google Play Console'da oluşturulan ProductType ile birlikte oluşturulan ürün kimliği dizelerinin listesini belirten bir QueryProductDetailsParams örneği iletin. ProductType, tek seferlik ürünler için ProductType.INAPP veya abonelikler için ProductType.SUBS olabilir.

Kotlin uzantılarıyla sorgulama

Kotlin uzantıları kullanıyorsanız queryProductDetails() uzantı işlevini çağırarak uygulama içi ürün ayrıntılarını sorgulayabilirsiniz.

queryProductDetails(), ayrı bir işleyici tanımlamanıza gerek kalmaması için Kotlin eş yordamlarından yararlanır. Bunun yerine, sorgu işlemi tamamlanana kadar işlev askıya alınır. Bu işlemin ardından sonucu işleyebilirsiniz:

suspend fun processPurchases() {
    val productList = ArrayList<String>()
    productList.add(
              QueryProductDetailsParams.Product.newBuilder()
                  .setProductId("product_id_example")
                  .setProductType(BillingClient.ProductType.SUBS)
                  .build()
           )
    val params = QueryProductDetailsParams.newBuilder()
    params.setProductList(productList)

    // leverage queryProductDetails Kotlin extension function
    val productDetailsResult = withContext(Dispatchers.IO) {
        billingClient.queryProductDetails(params.build())
    }

    // Process the result.
}

Nadiren de olsa bazı cihazlar ProductDetails ve queryProductDetailsAsync() hizmetlerini desteklemeyebilir. Bu durum genellikle Google Play Hizmetleri'nin eski sürümlerinden kaynaklanır. Bu senaryonun doğru şekilde desteklenmesini sağlamak için Play Faturalandırma Kitaplığı 5 taşıma kılavuzundan geriye dönük uyumluluk özelliklerinin nasıl kullanılacağını öğrenebilirsiniz.

Sonucu işleyin

Google Play Faturalandırma Kitaplığı, sorgu sonuçlarını List/ProductDetails nesnesi olarak depolar. Daha sonra, uygulama içi bir ürünle ilgili fiyatı veya açıklaması gibi alakalı bilgileri görüntülemek için listedeki her ProductDetails nesnesinde çeşitli yöntemleri çağırabilirsiniz. Kullanılabilir ürün ayrıntıları bilgilerini görüntülemek için ProductDetails sınıfındaki yöntem listesine bakın.

Bir öğeyi satışa sunmadan önce kullanıcının öğeye sahip olup olmadığını kontrol edin. Kullanıcının hâlâ öğe kitaplığında bulunan bir tüketim malzemesi varsa tekrar satın almadan önce öğeyi tüketmesi gerekir.

Abonelik sunmadan önce kullanıcının abone olmadığını doğrulayın. Ayrıca aşağıdakilere de dikkat edin:

  • queryProductDetailsAsync(), abonelik ürün ayrıntılarını ve abonelik başına en fazla 50 fırsatı döndürür.
  • queryProductDetailsAsync(), yalnızca kullanıcının uygun olduğu teklifleri döndürür. Kullanıcı, uygun olmadığı bir teklifi satın almaya çalışırsa (örneğin, uygulamada uygun fırsatların eski bir listesi gösteriliyorsa) Play kullanıcıya bu teklifin uygun olmadığını bildirir ve kullanıcı bunun yerine temel planı satın almayı seçebilir.

Satın alma akışını başlatma

Uygulamanızdan satın alma isteği başlatmak için uygulamanızın ana iş parçacığından launchBillingFlow() yöntemini çağırın. Bu yöntem, queryProductDetailsAsync() çağrısından elde edilen ilgili ProductDetails nesnesini içeren bir BillingFlowParams nesnesine referans verir. BillingFlowParams nesnesi oluşturmak için BillingFlowParams.Builder sınıfını kullanın.

Kotlin

// An activity reference from which the billing flow will be launched.
val activity : Activity = ...;

val productDetailsParamsList = listOf(
    BillingFlowParams.ProductDetailsParams.newBuilder()
        // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
        .setProductDetails(productDetails)
        // to get an offer token, call ProductDetails.subscriptionOfferDetails()
        // for a list of offers that are available to the user
        .setOfferToken(selectedOfferToken)
        .build()
)

val billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build()

// Launch the billing flow
val billingResult = billingClient.launchBillingFlow(activity, billingFlowParams)

Java

// An activity reference from which the billing flow will be launched.
Activity activity = ...;

ImmutableList productDetailsParamsList =
    ImmutableList.of(
        ProductDetailsParams.newBuilder()
             // retrieve a value for "productDetails" by calling queryProductDetailsAsync()
            .setProductDetails(productDetails)
            // to get an offer token, call ProductDetails.getSubscriptionOfferDetails()
            // for a list of offers that are available to the user
            .setOfferToken(selectedOfferToken)
            .build()
    );

BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
    .setProductDetailsParamsList(productDetailsParamsList)
    .build();

// Launch the billing flow
BillingResult billingResult = billingClient.launchBillingFlow(activity, billingFlowParams);

launchBillingFlow() yöntemi, BillingClient.BillingResponseCode içinde listelenen çeşitli yanıt kodlarından birini döndürür. Satın alma akışını başlatırken herhangi bir hata olmadığından emin olmak için bu sonucu kontrol edin. BillingResponseCode değerinin OK olması, lansmanın başarılı olduğunu gösterir.

launchBillingFlow() numaralı telefona yapılan başarılı bir çağrıda sistem, Google Play satın alma ekranını görüntüler. Şekil 1'de bir abonelik satın alma ekranı gösterilmektedir:

google play satın alma ekranında, satın alınabilecek bir abonelik gösteriliyor
Şekil 1. Google Play satın alma ekranında, satın alınabilecek bir abonelik gösterilir.

Google Play, satın alma işleminin sonucunu PurchasesUpdatedListener arayüzünü uygulayan bir dinleyiciye iletmek için onPurchasesUpdated() çağrısı yapar. İşleyici, istemcinizi başlattığınızda setListener() yöntemi kullanılarak belirtilir.

Olası yanıt kodlarını işlemek için onPurchasesUpdated() uygulamanız gerekir. Aşağıdaki örnekte onPurchasesUpdated() öğesinin nasıl geçersiz kılınacağı gösterilmektedir:

Kotlin

override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
   if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) {
       for (purchase in purchases) {
           handlePurchase(purchase)
       }
   } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) {
       // Handle an error caused by a user cancelling the purchase flow.
   } else {
       // Handle any other error codes.
   }
}

Java

@Override
void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
    if (billingResult.getResponseCode() == BillingResponseCode.OK
        && purchases != null) {
        for (Purchase purchase : purchases) {
            handlePurchase(purchase);
        }
    } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) {
        // Handle an error caused by a user cancelling the purchase flow.
    } else {
        // Handle any other error codes.
    }
}

Başarılı bir satın alma işlemi, şekil 2'ye benzer bir Google Play satın alma başarısı ekranı oluşturur.

google play&#39;in satın alma başarısı ekranı
Şekil 2. Google Play'in satın alma başarısı ekranı.

Başarılı bir satın alma işlemi ayrıca bir satın alma jetonu da oluşturur. Bu jeton, kullanıcıyı ve satın aldığı uygulama içi ürünün ürün kimliğini temsil eden benzersiz bir tanımlayıcıdır. Uygulamalarınız satın alma jetonunu yerel olarak depolayabilir, ancak jetonu güvenli arka uç sunucunuza iletmenizi öneririz. Burada satın alma işlemini doğrulayabilir ve sahtekarlığa karşı koruma sağlayabilirsiniz. Bu süreç aşağıdaki bölümde daha ayrıntılı olarak açıklanmıştır.

Kullanıcıya, bir Sipariş Kimliği veya işlemin benzersiz kimliğini içeren bir işlem makbuzu da e-postayla gönderilir. Kullanıcılar, her bir tek seferlik ürün satın alma işlemi ve ayrıca ilk abonelik satın alma işlemi ve sonraki yinelenen otomatik yenilemeler için benzersiz bir Sipariş Kimliği içeren e-posta alır. Google Play Console'da geri ödemeleri yönetmek için Sipariş Kimliği'ni kullanabilirsiniz.

Kişiselleştirilmiş bir fiyat belirtin

Uygulamanız Avrupa Birliği'ndeki kullanıcılara dağıtılabiliyorsa kullanıcılara bir öğenin fiyatının otomatik karar alma mekanizması kullanılarak kişiselleştirildiğini açıklamak için setIsOfferPersonalized() yöntemini kullanın.

Fiyatın kullanıcı için özelleştirildiğini gösteren Google Play satın alma ekranı.
Şekil 3. Fiyatın kullanıcı için özelleştirildiğini belirten Google Play satın alma ekranı.

Çalışmanızı Kullanıcılara sunduğunuz fiyatın kişiselleştirilmiş olup olmadığını belirlemek için Tüketici Hakları Direktifi'nin (2011/83/EU) 6 (1) (ea) CRD'si.

setIsOfferPersonalized() bir boole girişi alır. true, Play kullanıcı arayüzünde açıklama içerir. false değerine ayarlanırsa kullanıcı arayüzü açıklamayı atlar. Varsayılan değer false'tir.

Daha fazla bilgi için Tüketici Yardım Merkezi'ne göz atın.

Satın alma işlemleri işleniyor

Kullanıcı bir satın alma işlemini tamamladığında, uygulamanızın bu satın alma işlemini işlemesi gerekir. Çoğu durumda, uygulamanıza PurchasesUpdatedListener aracılığıyla yapılan satın alma işlemleri bildirilir. Bununla birlikte, Satın almaları getirme bölümünde açıklandığı gibi uygulamanızda BillingClient.queryPurchasesAsync() çağrısı yapılarak satın alma işlemlerinin gerçekleştirildiği durumlar vardır.

Ayrıca, güvenli arka ucunuzda Gerçek Zamanlı Geliştirici Bildirimleri istemciniz varsa yeni satın alma işlemleri konusunda sizi uyaran bir subscriptionNotification veya oneTimeProductNotification (yalnızca bekleyen satın alma işlemleri için) alarak yeni satın alma işlemlerini kaydedebilirsiniz. Bu bildirimleri aldıktan sonra, tam durumu almak ve kendi arka uç durumunuzu güncellemek için Google Play Developer API'yi çağırın.

Uygulamanız satın alma işlemlerini aşağıdaki şekilde gerçekleştirmelidir:

  1. Satın alma işlemini doğrulayın.
  2. Kullanıcıya içerik verin ve içeriğin teslim edilmesini onaylayın. İsteğe bağlı olarak, kullanıcının tekrar satın alabilmesi için öğeyi "tüketilen" olarak işaretleyin.

Bir satın alma işlemini doğrulamak için öncelikle satın alma durumunun PURCHASED olduğunu kontrol edin. Satın alma işlemi PENDING ise satın alma işlemini Bekleyen işlemleri yönetme bölümünde açıklandığı şekilde gerçekleştirmeniz gerekir. onPurchasesUpdated() veya queryPurchasesAsync() üzerinden alınan satın alma işlemlerinde, uygulamanız yararlanma hakkı vermeden önce meşruluğu sağlamak için satın alma işlemini daha ayrıntılı doğrulamanız gerekir. Bir satın alma işlemini doğru şekilde nasıl doğrulayacağınızı öğrenmek için Yararlanma hakkı vermeden önce satın alma işlemlerini doğrulama bölümüne bakın.

Satın alma işlemini doğrulamanızın ardından uygulamanız kullanıcıya yararlanma hakkı vermeye hazır hale gelir. Satın alma işlemiyle ilişkili kullanıcı hesabı, Purchases.products:get tarafından uygulama içi ürün satın alma işlemleri için Purchases.products:get tarafından, sunucu tarafındaki abonelikler için Purchases.subscriptions:get tarafından iade edilen SubscriptionPurchase.obfuscatedExternalAccountId veya istemci tarafında Purchase.getAccountIdentifiers() tarafından iade edilen Purchase.getAccountIdentifiers() tarafından ({/20/}{/18/} belirlendiyse) tarafından iade edilen obfuscatedAccountId ile tanımlanabilir.ProductPurchase.obfuscatedExternalAccountIdsetObfuscatedAccountId

Yararlanma hakkı sağlandıktan sonra uygulamanızın satın alma işlemini onaylaması gerekir. Bu onay, satın alma için yararlanma hakkı verdiğinizi Google Play'e bildirir.

Yararlanma hakkı verme ve satın alma işlemini onaylama süreci, satın alma işleminin tüketilebilir mi, tüketilemez veya abonelik mi olduğuna bağlıdır.

Tüketim Ürünleri

Tüketilebilir öğeler söz konusu olduğunda, uygulamanızın güvenli bir arka ucu varsa satın alma işlemlerinden güvenli bir şekilde yararlanmak için Purchases.products:consume kullanmanızı öneririz. Purchases.products:get çağrısının sonucundan consumptionState değerini kontrol ederek satın alma işleminin zaten gerçekleşmediğinden emin olun. Uygulamanız, arka uç olmadan yalnızca müşteri kullanıyorsa Google Play Faturalandırma Kitaplığı'ndaki consumeAsync() öğesini kullanın. Her iki yöntem de onay şartını karşılar ve uygulamanızın kullanıcıya yararlanma hakkı verdiğini belirtir. Bu yöntemler ayrıca uygulamanızın, giriş satın alma jetonuna karşılık gelen tek seferlik ürünü yeniden satın alma için kullanılabilir hale getirmesini sağlar. consumeAsync() ile ConsumeResponseListener arayüzünü uygulayan bir nesne de iletmeniz gerekir. Bu nesne, tüketim işleminin sonucunu işler. İşlem tamamlandığında Google Play Faturalandırma Kitaplığı'nın çağırdığı onConsumeResponse() yöntemini geçersiz kılabilirsiniz.

Aşağıdaki örnekte, ilişkili satın alma jetonu kullanılarak bir ürünün Google Play Faturalandırma Kitaplığı ile tüketilmesi gösterilmektedir:

Kotlin

suspend fun handlePurchase(purchase: Purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    val purchase : Purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant entitlement to the user.

    val consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build()
    val consumeResult = withContext(Dispatchers.IO) {
        client.consumePurchase(consumeParams)
    }
}

Java

void handlePurchase(Purchase purchase) {
    // Purchase retrieved from BillingClient#queryPurchasesAsync or your PurchasesUpdatedListener.
    Purchase purchase = ...;

    // Verify the purchase.
    // Ensure entitlement was not already granted for this purchaseToken.
    // Grant entitlement to the user.

    ConsumeParams consumeParams =
        ConsumeParams.newBuilder()
            .setPurchaseToken(purchase.getPurchaseToken())
            .build();

    ConsumeResponseListener listener = new ConsumeResponseListener() {
        @Override
        public void onConsumeResponse(BillingResult billingResult, String purchaseToken) {
            if (billingResult.getResponseCode() == BillingResponseCode.OK) {
                // Handle the success of the consume operation.
            }
        }
    };

    billingClient.consumeAsync(consumeParams, listener);
}

Tüketilebilir Olmayan Ürünler

Tüketilebilir olmayan satın alma işlemlerini onaylamak amacıyla, uygulamanızın güvenli bir arka ucu varsa satın alma işlemlerini güvenilir bir şekilde onaylamak için Purchases.products:acknowledge kullanmanızı öneririz. Purchases.products:get çağrısının sonucunda bulunan acknowledgementState değerini kontrol ederek satın alma işleminin daha önce onaylanmadığından emin olun.

Uygulamanız yalnızca müşteri kullanımına yönelikse uygulamanızdaki Google Play Faturalandırma Kitaplığı'nda bulunan BillingClient.acknowledgePurchase() öğesini kullanın. Bir satın alma işlemini onaylamadan önce uygulamanızın halihazırda Google Play Faturalandırma Kitaplığı'ndaki isAcknowledged() yöntemini kullanarak onaylanıp onaylanmadığını kontrol etmesi gerekir.

Aşağıdaki örnekte, bir satın alma işleminin Google Play Faturalandırma Kitaplığı kullanılarak nasıl onaylanacağı gösterilmektedir:

Kotlin

val client: BillingClient = ...
val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ...

suspend fun handlePurchase() {
    if (purchase.purchaseState === PurchaseState.PURCHASED) {
        if (!purchase.isAcknowledged) {
            val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.purchaseToken)
            val ackPurchaseResult = withContext(Dispatchers.IO) {
               client.acknowledgePurchase(acknowledgePurchaseParams.build())
            }
        }
     }
}

Java

BillingClient client = ...
AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ...

void handlePurchase(Purchase purchase) {
    if (purchase.getPurchaseState() == PurchaseState.PURCHASED) {
        if (!purchase.isAcknowledged()) {
            AcknowledgePurchaseParams acknowledgePurchaseParams =
                AcknowledgePurchaseParams.newBuilder()
                    .setPurchaseToken(purchase.getPurchaseToken())
                    .build();
            client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
        }
    }
}

Abonelikler

Abonelikler, tüketilebilir olmayan öğelere benzer şekilde işlenir. Mümkünse satın alma işlemini güvenli arka ucunuzdan güvenilir bir şekilde onaylamak için Google Play Developer API'den Purchases.subscriptions.acknowledge kullanın. Purchases.subscriptions:get'teki satın alma kaynağında acknowledgementState öğesini kontrol ederek satın alma işleminin daha önce onaylanmadığını doğrulayın. Aksi takdirde, isAcknowledged() adresini kontrol ettikten sonra Google Play Faturalandırma Kitaplığı'ndan BillingClient.acknowledgePurchase() adresini kullanarak aboneliği onaylayabilirsiniz. İlk abonelik satın alma işlemlerinin tümünün onaylanması gerekir. Abonelik yenilemelerinin onaylanması gerekmez. Aboneliklerin ne zaman onaylanması gerektiği hakkında daha fazla bilgi için Abonelik satma konusuna göz atın.

Satın alınanlar getiriliyor

Satın alma güncellemelerini PurchasesUpdatedListener kullanarak dinlemek, uygulamanızın tüm satın alma işlemlerini işlemesini sağlamak için yeterli değildir. Uygulamanız, kullanıcının yaptığı tüm satın alma işlemlerinden haberdar olmayabilir. Uygulamanızın takip etmeyi kaybedebileceği veya satın alma işlemlerinden habersiz olabileceği bazı senaryolar aşağıda verilmiştir:

  • Satın alma işlemi sırasındaki Ağ Sorunları: Bir kullanıcı başarılı bir satın alma işlemi gerçekleştirir ve Google'dan onay alır, ancak PurchasesUpdatedListener üzerinden satın alma işlemiyle ilgili bildirim almadan önce cihazı ağ bağlantısını kaybeder.
  • Birden fazla cihaz: Bir kullanıcı bir cihazda bir öğe satın alır ve daha sonra cihaz değiştirdiğinde öğeyi görmeyi bekler.
  • Uygulamanızın dışında yapılan satın alma işlemlerini işleme: Promosyon kullanımları gibi bazı satın alma işlemleri, uygulamanızın dışında yapılabilir.

Bu tür durumların üstesinden gelmek için uygulamanızın onResume() yönteminizde BillingClient.queryPurchasesAsync() çağrısı yaptığından emin olun ve tüm satın alma işlemlerinin, satın almaları işleme bölümünde açıklandığı gibi başarıyla işlendiğinden emin olun.

Aşağıdaki örnekte, bir kullanıcının abonelik satın alma işlemlerinin nasıl getirileceği gösterilmektedir. queryPurchasesAsync() öğesinin yalnızca etkin abonelikleri ve tüketilmeyen tek seferlik satın alımları döndürdüğünü unutmayın.

Kotlin

val params = QueryPurchasesParams.newBuilder()
               .setProductType(ProductType.SUBS)

// uses queryPurchasesAsync Kotlin extension function
val purchasesResult = billingClient.queryPurchasesAsync(params.build())

// check purchasesResult.billingResult
// process returned purchasesResult.purchasesList, e.g. display the plans user owns

Java

billingClient.queryPurchasesAsync(
    QueryPurchasesParams.newBuilder()
      .setProductType(ProductType.SUBS)
      .build(),
    new PurchasesResponseListener() {
      public void onQueryPurchasesResponse(BillingResult billingResult, List purchases) {
        // check billingResult
        // process returned purchase list, e.g. display the plans user owns

      }
    }
);

İşlem geçmişi getiriliyor

queryPurchaseHistoryAsync(); kullanıcının her ürün için yaptığı en son satın alma işlemini döndürür (satın alma işleminin süresi dolmuş, iptal edilmiş veya tüketilmiş olsa bile).

Kotlin uzantıları kullanıyorsanız queryPurchaseHistory() uzantı işlevini kullanabilirsiniz.

Kotlin

val params = QueryPurchaseHistoryParams.newBuilder()
               .setProductType(ProductType.SUBS)

// uses queryPurchaseHistory Kotlin extension function
val purchaseHistoryResult = billingClient.queryPurchaseHistory(params.build())

// check purchaseHistoryResult.billingResult
// process returned purchaseHistoryResult.purchaseHistoryRecordList, e.g. display purchase

Java

billingClient.queryPurchaseHistoryAsync(
    QueryPurchaseHistoryParams.newBuilder()
        .setProductType(ProductType.SUBS)
        .build(),
    new PurchaseHistoryResponseListener() {
      public void onPurchaseHistoryResponse(
        BillingResult billingResult, List purchasesHistoryList) {
          // check billingResult
          // process returned purchase history list, e.g. display purchase history
        }
    }
);

Uygulamanızın dışında yapılan satın alma işlemlerini işleme

Promosyon kullanımları gibi bazı satın alma işlemleri, uygulamanızın dışında gerçekleşebilir. Kullanıcı, uygulamanızın dışında satın alma işlemi gerçekleştirdiğinde, uygulamanızın uygulama içi bir mesaj göstermesini bekler veya uygulamanın, satın alma işlemini doğru bir şekilde aldığını ve işlediğini kullanıcıya bildirmek için bir tür bildirim mekanizması kullanır. Kabul edilebilir mekanizmalardan bazıları şunlardır:

  • Uygulama içi pop-up göster.
  • Mesajı bir uygulama içi mesaj kutusuna iletin ve uygulama içi mesaj kutusunda yeni bir mesaj olduğunu açıkça belirtin.
  • İşletim sistemi bildirim mesajı kullanın.

Uygulamanız, satın alma işlemini tanıdığında herhangi bir durumda olabileceğini unutmayın. Uygulamanızın, satın alma işlemi yapıldığında yüklenmemiş bile olması mümkündür. Kullanıcılar, uygulamanın durumundan bağımsız olarak uygulamayı devam ettirdiklerinde satın alma işlemlerini almayı beklerler.

Satın alma işlemlerini, uygulamanın satın alındığı durumdan bağımsız olarak tespit etmeniz gerekir. Bununla birlikte, öğenin alındığını kullanıcıya hemen bildirmemenin kabul edilebilir olduğu bazı istisnalar vardır. Örneğin:

  • Oyunda bir mesaj göstermenin kullanıcının dikkatini dağıtabileceği aksiyon kısmı sırasında. Bu durumda, işlem bölümü bittikten sonra kullanıcıyı bilgilendirmeniz gerekir.
  • Bir mesaj göstermenin kullanıcının dikkatini dağıtabileceği ara sahneler sırasında. Bu durumda, ara sahne bittikten sonra kullanıcıyı bilgilendirmeniz gerekir.
  • Oyunun ilk eğitim ve kullanıcı kurulumu bölümleri sırasında. Yeni kullanıcıları oyunu açtıktan hemen sonra veya ilk kullanıcı kurulumu sırasında bilgilendirmenizi öneririz. Bununla birlikte, ana oyun sırasının kullanıcıyı bilgilendirmek için hazır olmasını bekleyebilirsiniz.

Kullanıcılarınıza uygulamanızın dışında yapılan satın alma işlemleri konusunda ne zaman ve nasıl bildireceğinize karar verirken her zaman kullanıcıyı aklınızda bulundurun. Bir kullanıcı hemen bildirim almadığında kafası karışabilir ve uygulamanızı kullanmayı bırakabilir, kullanıcı desteğiyle iletişime geçebilir veya sosyal medya üzerinden şikayette bulunabilir. Not: PurchasesUpdatedListener, uygulamanızın dışında başlatılan satın alma işlemleri de dahil olmak üzere satın alma güncellemelerini işlemek için uygulama bağlamınıza kaydedilmiştir. Yani, uygulama işleminiz mevcut değilse PurchasesUpdatedListener cihazınıza bildirim gönderilmez. Bu nedenle, uygulamanız Satın Alma İşlemleri bölümünde belirtildiği gibi onResume() yönteminde BillingClient.queryPurchasesAsync() çağrısı yapmalıdır.

Beklemedeki işlemleri yönetme

Google Play, bekleyen işlemleri veya kullanıcının satın alma işlemini başlatması ile satın alma işleminin ödeme yönteminin işlenmesi arasında bir ya da daha fazla ek adım gerektiren işlemleri destekler. Google, kullanıcının ödeme yönteminden başarılı bir şekilde ödeme alındığını bildirene kadar uygulamanız bu tür satın alma işlemlerinden yararlanma hakkı vermemelidir.

Örneğin, bir kullanıcı ödeme şekli olarak nakit parayı seçerek bir uygulama içi öğe satın almak için PENDING tutarında bir satın alma işlemi oluşturabilir. Kullanıcı daha sonra işlemi tamamlayacağı ve hem bildirim hem de e-posta yoluyla bir kod alacağı fiziksel bir mağaza seçebilir. Kullanıcı fiziksel mağazaya geldiğinde kasiyerle kodu kullanabilir ve nakit ödeme yapabilir. Ardından Google hem size hem de kullanıcıya nakit para alındığını bildirir. Uygulamanız daha sonra kullanıcıya yararlanma hakkı verebilir.

Uygulamanız, başlatma işleminin bir parçası olarak enablePendingPurchases() çağrısı yaparak bekleyen işlemleri desteklemelidir.

Uygulamanız PurchasesUpdatedListener aracılığıyla veya queryPurchasesAsync() çağrısının sonucunda yeni bir satın alma işlemi aldığında satın alma durumunun PURCHASED veya PENDING olduğunu belirlemek için getPurchaseState() yöntemini kullanın.

Kullanıcı satın alma işlemini tamamladığında uygulamanız çalışıyorsa PurchasesUpdatedListener yeniden aranır ve PurchaseState artık PURCHASED olur. Bu noktada uygulamanız, tek seferlik satın alma işlemlerini işleme için standart yöntemi kullanarak satın alma işlemini işleyebilir. Uygulamanız, çalışmadığı sırada PURCHASED durumuna geçirilen satın alma işlemlerini işlemek için uygulamanızın onResume() yönteminde queryPurchasesAsync() çağrısını da yapmalıdır.

Uygulamanız ayrıca OneTimeProductNotifications dinleyerek bekleyen satın alma işlemleriyle ilgili Gerçek zamanlı geliştirici bildirimlerini kullanabilir. Satın alma işlemi PENDING tarihinden PURCHASED tarihine geçtiğinde uygulamanız bir ONE_TIME_PRODUCT_PURCHASED bildirimi alır. Satın alma işlemi iptal edilirse uygulamanız bir ONE_TIME_PRODUCT_CANCELED bildirimi alır. Müşteriniz ödemeyi gereken zaman diliminde tamamlamazsa bu durumla karşılaşabilirsiniz. Bu bildirimleri alırken, Purchases.products için PENDING durumunu içeren Google Play Geliştirici API'sini kullanabilirsiniz.

Bu senaryonun nasıl test edileceğiyle ilgili ayrıntılı adımları Bekleyen satın alma işlemlerini test etme bölümünde bulabilirsiniz.

Çoklu miktar satın alma işlemlerini yönetme

Google Play Faturalandırma Kitaplığı'nın 4.0 ve üzeri sürümlerinde desteklenen Google Play, müşterilerin satın alma sepetindeki miktarı belirterek bir işlemde aynı uygulama içi üründen birden fazla ürün satın almasına olanak tanır. Uygulamanızın çoklu miktar satın alma işlemlerini işlemesi ve belirtilen satın alma miktarına göre yararlanma hakkı sağlaması beklenir.

Çoklu miktar satın alma işlemlerini kabul etmek için uygulamanızın temel hazırlık mantığının, öğe miktarını kontrol etmesi gerekir. quantity alanına aşağıdaki API'lerin birinden erişebilirsiniz:

Çoklu miktar satın alma işlemlerini işlemek için mantık ekledikten sonra, Google Play Geliştirici Konsolu'ndaki uygulama içi ürün yönetimi sayfasında ilgili ürün için çoklu miktar özelliğini etkinleştirmeniz gerekir.

Kullanıcının Faturalandırma Yapılandırmasını Sorgulama

getBillingConfigAsync(), kullanıcının Google Play için kullandığı ülkeyi belirtir.

BillingClient oluşturduktan sonra kullanıcının faturalandırma yapılandırmasını sorgulayabilirsiniz. Aşağıdaki kod snippet'inde getBillingConfigAsync() numaralı telefonu nasıl arayacağınız açıklanmaktadır. BillingConfigResponseListener özelliğini uygulayarak yanıtı işleyin. Bu işleyici, uygulamanızdan başlatılan tüm faturalandırma yapılandırması sorguları için güncellemeler alır.

Döndürülen BillingResult hata içermiyorsa kullanıcının Play Ülkesini edinmek için BillingConfig nesnesindeki countryCode alanını kontrol edebilirsiniz.

Kotlin

// Use the default GetBillingConfigParams.
val getBillingConfigParams = GetBillingConfigParams.newBuilder().build()
billingClient.getBillingConfigAsync(getBillingConfigParams,
    object : BillingConfigResponseListener {
        override fun onBillingConfigResponse(
            billingResult: BillingResult,
            billingConfig: BillingConfig?
        ) {
            if (billingResult.responseCode == BillingResponseCode.OK
                && billingConfig != null) {
                val countryCode = billingConfig.countryCode
                ...
            } else {
                // TODO: Handle errors
            }
        }
    })

Java

// Use the default GetBillingConfigParams.
GetBillingConfigParams getBillingConfigParams = GetBillingConfigParams.newBuilder().build();
billingClient.getBillingConfigAsync(getBillingConfigParams,
    new BillingConfigResponseListener() {
      public void onBillingConfigResponse(
          BillingResult billingResult, BillingConfig billingConfig) {
        if (billingResult.getResponseCode() == BillingResponseCode.OK
            && billingConfig != null) {
            String countryCode = billingConfig.getCountryCode();
            ...
         } else {
            // TODO: Handle errors
        }
      }
    });