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,144 +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- getListenerTaskAsTask. 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- /// Helper function that fetches and unwraps all verified transactions
151- private func rawTransactions( ) async -> [ Transaction ] {
152- var transactions : [ Transaction ] = [ ]
153- for await verificationResult in Transaction . all {
154- switch verificationResult {
155- case . verified( let transaction) :
156- transactions. append ( transaction)
157- case . unverified:
158- break
159- }
160- }
161- return transactions
162- }
163-
164- /// Helper function to fetch specific transaction
165- private func fetchTransaction( by id: UInt64 ) async throws -> Transaction ? {
166- for await result in Transaction . all {
167- switch result {
168- case . verified( let transaction) :
169- if transaction. id == id {
170- return transaction
171- }
172- case . unverified:
173- continue
174- }
175- }
176- return nil
177- }
17837}
0 commit comments