1. Pengantar
Codelab ini mengajarkan cara menggunakan Google Play Billing Library (PBL) untuk mengelola perubahan paket langganan. Anda akan menemukan pengaruh berbagai mode penggantian terhadap harga dan hak pengguna sekaligus mempelajari cara memproses Notifikasi Developer Real-time (RTDN) backend.
Penonton
Dirancang untuk developer aplikasi Android, codelab ini memberikan panduan tentang cara menerapkan fitur pengelolaan langganan yang canggih. Panduan ini membantu Anda menawarkan pengalaman yang lancar kepada pengguna untuk mengupgrade, mendowngrade, atau beralih antar-paket langganan yang berbeda.
Yang akan Anda pelajari ...
- Cara membuat Langganan di Konsol Play.
- Cara memilih
ReplacementModeyang benar (misalnya,WITH_TIME_PRORATIONversusDEFERRED) agar sesuai dengan kebijakan upgrade dan downgrade aplikasi Anda. - Cara mengonfigurasi
BillingFlowParamsdalamlaunchBillingFlowuntuk memicu alur pembelian Google Play untuk penggantian paket. - Cara menggunakan Notifikasi Developer Real-time (RTDN) dan
purchases.subscriptionsv2API untuk mencabut akses lama dan memberikan akses baru dengan aman di backend Anda
Yang Anda butuhkan
- Akses ke Konsol Google Play dengan akun developer. Jika Anda tidak memiliki akun developer, Anda harus membuat akun.
- Aplikasi contoh untuk codelab ini yang dapat Anda download dari GitHub.
- Android Studio
2. Mem-build aplikasi contoh
Codelab ini menggunakan aplikasi Android contoh untuk menunjukkan cara menerapkan penggantian langganan di PBL. Aplikasi contoh dirancang sebagai aplikasi Android yang berfungsi penuh dan memiliki kode sumber lengkap yang menunjukkan aspek berikut:
- Mengintegrasikan aplikasi dengan PBL
- Menerapkan penggantian langganan
Jika sudah memahami penggantian langganan dan PBL, Anda dapat mendownload aplikasi contoh dan mencobanya.
Video demo berikut menunjukkan tampilan dan perilaku aplikasi contoh setelah di-deploy dan dijalankan.
Prasyarat
Sebelum Anda membuat dan men-deploy aplikasi contoh, lakukan hal berikut:
- Buat akun developer Konsol Google Play. Jika Anda sudah memiliki akun developer, lewati langkah ini.
- Buat aplikasi baru di Konsol Play dengan fitur monetisasi yang diaktifkan. Atau, Anda dapat menggunakan aplikasi yang sudah ada di Konsol Play. Jika fitur monetisasi belum diaktifkan untuk aplikasi Anda, ikuti langkah-langkah ini untuk menyiapkannya.
- Menginstal Android Studio.
Build
Untuk mem-build aplikasi contoh sesuai yang diperlukan untuk mengikuti codelab:
- Download aplikasi contoh dari GitHub.
- Perbarui
applicationIddalambuild.gradleaplikasi contoh agar mencerminkan ID Aplikasi aplikasi Anda di Konsol Play. - Build aplikasi contoh.
Catatan: Tindakan ini akan berhasil mem-build aplikasi untuk pengujian lokal. Namun, menjalankan aplikasi tidak mengambil produk dan harga karena langganan yang diperlukan belum dibuat di Konsol Play. Bagian berikutnya akan membahas cara membuat langganan di Konsol Developer.
3. Membuat langganan di Konsol Play
Sistem langganan Google Play memberi Anda fleksibilitas dalam cara membuat, mengelola, dan menjual langganan. Di Konsol Play, Anda dapat mengonfigurasi langganan dengan beberapa paket dasar, yang masing-masing berisi beberapa penawaran. Penawaran langganan dapat memiliki berbagai model harga dan opsi kelayakan. Untuk codelab ini, Anda akan membuat tiga langganan: Premium Plan, Basic Plan, dan Lite Plan, yang menyimulasikan penawaran langganan umum pada berbagai titik harga. Setiap langganan akan memiliki satu paket dasar berulang bulanan.
Buat langganan baru
Untuk membuat langganan baru
- Buka Konsol Play, lalu buka halaman Langganan (Monetisasi dengan Play > Produk > Langganan)
- Klik Buat langganan.
- Masukkan detail langganan Anda:
- ProductID : Masukkan ID produk yang unik. Masukkan
premium_plan. - Nama : Masukkan nama singkat untuk langganan. Contoh:
Premium Plan.
- ProductID : Masukkan ID produk yang unik. Masukkan
- Klik Buat.
Buat Paket dasar
- Buka Konsol Play, lalu buka halaman Langganan (Monetisasi dengan Play > Produk > Langganan)
- Di samping langganan yang paket dasarnya ingin Anda buat, klik panah kanan untuk melihat detail langganan.
- Klik Tambahkan paket dasar.
- Masukkan ID paket dasar. Contoh
monthly-auto-renewing. - Pilih jenis sebagai Perpanjangan otomatis.
- Untuk paket dasar Perpanjangan otomatis, tetapkan hal berikut:
- Periode penagihan: Bulanan.
- Masa tenggang: 7 hari.
- Perubahan penawaran dan paket penagihan: Penagihan pada tanggal penagihan.
- Berlangganan kembali: Izinkan.
- Di bagian Harga dan ketersediaan, klik Tetapkan Harga untuk menetapkan harga paket dasar.
- Pilih semua negara dan wilayah, lalu klik Tetapkan harga.
- Tetapkan harga sebagai $10 untuk paket dasar ini, lalu klik Perbarui.
- Setelah harga untuk paket dasar ditetapkan, klik Simpan di kanan bawah, lalu klik Aktifkan.
Membuat langganan untuk aplikasi contoh
Untuk tujuan codelab ini, buat dua langganan tambahan dengan konfigurasi berikut:
- Paket Dasar
- ID Produk: basic_plan
- Nama: Paket Dasar
- ID Paket Dasar: monthly-auto-renewing
- Harga: $5
- Paket Lite
- ID Produk: lite_plan
- Nama: Lite Plan
- ID Paket Dasar: monthly-auto-renewing
- Harga: $3
Aplikasi contoh dikonfigurasi untuk menggunakan ID produk dan ID paket dasar ini. Anda dapat membuat langganan yang berbeda dengan konfigurasi yang berbeda. Dalam hal ini, Anda harus mengubah aplikasi contoh untuk menggunakan ID produk yang telah dibuat.
Video pembuatan langganan
Video berikut menunjukkan langkah-langkah yang dijelaskan sebelumnya untuk membuat Langganan di Konsol Developer Play.
4. Penggantian Langganan
Developer yang terintegrasi dengan PBL dapat memberi pelanggan lama berbagai opsi untuk mengubah paket langganan agar mereka dapat memenuhi kebutuhan dengan lebih baik:
- Jika Anda menjual beberapa tingkat langganan, seperti langganan dasar dan premium, Anda dapat mengizinkan pengguna untuk beralih tingkat dengan membeli paket dasar atau penawaran langganan yang berbeda.
- Anda dapat mengizinkan pengguna mengubah periode penagihan saat ini, seperti beralih dari paket bulanan ke tahunan.
- Anda juga dapat mengizinkan pengguna beralih antar-paket perpanjangan otomatis dan prabayar.
Saat pengguna memutuskan untuk mengupgrade, mendowngrade, atau mengubah langganan mereka, Anda menentukan mode penggantian yang menentukan cara penerapan nilai prorata dari periode penagihan saat ini, dan kapan perubahan hak terjadi untuk pengguna.
Play Billing Library menyediakan beberapa opsi ReplacementMode untuk mengontrol perilaku ini.
Mode penggantian yang tersedia
WITH_TIME_PRORATION: Item langganan langsung diupgrade atau didowngrade. Semua sisa waktu disesuaikan berdasarkan perbedaan harga, dan dikreditkan ke langganan yang baru dengan memperbarui tanggal penagihan berikutnya. Ini adalah perilaku default.CHARGE_PRORATED_PRICE: Item langganan langsung diupgrade, dan siklus penagihan tetap sama. Perbedaan harga untuk periode yang tersisa akan ditagihkan kepada pengguna.CHARGE_FULL_PRICE: Item langganan langsung diupgrade atau didowngrade, dan pengguna akan langsung dikenai biaya penuh untuk hak baru ini. Nilai yang tersisa dari langganan sebelumnya akan dipindahkan ke hak yang sama, atau diproporsionalkan sesuai dengan waktu pada saat pelanggan beralih ke hak yang berbeda.WITHOUT_PRORATION: Item langganan langsung diupgrade atau didowngrade, dan harga baru akan dikenakan saat langganan diperpanjang. Siklus penagihan tetap sama.DEFERRED: Item langganan diupgrade atau didowngrade hanya saat langganan diperpanjang.
5. WITH_TIME_PRORATION
Dalam mode penggantian ini, item langganan langsung diupgrade atau didowngrade. Semua sisa waktu disesuaikan berdasarkan perbedaan harga, dan dikreditkan ke langganan yang baru dengan memajukan tanggal penagihan berikutnya. Ini merupakan perilaku default.
Contoh skenario
Pengguna beralih dari paket Basic ($4,99 per bulan) ke paket Premium ($9,99 per bulan) pada 15 April, yaitu di tengah siklus penagihan bulanan.
Dalam skenario ini:
- Pengguna akan langsung mendapatkan akses ke paket Premium.
- Google Play otomatis menghitung periode prorata. Misalnya, jika Play menghitung bahwa 15 hari yang tersisa dari paket Basic setara dengan 7 hari paket Premium, tanggal penagihan berikutnya akan dimajukan ke 21 April.
- Pengguna tidak perlu melakukan pembayaran langsung.
Cuplikan kode
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Upgrade dengan WITH_TIME_PRORATION
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Premium.
Hak pengguna akan langsung diupgrade ke paket Premium. Jumlah yang harus segera dibayar oleh pengguna adalah $0,00. Nilai yang tersisa dari paket Basic dihitung secara prorata menjadi waktu untuk paket Premium, yang memajukan tanggal perpanjangan berikutnya. Pengguna akan ditagih jumlah perpanjangan sebesar $9,99 pada tanggal penagihan yang baru disesuaikan.
Turunkan versi dengan WITH_TIME_PRORATION
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.WITH_TIME_PRORATION. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Lite.
Hak pengguna akan langsung didowngrade ke paket Lite. Jumlah yang harus dibayar segera adalah $0,00. Nilai yang tersisa dari paket Basic dihitung secara prorata menjadi waktu untuk paket Lite, yang memperpanjang tanggal perpanjangan berikutnya secara signifikan. Pengguna akan ditagih jumlah perpanjangan sebesar $2,99 pada tanggal penagihan yang baru disesuaikan.
Kesimpulan
Di bagian ini, Anda telah mempelajari cara WITH_TIME_PRORATION mengubah hak pengguna tanpa biaya langsung dengan menyesuaikan waktu hingga perpanjangan berikutnya berdasarkan perbedaan harga. Strategi ini adalah strategi default yang efektif untuk meng-upgrade atau mendowngrade pengguna.
6. CHARGE_PRORATED_PRICE
Dalam mode penggantian ini, item langganan langsung diupgrade, dan siklus penagihan tetap sama. Perbedaan harga untuk periode yang tersisa akan ditagihkan kepada pengguna.
Catatan: Opsi ini hanya tersedia untuk upgrade item langganan, dengan harga per unit waktu yang dinaikkan.
Contoh skenario
Pengguna yang menggunakan paket Basic ($4,99 per bulan) memutuskan untuk mengupgrade ke paket Premium ($9,99 per bulan) pada 20 April dengan sisa sekitar 10 hari dalam siklus penagihan bulanan mereka.
Dalam skenario ini:
- Pengguna akan langsung mendapatkan akses ke paket Premium.
- Pengguna akan langsung ditagih selisih prorata untuk 10 hari yang tersisa dalam siklus penagihan saat ini. Jumlah ini kira-kira setara dengan Rp45.000, yang mewakili nilai paket Premium selama 10 hari.
- Tanggal penagihan untuk pengguna tidak berubah.
Cuplikan kode
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Upgrade dengan CHARGE_PRORATED_PRICE
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Premium.
Pengguna akan langsung diupgrade ke paket Premium, dengan tetap mempertahankan tanggal perpanjangan awal. Jumlah yang harus segera dibayarkan adalah selisih prorata antara harga paket Premium dan Dasar untuk sisa hari dalam siklus saat ini. Pada tanggal perpanjangan, pengguna akan ditagih jumlah perpanjangan Premium penuh sebesar $9,99.
Turunkan versi dengan CHARGE_PRORATED_PRICE
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.CHARGE_PRORATED_PRICE. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Lite.
Mode penggantian ini akan menghasilkan error selama downgrade karena hanya tersedia untuk upgrade item langganan dengan harga per unit waktu yang dinaikkan. Alur penagihan akan gagal dan menampilkan error kepada pengguna yang menyatakan bahwa mode penghitungan prorata tidak didukung untuk downgrade.
Kesimpulan
Bagian ini menjelaskan cara CHARGE_PRORATED_PRICE memungkinkan upgrade langsung dengan menagih pengguna selisih harga yang tepat untuk periode penagihan yang tersisa sekaligus mempertahankan siklus penagihan. Hal ini berguna jika pengguna ingin mengupgrade ke tingkatan yang lebih mahal, tanpa mengubah tanggal penagihan.
7. CHARGE_FULL_PRICE
Dalam mode penggantian ini, item langganan langsung diupgrade atau didowngrade, dan pengguna akan langsung dikenai biaya penuh untuk hak baru. Nilai yang tersisa dari langganan sebelumnya akan dipindahkan ke hak yang sama, atau diproporsionalkan sesuai dengan waktu pada saat pelanggan beralih ke hak yang berbeda.
Contoh skenario
Pengguna menggunakan paket Basic ($4,99 per bulan mulai 1 April). Pada 20 April, pengguna ingin beralih ke paket Premium ($9,99 per bulan).
Dalam skenario ini:
- Pengguna akan langsung ditagih harga penuh paket Premium ($9,99).
- Sisa nilai dari paket Basic (misalnya, senilai 10 hari) dikonversi menjadi waktu yang setara untuk paket Premium. Dalam contoh ini, 10 hari Dasar setara dengan 5 hari Premium.
- Tanggal perpanjangan berikutnya pengguna disesuaikan untuk menyertakan waktu yang diprorata ini. Jadi, tanggal perpanjangan menjadi 25 Mei (20 April + 1 bulan + 5 hari).
- Perpanjangan selanjutnya akan dilakukan setiap bulan mulai 25 Mei.
Cuplikan kode
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Upgrade dengan CHARGE_FULL_PRICE
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Premium.
Pengguna akan langsung diupgrade ke paket Premium. Jumlah yang harus dibayar segera adalah harga penuh Paket Premium - $9,99. Setiap nilai yang tersisa dari paket Dasar akan dikonversi menjadi waktu pada paket Premium baru, sehingga sedikit memperpanjang tanggal perpanjangan pertama. Setelah itu, jumlah perpanjangan akan menjadi $9,99 per siklus.
Turunkan versi dengan CHARGE_FULL_PRICE
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.CHARGE_FULL_PRICE. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Lite.
Pengguna akan langsung didowngrade ke paket Lite, dan siklus penagihan baru akan dimulai. Jumlah yang harus dibayar segera adalah harga target penuh sebesar $2,99. Bagian yang tidak digunakan dari paket Basic akan dihitung secara prorata menjadi waktu untuk paket Lite yang baru, sehingga memperpanjang tanggal perpanjangan pertama. Setelah itu, jumlah perpanjangan akan menjadi $2,99 per siklus.
Kesimpulan
Di bagian ini, kita membahas cara CHARGE_FULL_PRICE menagih pengguna sepenuhnya di luar biaya yang ditanggung pada hari peralihan, dengan segera memulai siklus penagihan baru. Sisa saldo dari paket sebelumnya akan diterapkan secara linear ke tanggal perpanjangan berikutnya.
8. WITHOUT_PRORATION
Dalam mode penggantian ini, item langganan langsung diupgrade atau didowngrade, dan harga baru akan dikenakan saat langganan diperpanjang.
Contoh skenario
Pengguna menggunakan paket Basic ($4,99 per bulan mulai 1 April). Pada 20 April, pengguna ingin beralih ke paket Premium ($9,99 per bulan).
Dalam skenario ini:
- Pengguna akan langsung mendapatkan akses ke paket Premium.
- Pengguna tidak perlu membayar harga yang lebih tinggi, yaitu $9,99, hingga tanggal perpanjangan langganan berikutnya (1 Mei).
Cuplikan kode
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Upgrade dengan WITHOUT_PRORATION
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Premium.
Pengguna akan langsung diupgrade ke paket Premium dengan tetap mempertahankan tanggal perpanjangan yang ada. Jumlah yang harus dibayar segera adalah $0,00. Pengguna memiliki akses ke paket Premium selama sisa waktu dalam siklus yang diberikan, sebelum beralih ke jumlah perpanjangan baru sebesar $9,99 pada tanggal penagihan berikutnya.
Downgrade dengan WITHOUT_PRORATION
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.WITHOUT_PRORATION. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Lite.
Pengguna akan langsung didowngrade ke paket Lite dan kehilangan fitur Basic yang telah dibayar. Jumlah yang harus dibayar segera adalah $0,00. Siklus penagihan akan tetap sama, dan pengguna akan membayar tarif baru yang lebih rendah sebesar $2, 99 pada perpanjangan terjadwal berikutnya.
Kesimpulan
Bagian ini menunjukkan cara WITHOUT_PRORATION langsung menukar hak pengguna tanpa biaya checkout sekaligus membiarkan siklus penagihan tidak berubah.
9. DEFERRED
Dalam mode penggantian ini, item langganan diupgrade atau didowngrade hanya saat langganan diperpanjang, tetapi pembelian baru akan segera diberikan. Item yang ada ditetapkan sebagai tidak dapat diperpanjang dan akan berakhir pada akhir siklus penagihan saat ini, sedangkan hak yang baru diminta akan dimulai tepat setelahnya.
Contoh skenario
Pengguna menggunakan paket Basic ($4,99 per bulan mulai 1 April). Pada 20 April, pengguna ingin beralih ke paket Premium ($9,99 per bulan).
Dalam skenario ini:
- Pengguna tidak akan langsung dikenai biaya.
- Pengguna akan terus menerima fitur Basic hingga akhir siklus penagihan saat ini (30 April).
- Paket langganan otomatis diupgrade ke Premium pada tanggal perpanjangan berikutnya (1 Mei).
Cuplikan kode
// ProductDetails for the plan to be switched to
ProductDetails productDetails = ...;
// The specific offer token for the toBeSwitched plan's base plan
String offerToken = "...";
// The purchase token of the user's current subscription
String oldPurchaseToken = "...";
// The productId for the user's current subscription
String oldProductId = "...";
// The replacementMode to replace the user's subscription
int replacementMode = SubscriptionProductReplacementParams.ReplacementMode.DEFERRED;
SubscriptionProductReplacementParams subscriptionProductReplacementParams =
SubscriptionProductReplacementParams.newBuilder()
.setOldProductId(oldProductId)
.setReplacementMode(replacementMode)
.build();
ProductDetailsParams productDetailsParams =
ProductDetailsParams.newBuilder()
.setProductDetails(productDetails)
.setSubscriptionProductReplacementParams(subscriptionProductReplacementParams)
.setOfferToken(offerToken)
.build();
List<ProductDetailsParams> productDetailsParamsList = ImmutableList.of(productDetailsParams);
BillingFlowParams billingFlowParams =
BillingFlowParams.newBuilder()
.setProductDetailsParamsList(productDetailsParamsList)
.setSubscriptionUpdateParams(
SubscriptionUpdateParams.newBuilder().setOldPurchaseToken(oldPurchaseToken).build())
.build();
billingClient.launchBillingFlow(activity, billingFlowParams);
Upgrade dengan DEFERRED
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.DEFERRED. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Premium.
Pengguna akan tetap menggunakan paket Basic hingga akhir siklus penagihan saat ini. Jumlah yang harus dibayar segera adalah $0,00. Pada tanggal perpanjangan, haknya akan diupgrade ke paket Premium dan dia akan ditagih jumlah perpanjangan baru sebesar $9,99.
Downgrade dengan DEFERRED
Untuk menyimulasikan skenario ini:
- Di
MainActivityaplikasi contoh, perbaruireplacementModedalam cuplikan kode menjadiSubscriptionProductReplacementParams.ReplacementMode.DEFERRED. - Bangun ulang dan luncurkan aplikasi.
- Batalkan langganan yang ada (jika ada) dari Google Play Store dan biarkan langganan tersebut berakhir.
- Beli paket Basic.
- Beralih ke paket Lite.
Pengguna akan tetap menggunakan paket Basic hingga akhir siklus penagihan saat ini. Jumlah yang harus dibayar segera adalah $0,00. Pada tanggal perpanjangan, haknya akan diupgrade ke paket Lite dan dia akan ditagih jumlah perpanjangan baru sebesar $2,99.
Kesimpulan
Bagian ini menjelaskan cara mode penggantian DEFERRED menunda upgrade atau downgrade hingga akhir waktu berbayar pengguna aktif. Hal ini menjadikannya sangat ideal untuk downgrade guna mencegah hilangnya fitur yang sudah dibeli.
10. Pemrosesan Backend dan Sisi Klien
Setelah pengguna memicu penggantian langganan yang berhasil, pastikan aplikasi dan backend Anda menangani perubahan dengan benar untuk menghindari masalah seperti gangguan layanan atau penagihan ganda.
Contoh Skenario
- Pengguna memiliki paket bulanan Basic (product_id
basic_plandan purchase_tokenbasic_purchase_token_123). - Pengguna beralih ke paket Premium menggunakan mode penggantian langsung (salah satu dari
WITHOUT_PRORATION,WITH_TIME_PRORATION,CHARGE_PRORATED_PRICE,CHARGE_FULL_PRICE) - Setelah peralihan langganan berhasil, Google akan memperlakukannya sebagai langganan BARU dan membuat token pembelian baru yang berbeda untuk Paket Premium (product_id
premium_plandan purchase_tokenpremium_purchase_token_123).
Pemrosesan sisi klien
onPurchasesUpdated
Saat pembelian pengganti selesai, PurchasesUpdatedListener dipicu. Meskipun ini adalah pengalihan, Google Play memperlakukan paket Premium sebagai pembelian yang benar-benar baru.
Aplikasi akan menerima objek Purchase yang berisi premium_purchase_token_123 token pembelian dan product_id premium_plan. Anda harus memperlakukannya persis seperti pelanggan baru: verifikasi token dan bersiap untuk memberikan akses
@Override
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) {
for (Purchase purchase : purchases) {
// purchase.getPurchaseToken() = premium_purchase_token_123
// purchase.getProducts() will contain premium_plan
// Verify the purchase and grant entitlement
handleNewPurchase(purchase);
}
}
}
queryPurchasesAsync
queryPurchasesAsync hanya menampilkan langganan aktif yang dibeli dari aplikasi Anda. Anda harus mengandalkan metode ini untuk menentukan hak yang akan ditampilkan kepada pengguna. Untuk penggantian langsung, queryPurchasesAsync() akan berhenti menampilkan token pembelian BASIC lama dan sekarang hanya akan menampilkan token pembelian PREMIUM baru.
Setiap kali aplikasi Anda dilanjutkan atau pembelian selesai, panggil metode ini. Jika token Premium ada, segera berikan fitur Premium dan hapus fitur Dasar.
Pemrosesan backend (RTDN)
Saat penggantian terjadi, Google Play akan mengirimkan Notifikasi Developer Real Time (RTDN) ke topik pub/sub yang Anda konfigurasi.
- Dalam kasus penggantian langsung, Google mengirimkan RTDN
SUBSCRIPTION_PURCHASEDdengan token pembelian baru.Contoh Payload RTDN{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":4, // SUBSCRIPTION_PURCHASED "purchaseToken":"premium_purchase_token_123" //purchase token for the new subscription } } - Saat server Anda menerima token pembelian baru dari RTDN, panggil API
purchases.subscriptionsV2dengan token pembelian baru untuk mengambil detail pembelian. Respons API berisi kolomlinkedPurchaseTokenyang digunakan untuk menentukan apakah token pembelian merujuk ke pembelian langganan baru atau penggantian langganan. - Dalam kasus penggantian langganan,
linkedPurchaseTokenmengacu pada token pembelian langganan lama. Dalam skenario ini, responsnya adalahbasic_purchase_token_123.Contoh responsGET purchases.subscriptionsV2curl \ 'https://androidpublisher.googleapis.com/androidpublisher/v3/applications/<application_id>/purchases/subscriptionsv2/tokens/premium_purchase_token_123' \ --header 'Authorization: Bearer [YOUR_ACCESS_TOKEN]' \ --header 'Accept: application/json' { "kind": "androidpublisher#subscriptionPurchaseV2", "startTime": "...", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>", "linkedPurchaseToken": "basic_purchase_token_123", // The purchase token of the subscription that was replaced (Basic Plan in this case) "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // productID of the new subscription (Premium Plan in this case) "expiryTime": "....", "autoRenewingPlan": {...}, "offerDetails": { "basePlanId": "monthly-auto-renewing" // base plan ID of the new subscription }, "itemReplacement": { // Details about the subscription replacement "productId": "subscription_basic", // productID of the old subscription (Basic Plan in this case) "replacementMode": "CHARGE_PRORATED_PRICE", // Replacement strategy used for this subscription change "basePlanId": "monthly-auto-renewing" // base plan ID of the old subscription }, "offerPhase": {...} } ], "etag": "<etag_value>" } - Anda harus mengonfirmasi pembelian Premium baru. Hal ini dapat dilakukan di dalam aplikasi atau di backend Anda. Jika pembelian tidak dikonfirmasi dalam waktu 3 hari, hak akan dikembalikan dananya dan dicabut. Untuk mengetahui detail selengkapnya tentang pemrosesan dan konfirmasi pembelian, lihat dokumentasi developer.
Kesimpulan
Bagian ini membahas langkah-langkah untuk menangani penggantian langganan langsung di klien dan backend Anda. Anda telah mempelajari bahwa Google Play memperlakukan paket baru sebagai pembelian baru, dengan mengeluarkan token pembelian baru. Di klien, Anda harus memproses pembelian baru ini menggunakan PurchasesUpdatedListener dan memperbarui hak berdasarkan respons dari queryPurchasesAsync. Di backend, Anda harus memproses RTDN SUBSCRIPTION_PURCHASED untuk token baru, menggunakan API purchases.subscriptionsv2 untuk mengidentifikasi linkedPurchaseToken langganan lama, dan segera mencabut akses yang terkait dengan token lama sambil memberikan hak baru. Ingatlah untuk selalu mengonfirmasi pembelian yang baru.
11. Memproses Penggantian yang DITANGGUHKAN
Tidak seperti mode penggantian langsung, ReplacementMode.DEFERRED menunda perubahan langganan dan pembaruan hak hingga akhir siklus penagihan saat ini. Penanganan penggantian yang ditangguhkan memerlukan logika khusus untuk memastikan pengguna menerima hak yang benar pada waktu yang tepat.
Contoh Skenario
- Pengguna memiliki paket bulanan Basic (product_id
basic_plandan purchase_tokenbasic_purchase_token_123) yang diperpanjang pada 15 April. - Pada 1 April, pengguna memutuskan untuk beralih ke paket Premium menggunakan
ReplacementMode.DEFERRED. - Google akan langsung membuat token pembelian BARU untuk paket Premium (product_id
premium_plandan purchase_tokenpremium_purchase_123), tetapi jumlah yang akan ditagih dari pengguna dan haknya dijadwalkan pada 15 April.
Memproses penggantian yang ditangguhkan
1. Segera setelah alur pembeliannya berhasil (aplikasi)
PurchasesUpdatedListenerdipanggil setelah alur pembelian selesai. Aplikasi akan menerima objekPurchaseyang berisi token pembelian barupremium_purchase_token_123, tetapi product_id akan tetap merujuk kebasic_planlama karena pengguna hanya memiliki hak atas paket Basic. Anda harus memperlakukannya persis seperti pembelian baru dan mengonfirmasi token.@Override public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) { if (billingResult.getResponseCode() == BillingResponseCode.OK && purchases != null) { for (Purchase purchase : purchases) { // purchase.getPurchaseToken() = premium_purchase_token_123 // purchase.getProducts() will contain basic_plan // Verify and acknowledge the purchase handleNewPurchase(purchase); } } }queryPurchasesAsynclangsung mengembalikan pembelian dengan token pembelian baru (premium_purchase_token_123), dan hak asli (basic_plan) yang terkait dengannya. Anda dapat mengandalkan hal ini untuk terus memberikan hak paket Basic kepada pengguna.
2. Tepat setelah alur pembeliannya berhasil (backend)
- RTDN SUBSCRIPTION_PURCHASED dikirim segera setelah alur pembelian untuk token pembelian yang baru (
premium_purchase_token_123).Contoh Payload RTDN{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":4, // SUBSCRIPTION_PURCHASED "purchaseToken":"premium_purchase_token_123" //purchase token for the new subscription } } - Panggil
GET purchases.subscriptionsv2dengan token pembelian baru untuk mengambil detail pembelian. Respons berisi 2 item baris.- Satu item baris mewakili langganan lama (paket dasar) dan memiliki
expiryTimedi masa mendatang. Langganan lama tidak akan diperpanjang dan memilikideferredItemReplacementyang berisi langganan baru (paket premium). Hal ini menunjukkan penggantian tertunda hak lama setelah masa berlakunya berakhir. - Satu mewakili langganan yang baru dibeli. Tidak ada nilai yang ditetapkan untuk ‘expiryTime'
{ "kind": "androidpublisher#subscriptionPurchaseV2", "startTime": "2026-05-07T15:50:11.383Z", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>", "linkedPurchaseToken": "basic_purchase_token_123", "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // Premium Plan has no expiry time "autoRenewingPlan": {...}, "offerDetails": {...}, "itemReplacement": {. // Subscription replacement details "productId": "basic_plan", "replacementMode": "DEFERRED", "basePlanId": "monthly-auto-renewing" }, "offerPhase": {} }, { "productId": "basic_plan", // Subscription to be replaced "expiryTime": "2026-05-07T15:54:34.768Z", // Expiry time in the future "autoRenewingPlan": {}, "offerDetails": {...}, "deferredItemReplacement": { // identifier indicating this subscription will be replaced upon renewal "productId": "subscription_premium" }, "latestSuccessfulOrderId": "GPA.<order_id>", "itemReplacement": {...}, } ], "etag": "<etag>" } - Satu item baris mewakili langganan lama (paket dasar) dan memiliki
- Anda harus mengonfirmasi token pembelian baru. Hal ini dapat dilakukan di dalam aplikasi atau di backend Anda. Untuk mengetahui detail selengkapnya tentang pemrosesan dan konfirmasi pembelian, lihat dokumentasi developer.
- RTDN SUBSCRIPTION_EXPIRED dikirim untuk token pembelian lama (
basic_purchase_token_123).Contoh Payload RTDN{ "version":"1.0", "packageName":"com.google.play.billing.samples.subscriptions", "eventTimeMillis":"...", "subscriptionNotification": { "version":"1.0", "notificationType":13, // SUBSCRIPTION_EXPIRED "purchaseToken":"basic_purchase_token_123" //purchase token for the old subscription } } - Saat memanggil API
GET purchases.subscriptionsv2dengan token pembelian lama, API tersebut akan ditampilkan sebagai sudah tidak berlaku (SUBSCRIPTION_STATE_EXPIRED). Hak untuk paket lama ditransfer ke pembelian baru untuk sisa waktu yang ada.
3. Pada tanggal penggantian - perpanjangan pertama setelah alur pembelian (aplikasi)
queryPurchasesAsyncmenampilkan pembelian dengan token pembelian baru (premium_purchase_token_123), dan langganan baru yang terkait dengannya (premium_plan).- Pembelian yang baru seharusnya sudah diproses saat alur pembelian berhasil, Anda tidak perlu melakukan tindakan khusus apa pun selain memastikan akses ke langganan yang tepat diberikan kepada pengguna.
4. Pada tanggal penggantian - perpanjangan pertama setelah alur pembelian (backend)
- Dengan
ReplacementMode.DEFERRED, perpanjangan pertama akan mengikuti perilaku standar perpanjangan lainnya yang memproses RTDNSUBSCRIPTION_RENEWED. Anda tidak perlu memiliki logika khusus untuk penggantian saat hal ini terjadi. - Panggil
GET purchases.subscriptionsv2dengan token pembelian baru untuk mengambil detail pembelian. Respons berisi 2 item baris.- Satu item baris mewakili langganan lama (paket dasar) dan memiliki
expiryTimedi masa lalu. Langganan lama tidak akan lagi memiliki nilai yang ditetapkan untuk kolomdeferredItemReplacement. - Satu lagi mewakili langganan baru dengan
expiryTimepada masa mendatang dan kolomautoRenewEnabledditetapkan ketrue.
{ "kind": "androidpublisher#subscriptionPurchaseV2", "subscriptionState": "SUBSCRIPTION_STATE_ACTIVE", "latestOrderId": "GPA.<order_id>..0", "linkedPurchaseToken": "basic_purchase_token_123", // purchase token of the old subscription "acknowledgementState": "ACKNOWLEDGEMENT_STATE_ACKNOWLEDGED", "lineItems": [ { "productId": "premium_plan", // New subscription "expiryTime": "2026-05-07T16:00:09.437Z", // Expiry time set in the future "autoRenewingPlan": { "autoRenewEnabled": true, // Auto Renewing Flag set to True "recurringPrice": {...} }, "offerDetails": {...}, "latestSuccessfulOrderId": "GPA.<order_id>..0", "itemReplacement": {. // Details of the subscription replacement "productId": "basic_plan", "replacementMode": "DEFERRED", "basePlanId": "monthly-auto-renewing" }, "offerPhase": {...} }, { "productId": "basic_plan", // Old subscription, Does not contains the deferredItemReplacement field "expiryTime": "2026-05-07T15:54:34.768Z", // Expiry time set in the past "autoRenewingPlan": {}, "offerDetails": {...}, "latestSuccessfulOrderId": "GPA.<order_id>..0", "itemReplacement": {...}, } ], "etag": "<etag>" } - Satu item baris mewakili langganan lama (paket dasar) dan memiliki
Kesimpulan
Bagian ini menjelaskan penanganan unik yang diperlukan untuk ReplacementMode.DEFERRED. Anda telah mempelajari bahwa tidak seperti mode langsung, perubahan hak hanya terjadi di akhir siklus penagihan saat ini. Bagian ini membahas langkah-langkah yang diperlukan agar aplikasi dan backend Anda dapat memproses pembelian awal dengan benar, mengonfirmasi token baru, dan mengelola peralihan hak saat langganan lama berakhir dan langganan baru menjadi aktif.
12. Playground Penggantian Langganan
Fitur Replacement Playground di aplikasi contoh memungkinkan Anda menguji upgrade dan downgrade langganan untuk produk langganan yang dikonfigurasi di akun Konsol Google Play Anda. Bagian ini menjelaskan cara menggunakan fitur Replacement Playground.
Penyiapan
Untuk menggunakan fitur Playground Penggantian, pastikan hal berikut:
packageIddi filebuild.gradleAnda cocok dengan aplikasi yang dikonfigurasi di Konsol Google Play.- Akun pengguna penguji Anda terdaftar sebagai penguji lisensi di Konsol Google Play. Untuk mempelajari lebih lanjut pengujian lisensi, lihat Menguji penerapan penagihan aplikasi Anda.
Playground Penggantian Langganan
Aplikasi contoh menyertakan tab Replacement Playground, yang memungkinkan Anda menyimulasikan perubahan langganan. Anda dapat membuat kueri langganan yang ditentukan di Konsol Play dan menguji peralihan di antara langganan tersebut menggunakan berbagai mode penggantian. Playground ini membantu Anda memahami pengaruh berbagai mode terhadap siklus penagihan dan hak untuk langganan Anda, sehingga Anda dapat menentukan opsi mana yang paling sesuai dengan kebutuhan bisnis Anda.
Untuk menyimulasikan penggantian menggunakan playground, ikuti langkah-langkah berikut:
- Buka tab Playground.
- Jika Anda memiliki langganan aktif: Langganan tersebut akan ditandai. Ini adalah langganan yang akan diganti.

- Jika Anda tidak memiliki langganan aktif: Anda harus membelinya terlebih dahulu.
- Playground mencantumkan paket Basic, Premium, dan Lite yang dibuat untuk codelab ini secara default.
- Untuk menguji dengan paket lain yang dikonfigurasi di Konsol Developer Play, klik Tambahkan Paket Kustom, telusuri menurut
productIddanbasePlanId. - Beli langganan yang dipilih.
- Langganan aktif yang baru dibeli pengguna kini akan ditampilkan.

- Pilih langganan target yang ingin digunakan pengguna untuk beralih.
- Pilih Mode Penggantian untuk transisi.

- Klik tombol Uji Penggantian untuk menyimulasikan penggantian langganan.
- Anda akan melihat sheet bawah penagihan Google Play dengan detail penggantian langganan yang dihitung (seperti biaya langsung dan penyesuaian siklus penagihan).

- Selesaikan transaksi.
- Buka halaman Kelola Langganan di aplikasi Play Store untuk melihat perubahan langganan aktif beserta detail tentang tanggal dan harga perpanjangan yang diperbarui.

13. Langkah berikutnya
- Pelajari cara memaksimalkan integrasi layanan penagihan Play Anda.
- Jangan lupa untuk mengikuti praktik terbaik untuk memverifikasi dan memproses pembelian di backend aman Anda setelah pengguna mulai membeli produk ini.
Dokumen referensi
14. Selamat
Selamat! Anda telah berhasil menerapkan penggantian langganan dengan berbagai mode prorata dan mengonfigurasi penanganan backend untuk transisi paket.
Yang telah Anda pelajari
- Cara mengonfigurasi
SubscriptionProductReplacementParamsdengan mode penggantian tertentu. - Perbedaan antara upgrade langsung dan downgrade yang ditangguhkan.
- Cara menghentikan penggunaan token langganan lama menggunakan
linkedPurchaseTokenmenggunakan RTDN.
Survei
Masukan Anda tentang codelab ini sangat kami hargai. Luangkan waktu beberapa menit untuk mengisi survei kami.