mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
iOS InAppPurchases: Use recommended receipt verification procedure
This commit is contained in:
parent
48a7274b08
commit
2073e46e79
1 changed files with 51 additions and 36 deletions
|
|
@ -544,10 +544,10 @@ struct InAppPurchases::Pimpl : public SKDelegateAndPaymentObserver
|
|||
void fetchReceiptDetailsFromAppStore (NSData* receiptData, const String& secret)
|
||||
{
|
||||
auto requestContents = [NSMutableDictionary dictionaryWithCapacity: (NSUInteger) (secret.isNotEmpty() ? 2 : 1)];
|
||||
[requestContents setObject: [receiptData base64EncodedStringWithOptions:0] forKey: nsStringLiteral ("receipt-data")];
|
||||
[requestContents setObject: [receiptData base64EncodedStringWithOptions:0] forKey: @"receipt-data"];
|
||||
|
||||
if (secret.isNotEmpty())
|
||||
[requestContents setObject: juceStringToNS (secret) forKey: nsStringLiteral ("password")];
|
||||
[requestContents setObject: juceStringToNS (secret) forKey: @"password"];
|
||||
|
||||
NSError* error;
|
||||
auto requestData = [NSJSONSerialization dataWithJSONObject: requestContents
|
||||
|
|
@ -559,47 +559,62 @@ struct InAppPurchases::Pimpl : public SKDelegateAndPaymentObserver
|
|||
return;
|
||||
}
|
||||
|
||||
#if JUCE_IN_APP_PURCHASES_USE_SANDBOX_ENVIRONMENT
|
||||
auto storeURL = "https://sandbox.itunes.apple.com/verifyReceipt";
|
||||
#else
|
||||
auto storeURL = "https://buy.itunes.apple.com/verifyReceipt";
|
||||
#endif
|
||||
verifyReceipt ("https://buy.itunes.apple.com/verifyReceipt", requestData);
|
||||
}
|
||||
|
||||
// TODO: use juce URL here
|
||||
auto* urlPtr = [NSURL URLWithString: nsStringLiteral (storeURL)];
|
||||
auto storeRequest = [NSMutableURLRequest requestWithURL: urlPtr];
|
||||
[storeRequest setHTTPMethod: nsStringLiteral ("POST")];
|
||||
void verifyReceipt (const String& endpoint, NSData* requestData)
|
||||
{
|
||||
const auto nsurl = [NSURL URLWithString: juceStringToNS (endpoint)];
|
||||
|
||||
if (nsurl == nullptr)
|
||||
return;
|
||||
|
||||
const auto storeRequest = [NSMutableURLRequest requestWithURL: nsurl];
|
||||
[storeRequest setHTTPMethod: @"POST"];
|
||||
[storeRequest setHTTPBody: requestData];
|
||||
|
||||
auto task = [[NSURLSession sharedSession] dataTaskWithRequest: storeRequest
|
||||
completionHandler:
|
||||
^(NSData* data, NSURLResponse*, NSError* connectionError)
|
||||
{
|
||||
if (connectionError != nil)
|
||||
{
|
||||
sendReceiptFetchFail();
|
||||
}
|
||||
else
|
||||
{
|
||||
NSError* err;
|
||||
constexpr auto sandboxURL = "https://sandbox.itunes.apple.com/verifyReceipt";
|
||||
|
||||
if (NSDictionary* receiptDetails = [NSJSONSerialization JSONObjectWithData: data options: 0 error: &err])
|
||||
processReceiptDetails (receiptDetails);
|
||||
else
|
||||
sendReceiptFetchFail();
|
||||
}
|
||||
}];
|
||||
const auto shouldRetryWithSandboxUrl = [isProduction = (endpoint != sandboxURL)] (NSDictionary* receiptDetails)
|
||||
{
|
||||
if (isProduction)
|
||||
if (const auto* status = getAs<NSNumber> (receiptDetails[@"status"]))
|
||||
return [status intValue] == 21007;
|
||||
|
||||
[task resume];
|
||||
return false;
|
||||
};
|
||||
|
||||
[[[NSURLSession sharedSession] dataTaskWithRequest: storeRequest
|
||||
completionHandler: ^(NSData* responseData, NSURLResponse*, NSError* connectionError)
|
||||
{
|
||||
if (connectionError == nullptr)
|
||||
{
|
||||
NSError* err = nullptr;
|
||||
|
||||
if (NSDictionary* receiptDetails = [NSJSONSerialization JSONObjectWithData: responseData options: 0 error: &err])
|
||||
{
|
||||
if (shouldRetryWithSandboxUrl (receiptDetails))
|
||||
{
|
||||
verifyReceipt (sandboxURL, requestData);
|
||||
return;
|
||||
}
|
||||
|
||||
processReceiptDetails (receiptDetails);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
sendReceiptFetchFail();
|
||||
}] resume];
|
||||
}
|
||||
|
||||
void processReceiptDetails (NSDictionary* receiptDetails)
|
||||
{
|
||||
if (auto receipt = getAs<NSDictionary> (receiptDetails[nsStringLiteral ("receipt")]))
|
||||
if (auto receipt = getAs<NSDictionary> (receiptDetails[@"receipt"]))
|
||||
{
|
||||
if (auto bundleId = getAs<NSString> (receipt[nsStringLiteral ("bundle_id")]))
|
||||
if (auto bundleId = getAs<NSString> (receipt[@"bundle_id"]))
|
||||
{
|
||||
if (auto inAppPurchases = getAs<NSArray> (receipt[nsStringLiteral ("in_app")]))
|
||||
if (auto inAppPurchases = getAs<NSArray> (receipt[@"in_app"]))
|
||||
{
|
||||
Array<Listener::PurchaseInfo> purchases;
|
||||
|
||||
|
|
@ -608,14 +623,14 @@ struct InAppPurchases::Pimpl : public SKDelegateAndPaymentObserver
|
|||
if (auto* purchaseData = getAs<NSDictionary> (inAppPurchaseData))
|
||||
{
|
||||
// Ignore products that were cancelled.
|
||||
if (purchaseData[nsStringLiteral ("cancellation_date")] != nil)
|
||||
if (purchaseData[@"cancellation_date"] != nil)
|
||||
continue;
|
||||
|
||||
if (auto transactionId = getAs<NSString> (purchaseData[nsStringLiteral ("original_transaction_id")]))
|
||||
if (auto transactionId = getAs<NSString> (purchaseData[@"original_transaction_id"]))
|
||||
{
|
||||
if (auto productId = getAs<NSString> (purchaseData[nsStringLiteral ("product_id")]))
|
||||
if (auto productId = getAs<NSString> (purchaseData[@"product_id"]))
|
||||
{
|
||||
auto purchaseTime = getPurchaseDateMs (purchaseData[nsStringLiteral ("purchase_date_ms")]);
|
||||
auto purchaseTime = getPurchaseDateMs (purchaseData[@"purchase_date_ms"]);
|
||||
|
||||
if (purchaseTime > 0)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue