Semua artikel
Deep diveWaktu baca 8 menit

Deteksi refund StoreKit 2 bermuara pada satu property di transaction, dan itu adalah revocationDate

Ketika Apple memberi refund kepada salah satu pelanggan Anda, refund itu sudah ada di dalam app Anda pada revocationDate transaction, sebelum tugas server Anda berjalan. Berikut tempat deteksi refund StoreKit 2 muncul di perangkat, apa yang diberitahukan revocationDate dan revocationReason kepada Anda, dan mengapa klien untuk kecepatan dan server untuk kebenaran.

Sebuah ponsel pintar bercahaya di meja developer yang gelap di samping jam mekanik, menggambarkan deteksi refund StoreKit 2 yang muncul di dalam sebuah app

Poin utama

  • Di StoreKit 2 sebuah purchase yang di-refund membawa revocationDate non-nil pada Transaction-nya, sehingga app Anda dapat mendeteksi refund sendiri, tanpa memanggil server Anda.
  • revocationDate diatur saat App Store me-refund sebuah transaction atau saat pelanggan kehilangannya melalui Family Sharing, jadi tanggal non-nil tidak selalu berarti refund.
  • revocationReason memberi tahu Anda alasannya: developerIssue berarti pelanggan menyebut ada masalah di app Anda, dan other mencakup setiap alasan refund lainnya yang tersisa.
  • Transaction.currentEntitlements sudah mengecualikan purchase yang di-refund dan dicabut, jadi gerbang sisi klien paling bersih untuk akses cukup apakah sebuah product masih muncul di sana.
  • Transaction.updates hanya mengantarkan refund yang terjadi saat app Anda tertutup jika Anda mulai mendengarkan saat peluncuran, jadi Task yang hilang berarti refund yang terlewat.
  • Deteksi sisi klien hanya berjalan saat app terbuka, itulah mengapa REFUND dari App Store Server Notifications V2 tetap menjadi sinyal otoritatif yang menghentikan Anda membayar untuk melayani pengguna yang di-refund.
  • Sebuah refund dapat dibalik, dan ketika itu terjadi, field revocation dihapus dari transaction dan Anda diharapkan memulihkan akses yang Anda putus.

Sebagian besar app mengetahui refund Apple dari server mereka, melalui App Store Server Notification, dan tidak pernah menyadari bahwa refund yang sama sudah ada di dalam app. Ia ada pada transaction, dalam sebuah property bernama revocationDate, dan membacanya memungkinkan app Anda memutus akses pelanggan yang di-refund saat berikutnya mereka membukanya, alih-alih menunggu tugas backend. Deteksi refund StoreKit 2 adalah sinyal sisi klien yang dilewati sebagian besar tim. Berikut persis di mana sebuah refund muncul di perangkat, apa yang diberitahukannya, apa yang tidak, dan mengapa ia seharusnya berada di samping notifikasi server Anda, bukan menggantikannya.

Di mana sebuah refund muncul di dalam StoreKit 2

StoreKit 2 menyerahkan transaction kepada Anda sebagai nilai bertanda tangan, dan sebuah refund tidak menghapus transaction. Ia menandainya. Dua property pada Transaction membawa tanda itu, dan keduanya tetap nil selama seluruh masa hidup sebuah purchase yang sehat. Ketika salah satunya menjadi non-nil, App Store telah mengambil kembali purchase tersebut.

revocationDate adalah field yang berbalik

revocationDate adalah Date opsional. Deskripsi Apple sendiri tepat: itu adalah tanggal App Store me-refund transaction atau mencabutnya dari Family Sharing. Untuk sebuah purchase yang masih baik, nilainya nil. Pada saat sebuah refund diproses, ia menyimpan cap waktu refund tersebut. Satu pemeriksaan itu, apakah revocationDate non-nil, itulah seluruh deteksi refund sisi klien. Segala hal lain adalah nuansa yang ditumpuk di atasnya.

revocationReason memberi tahu Anda mengapa Apple menariknya

revocationReason berada di samping tanggal dan menjelaskan penyebabnya. StoreKit memberinya dua nilai yang penting untuk refund. developerIssue berarti pelanggan memberi tahu Apple bahwa refund itu karena masalah nyata atau yang dirasakan di app Anda. other mencakup setiap alasan yang tersisa. Nilai ketiga, upgradedToBundle, sama sekali bukan refund; ia menandai sebuah transaction yang dicabut App Store karena pelanggan berpindah ke subscription bundle. Baca alasannya sebelum Anda bertindak, karena developerIssue adalah yang layak dihitung: sekumpulan darinya adalah produk Anda sendiri yang memberi tahu di mana ia rusak.

PropertyTypeApa arti nilai non-nil
revocationDateDate?App Store me-refund transaction ini, atau mencabutnya melalui Family Sharing, pada tanggal ini
revocationReason adalah developerIssuereasonPelanggan menyebut masalah nyata atau yang dirasakan di app Anda
revocationReason adalah otherreasonRefund terjadi karena alasan lain yang tidak dirinci Apple
revocationReason adalah upgradedToBundlereasonBukan refund; transaction dicabut karena pelanggan beralih ke subscription bundle

currentEntitlements sudah menjatuhkan sebuah purchase yang di-refund

Anda tidak selalu harus membaca field revocation sendiri. Transaction.currentEntitlements adalah urutan purchase yang masih menjadi hak pelanggan saat ini, dan Apple membangunnya untuk mengesampingkan yang tidak seharusnya Anda hormati. Sebuah product yang telah di-refund atau dicabut App Store tidak muncul di dalamnya. Begitu pula subscription yang kedaluwarsa, atau consumable, yang lenyap saat selesai digunakan.

Itu menjadikan currentEntitlements gerbang paling bersih untuk akses. Tanyakan apa yang dimiliki pelanggan, berikan persis itu, dan sebuah refund menghapus entitlement untuk Anda tanpa satu pun pemeriksaan revocationDate. Field revocation untuk saat Anda menginginkan detailnya, tanggal dan alasannya, untuk mencatat peristiwa atau menanggapinya. Daftar entitlement untuk pertanyaan sederhana apakah lampu tetap menyala.

Deteksi refund StoreKit 2 dalam praktik, dari peluncuran dan saat app berjalan

Ada dua momen app Anda dapat menangkap refund di perangkat, dan keduanya butuh kode berbeda. Satu saat app terbuka dan sebuah refund terjadi langsung atau di perangkat lain. Yang lain saat peluncuran, mengejar semua yang berubah saat Anda tertutup. Lewatkan yang kedua dan deteksi refund StoreKit 2 Anda punya lubang tepat di tempat sebagian besar refund jatuh, karena pelanggan jarang membuka app Anda saat meminta refund.

Mulai mendengarkan saat peluncuran atau Anda melewatkan refund yang terjadi saat tertutup

Transaction.updates adalah urutan async yang memancarkan sebuah transaction setiap kali sistem membuat atau memperbaruinya di luar app Anda atau di perangkat lain, termasuk sebuah refund. Instruksi Apple tegas: mulai sebuah Task yang mengiterasinya begitu app Anda diluncurkan, atau Anda mungkin melewatkan transaction yang hanya diantarkannya sekali saat startup. Sebuah refund yang mendarat semalaman tiba melalui updates saat berikutnya app dibuka, tetapi hanya jika sebuah listener sudah berjalan untuk menerimanya. Tanpa listener, tanpa event, dan refund tetap tak terlihat sampai sesuatu yang lain merekonsiliasinya.

Sebuah purchase di perangkat yang sama tidak datang melalui updates

Satu jebakan menjerat orang yang menguji refund secara manual. Sebuah purchase normal yang dibuat di perangkat yang sama tidak tiba melalui updates; StoreKit mengembalikannya langsung dari hasil panggilan purchase. updates untuk perubahan di luar jalur: refund, persetujuan Ask to Buy, penukaran offer-code, dan purchase yang dibuat di tempat lain. Jadi bangun penanganan refund Anda di sekitar updates dan currentEntitlements, bukan di sekitar alur purchase, karena refund tidak akan pernah kembali melalui jalur yang dilalui penjualan.

Sebuah struk kertas kusut di permukaan gelap dengan cap merah samar ditekan melintasinya, mewakili sebuah transaction yang di-refund yang ditandai StoreKit 2 dengan revocation date

Apa yang tidak dapat dilakukan deteksi sisi klien untuk Anda

Membaca refund di perangkat cepat dan gratis, tetapi ada batasnya, dan berpura-pura tidak ada adalah cara pendapatan bocor. Perangkat hanya tahu apa yang diberitahukan StoreKit, dan StoreKit hanya berbicara saat app Anda berjalan. Pelanggan yang mendapat refund dan tidak pernah membuka app Anda lagi adalah pelanggan yang tidak pernah dilihat pemeriksaan sisi klien Anda.

Sebuah revocationDate tidak selalu berarti refund

Field yang sama berbalik untuk Family Sharing. Ketika seorang pelanggan kehilangan akses ke purchase bersama, karena penyelenggara menghapusnya atau berbagi berakhir, transaction itu juga mendapatkan revocationDate. Jadi tanggal non-nil berarti pelanggan tidak lagi memiliki purchase ini, yang persis apa yang Anda butuhkan untuk kontrol akses, tetapi tidak selalu berarti uang keluar kembali. Jika Anda menghitung refund untuk pendapatan, pisahkan pencabutan Family Sharing dari yang sungguhan sebelum Anda memercayai angkanya.

Sebuah refund dapat dibalik

Sebuah refund tidak selalu final. Apple dapat membalikkannya, dan ketika itu terjadi, field revocation dihapus dari transaction dan purchase valid kembali. Jika Anda memutus akses saat refund, Anda diharapkan memulihkannya saat pembalikan. Di perangkat itu muncul sebagai event updates lain dengan transaction yang bersih; di server Anda itu adalah notifikasi REFUND_REVERSED yang berbeda. Tangani hanya refund dan Anda akan menelantarkan pelanggan yang membayar tanpa akses dan dengan struk yang berfungsi.

Berapa sebenarnya biaya pencabutan yang terlambat

Sebuah refund jarang hanya harga jual yang meninggalkan rekening Anda. Pada saat ia terselesaikan Anda biasanya sudah menghabiskan uang nyata untuk melayani purchase itu, dan pengeluaran itu tidak kembali. Gambar yang dihasilkan menghabiskan menit GPU. Jawaban chat menghabiskan panggilan model API yang ditagihkan kepada Anda per token. Unggahan menghabiskan penyimpanan yang masih Anda bayar untuk menyimpannya. Jika purchase mendanai pembayaran kepada seorang kreator, uang itu sudah keluar. Tak satu pun dari itu terbalik dengan refund.

Deteksi sisi klien mempersempit jendela pada satu bagian yang masih dapat Anda kendalikan, yaitu pengeluaran masa depan. Semakin cepat Anda tahu sebuah purchase di-refund, semakin cepat Anda berhenti melayaninya. Tetapi perangkat hanya memberi tahu Anda saat app terbuka, jadi pengguna yang di-refund yang tidak pernah kembali menyimpan akses sisi server apa pun yang Anda berikan, diam-diam membebani Anda setiap kali tugas latar belakang atau perangkat tersinkron bertindak atas nama mereka. Klien membuat pencabutan cepat. Ia tidak membuatnya terjamin.

Gunakan klien untuk kecepatan dan server untuk kebenaran

Desain yang bersih menggunakan kedua sinyal untuk apa yang masing-masing kuasai. Di perangkat, Transaction.updates dan currentEntitlements memberi Anda reaksi lokal yang instan saat pelanggan yang di-refund membuka app, baik untuk UI dan untuk menyelesaikan perubahan entitlement tanpa perjalanan bolak-balik. Di server, App Store Server Notifications V2 mengirim pesan REFUND yang tiba entah app pernah dibuka lagi atau tidak, yang merupakan satu-satunya sinyal yang secara andal menghentikan backend Anda dari membelanjakan pada akun yang di-refund.

SignalDi mana ia beradaBerjalan saatPercayai ia untuk
revocationDate pada sebuah transactionDevice, StoreKit 2App Anda membaca transactionMemberi tahu bahwa purchase tertentu di-refund atau dicabut
Transaction.updatesDevice, StoreKit 2Refund mendarat saat app berjalan, atau saat peluncuran jika Anda mendengarkanBereaksi instan untuk pelanggan yang hadir
currentEntitlementsDevice, StoreKit 2Anda memeriksa apa yang dimiliki pelanggan sekarangGerbangi akses tanpa melacak refund sendiri
REFUND notificationServer Anda, App Store Server Notifications V2Apple memproses refund, app terbuka atau tidakMenghentikan pengeluaran sisi server pada pelanggan yang tidak pernah kembali

Pasang sinyal perangkat untuk pelanggan yang memegang ponsel, dan notifikasi server untuk yang tidak. Refund muncul di kedua tempat dengan sengaja. Membaca hanya salah satunya adalah cara akun yang di-refund terus membebani Anda setelah penjualan sudah lenyap.

Pertanyaan yang sering diajukan

Bagaimana cara saya mendeteksi refund di StoreKit 2?
Periksa revocationDate transaction. Nilainya nil untuk purchase yang valid dan menyimpan tanggal begitu App Store me-refund transaction, jadi revocationDate non-nil adalah sinyal bahwa sebuah purchase di-refund atau dicabut.
Apa perbedaan antara revocationDate dan revocationReason?
revocationDate adalah kapan App Store mengambil kembali purchase, dan revocationReason adalah mengapa. Alasannya developerIssue saat pelanggan menyebut masalah di app Anda dan other untuk hal lainnya.
Apakah purchase yang di-refund masih muncul di currentEntitlements?
Tidak. Transaction.currentEntitlements mengecualikan purchase yang telah di-refund atau dicabut App Store, jadi product yang di-refund jatuh dari entitlement pelanggan dengan sendirinya, yang menjadikannya gerbang aman untuk akses.
Akankah StoreKit memberi tahu app saya tentang refund yang terjadi saat app tertutup?
Hanya jika Anda mendengarkan sejak peluncuran. Transaction.updates mengantarkan perubahan itu sekali saat startup, jadi Anda harus memulai Task yang mengiterasinya saat app Anda diluncurkan atau refund terlewat sampai sesuatu yang lain merekonsiliasinya.
Apakah deteksi refund sisi klien cukup dengan sendirinya?
Tidak. Perangkat hanya mengetahui refund saat app Anda berjalan, jadi pelanggan yang tidak pernah membuka kembali app tak terlihat olehnya. REFUND dari App Store Server Notifications V2 adalah sinyal yang menjangkau Anda terlepas dari itu.
Apakah revocationDate selalu berarti pelanggan di-refund?
Tidak. revocationDate juga diatur saat pelanggan kehilangan purchase melalui Family Sharing, jadi tanggal non-nil berarti mereka tidak lagi memiliki purchase tetapi tidak selalu berarti uang dikembalikan.

Sumber dan bacaan lanjutan

RefundHalt

Autopilot refund untuk App Store dan Google Play

Baca selanjutnya

Permintaan refund berikutnya sudah menuju kepada Anda.

Siapkan RefundHalt dalam waktu yang dibutuhkan untuk membaca satu lagi email dukungan tentang refund yang tidak sempat Anda sengketakan.