-
Notifications
You must be signed in to change notification settings - Fork 3.6k
[in_app_purchase_storekit] Add support for purchase and transactions #7574
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
b126a15
ae9095a
c38b66f
268a50e
f6ec07a
aa36dfd
8724d40
a6cbd98
b75eec7
4d2fd59
aeef979
acf499f
c3c7204
9021b6f
666df56
97b746f
add5bf5
06b42d0
0701d2a
8f225c0
2c6efdb
72ce51c
2e940fe
442c158
f48510b
6076bf1
d8dcad2
9c2893b
1a74fb7
1b688ae
74c2de3
71c9a1b
582156b
e6bec70
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
- Loading branch information
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,7 +3,7 @@ | |
| // found in the LICENSE file. | ||
|
|
||
| @available(iOS 15.0, macOS 12.0, *) | ||
| extension InAppPurchasePlugin: @preconcurrency InAppPurchase2API { | ||
| extension InAppPurchasePlugin: InAppPurchase2API { | ||
| // MARK: - Pigeon Functions | ||
|
|
||
| /// Wrapper method around StoreKit2's canMakePayments() method | ||
|
|
@@ -37,12 +37,12 @@ extension InAppPurchasePlugin: @preconcurrency InAppPurchase2API { | |
|
|
||
| /// Gets the appropriate product, then calls purchase on it. | ||
| /// https://developer.apple.com/documentation/storekit/product/3791971-purchase | ||
| @MainActor | ||
| func purchase( | ||
| id: String, options: SK2ProductPurchaseOptionsMessage?, | ||
| completion: @escaping (Result<SK2ProductPurchaseResultMessage, Error>) -> Void | ||
| ) { | ||
| Task { | ||
| @MainActor in | ||
LouiseHsu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| do { | ||
| let product = try await Product.products(for: [id]).first | ||
| guard let product = product else { | ||
LouiseHsu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
@@ -59,7 +59,7 @@ extension InAppPurchasePlugin: @preconcurrency InAppPurchase2API { | |
| case .success(let verification): | ||
| switch verification { | ||
| case .verified(let transaction): | ||
| self.transactionListenerAPI?.transactionUpdated(updatedTransactions: transaction) | ||
| self.sendTransactionUpdate(transaction: transaction) | ||
| completion(.success(result.convertToPigeon())) | ||
| case .unverified(_, let error): | ||
| completion(.failure(error)) | ||
|
|
@@ -94,6 +94,7 @@ extension InAppPurchasePlugin: @preconcurrency InAppPurchase2API { | |
| completion: @escaping (Result<[SK2TransactionMessage], Error>) -> Void | ||
| ) { | ||
| Task { | ||
| @MainActor in | ||
| do { | ||
| let transactionsMsgs = await rawTransactions().map { | ||
| $0.convertToPigeon() | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: use keypath
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "Keypath can’t be used on instance methods"
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. oh you are right |
||
|
|
@@ -117,12 +118,12 @@ extension InAppPurchasePlugin: @preconcurrency InAppPurchase2API { | |
| /// https://developer.apple.com/documentation/storekit/transaction/3851206-updates | ||
| /// This function should be called as soon as the app starts to avoid missing any Transactions done outside of the app. | ||
| func startListeningToTransactions() throws { | ||
| self.updateListenerTask = Task { | ||
| self.updateListenerTask = Task { [weak self] in | ||
| for await verificationResult in Transaction.updates { | ||
| switch verificationResult { | ||
| case .verified(let transaction): | ||
| self.transactionListenerAPI?.transactionUpdated(updatedTransactions: transaction) | ||
| case .unverified(_, _): | ||
| self?.sendTransactionUpdate(transaction: transaction) | ||
| case .unverified: | ||
| break | ||
| } | ||
| } | ||
|
|
@@ -131,18 +132,29 @@ extension InAppPurchasePlugin: @preconcurrency InAppPurchase2API { | |
|
|
||
| /// Stop subscribing to Transaction.updates | ||
| func stopListeningToTransactions() throws { | ||
| self.updateListenerTask = nil | ||
| getUpdateListenerTask().cancel() | ||
| } | ||
|
|
||
| /// Sends an transaction back to Dart. Access these transactions with `purchaseStream` | ||
| func sendTransactionUpdate(transaction: Transaction) { | ||
| let transactionMsg = transaction.convertToPigeon() | ||
LouiseHsu marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| transactionDelegate?.onTransactionsUpdated(newTransaction: transactionMsg) { result in | ||
| switch result { | ||
| case .success: break | ||
| case .failure(let error): | ||
| print("Failed to send transaction updates: \(error)") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /// Helper function that fetches and unwraps all verified transactions | ||
| private func rawTransactions() async -> [Transaction] { | ||
| var transactions: [Transaction] = [] | ||
|
|
||
| for await verificationResult in Transaction.all { | ||
| switch verificationResult { | ||
| case .verified(let transaction): | ||
| transactions.append(transaction) | ||
| case .unverified(_, _): | ||
| case .unverified: | ||
| break | ||
| } | ||
| } | ||
|
|
@@ -157,10 +169,15 @@ extension InAppPurchasePlugin: @preconcurrency InAppPurchase2API { | |
| if transaction.id == id { | ||
| return transaction | ||
| } | ||
| case .unverified(_, _): | ||
| case .unverified: | ||
| continue | ||
| } | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| /// Helper function to cast updateListenerTask to a task | ||
| func getUpdateListenerTask() -> Task<(), Never> { | ||
|
||
| return self.updateListenerTask as! Task<(), Never> | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,26 +1,27 @@ | ||
| // Copyright 2013 The Flutter Authors. All rights reserved. | ||
| // Use of this source code is governed by a BSD-style license that can be | ||
| // found in the LICENSE file. | ||
|
|
||
| final class TransactionCallbacks: InAppPurchase2CallbackAPI { | ||
| let callbackAPI: InAppPurchase2CallbackAPI | ||
|
|
||
| init(binaryMessenger: FlutterBinaryMessenger) { | ||
| callbackAPI = InAppPurchase2CallbackAPI(binaryMessenger: binaryMessenger) | ||
| super.init(binaryMessenger: binaryMessenger) | ||
| } | ||
|
|
||
| @available(iOS 15.0, macOS 12.0, *) | ||
| func transactionUpdated(updatedTransactions: Transaction, restoring: Bool = false) { | ||
| let transactionMsg = updatedTransactions.convertToPigeon( | ||
| restoring: restoring) | ||
| callbackAPI.onTransactionsUpdated(newTransaction: transactionMsg) { result in | ||
| switch result { | ||
| case .success: break | ||
| case .failure(let error): | ||
| print("Failed to send transaction updates: \(error)") | ||
| } | ||
| } | ||
| } | ||
|
|
||
| } | ||
| //// Copyright 2013 The Flutter Authors. All rights reserved. | ||
| //// Use of this source code is governed by a BSD-style license that can be | ||
| //// found in the LICENSE file. | ||
| // | ||
| ///// TODO Move to main plugin | ||
| //final class TransactionCallbacks: InAppPurchase2CallbackAPI { | ||
| // let callbackAPI: InAppPurchase2CallbackAPI | ||
| // | ||
| // init(binaryMessenger: FlutterBinaryMessenger) { | ||
| // callbackAPI = InAppPurchase2CallbackAPI(binaryMessenger: binaryMessenger) | ||
| // super.init(binaryMessenger: binaryMessenger) | ||
| // } | ||
| // | ||
| // @available(iOS 15.0, macOS 12.0, *) | ||
| // func transactionUpdated(updatedTransactions: Transaction, restoring: Bool = false) { | ||
| // let transactionMsg = updatedTransactions.convertToPigeon( | ||
| // restoring: restoring) | ||
| // callbackAPI.onTransactionsUpdated(newTransaction: transactionMsg) { result in | ||
| // switch result { | ||
| // case .success: break | ||
| // case .failure(let error): | ||
| // print("Failed to send transaction updates: \(error)") | ||
| // } | ||
| // } | ||
| // } | ||
| // | ||
| //} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you try out that getter trick discussed yesterday?