Open gerchicov-bp opened 5 years ago
Hi @gerchicov-bp, Do you know any case got rejected by Apple because of this reason? I'm about to use this approach to avoid BE workload, hope this won't be an issue.
@canhth the problem I faced is another one - my customers want to have a possibility to move apps from a publisher to another and it is not possible when receipts are checked with remote server.
Yes, you are correct, Apple says:
Do not call the App Store server
verifyReceipt
endpoint from your app. You also never want to store your app-specific shared secret in your app binary either.
This can actually be fixed rather easily. Look at the struct AppleReceiptValidator
. It conforms to the ReceiptValidator
protocol. The AppleReceiptValidator
calls Apple's verifyReceipt
endpoint from the device which requires you to store your App-Specific Shared Secret in the binary which is not safe! You need to call Apple's verifyReceipt
endpoint from your own server in order to be safe.
So in my case, I am using PHP so I make a new PHP page that mimics exactly what apple's verifyReceipt.php
does, except that it only requires the receipt-data field because I will provide the app-specific shared secret from my server instead as shown below. My PHP page will return the exact same data as Apple's verifyReceipt
page does so it will still be compatible with SwiftyStoreKit
<?php
header('Content-type: application/json');
$encoded = file_get_contents('php://input');
$data = json_decode($encoded, true);
const APPLE_SHARED_SECRET = "<insert your shared secret here>";
const APPLE_RECEIPT_VERIFY_URL = "https://buy.itunes.apple.com/verifyReceipt";
const APPLE_SANDBOX_RECEIPT_VERIFY_URL = "https://sandbox.itunes.apple.com/verifyReceipt";
$request = json_encode(array("receipt-data" => $data["receipt-data"],"password"=>APPLE_SHARED_SECRET));
$ch = curl_init(APPLE_RECEIPT_VERIFY_URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
$jsonresult = curl_exec($ch);
$jsonresult = json_decode($jsonresult);
$http_status = $jsonresult->status;
curl_close($ch);
if($http_status == 21007){
$ch = curl_init(APPLE_SANDBOX_RECEIPT_VERIFY_URL);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
$jsonresult = curl_exec($ch);
$jsonresult = json_decode($jsonresult);
$http_status = $jsonresult->status;
curl_close($ch);
}
echo json_encode($jsonresult);
?>
Create a new struct that conforms to the ReceiptValidator
protocol. Then copy and paste all the code out of AppleReceiptValidator
into that struct. In the VerifyReceiptURLType
enum add an entry called custom
that points to a page on your server such as
case custom = "https://www.mywebsite.com/verifyReceipt.php"
Now change the default VerifyReceiptURLType
to .custom
in the public init
function. You might get an error about how receiptStatus.isValid
is inaccessible due to protection level, so instead of checking isValid
just do this:
if receiptStatus == .valid {
// The receipt is valid...
}
Since we check for the 21007
error code on our PHP page we can also get rid of that check for .testReceipt
too.
I hope this helps someone 🥂 !
Platform
In-app purchase type
Environment
Version
Latest (0.15.0), maybe all versions
Related issues
101, but it is written as a suggestion to implement while it is actually obligatory!
Report
Issue summary
What did you expect to happen
verifyReceipt
endpoint is not used (how it is explained in the official Apple documentation)What happened instead
verifyReceipt
endpoint is used