44
55@available ( iOS 15 . 0 , macOS 12 . 0 , * )
66extension InAppPurchasePlugin : InAppPurchase2API {
7-
87 // MARK: - Pigeon Functions
98
10- /// Wrapper method around StoreKit2's canMakePayments() method
11- /// https://developer.apple.com/documentation/storekit/appstore/3822277-canmakepayments
9+ // Wrapper method around StoreKit2's canMakePayments() method
10+ // https://developer.apple.com/documentation/storekit/appstore/3822277-canmakepayments
1211 func canMakePayments( ) throws -> Bool {
1312 return AppStore . canMakePayments
1413 }
1514
16- /// Wrapper method around StoreKit2's products() method
17- /// https://developer.apple.com/documentation/storekit/product/3851116-products
15+ // Wrapper method around StoreKit2's products() method
16+ // https://developer.apple.com/documentation/storekit/product/3851116-products
1817 func products(
1918 identifiers: [ String ] , completion: @escaping ( Result < [ SK2ProductMessage ] , Error > ) -> Void
2019 ) {
@@ -35,146 +34,4 @@ extension InAppPurchasePlugin: InAppPurchase2API {
3534 }
3635 }
3736 }
38-
39- /// Gets the appropriate product, then calls purchase on it.
40- /// https://developer.apple.com/documentation/storekit/product/3791971-purchase
41- func purchase(
42- id: String , options: SK2ProductPurchaseOptionsMessage ? ,
43- completion: @escaping ( Result < SK2ProductPurchaseResultMessage , Error > ) -> Void
44- ) {
45- Task { @MainActor in
46- do {
47- guard let product = try await Product . products ( for: [ id] ) . first else {
48- let error = PigeonError (
49- code: " storekit2_failed_to_fetch_product " ,
50- message: " Storekit has failed to fetch this product. " ,
51- details: " Product ID : \( id) " )
52- return completion ( . failure( error) )
53- }
54-
55- let result = try await product. purchase ( options: [ ] )
56-
57- switch result {
58- case . success( let verification) :
59- switch verification {
60- case . verified( let transaction) :
61- self . sendTransactionUpdate ( transaction: transaction)
62- completion ( . success( result. convertToPigeon ( ) ) )
63- case . unverified( _, let error) :
64- completion ( . failure( error) )
65- }
66- case . pending:
67- completion (
68- . failure(
69- PigeonError (
70- code: " storekit2_purchase_pending " ,
71- message:
72- " This transaction is still pending and but may complete in the future. If it completes, it will be delivered via `purchaseStream` " ,
73- details: " Product ID : \( id) " ) ) )
74- case . userCancelled:
75- completion (
76- . failure(
77- PigeonError (
78- code: " storekit2_purchase_cancelled " ,
79- message: " This transaction has been cancelled by the user. " ,
80- details: " Product ID : \( id) " ) ) )
81- @unknown default :
82- fatalError ( " An unknown StoreKit PurchaseResult has been encountered. " )
83- }
84- } catch {
85- completion ( . failure( error) )
86- }
87- }
88- }
89-
90- /// Wrapper method around StoreKit2's transactions() method
91- /// https://developer.apple.com/documentation/storekit/product/3851116-products
92- func transactions(
93- completion: @escaping ( Result < [ SK2TransactionMessage ] , Error > ) -> Void
94- ) {
95- Task {
96- @MainActor in
97- do {
98- let transactionsMsgs = await rawTransactions ( ) . map {
99- $0. convertToPigeon ( )
100- }
101- completion ( . success( transactionsMsgs) )
102- }
103- }
104- }
105-
106- /// Wrapper method around StoreKit2's finish() method https://developer.apple.com/documentation/storekit/transaction/3749694-finish
107- func finish( id: Int64 , completion: @escaping ( Result < Void , Error > ) -> Void ) {
108- Task {
109- let transaction = try await fetchTransaction ( by: UInt64 ( id) )
110- if let transaction = transaction {
111- await transaction. finish ( )
112- }
113- }
114- }
115-
116- /// This Task listens to Transation.updates as shown here
117- /// https://developer.apple.com/documentation/storekit/transaction/3851206-updates
118- /// This function should be called as soon as the app starts to avoid missing any Transactions done outside of the app.
119- func startListeningToTransactions( ) throws {
120- self . setListenerTaskAsTask (
121- task: Task { [ weak self] in
122- for await verificationResult in Transaction . updates {
123- switch verificationResult {
124- case . verified( let transaction) :
125- self ? . sendTransactionUpdate ( transaction: transaction)
126- case . unverified:
127- break
128- }
129- }
130- } )
131- }
132-
133- /// Stop subscribing to Transaction.updates
134- func stopListeningToTransactions( ) throws {
135- updateListenerTask. cancel ( )
136- }
137-
138- /// Sends an transaction back to Dart. Access these transactions with `purchaseStream`
139- func sendTransactionUpdate( transaction: Transaction ) {
140- let transactionMessage = transaction. convertToPigeon ( )
141- transactionCallbackAPI? . onTransactionsUpdated ( newTransaction: transactionMessage) { result in
142- switch result {
143- case . success: break
144- case . failure( let error) :
145- print ( " Failed to send transaction updates: \( error) " )
146- }
147- }
148- }
149-
150- // MARK: - Convenience Functions
151-
152- /// Helper function that fetches and unwraps all verified transactions
153- private func rawTransactions( ) async -> [ Transaction ] {
154- var transactions : [ Transaction ] = [ ]
155- for await verificationResult in Transaction . all {
156- switch verificationResult {
157- case . verified( let transaction) :
158- transactions. append ( transaction)
159- case . unverified:
160- break
161- }
162- }
163- return transactions
164- }
165-
166- /// Helper function to fetch specific transaction
167- private func fetchTransaction( by id: UInt64 ) async throws -> Transaction ? {
168- for await result in Transaction . all {
169- switch result {
170- case . verified( let transaction) :
171- if transaction. id == id {
172- return transaction
173- }
174- case . unverified:
175- continue
176- }
177- }
178- return nil
179- }
18037}
0 commit comments