Reputation: 675
I am wondering how after a successful purchase can I get the transaction id or receipt information so that i can then send to my server and use for purchase validation. Also on that same topic I am wondering that if for some reason the connection is interrupted before I send the purchase information to my server then how would I go about linking the notifications to the user that purchased the subscriptions?
Thanks
So I want to do my processing in the .purchased part of the switch below
import Foundation
import StoreKit
class StoreManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
//FETCH PRODUCTS
var request: SKProductsRequest!
@Published var myProducts = [SKProduct]()
func getProducts(productIDs: [String]) {
print("Start requesting products ...")
let request = SKProductsRequest(productIdentifiers: Set(productIDs))
request.delegate = self
request.start()
}
func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("Did receive response")
if !response.products.isEmpty {
for fetchedProduct in response.products {
DispatchQueue.main.async {
self.myProducts.append(fetchedProduct)
}
}
}
for invalidIdentifier in response.invalidProductIdentifiers {
print("Invalid identifiers found: \(invalidIdentifier)")
}
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("Request did fail: \(error)")
}
//HANDLE TRANSACTIONS
@Published var transactionState: SKPaymentTransactionState?
func purchaseProduct(product: SKProduct) {
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
} else {
print("User can't make payment.")
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchasing:
transactionState = .purchasing
case .purchased:
UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
transactionState = .purchased
case .restored:
UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
transactionState = .restored
case .failed, .deferred:
print("Payment Queue Error: \(String(describing: transaction.error))")
queue.finishTransaction(transaction)
transactionState = .failed
default:
queue.finishTransaction(transaction)
}
}
}
func restoreProducts() {
print("Restoring products ...")
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
Upvotes: 4
Views: 4675
Reputation: 10102
You can try this -
if let url = Bundle.main.appStoreReceiptURL,
let data = try? Data(contentsOf: url) {
let receiptBase64 = data.base64EncodedString()
// Send to server
}
Wondering what your would recommend if eg the connection is interrupted before the receipt strings is sent to my server and for some reason the user deletes the app or something before I can process it.
true
value in UserDefaults for a variable called needsToSendPurchaseReceiptToServer
.false
after successful completion of the API call.appDidBecomeActive
callback, you check for this flag and if it is still true
, try sending the receipt to server again.Restore Purchase
option.Upvotes: 7