এই ডকুমেন্টে বর্ণনা করা হয়েছে কীভাবে আপনার অ্যাপে গুগল প্লে বিলিং লাইব্রেরি ইন্টিগ্রেট করে পণ্য বিক্রি শুরু করবেন।
ক্রয়ের জীবনকাল
এককালীন ক্রয় বা সাবস্ক্রিপশনের জন্য একটি সাধারণ ক্রয় প্রক্রিয়া নিচে দেওয়া হলো।
- ব্যবহারকারীকে দেখান তিনি কী কিনতে পারেন।
- ব্যবহারকারীর ক্রয়টি গ্রহণ করার জন্য ক্রয় প্রক্রিয়াটি চালু করুন।
- আপনার সার্ভারে ক্রয়টি যাচাই করুন।
- ব্যবহারকারীকে বিষয়বস্তু প্রদান করুন।
- কন্টেন্ট ডেলিভারি হওয়ার বিষয়টি স্বীকার করুন। ব্যবহারযোগ্য পণ্যের ক্ষেত্রে, ক্রয়টি সম্পন্ন করুন যাতে ব্যবহারকারী আইটেমটি আবার কিনতে পারেন।
সাবস্ক্রিপশন বাতিল না করা পর্যন্ত স্বয়ংক্রিয়ভাবে নবায়ন হতে থাকে। একটি সাবস্ক্রিপশন নিম্নলিখিত পর্যায়গুলোর মধ্য দিয়ে যেতে পারে:
- সক্রিয় : ব্যবহারকারীর অবস্থা ভালো এবং সাবস্ক্রিপশনটি ব্যবহারের অনুমতি আছে।
- বাতিল করা হয়েছে : ব্যবহারকারী বাতিল করেছেন কিন্তু মেয়াদ শেষ না হওয়া পর্যন্ত তাঁর অ্যাক্সেস থাকবে।
- গ্রেস পিরিয়ডে : ব্যবহারকারী পেমেন্ট সংক্রান্ত সমস্যার সম্মুখীন হয়েছেন, কিন্তু গুগল পেমেন্ট পদ্ধতিটি পুনরায় চেষ্টা করার সময় পর্যন্ত তিনি অ্যাক্সেস পাচ্ছেন।
- স্থগিত : ব্যবহারকারী পেমেন্ট সংক্রান্ত সমস্যার সম্মুখীন হয়েছেন এবং গুগল পেমেন্ট পদ্ধতিটি পুনরায় চেষ্টা করার কারণে তিনি আর অ্যাক্সেস পাচ্ছেন না।
- স্থগিত : ব্যবহারকারী তার প্রবেশাধিকার স্থগিত করেছেন এবং পুনরায় চালু না করা পর্যন্ত তিনি প্রবেশাধিকার পাবেন না।
- মেয়াদোত্তীর্ণ : ব্যবহারকারী সাবস্ক্রিপশন বাতিল করেছেন এবং এর অ্যাক্সেস হারিয়েছেন। মেয়াদ শেষ হলে ব্যবহারকারীকে সাবস্ক্রিপশন থেকে বাদ দেওয়া হয়েছে বলে গণ্য করা হয়।
গুগল প্লে-এর সাথে একটি সংযোগ শুরু করুন
গুগল প্লে-এর বিলিং সিস্টেমের সাথে সংযুক্ত হওয়ার প্রথম ধাপ হলো আপনার অ্যাপে গুগল প্লে বিলিং লাইব্রেরি যোগ করা এবং একটি সংযোগ স্থাপন করা।
Google Play বিলিং লাইব্রেরি নির্ভরতা যোগ করুন
দেখানো অনুযায়ী আপনার অ্যাপের build.gradle ফাইলে Google Play Billing Library ডিপেন্ডেন্সিটি যোগ করুন:
গ্রোভি
dependencies { def billing_version = "8.3.0" implementation "com.android.billingclient:billing:$billing_version" }
কোটলিন
dependencies { val billing_version = "8.3.0" implementation("com.android.billingclient:billing:$billing_version") }
আপনি যদি কোটলিন ব্যবহার করেন, তাহলে গুগল প্লে বিলিং লাইব্রেরি KTX মডিউলটিতে কোটলিন এক্সটেনশন এবং কো-রুটিন সাপোর্ট রয়েছে, যা আপনাকে গুগল প্লে বিলিং লাইব্রেরি ব্যবহার করার সময় প্রচলিত কোটলিন কোড লিখতে সক্ষম করে। আপনার প্রোজেক্টে এই এক্সটেনশনগুলো অন্তর্ভুক্ত করতে, দেখানো অনুযায়ী আপনার অ্যাপের build.gradle ফাইলে নিম্নলিখিত ডিপেন্ডেন্সিটি যোগ করুন:
গ্রোভি
dependencies { def billing_version = "8.3.0" implementation "com.android.billingclient:billing-ktx:$billing_version" }
কোটলিন
dependencies { val billing_version = "8.3.0" implementation("com.android.billingclient:billing-ktx:$billing_version") }
একটি বিলিং ক্লায়েন্ট শুরু করুন
একবার আপনি গুগল প্লে বিলিং লাইব্রেরির উপর নির্ভরতা যোগ করলে, আপনাকে একটি BillingClient ইনস্ট্যান্স ইনিশিয়ালাইজ করতে হবে। গুগল প্লে বিলিং লাইব্রেরি এবং আপনার অ্যাপের বাকি অংশের মধ্যে যোগাযোগের জন্য BillingClient হলো প্রধান ইন্টারফেস। BillingClient অনেক সাধারণ বিলিং অপারেশনের জন্য সিনক্রোনাস এবং অ্যাসিনক্রোনাস উভয় ধরনের সুবিধাজনক মেথড সরবরাহ করে। নিম্নলিখিত বিষয়গুলো লক্ষ্য করুন:
- একটি ইভেন্টের জন্য একাধিক
PurchasesUpdatedListenerকলব্যাক এড়ানোর জন্য, একবারে একটি সক্রিয়BillingClientকানেকশন খোলা রাখার পরামর্শ দেওয়া হয়। - আপনার অ্যাপটি যাতে সময়মতো কেনাকাটা প্রক্রিয়া করতে পারে, তা নিশ্চিত করার জন্য অ্যাপটি চালু হওয়ার সময় বা ফোরগ্রাউন্ডে আসার সময় BillingClient-এর জন্য একটি সংযোগ শুরু করার পরামর্শ দেওয়া হয়। এটি করার জন্য,
registerActivityLifecycleCallbacksদ্বারা নিবন্ধিতActivityLifecycleCallbacksব্যবহার করতে হবে এবং যখন আপনি প্রথম কোনো অ্যাক্টিভিটি পুনরায় শুরু হতে দেখবেন, তখন একটি সংযোগ শুরু করার জন্য onActivityResumed-এর জন্য লিসেন করতে হবে। এই সেরা অনুশীলনটি কেন অনুসরণ করা উচিত, সে সম্পর্কে আরও বিস্তারিত জানতে কেনাকাটা প্রক্রিয়াকরণ সম্পর্কিত বিভাগটি দেখুন। এছাড়াও, আপনার অ্যাপটি বন্ধ করার সময় সংযোগটি শেষ করতে মনে রাখবেন।
একটি BillingClient তৈরি করতে, newBuilder ব্যবহার করুন। আপনি newBuilder() এ যেকোনো কনটেক্সট পাস করতে পারেন, এবং BillingClient সেটি ব্যবহার করে একটি অ্যাপ্লিকেশন কনটেক্সট গ্রহণ করে। এর মানে হলো, আপনাকে মেমোরি লিক নিয়ে চিন্তা করতে হবে না। কেনাকাটার আপডেট পেতে, আপনাকে অবশ্যই একটি PurchasesUpdatedListener এর রেফারেন্স পাস করে setListener কল করতে হবে। এই লিসেনারটি আপনার অ্যাপের সমস্ত কেনাকাটার আপডেট গ্রহণ করে।
কোটলিন
private val purchasesUpdatedListener = PurchasesUpdatedListener { billingResult, purchases -> // To be implemented in a later section. } private var billingClient = BillingClient.newBuilder(context) .setListener(purchasesUpdatedListener) // Configure other settings. .build()
জাভা
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) // Configure other settings. .build();
Google Play-এর সাথে সংযোগ করুন
BillingClient তৈরি করার পরে, আপনাকে গুগল প্লে-এর সাথে একটি সংযোগ স্থাপন করতে হবে।
Google Play-এর সাথে সংযোগ করতে startConnection কল করুন। সংযোগ প্রক্রিয়াটি অ্যাসিঙ্ক্রোনাস, এবং ক্লায়েন্টের সেটআপ সম্পূর্ণ হলে ও এটি পরবর্তী অনুরোধ করার জন্য প্রস্তুত হলে একটি কলব্যাক পাওয়ার জন্য আপনাকে অবশ্যই একটি BillingClientStateListener ইমপ্লিমেন্ট করতে হবে।
আপনি যদি স্বয়ংক্রিয় পরিষেবা পুনঃসংযোগ চালু না করে থাকেন, তাহলে Google Play-এর সাথে সংযোগ বিচ্ছিন্ন হয়ে গেলে তা সামলানোর জন্য আপনাকে অবশ্যই রিট্রাই লজিক প্রয়োগ করতে হবে। রিট্রাই লজিক প্রয়োগ করার জন্য, onBillingServiceDisconnected() কলব্যাক মেথডটি ওভাররাইড করুন এবং নিশ্চিত করুন যে BillingClient পরবর্তী অনুরোধ করার আগে Google Play-এর সাথে পুনরায় সংযোগ করার জন্য startConnection() মেথডটি কল করে। আপনি যদি স্বয়ংক্রিয় পরিষেবা পুনঃসংযোগ চালু করে থাকেন, তাহলে আপনি এই মেথডটি একটি নো-অপ হিসেবে প্রয়োগ করতে পারেন।
নিম্নলিখিত উদাহরণটি দেখায় কিভাবে একটি সংযোগ শুরু করতে হয় এবং সেটি ব্যবহারের জন্য প্রস্তুত কিনা তা পরীক্ষা করতে হয়:
কোটলিন
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() { // If automatic service reconnection is enabled, this can be left empty (no-op) // because the library handles retries. You can still use this for non-retry // tasks like logging or updating the UI to reflect a disconnected state. // Otherwise, try to restart the connection on the next request to // Google Play by calling the startConnection() method. } })
জাভা
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() { // If automatic service reconnection is enabled, this can be left empty (no-op) // because the library handles retries. You can still use this for non-retry // tasks like logging or updating the UI to reflect a disconnected state. // Otherwise, try to restart the connection on the next request to // Google Play by calling the startConnection() method. } });
স্বয়ংক্রিয়ভাবে সংযোগ পুনঃস্থাপন করুন
সংস্করণ 8.0.0-এ BillingClient.Builder এ enableAutoServiceReconnection() মেথডটি চালু হওয়ার ফলে, সার্ভিস সংযোগ বিচ্ছিন্ন থাকা অবস্থায় কোনো API কল করা হলে প্লে বিলিং লাইব্রেরি এখন স্বয়ংক্রিয়ভাবে সার্ভিস সংযোগটি পুনরায় স্থাপন করতে পারে। এর ফলে SERVICE_DISCONNECTED রেসপন্সের সংখ্যা কমে আসতে পারে, কারণ API কল করার আগেই অভ্যন্তরীণভাবে পুনঃসংযোগের বিষয়টি সম্পন্ন হয়ে যায়।
স্বয়ংক্রিয় পুনঃসংযোগ কীভাবে চালু করবেন
BillingClient ইনস্ট্যান্স তৈরি করার সময়, স্বয়ংক্রিয় পুনঃসংযোগ চালু করতে BillingClient.Builder এ enableAutoServiceReconnection() মেথডটি ব্যবহার করুন।
কোটলিন
val billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.enableAutoServiceReconnection() // Add this line to enable reconnection
.build()
জাভা
BillingClient billingClient = BillingClient.newBuilder(context)
.setListener(listener)
.enablePendingPurchases()
.enableAutoServiceReconnection() // Add this line to enable reconnection
.build();
কেনার জন্য উপলব্ধ পণ্যগুলি দেখান
গুগল প্লে-এর সাথে সংযোগ স্থাপন করার পর, আপনি আপনার উপলব্ধ পণ্যগুলো অনুসন্ধান করতে এবং ব্যবহারকারীদের কাছে সেগুলো প্রদর্শন করতে প্রস্তুত।
ব্যবহারকারীদের কাছে আপনার পণ্য প্রদর্শন করার আগে পণ্যের বিবরণ জানতে চাওয়া একটি গুরুত্বপূর্ণ পদক্ষেপ, কারণ এটি স্থানীয় ভাষায় পণ্যের তথ্য প্রদান করে। সাবস্ক্রিপশনের ক্ষেত্রে, আপনার পণ্য প্রদর্শন Play-এর সমস্ত নীতিমালা মেনে চলছে কিনা তা যাচাই করুন।
এককালীন পণ্যের বিবরণ জানতে queryProductDetailsAsync মেথডটি কল করুন। এই মেথডটি আপনার এককালীন পণ্যের কনফিগারেশনের উপর ভিত্তি করে একাধিক অফার ফেরত দিতে পারে। আরও তথ্যের জন্য, এককালীন পণ্যের জন্য একাধিক ক্রয়ের বিকল্প এবং অফার দেখুন।
অ্যাসিঙ্ক্রোনাস অপারেশনের ফলাফল পরিচালনা করার জন্য, আপনাকে অবশ্যই একটি লিসেনার নির্দিষ্ট করতে হবে যা ProductDetailsResponseListener ইন্টারফেসটি ইমপ্লিমেন্ট করে। এরপর আপনি onProductDetailsResponse ওভাররাইড করতে পারেন, যা কোয়েরি শেষ হলে লিসেনারকে অবহিত করে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে:
কোটলিন
val queryProductDetailsParams = QueryProductDetailsParams.newBuilder() .setProductList( ImmutableList.of( Product.newBuilder() .setProductId("product_id_example") .setProductType(ProductType.SUBS) .build())) .build() billingClient.queryProductDetailsAsync(queryProductDetailsParams) { billingResult, queryProductDetailsResult -> if (billingResult.getResponseCode() == BillingResponseCode.OK) { for (ProductDetails productDetails : queryProductDetailsResult.getProductDetailsList()) { // Process successfully retrieved product details here. } for (UnfetchedProduct unfetchedProduct : queryproductDetailsResult.getUnfetchedProductList()) { // Handle any unfetched products as appropriate. } } }
জাভা
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, QueryProductDetailsResult queryProductDetailsResult) { if (billingResult.getResponseCode() == BillingResponseCode.OK) { for (ProductDetails productDetails : queryProductDetailsResult().getProductDetailsList()) { // Process success retrieved product details here. } for (UnfetchedProduct unfetchedProduct : queryproductDetailsResult.getUnfetchedProductList()) { // Handle any unfetched products as appropriate. } } } } )
পণ্যের বিবরণ জানতে চাওয়ার সময়, QueryProductDetailsParams এর একটি ইনস্ট্যান্স পাস করুন, যেখানে Google Play Console-এ তৈরি করা প্রোডাক্ট আইডি স্ট্রিংগুলির একটি তালিকার সাথে একটি ProductType উল্লেখ থাকবে। এককালীন পণ্যের জন্য ProductType অথবা সাবস্ক্রিপশনের জন্য ProductType.INAPP হতে পারে ProductType.SUBS
কোটলিন এক্সটেনশন দিয়ে কোয়েরি করুন
আপনি যদি কোটলিন এক্সটেনশন ব্যবহার করেন , তাহলে queryProductDetails() এক্সটেনশন ফাংশনটি কল করে এককালীন পণ্যের বিবরণ জানতে পারেন।
queryProductDetails() কোটলিন কোরাউটিন ব্যবহার করে, ফলে আপনাকে আলাদা কোনো লিসেনার সংজ্ঞায়িত করতে হয় না। এর পরিবর্তে, কোয়েরি সম্পন্ন না হওয়া পর্যন্ত ফাংশনটি সাসপেন্ড থাকে, এবং কোয়েরি সম্পন্ন হওয়ার পর আপনি ফলাফলটি প্রসেস করতে পারেন।
suspend fun processPurchases() {
val productList = listOf(
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.
}
কদাচিৎ, কিছু ডিভাইস ProductDetails এবং queryProductDetailsAsync() সমর্থন করতে পারে না, সাধারণত Google Play Services- এর পুরোনো সংস্করণের কারণে। এই পরিস্থিতির জন্য যথাযথ সহায়তা প্রদান করতে, Play Billing Library 7 মাইগ্রেশন গাইড থেকে ব্যাকওয়ার্ড কম্প্যাটিবিলিটি ফিচারগুলো কীভাবে ব্যবহার করতে হয় তা জেনে নিন।
ফলাফল প্রক্রিয়া করুন
গুগল প্লে বিলিং লাইব্রেরি কোয়েরির ফলাফল একটি QueryProductDetailsResult অবজেক্টে সংরক্ষণ করে। QueryProductDetailsResult ProductDetails অবজেক্টের একটি List থাকে। এরপর আপনি সফলভাবে আনা কোনো ওয়ান-টাইম প্রোডাক্টের প্রাসঙ্গিক তথ্য, যেমন তার মূল্য বা বিবরণ, দেখার জন্য লিস্টের প্রতিটি ProductDetails অবজেক্টের উপর বিভিন্ন মেথড কল করতে পারেন। উপলব্ধ প্রোডাক্টের বিস্তারিত তথ্য দেখতে, ProductDetails ক্লাসের মেথডগুলোর তালিকা দেখুন।
QueryProductDetailsResult UnfetchedProduct অবজেক্টের একটি List ও থাকে। এরপর আপনি প্রতিটি UnfetchedProduct-কে কোয়েরি করে ফেচ ব্যর্থতার কারণ অনুযায়ী স্ট্যাটাস কোড পেতে পারেন। উপলব্ধ আনফেচড প্রোডাক্টের তথ্য দেখতে, UnfetchedProduct ক্লাসের মেথডগুলোর তালিকা দেখুন।
কোনো আইটেম বিক্রির জন্য দেওয়ার আগে, যাচাই করে নিন যে ব্যবহারকারীর কাছে আইটেমটি আগে থেকেই আছে কি না। যদি ব্যবহারকারীর আইটেম লাইব্রেরিতে কোনো ব্যবহারযোগ্য আইটেম থেকে যায়, তবে সেটি পুনরায় কেনার আগে তাকে অবশ্যই সেটি ব্যবহার করে ফেলতে হবে।
সাবস্ক্রিপশন দেওয়ার আগে যাচাই করে নিন যে ব্যবহারকারী আগে থেকেই সাবস্ক্রাইব করা নেই। এছাড়াও নিম্নলিখিত বিষয়গুলো লক্ষ্য করুন:
সাবস্ক্রিপশনের ক্ষেত্রে,
queryProductDetailsAsync()মেথডটি সাবস্ক্রিপশন প্রোডাক্টের বিবরণ এবং প্রতিটি সাবস্ক্রিপশনের জন্য সর্বোচ্চ ৫০টি ব্যবহারকারীর জন্য যোগ্য অফার রিটার্ন করে। যদি ব্যবহারকারী কোনো অযোগ্য অফার কেনার চেষ্টা করেন (উদাহরণস্বরূপ, যদি অ্যাপটি যোগ্য অফারগুলির একটি পুরোনো তালিকা প্রদর্শন করে), Play ব্যবহারকারীকে জানিয়ে দেয় যে তিনি অযোগ্য, এবং ব্যবহারকারী এর পরিবর্তে বেস প্ল্যানটি কেনার বিকল্প বেছে নিতে পারেন।এককালীন প্রোডাক্টের ক্ষেত্রে,
queryProductDetailsAsync()মেথডটি ব্যবহারকারীকে শুধুমাত্র যোগ্য অফারগুলোই ফেরত দেয়। যদি ব্যবহারকারী এমন কোনো অফার কেনার চেষ্টা করেন যার জন্য তিনি যোগ্য নন (উদাহরণস্বরূপ, যদি ব্যবহারকারী কেনার পরিমাণের সর্বোচ্চ সীমায় পৌঁছে যান), তাহলে Play ব্যবহারকারীকে জানিয়ে দেয় যে তিনি অযোগ্য, এবং ব্যবহারকারী এর পরিবর্তে অন্য কোনো ক্রয় বিকল্প অফার বেছে নিতে পারেন।
ক্রয় প্রক্রিয়া চালু করুন
আপনার অ্যাপ থেকে একটি ক্রয়ের অনুরোধ শুরু করতে, আপনার অ্যাপের প্রধান থ্রেড থেকে launchBillingFlow() মেথডটি কল করুন। এই মেথডটি একটি BillingFlowParams অবজেক্টের রেফারেন্স গ্রহণ করে, যেটিতে queryProductDetailsAsync কল করে প্রাপ্ত প্রাসঙ্গিক ProductDetails অবজেক্টটি থাকে। একটি BillingFlowParams অবজেক্ট তৈরি করতে, BillingFlowParams.Builder ক্লাসটি ব্যবহার করুন।
কোটলিন
// 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) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, 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)
জাভা
// An activity reference from which the billing flow will be launched. Activity activity = ...; ImmutableList<ProductDetailsParams> productDetailsParamsList = ImmutableList.of( ProductDetailsParams.newBuilder() // retrieve a value for "productDetails" by calling queryProductDetailsAsync() .setProductDetails(productDetails) // Get the offer token: // a. For one-time products, call ProductDetails.getOneTimePurchaseOfferDetailsList() // for a list of offers that are available to the user. // b. For subscriptions, call ProductDetails.subscriptionOfferDetails() // 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() মেথডটি BillingClient.BillingResponseCode এ তালিকাভুক্ত বেশ কয়েকটি রেসপন্স কোডের মধ্যে একটি রিটার্ন করে। পারচেজ ফ্লোটি চালু করার সময় কোনো ত্রুটি হয়নি তা যাচাই করতে এই ফলাফলটি অবশ্যই পরীক্ষা করে দেখুন। OK এর একটি BillingResponseCode একটি সফল লঞ্চ নির্দেশ করে।
launchBillingFlow() সফলভাবে কল করা হলে, সিস্টেমটি গুগল প্লে-এর ক্রয় স্ক্রিন প্রদর্শন করে। চিত্র ১-এ একটি সাবস্ক্রিপশনের ক্রয় স্ক্রিন দেখানো হয়েছে:

Google Play, PurchasesUpdatedListener ইন্টারফেসটি ইমপ্লিমেন্ট করা একটি লিসেনারের কাছে ক্রয় প্রক্রিয়ার ফলাফল পৌঁছে দিতে onPurchasesUpdated() কল করে। আপনার ক্লায়েন্ট ইনিশিয়ালাইজ করার সময় setListener() মেথড ব্যবহার করে এই লিসেনারটি নির্দিষ্ট করা হয়।
সম্ভাব্য প্রতিক্রিয়া কোডগুলি পরিচালনা করার জন্য আপনাকে অবশ্যই onPurchasesUpdated() প্রয়োগ করতে হবে। নিম্নলিখিত উদাহরণটি দেখায় কিভাবে onPurchasesUpdated() ওভাররাইড করতে হয়:
কোটলিন
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) { if (billingResult.responseCode == BillingResponseCode.OK && purchases != null) { for (purchase in purchases) { // Process the purchase as described in the next section. } } else if (billingResult.responseCode == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
জাভা
@Override void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { // Process the purchase as described in the next section. } } else if (billingResult.getResponseCode() == BillingResponseCode.USER_CANCELED) { // Handle an error caused by a user canceling the purchase flow. } else { // Handle any other error codes. } }
সফলভাবে কেনাকাটা সম্পন্ন হলে চিত্র ২-এর অনুরূপ একটি গুগল প্লে ক্রয় সফলতার স্ক্রিন প্রদর্শিত হয়।

একটি সফল কেনাকাটা একটি পারচেজ টোকেনও তৈরি করে, যা একটি অনন্য শনাক্তকারী এবং এটি ব্যবহারকারী ও তার কেনা এককালীন প্রোডাক্টটির প্রোডাক্ট আইডি নির্দেশ করে। আপনার অ্যাপগুলো পারচেজ টোকেনটি স্থানীয়ভাবে সংরক্ষণ করতে পারে, তবে আমরা টোকেনটি আপনার সুরক্ষিত ব্যাকএন্ড সার্ভারে পাঠানোর জন্য দৃঢ়ভাবে সুপারিশ করি, যেখানে আপনি কেনাকাটাটি যাচাই করতে এবং জালিয়াতি থেকে সুরক্ষা দিতে পারবেন। এই প্রক্রিয়াটি ‘কেনাকাটা শনাক্তকরণ এবং প্রক্রিয়াকরণ’ অংশে আরও বিস্তারিতভাবে বর্ণনা করা হয়েছে।
ব্যবহারকারীকে লেনদেনের একটি রসিদও ইমেল করা হয়, যাতে একটি অর্ডার আইডি বা লেনদেনের একটি অনন্য আইডি থাকে। ব্যবহারকারীরা প্রতিটি এককালীন পণ্য ক্রয়ের জন্য, এবং প্রাথমিক সাবস্ক্রিপশন ক্রয় ও পরবর্তী পুনরাবৃত্ত স্বয়ংক্রিয় নবায়নের জন্যও একটি অনন্য অর্ডার আইডি সহ ইমেল পান। আপনি গুগল প্লে কনসোলে রিফান্ড পরিচালনা করতে অর্ডার আইডিটি ব্যবহার করতে পারেন।
একটি ব্যক্তিগতকৃত মূল্য নির্দেশ করুন
আপনার অ্যাপটি যদি ইউরোপীয় ইউনিয়নের ব্যবহারকারীদের কাছে বিতরণ করা যায়, তাহলে launchBillingFlow কল করার সময় setIsOfferPersonalized() মেথডটি ব্যবহার করুন, যাতে ব্যবহারকারীরা জানতে পারে যে স্বয়ংক্রিয় সিদ্ধান্ত গ্রহণের মাধ্যমে কোনো আইটেমের মূল্য ব্যক্তিগতকৃত করা হয়েছে।

আপনি ব্যবহারকারীদের যে মূল্য দিচ্ছেন তা ব্যক্তিগতকৃত কিনা তা নির্ধারণ করতে আপনাকে অবশ্যই ভোক্তা অধিকার নির্দেশিকা 2011/83/EU এর ধারা 6 (1) (ea) CRD দেখতে হবে।
setIsOfferPersonalized() একটি বুলিয়ান ইনপুট গ্রহণ করে। যখন true , তখন প্লে UI-তে ডিসক্লোজারটি অন্তর্ভুক্ত থাকে। যখন এটি false , তখন UI ডিসক্লোজারটি বাদ দেয়। ডিফল্ট মান হলো false ।
আরও তথ্যের জন্য গ্রাহক সহায়তা কেন্দ্র দেখুন।
ব্যবহারকারী শনাক্তকারী সংযুক্ত করুন
যখন আপনি ক্রয় প্রক্রিয়াটি চালু করেন, তখন আপনার অ্যাপ obfuscatedAccountId বা obfuscatedProfileId ব্যবহার করে ক্রয়কারী ব্যবহারকারীর জন্য আপনার কাছে থাকা যেকোনো ব্যবহারকারী শনাক্তকারী সংযুক্ত করতে পারে। একটি উদাহরণ শনাক্তকারী হতে পারে আপনার সিস্টেমে থাকা ব্যবহারকারীর লগইনের একটি অস্পষ্ট সংস্করণ। এই প্যারামিটারগুলো সেট করা গুগলকে জালিয়াতি শনাক্ত করতে সাহায্য করতে পারে। এছাড়াও, ব্যবহারকারীদের এনটাইটেলমেন্ট প্রদানের ক্ষেত্রে যেমন আলোচনা করা হয়েছে, এটি আপনাকে নিশ্চিত করতে সাহায্য করতে পারে যে ক্রয়গুলো সঠিক ব্যবহারকারীর নামে আরোপিত হচ্ছে।
ক্রয় সনাক্ত এবং প্রক্রিয়া করুন
এই বিভাগে বর্ণিত ক্রয়ের সনাক্তকরণ এবং প্রক্রিয়াকরণ সকল প্রকার ক্রয়ের ক্ষেত্রে প্রযোজ্য, যার মধ্যে প্রচারমূলক অফার গ্রহণ (প্রমোশন রিডেম্পশন)-এর মতো অ্যাপের বাইরের ক্রয়ও অন্তর্ভুক্ত।
আপনার অ্যাপ নিম্নলিখিত উপায়গুলির মধ্যে কোনো একটির মাধ্যমে নতুন কেনাকাটা এবং সম্পন্ন হওয়া অপেক্ষমান কেনাকাটা শনাক্ত করে:
- যখন আপনার অ্যাপ
launchBillingFlowকল করার ফলেonPurchasesUpdatedকল হয় (যেমনটি আগের বিভাগে আলোচনা করা হয়েছে), অথবা যখন আপনার অ্যাপটি একটি সক্রিয় বিলিং লাইব্রেরি সংযোগের সাথে চলছে এবং আপনার অ্যাপের বাইরে কোনো কেনাকাটা করা হয় বা কোনো অপেক্ষাধীন কেনাকাটা সম্পন্ন হয়। উদাহরণস্বরূপ, পরিবারের কোনো সদস্য অন্য কোনো ডিভাইসে একটি অপেক্ষাধীন কেনাকাটা অনুমোদন করেন। - যখন আপনার অ্যাপ ব্যবহারকারীর কেনাকাটা সম্পর্কে জানতে queryPurchasesAsync কল করে
#১ এর জন্য, যতক্ষণ আপনার অ্যাপটি চালু থাকবে এবং একটি সক্রিয় গুগল প্লে বিলিং লাইব্রেরি সংযোগ থাকবে, ততক্ষণ নতুন বা সম্পন্ন হওয়া কেনাকাটার জন্য onPurchasesUpdated স্বয়ংক্রিয়ভাবে কল করা হবে। যদি আপনার অ্যাপ্লিকেশনটি চালু না থাকে বা আপনার অ্যাপের একটি সক্রিয় গুগল প্লে বিলিং লাইব্রেরি সংযোগ না থাকে, তাহলে onPurchasesUpdated কল করা হবে না। মনে রাখবেন, আপনার অ্যাপটি ফোরগ্রাউন্ডে থাকা অবস্থায় একটি সক্রিয় সংযোগ বজায় রাখার চেষ্টা করার পরামর্শ দেওয়া হয়, যাতে আপনার অ্যাপ সময়মতো কেনাকাটার আপডেট পায়।
#২ এর জন্য, আপনার অ্যাপ যেন সমস্ত কেনাকাটা প্রক্রিয়া করে তা নিশ্চিত করতে আপনাকে অবশ্যই BillingClient.queryPurchasesAsync() কল করতে হবে। যখন আপনার অ্যাপ সফলভাবে গুগল প্লে বিলিং লাইব্রেরির সাথে একটি সংযোগ স্থাপন করে, তখন এটি করার পরামর্শ দেওয়া হয় (যা আপনার অ্যাপ চালু হওয়ার সময় বা ফোরগ্রাউন্ডে আসার সময় করার পরামর্শ দেওয়া হয়, যেমনটি একটি BillingClient ইনিশিয়ালাইজ করার অংশে আলোচনা করা হয়েছে)। onServiceConnected- এ একটি সফল ফলাফল পাওয়ার পর queryPurchasesAsync কল করার মাধ্যমে এটি সম্পন্ন করা যেতে পারে। এই পরামর্শটি অনুসরণ করা নিম্নলিখিত ইভেন্ট এবং পরিস্থিতিগুলি পরিচালনা করার জন্য অত্যন্ত গুরুত্বপূর্ণ:
- ক্রয়ের সময় নেটওয়ার্ক সমস্যা : একজন ব্যবহারকারী সফলভাবে কেনাকাটা করতে পারেন এবং গুগল থেকে নিশ্চিতকরণও পেতে পারেন, কিন্তু
PurchasesUpdatedListenerএর মাধ্যমে তার ডিভাইস এবং আপনার অ্যাপে কেনাকাটার বিজ্ঞপ্তি পৌঁছানোর আগেই তার ডিভাইসের নেটওয়ার্ক সংযোগ বিচ্ছিন্ন হয়ে যায়। - একাধিক ডিভাইস : একজন ব্যবহারকারী একটি ডিভাইসে কোনো আইটেম কিনতে পারেন এবং পরে ডিভাইস পরিবর্তন করলে আইটেমটি দেখতে পাওয়ার আশা করতে পারেন।
- আপনার অ্যাপের বাইরে করা কেনাকাটা পরিচালনা : কিছু কেনাকাটা, যেমন প্রচারমূলক অফার গ্রহণ, আপনার অ্যাপের বাইরে করা যেতে পারে।
- ক্রয় অবস্থার পরিবর্তন পরিচালনা : আপনার অ্যাপ্লিকেশনটি চালু না থাকা অবস্থায় একজন ব্যবহারকারী একটি অপেক্ষমান ক্রয়ের জন্য অর্থপ্রদান সম্পন্ন করতে পারেন এবং আশা করতে পারেন যে, যখন তিনি আপনার অ্যাপটি খুলবেন, তখন ক্রয়টি সম্পন্ন হওয়ার একটি নিশ্চিতকরণ বার্তা পাবেন।
- স্থগিত সাবস্ক্রিপশন : একটি সাবস্ক্রিপশন তার সাবস্ক্রিপশন লাইফসাইকেল চলাকালীন স্থগিত হয়ে যেতে পারে। BillingClient.queryPurchasesAsync() শুধুমাত্র তখনই স্থগিত সাবস্ক্রিপশনগুলো রিটার্ন করবে, যদি
QueryPurchasesParams.BuilderএincludeSuspendedSubscriptionsপ্যারামিটারটি সেট করা থাকে।PurchasesUpdatedListenerএ স্থগিত সাবস্ক্রিপশনগুলো রিটার্ন করা হয় না।
আপনার অ্যাপ কোনো নতুন বা সম্পন্ন হওয়া কেনাকাটা শনাক্ত করার পর, আপনার অ্যাপের যা করা উচিত:
- ক্রয়টি যাচাই করুন।
- সম্পন্ন ক্রয়ের জন্য ব্যবহারকারীকে বিষয়বস্তু প্রদান করুন।
- ব্যবহারকারীকে অবহিত করুন।
- আপনার অ্যাপ যে কেনাকাটাগুলো সম্পন্ন করেছে, সে বিষয়ে গুগলকে অবহিত করুন।
এই ধাপগুলো পরবর্তী বিভাগগুলোতে বিস্তারিতভাবে আলোচনা করা হয়েছে এবং এরপর সমস্ত ধাপগুলোর পুনরালোচনার জন্য একটি বিভাগ রয়েছে।
ক্রয় যাচাই করুন
কোনো ব্যবহারকারীকে সুবিধা দেওয়ার আগে আপনার অ্যাপের উচিত কেনাকাটার বৈধতা সর্বদা যাচাই করা। ‘সুবিধা দেওয়ার আগে কেনাকাটা যাচাই করুন’ অংশে বর্ণিত নির্দেশিকা অনুসরণ করে এটি করা যেতে পারে। কেনাকাটা যাচাই করার পরেই আপনার অ্যাপের উচিত কেনাকাটাটি প্রক্রিয়া করা এবং ব্যবহারকারীকে সুবিধা প্রদান করা, যা পরবর্তী বিভাগে আলোচনা করা হয়েছে।
ব্যবহারকারীকে অধিকার প্রদান করুন
আপনার অ্যাপ একবার কোনো কেনাকাটা যাচাই করে নিলে, এটি ব্যবহারকারীকে অধিকার প্রদান করতে এবং তাকে অবহিত করতে পারে। অধিকার প্রদানের আগে, যাচাই করুন যে আপনার অ্যাপটি কেনাকাটার অবস্থা ' ক্রয়কৃত' PURCHASED ) কিনা তা পরীক্ষা করছে। যদি কেনাকাটাটি 'অপেক্ষমাণ' (PENDING) অবস্থায় থাকে, তবে আপনার অ্যাপের উচিত ব্যবহারকারীকে জানানো যে অধিকার প্রদানের আগে কেনাকাটাটি সম্পূর্ণ করার জন্য তাদের আরও কিছু কাজ সম্পন্ন করতে হবে। শুধুমাত্র তখনই অধিকার প্রদান করুন যখন কেনাকাটাটি 'অপেক্ষমাণ' (PENDING) থেকে 'সফল' (SUCCESS) অবস্থায় পরিবর্তিত হয়। অতিরিক্ত তথ্য 'অপেক্ষমাণ লেনদেন পরিচালনা' (Handling pending transactions) অংশে পাওয়া যাবে।
ব্যবহারকারী শনাক্তকারী সংযুক্ত করার বিষয়ে আলোচিত পদ্ধতি অনুযায়ী, আপনি যদি ক্রয়ের সাথে ব্যবহারকারী শনাক্তকারী সংযুক্ত করে থাকেন, তবে আপনি আপনার সিস্টেমে সঠিক ব্যবহারকারীকে চিহ্নিত করার জন্য সেগুলি পুনরুদ্ধার এবং ব্যবহার করতে পারেন। এই কৌশলটি সেইসব ক্রয়ের হিসাব মেলানোর ক্ষেত্রে কার্যকর, যেখানে আপনার অ্যাপ হয়তো ক্রয়টি কোন ব্যবহারকারীর জন্য করা হয়েছে সে সম্পর্কে ধারণা হারিয়ে ফেলেছে। উল্লেখ্য, আপনার অ্যাপের বাইরে করা ক্রয়ের ক্ষেত্রে এই শনাক্তকারীগুলি সেট করা থাকবে না। এই ক্ষেত্রে আপনার অ্যাপ হয় লগ-ইন করা ব্যবহারকারীকে অধিকারটি প্রদান করতে পারে, অথবা ব্যবহারকারীকে একটি পছন্দের অ্যাকাউন্ট বেছে নিতে বলতে পারে।
প্রি-অর্ডারের ক্ষেত্রে, রিলিজের সময় আসার আগে পর্যন্ত ক্রয়টি 'পেন্ডিং' অবস্থায় থাকে। রিলিজের সময় প্রি-অর্ডারের ক্রয়টি সম্পন্ন হবে এবং কোনো অতিরিক্ত পদক্ষেপ ছাড়াই এর অবস্থা 'পারচেজড'-এ পরিবর্তিত হবে।
ব্যবহারকারীকে অবহিত করুন
ব্যবহারকারীকে অধিকার দেওয়ার পর, আপনার অ্যাপের উচিত সফল ক্রয়টি নিশ্চিত করতে একটি নোটিফিকেশন দেখানো। এই নোটিফিকেশনের কারণে, ক্রয়টি সফলভাবে সম্পন্ন হয়েছে কি না, সে বিষয়ে ব্যবহারকারীর কোনো বিভ্রান্তি থাকে না। অন্যথায়, ব্যবহারকারী আপনার অ্যাপ ব্যবহার করা বন্ধ করে দিতে পারেন, ইউজার সাপোর্টে যোগাযোগ করতে পারেন, অথবা সোশ্যাল মিডিয়ায় এ বিষয়ে অভিযোগ করতে পারেন। মনে রাখবেন যে, আপনার অ্যাপ্লিকেশনের জীবনচক্রের যেকোনো সময়ে অ্যাপটি ক্রয়ের আপডেট শনাক্ত করতে পারে। উদাহরণস্বরূপ, কোনো অভিভাবক অন্য ডিভাইসে একটি অপেক্ষমান ক্রয় অনুমোদন করলেন, সেক্ষেত্রে আপনার অ্যাপ ব্যবহারকারীকে একটি উপযুক্ত সময় পর্যন্ত নোটিফিকেশন পাঠাতে দেরি করতে চাইতে পারে। যেসব ক্ষেত্রে দেরি করা উপযুক্ত হবে, তার কয়েকটি উদাহরণ হলো:
- গেমের অ্যাকশন অংশ বা কাটসিন চলাকালীন কোনো বার্তা দেখালে তা ব্যবহারকারীর মনোযোগে ব্যাঘাত ঘটাতে পারে। এক্ষেত্রে, অ্যাকশন অংশটি শেষ হওয়ার পর আপনাকে অবশ্যই ব্যবহারকারীকে জানাতে হবে।
- গেমের প্রাথমিক টিউটোরিয়াল এবং ইউজার সেটআপ পর্ব চলাকালীন। উদাহরণস্বরূপ, কোনো ব্যবহারকারী আপনার অ্যাপটি ইনস্টল করার আগে এর বাইরে থেকে কোনো কেনাকাটা করে থাকতে পারেন। আমরা সুপারিশ করি যে, নতুন ব্যবহারকারীরা গেমটি খোলার সাথে সাথেই অথবা প্রাথমিক ইউজার সেটআপের সময় পুরস্কারটি সম্পর্কে তাদের অবহিত করুন। যদি আপনার অ্যাপটি কোনো সুবিধা দেওয়ার আগে ব্যবহারকারীকে একটি অ্যাকাউন্ট তৈরি করতে বা লগ ইন করতে বলে, তবে তাদের কেনা জিনিসটি দাবি করার জন্য কোন কোন ধাপ সম্পন্ন করতে হবে, তা ব্যবহারকারীকে জানিয়ে দেওয়ার পরামর্শ দেওয়া হয়। এটি অত্যন্ত গুরুত্বপূর্ণ, কারণ আপনার অ্যাপটি কেনাকাটাটি প্রসেস না করলে ৩ দিন পর টাকা ফেরত দেওয়া হয়।
ব্যবহারকারীকে কোনো কেনাকাটার বিষয়ে অবহিত করার ক্ষেত্রে, গুগল প্লে নিম্নলিখিত পদ্ধতিগুলো সুপারিশ করে:
- অ্যাপের মধ্যে একটি ডায়ালগ বক্স দেখান।
- মেসেজটি অ্যাপের ভেতরের মেসেজ বক্সে পৌঁছে দিন এবং সেখানে একটি নতুন মেসেজ এসেছে তা স্পষ্টভাবে উল্লেখ করুন।
- একটি OS নোটিফিকেশন মেসেজ ব্যবহার করুন।
নোটিফিকেশনটিতে ব্যবহারকারীকে তার প্রাপ্ত সুবিধা সম্পর্কে জানানো উচিত। উদাহরণস্বরূপ, "আপনি ১০০ গোল্ড কয়েন কিনেছেন!"। এছাড়াও, যদি কেনাকাটাটি প্লে পাস-এর মতো কোনো প্রোগ্রামের সুবিধার ফলস্বরূপ হয়ে থাকে, তবে আপনার অ্যাপটি ব্যবহারকারীকে এই বিষয়টি জানিয়ে দেয়। উদাহরণস্বরূপ, "আইটেম পাওয়া গেছে! আপনি এইমাত্র প্লে পাস-এর সাথে ১০০ জেম পেয়েছেন। চালিয়ে যান।"। সুবিধাগুলো জানানোর জন্য ব্যবহারকারীদের কাছে কোন ধরনের টেক্সট প্রদর্শন করা উচিত, সে বিষয়ে প্রতিটি প্রোগ্রামের নিজস্ব নির্দেশনা থাকতে পারে।
ক্রয় প্রক্রিয়া সম্পন্ন হয়েছে বলে গুগলকে অবহিত করুন।
আপনার অ্যাপ ব্যবহারকারীকে অধিকার প্রদান করার পর এবং সফল লেনদেন সম্পর্কে অবহিত করার পর, আপনার অ্যাপকে গুগলকে জানাতে হবে যে ক্রয়টি সফলভাবে সম্পন্ন হয়েছে। এটি ক্রয়টি স্বীকার করার মাধ্যমে করা হয় এবং অবশ্যই তিন দিনের মধ্যে করতে হবে, যাতে ক্রয়ের অর্থ স্বয়ংক্রিয়ভাবে ফেরত না যায় এবং অধিকার বাতিল না হয়ে যায় । বিভিন্ন ধরণের ক্রয় স্বীকার করার প্রক্রিয়াটি নিম্নলিখিত বিভাগগুলিতে বর্ণনা করা হয়েছে।
ভোগ্যপণ্য
ব্যবহারযোগ্য পণ্যের ক্ষেত্রে, যদি আপনার অ্যাপে একটি সুরক্ষিত ব্যাকএন্ড থাকে, তাহলে আমরা নির্ভরযোগ্যভাবে কেনাকাটা সম্পন্ন করার জন্য Purchases.products:consume ব্যবহার করার পরামর্শ দিই। Purchases.products:get কল করার ফলাফল থেকে consumptionState পরীক্ষা করে নিশ্চিত হন যে কেনাকাটাটি ইতিমধ্যেই সম্পন্ন হয়নি। যদি আপনার অ্যাপটি ব্যাকএন্ড ছাড়া শুধুমাত্র ক্লায়েন্ট-ভিত্তিক হয়, তাহলে Google Play Billing Library থেকে consumeAsync() ব্যবহার করুন। উভয় পদ্ধতিই স্বীকৃতির প্রয়োজনীয়তা পূরণ করে এবং নির্দেশ করে যে আপনার অ্যাপ ব্যবহারকারীকে অধিকার প্রদান করেছে। এই পদ্ধতিগুলো আপনার অ্যাপকে ইনপুট করা পারচেজ টোকেনের সাথে সম্পর্কিত ওয়ান-টাইম প্রোডাক্টটি পুনরায় কেনার জন্য উপলব্ধ করতেও সক্ষম করে। consumeAsync() এর সাথে আপনাকে অবশ্যই এমন একটি অবজেক্ট পাস করতে হবে যা ConsumeResponseListener ইন্টারফেসটি ইমপ্লিমেন্ট করে। এই অবজেক্টটি কনসাম্পশন অপারেশনের ফলাফল পরিচালনা করে। আপনি onConsumeResponse() পদ্ধতিটি ওভাররাইড করতে পারেন, যা Google Play Billing Library অপারেশনটি সম্পূর্ণ হলে কল করে।
নিম্নলিখিত উদাহরণটি সংশ্লিষ্ট ক্রয় টোকেন ব্যবহার করে গুগল প্লে বিলিং লাইব্রেরির মাধ্যমে একটি পণ্য ক্রয় করার পদ্ধতি প্রদর্শন করে:
কোটলিন
val consumeParams = ConsumeParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build() val consumeResult = withContext(Dispatchers.IO) { client.consumePurchase(consumeParams) }
জাভা
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);
অ-ভোগ্যপণ্য
অ-ব্যবহারযোগ্য কেনাকাটা স্বীকার করার জন্য, যদি আপনার অ্যাপের একটি সুরক্ষিত ব্যাকএন্ড থাকে, আমরা নির্ভরযোগ্যভাবে কেনাকাটা স্বীকার করতে Purchases.products:acknowledge ব্যবহার করার পরামর্শ দিই। Purchases.products:get কল করার ফলাফল থেকে acknowledgementState পরীক্ষা করে নিশ্চিত করুন যে কেনাকাটাটি আগে স্বীকার করা হয়নি।
আপনার অ্যাপটি যদি শুধুমাত্র ক্লায়েন্ট-ভিত্তিক হয়, তাহলে আপনার অ্যাপে গুগল প্লে বিলিং লাইব্রেরি থেকে BillingClient.acknowledgePurchase() ব্যবহার করুন। কোনো কেনাকাটা স্বীকার করার আগে, আপনার অ্যাপের উচিত গুগল প্লে বিলিং লাইব্রেরির isAcknowledged() মেথড ব্যবহার করে যাচাই করে দেখা যে সেটি আগে থেকেই স্বীকার করা হয়েছে কিনা।
নিম্নলিখিত উদাহরণটি দেখায় কিভাবে গুগল প্লে বিলিং লাইব্রেরি ব্যবহার করে একটি ক্রয় স্বীকার করতে হয়:
কোটলিন
val client: BillingClient = ... val acknowledgePurchaseResponseListener: AcknowledgePurchaseResponseListener = ... val acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.purchaseToken) val ackPurchaseResult = withContext(Dispatchers.IO) { client.acknowledgePurchase(acknowledgePurchaseParams.build()) }
জাভা
BillingClient client = ... AcknowledgePurchaseResponseListener acknowledgePurchaseResponseListener = ... AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder() .setPurchaseToken(purchase.getPurchaseToken()) .build(); client.acknowledgePurchase(acknowledgePurchaseParams, acknowledgePurchaseResponseListener);
সাবস্ক্রিপশন
সাবস্ক্রিপশনগুলো নন-কনজিউমেবলগুলোর মতোই পরিচালনা করা হয়। সম্ভব হলে, আপনার সুরক্ষিত ব্যাকএন্ড থেকে নির্ভরযোগ্যভাবে ক্রয়টি অ্যাকনলেজ করার জন্য Google Play Developer API-এর Purchases.subscriptions.acknowledge ব্যবহার করুন। Purchases.subscriptions:get থেকে পারচেজ রিসোর্সের acknowledgementState চেক করে যাচাই করুন যে ক্রয়টি আগে অ্যাকনলেজ করা হয়নি। অন্যথায়, isAcknowledged() চেক করার পর আপনি Google Play Billing Library থেকে BillingClient.acknowledgePurchase() ব্যবহার করে একটি সাবস্ক্রিপশন অ্যাকনলেজ করতে পারেন। সমস্ত প্রাথমিক সাবস্ক্রিপশন ক্রয় অ্যাকনলেজ করা প্রয়োজন। সাবস্ক্রিপশন রিনিউয়াল অ্যাকনলেজ করার প্রয়োজন নেই। কখন সাবস্ক্রিপশন অ্যাকনলেজ করতে হবে সে সম্পর্কে আরও তথ্যের জন্য, " Sell subscriptions" টপিকটি দেখুন।
পুনরালোচনা
নিম্নলিখিত হলো এই ধাপগুলোর একটি সংক্ষিপ্ত বিবরণ।
অধিকার প্রদানের আগে ক্রয় যাচাই করার জন্য আপনার সুরক্ষিত ব্যাকএন্ডে ক্রয়টি পাঠান।
ক্রয়ের তথ্য দিয়ে আপনার এনটাইটেলমেন্ট স্টোরেজ আপডেট করুন। যদি ক্রয়টি পেন্ডিং (PENDING) অবস্থায় থাকে, তবে নিশ্চিত করুন যে এনটাইটেলমেন্টটি পেন্ডিং হিসেবে চিহ্নিত আছে এবং ব্যবহারকারী এখনও কোনো সুবিধা পাচ্ছেন না। এই ধাপটি আপনার সুরক্ষিত ব্যাকএন্ডে করার পরামর্শ দেওয়া হচ্ছে এবং এটি ধাপ ১-এর ব্যাকএন্ডে করা এপিআই (API) কলের সাথে একত্রিত করা যেতে পারে।
উপযুক্ত বার্তার মাধ্যমে ব্যবহারকারীকে অবহিত করুন (পূর্বে আলোচনা অনুযায়ী প্রয়োজনে বিজ্ঞপ্তি প্রদানে বিলম্ব করা যেতে পারে)।
ক্রয় প্রক্রিয়াকরণ বিভাগে আলোচিত পদক্ষেপগুলি অনুসরণ করে Google-কে জানান যে ক্রয়টি সম্পন্ন হয়েছে।
আপনার অ্যাপে এই ধাপগুলো সঠিকভাবে প্রয়োগ করা হয়েছে কিনা তা যাচাই করতে আপনি টেস্টিং গাইডটি অনুসরণ করতে পারেন।
মুলতুবি লেনদেনগুলি পরিচালনা করুন
গুগল প্লে পেন্ডিং ট্রানজ্যাকশন সমর্থন করে, অর্থাৎ এমন ট্রানজ্যাকশন যা ব্যবহারকারীর কেনাকাটা শুরু করা এবং কেনাকাটার জন্য অর্থপ্রদানের পদ্ধতি প্রসেস হওয়ার মধ্যে এক বা একাধিক অতিরিক্ত ধাপের প্রয়োজন হয়। ব্যবহারকারীর অর্থপ্রদানের পদ্ধতি থেকে সফলভাবে অর্থ কেটে নেওয়া হয়েছে বলে গুগল আপনাকে অবহিত না করা পর্যন্ত আপনার অ্যাপের এই ধরনের কেনাকাটার অনুমোদন দেওয়া উচিত নয়।
উদাহরণস্বরূপ, একজন ব্যবহারকারী একটি ফিজিক্যাল স্টোর বেছে নিয়ে লেনদেন শুরু করতে পারেন, যেখানে তিনি পরে নগদে অর্থ পরিশোধ করবেন। ব্যবহারকারী নোটিফিকেশন এবং ইমেল উভয় মাধ্যমেই একটি কোড পান। ব্যবহারকারী যখন ফিজিক্যাল স্টোরে পৌঁছান, তখন তিনি ক্যাশিয়ারের কাছে কোডটি রিডিম করে নগদে অর্থ পরিশোধ করতে পারেন। এরপর গুগল আপনাকে এবং ব্যবহারকারী উভয়কেই জানিয়ে দেয় যে পেমেন্ট গৃহীত হয়েছে। তখন আপনার অ্যাপ ব্যবহারকারীকে সেই সুবিধাটি প্রদান করতে পারে।
আপনার অ্যাপের জন্য পেন্ডিং ট্রানজ্যাকশন চালু করতে BillingClient ইনিশিয়ালাইজ করার অংশ হিসেবে enablePendingPurchases() কল করুন। আপনার অ্যাপকে অবশ্যই ওয়ান-টাইম প্রোডাক্টের জন্য পেন্ডিং ট্রানজ্যাকশন চালু এবং সাপোর্ট করতে হবে। সাপোর্ট যোগ করার আগে, পেন্ডিং ট্রানজ্যাকশনের পারচেজ লাইফসাইকেল সম্পর্কে আপনার ধারণা আছে কিনা তা নিশ্চিত হয়ে নিন।
যখন আপনার অ্যাপে কোনো নতুন কেনাকাটা আসে, তা আপনার PurchasesUpdatedListener মাধ্যমেই হোক বা queryPurchasesAsync কল করার ফলেই হোক, তখন কেনাকাটার অবস্থা PURCHASED নাকি PENDING তা নির্ধারণ করতে getPurchaseState() মেথডটি ব্যবহার করুন। শুধুমাত্র যখন অবস্থাটি PURCHASED থাকবে, তখনই আপনার এনটাইটেলমেন্ট প্রদান করা উচিত।
যখন ব্যবহারকারী কেনাকাটা সম্পন্ন করেন, তখন যদি আপনার অ্যাপটি চালু থাকে এবং প্লে বিলিং লাইব্রেরির সাথে একটি সক্রিয় সংযোগ থাকে, তাহলে আপনার PurchasesUpdatedListener আবার কল করা হয় এবং PurchaseState তখন PURCHASED হয়ে যায়। এই পর্যায়ে, আপনার অ্যাপটি কেনাকাটা শনাক্তকরণ এবং প্রক্রিয়াকরণের জন্য প্রচলিত পদ্ধতি ব্যবহার করে কেনাকাটাটি সম্পন্ন করতে পারে। আপনার অ্যাপটি বন্ধ থাকার সময়ে যে কেনাকাটাগুলো PURCHASED অবস্থায় চলে গেছে, সেগুলো পরিচালনা করার জন্য আপনার অ্যাপের onResume() মেথডে queryPurchasesAsync() ফাংশনটিও কল করা উচিত।
যখন ক্রয়টি PENDING থেকে PURCHASED এ পরিবর্তিত হয়, তখন আপনার রিয়েল-টাইম ডেভেলপার নোটিফিকেশন ক্লায়েন্ট একটি ONE_TIME_PRODUCT_PURCHASED প্রোডাক্ট পারচেজড' বা SUBSCRIPTION_PURCHASED পারচেজড' নোটিফিকেশন পায়। যদি ক্রয়টি বাতিল করা হয়, তাহলে আপনি একটি ONE_TIME_PRODUCT_CANCELED প্রোডাক্ট ক্যান্সেলড' বা SUBSCRIPTION_PENDING_PURCHASE_CANCELED ' নোটিফিকেশন পাবেন। আপনার গ্রাহক যদি নির্ধারিত সময়ের মধ্যে পেমেন্ট সম্পন্ন না করেন, তবে এমনটা হতে পারে। মনে রাখবেন, আপনি যেকোনো ক্রয়ের বর্তমান অবস্থা যাচাই করার জন্য সর্বদা গুগল প্লে ডেভেলপার এপিআই ব্যবহার করতে পারেন।
একাধিক পরিমাণে ক্রয় পরিচালনা করুন
গুগল প্লে বিলিং লাইব্রেরির ৪.০ এবং তার পরবর্তী সংস্করণগুলোতে সমর্থিত এই ফিচারের মাধ্যমে, গ্রাহকরা পারচেজ কার্ট থেকে পরিমাণ নির্দিষ্ট করে একটি লেনদেনের মধ্যে একই ধরনের একাধিক ওয়ান-টাইম প্রোডাক্ট কিনতে পারেন। আপনার অ্যাপটি একাধিক পরিমাণে কেনাকাটা পরিচালনা করতে এবং নির্দিষ্ট ক্রয়ের পরিমাণের উপর ভিত্তি করে এনটাইটেলমেন্ট প্রদান করতে সক্ষম হবে বলে আশা করা হচ্ছে।
একাধিক পরিমাণে করা কেনাকাটা সম্পন্ন করতে, আপনার অ্যাপের প্রোভিশনিং লজিককে আইটেমের পরিমাণ যাচাই করতে হবে। আপনি নিম্নলিখিত API-গুলোর যেকোনো একটি থেকে quantity ফিল্ডটি অ্যাক্সেস করতে পারেন:
- গুগল প্লে বিলিং লাইব্রেরির
getQuantity()। - Google Play ডেভেলপার API থেকে
Purchases.products.quantity
একাধিক পরিমাণে কেনাকাটা পরিচালনা করার জন্য লজিক যোগ করার পরে, আপনাকে Google Play ডেভেলপার কনসোলের ওয়ান-টাইম প্রোডাক্ট ম্যানেজমেন্ট পেজে সংশ্লিষ্ট প্রোডাক্টটির জন্য মাল্টি-কোয়ান্টিটি ফিচারটি চালু করতে হবে।
ব্যবহারকারীর বিলিং কনফিগারেশন সম্পর্কে জিজ্ঞাসা করুন
getBillingConfigAsync() ব্যবহারকারীর গুগল প্লে-এর জন্য ব্যবহৃত দেশটি প্রদান করে।
You can query the user's billing configuration after creating a BillingClient . The following code snippet describes how to make a call to getBillingConfigAsync() . Handle the response by implementing the BillingConfigResponseListener . This listener receives updates for all billing config queries initiated from your app.
If the returned BillingResult contains no errors, you can then check the countryCode field in the BillingConfig object to obtain the user's Play Country.
কোটলিন
// 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 } } })
জাভা
// 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 } } });
Cart abandonment reminders in Google Play Games home (enabled by default)
For Games developers that monetize through one-time products, one way in which stock-keeping units (SKUs) that are active in Google Play Console can be sold outside of your app is the Cart Abandonment Reminder feature, which nudges users to complete their previously abandoned purchases while browsing the Google Play Store. These purchases happen outside of your app, from the Google Play Games home in the Google Play Store.
This feature is enabled by default to help users pick up where they left off and to help developers maximize sales. However, you can opt your app out of this feature by submitting the Cart Abandonment Reminder feature opt-out form . For best practices on managing SKUs within the Google Play Console, see Create an in-app product .
The following images show the Cart Abandonment Reminder appearing on the Google Play Store:

