-
Notifications
You must be signed in to change notification settings - Fork 11
Transaction persistence
dyf edited this page Feb 27, 2023
·
4 revisions
DYFStoreKit
provides an optional reference implementation for storing transactions in NSUserDefaults
(DYFStoreUserDefaultsPersistence
).
When the client crashes during the payment process, it is particularly important to store transaction information. When storekit notifies the uncompleted payment again, it takes the data directly from keychain and performs the receipt verification until the transaction is completed.
- (void)storeReceipt
{
DYFStoreLog();
NSURL *receiptURL = DYFStore.receiptURL;
NSData *data = [NSData dataWithContentsOfURL:receiptURL];
if (!data || data.length == 0) {
[self refreshReceipt];
return;
}
DYFStoreNotificationInfo *info = self.purchaseInfo;
DYFStoreUserDefaultsPersistence *persister = [[DYFStoreUserDefaultsPersistence alloc] init];
DYFStoreTransaction *transaction = [[DYFStoreTransaction alloc] init];
if (info.state == DYFStorePurchaseStateSucceeded) {
transaction.state = DYFStoreTransactionStatePurchased;
} else if (info.state == DYFStorePurchaseStateRestored) {
transaction.state = DYFStoreTransactionStateRestored;
}
transaction.productIdentifier = info.productIdentifier;
transaction.userIdentifier = info.userIdentifier;
transaction.transactionIdentifier = info.transactionIdentifier;
transaction.transactionTimestamp = info.transactionDate.timestamp;
transaction.originalTransactionTimestamp = info.originalTransactionDate.timestamp;
transaction.originalTransactionIdentifier = info.originalTransactionIdentifier;
transaction.transactionReceipt = data.base64EncodedString;
[persister storeTransaction:transaction];
[self verifyReceipt:data];
}
DYFStoreNotificationInfo *info = self.purchaseInfo;
DYFStore *store = DYFStore.defaultStore;
DYFStoreUserDefaultsPersistence *persister = [[DYFStoreUserDefaultsPersistence alloc] init];
if (info.state == DYFStorePurchaseStateRestored) {
SKPaymentTransaction *transaction = [store extractRestoredTransaction:info.transactionIdentifier];
[store finishTransaction:transaction];
} else {
SKPaymentTransaction *transaction = [store extractPurchasedTransaction:info.transactionIdentifier];
// The transaction can be finished only after the client and server adopt secure communication and data encryption and the receipt verification is passed. In this way, we can avoid refreshing orders and cracking in-app purchase. If we were unable to complete the verification, we want `StoreKit` to keep reminding us that there are still outstanding transactions.
[store finishTransaction:transaction];
}
[persister removeTransaction:info.transactionIdentifier];
if (info.originalTransactionIdentifier) {
[persister removeTransaction:info.originalTransactionIdentifier];
}
To learn more, please view the Demo.