
Hai Connected Denis from Apphud - layanan untuk analisis langganan yang dapat diperbarui untuk aplikasi iOS.
Seperti yang Anda ketahui, di WWDC 2019, Apple mengumumkan kerangka kerja SwiftUI deklaratif barunya. Pada artikel ini saya akan mencoba memberi tahu cara menggunakan SwiftUI untuk melakukan layar pembayaran dan mengimplementasikan fungsi langganan yang dapat diperbarui secara otomatis.
Jika Anda belum terbiasa dengan SwiftUI, Anda dapat membaca artikel pengantar singkat. Dan jika Anda ingin mempelajari lebih lanjut tentang langganan dan cara menerapkannya dengan benar, baca artikel ini .
Anda membutuhkan Xcode 11 untuk bekerja . Buat proyek baru dan pastikan ada tanda centang di sebelah "Gunakan SwiftUI".
SwiftUI adalah kerangka kerja untuk menulis antarmuka, dan oleh karena itu kami tidak dapat membuat manajer pembelian menggunakannya. Tetapi kami tidak akan menulis manajer kami, tetapi menggunakan solusi yang sudah jadi, yang akan kami tambahkan dengan kode kami. Anda dapat menggunakan, misalnya, SwiftyStoreKit . Dalam contoh kita, kita akan menggunakan kelas dari artikel kita sebelumnya .
Produk akan diinisialisasi pada layar utama, tanggal kedaluwarsa langganan kami dan tombol untuk beralih ke layar pembelian juga akan ditampilkan di sana.
ProductsStore.shared.initializeProducts() if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UIHostingController(rootView: ContentView(productsStore: ProductsStore.shared)) self.window = window window.makeKeyAndVisible() }
Pertimbangkan kelas SceneDelegate
. Di dalamnya, kami membuat ProductsStore
kelas tunggal, di mana produk diinisialisasi. Setelah itu, buat root ContentView
dan tentukan singleton sebagai parameter input.
Pertimbangkan kelas ProductsStore
:
class ProductsStore : ObservableObject { static let shared = ProductsStore() @Published var products: [SKProduct] = [] @Published var anyString = "123"
Kelas kecil ini, semacam "add-on" di atas IAPManager
, berfungsi untuk memperbarui ContentView
saat memperbarui daftar produk. Kelas ProductsStore
mendukung protokol ObservableObject
.
Apa itu ObservableObject
dan @Published
?
ObservableObject
adalah protokol khusus untuk mengamati objek dan melacak perubahan pada propertinya. Properti harus ditandai dengan atribut @Published
. Dalam contoh tersebut, pemberitahuan dikirimkan ketika array products
berubah, tetapi Anda dapat menambahkan pemberitahuan ini untuk metode dan properti objek apa pun.
Pemuatan produk itu sendiri dapat dilakukan dengan cara apa pun, tetapi pada akhir permintaan ini Anda harus menetapkan array produk ke variabel produk. Bagaimana cara mendengarkan perubahan? Ini dilakukan dengan menggunakan parameter kunci @ObservedObject
:
@ObservedObject var productsStore : ProductsStore
Sederhananya, ini adalah sesuatu yang mirip dengan Pusat Pemberitahuan. Dan agar View
Anda menerima pemberitahuan ini, Anda harus memiliki variabel objek ini dengan atribut @ObservedObject
.
Mari kita kembali ke logika kelas ProductsStore
. Tujuan utamanya adalah untuk mengunduh dan menyimpan daftar produk. Tetapi berbagai produk sudah tersimpan di IAPManager
, terjadi duplikasi. Ini tidak baik, tetapi, pertama, dalam artikel ini saya ingin menunjukkan kepada Anda bagaimana binning objek diimplementasikan, dan, kedua, tidak selalu mungkin untuk mengubah kelas selesai dari manajer pembelian. Misalnya, jika Anda menggunakan perpustakaan pihak ketiga, Anda tidak akan dapat menambahkan protokol ObservableObject
dan mengirim pemberitahuan.
Perlu dicatat bahwa selain atribut @ObservedObject
ada juga atribut @State
, yang membantu melacak perubahan dalam variabel sederhana (misalnya, String
atau Int
) dan @EnvironmentObject
yang lebih global, yang dapat memperbarui semua View
dalam aplikasi sekaligus tanpa harus melewati variabel antara objek.
Mari ContentView
layar awal ContentView
:
struct ContentView : View { @ObservedObject var productsStore : ProductsStore @State var show_modal = false var body: some View { VStack() { ForEach (productsStore.products, id: \.self) { prod in Text(prod.subscriptionStatus()).lineLimit(nil).frame(height: 80) } Button(action: { print("Button Pushed") self.show_modal = true }) { Text("Present") }.sheet(isPresented: self.$show_modal) { PurchaseView() } } } }
Mari kita cari tahu kodenya. Menggunakan ForEach
kami membuat View
tekstual, yang jumlahnya sama dengan jumlah produk. Karena kami mengikat variabel productsStore
, tampilan akan diperbarui setiap kali array produk di kelas ProductsStore
berubah.
Metode subscriptionStatus
adalah bagian dari SKProduct
kelas SKProduct
dan mengembalikan teks yang diinginkan tergantung pada tanggal berakhirnya berlangganan:
func subscriptionStatus() -> String { if let expDate = IAPManager.shared.expirationDateFor(productIdentifier) { let formatter = DateFormatter() formatter.dateStyle = .medium formatter.timeStyle = .medium let dateString = formatter.string(from: expDate) if Date() > expDate { return "Subscription expired: \(localizedTitle) at: \(dateString)" } else { return "Subscription active: \(localizedTitle) until:\(dateString)" } } else { return "Subscription not purchased: \(localizedTitle)" } }

Ini adalah layar mulai kami
Sekarang, masuklah ke layar berlangganan. Karena, menurut aturan Apple, layar pembayaran harus memiliki teks panjang tentang kondisi pembelian, sebaiknya menggunakan ScrollView
.
var body: some View { ScrollView (showsIndicators: false) { VStack { Text("Get Premium Membership").font(.title) Text("Choose one of the packages above").font(.subheadline) self.purchaseButtons() self.aboutText() self.helperButtons() self.termsText().frame(width: UIScreen.main.bounds.size.width) self.dismissButton() }.frame(width : UIScreen.main.bounds.size.width) }.disabled(self.isDisabled) }
Dalam contoh ini, kami membuat dua tampilan teks dengan font yang berbeda. Selanjutnya, semua pandangan lain disorot dalam metode mereka sendiri. Ini dilakukan karena tiga alasan:
Kode menjadi lebih mudah dibaca dan dimengerti untuk dipelajari.
Pada saat penulisan ini, Xcode 11 Beta sering membeku dan tidak dapat mengkompilasi kode, dan menempatkan bagian-bagian kode ke dalam fungsi membantu kompiler.
Tunjukkan bahwa tampilan dapat dibuat menjadi fungsi yang terpisah, membuat body
lebih mudah.
Pertimbangkan metode purchaseButtons()
:
func purchaseButtons() -> some View {
Di sini kita membuat tumpukan horisontal dan dalam loop ForEach
kita membuat PurchaseButton
kustom, di mana kita mentransfer produk dan blok panggilan balik.
PurchaseButton
Kelas PurchaseButton
:
struct PurchaseButton : View { var block : SuccessBlock! var product : SKProduct! var body: some View { Button(action: { self.block() }) { Text(product.localizedPrice()).lineLimit(nil).multilineTextAlignment(.center).font(.subheadline) }.padding().frame(height: 50).scaledToFill().border(Color.blue, width: 1) } }
Ini adalah tombol normal yang menyimpan dan memanggil blok yang dilewati saat membuat objek. Stroke pembulatan diterapkan untuk itu. Kami menampilkan harga produk dan durasi periode berlangganan sebagai teks dalam metode localizedPrice()
.
Pembelian berlangganan dilakukan sebagai berikut:
func purchaseProduct(skproduct : SKProduct){ print("did tap purchase product: \(skproduct.productIdentifier)") isDisabled = true IAPManager.shared.purchaseProduct(product: skproduct, success: { self.isDisabled = false ProductsStore.shared.handleUpdateStore() self.dismiss() }) { (error) in self.isDisabled = false ProductsStore.shared.handleUpdateStore() } }
Seperti yang Anda lihat, setelah pembelian handleUpdateStore
, metode handleUpdateStore
, yang dengannya pemberitahuan dikirim untuk memperbarui ContentView
. Ini untuk memastikan bahwa ContentView
status langganan ketika menyembunyikan layar modal. Metode dismiss
menyembunyikan jendela modal.
Karena SwiftUI adalah kerangka kerja deklaratif, menyembunyikan jendela modal tidak dilaksanakan seperti biasa. Kita harus memanggil metode @Environment
dismiss()
pada pembungkus variabel presentationMode
, mendeklarasikannya dengan atribut @Environment
:
struct PurchaseView : View { @State private var isDisabled : Bool = false @Environment(\.presentationMode) var presentationMode private func dismiss() { self.presentationMode.wrappedValue.dismiss() } func dismissButton() -> some View { Button(action: { self.dismiss() }) { Text("Not now").font(.footnote) }.padding() } ...
Variabel presentationMode
adalah bagian dari Nilai Lingkungan - set khusus metode dan properti global. Di SwiftUI, hampir semua tindakan terjadi ketika mengubah nilai variabel, Anda tidak dapat melakukan apa pun dalam runtime dalam arti kata sebenarnya - semuanya terikat terlebih dahulu. Dan untuk melakukan sesuatu saat runtime, Anda harus menggunakan pembungkus.

Layar pembelian berlangganan
Kesimpulan
Semoga artikel ini bermanfaat bagi Anda. Apple suka ketika pengembang menggunakan teknologi terbaru. Jika Anda merilis aplikasi untuk iOS 13 menggunakan SwiftUI, ada kemungkinan kemungkinan menjadi Apple yang terkenal. Jadi jangan takut dengan teknologi baru - gunakan saja. Anda dapat mengunduh kode proyek lengkap di sini .
Ingin menerapkan langganan di aplikasi iOS Anda dalam 10 menit? Integrasikan Apphud dan:
- Lakukan pembelian hanya menggunakan satu metode;
- secara otomatis melacak status langganan setiap pengguna;
- Integrasikan Penawaran Langganan dengan mudah
- kirim acara berlangganan ke Amplitude, Mixpanel, Slack dan Telegram dengan mempertimbangkan mata uang lokal pengguna;
- mengurangi tingkat Churn dalam aplikasi dan mengembalikan pengguna yang tidak berlangganan.
Apa yang harus dibaca?