验证在App购买中的收据

And*_*ndy 40 php iphone objective-c storekit in-app-purchase

我一直在玩应用程序购买几天,一切正常,直到我尝试通过应用程序商店验证收据,因为我经常回到无效状态.

我将收据数据传递给我的PHP服务器,然后从那里转发到应用商店,一旦得到有效的响应,我打算将收据数据添加到我的数据库.

商店套件编程指南和类引用对于这个特定区域来说并不是没用,因为它们并没有真正给你任何类型的例子,我确实找到了一篇有用的文章,它帮了我一点但有些东西仍然是错误的.

基本上我想知道是否有工作收据验证的人愿意分享他们的代码,因为我无处可去.

谢谢

Joe*_*rea 70

首先,发布的代码中有一些拼写错误.试试这个.(免责声明:Refactoring et.al留作读者的练习!)

- (BOOL)verifyReceipt:(SKPaymentTransaction *)transaction {
    NSString *jsonObjectString = [self encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];      
    NSString *completeString = [NSString stringWithFormat:@"http://url-for-your-php?receipt=%@", jsonObjectString];               
    NSURL *urlForValidation = [NSURL URLWithString:completeString];       
    NSMutableURLRequest *validationRequest = [[NSMutableURLRequest alloc] initWithURL:urlForValidation];              
    [validationRequest setHTTPMethod:@"GET"];         
    NSData *responseData = [NSURLConnection sendSynchronousRequest:validationRequest returningResponse:nil error:nil];  
    [validationRequest release];
    NSString *responseString = [[NSString alloc] initWithData:responseData encoding: NSUTF8StringEncoding];
    NSInteger response = [responseString integerValue];
    [responseString release];
    return (response == 0);
}

- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length {
    static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";

    NSMutableData *data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
    uint8_t *output = (uint8_t *)data.mutableBytes;

    for (NSInteger i = 0; i < length; i += 3) {
        NSInteger value = 0;
        for (NSInteger j = i; j < (i + 3); j++) {
            value <<= 8;

            if (j < length) {
                value |= (0xFF & input[j]);
            }
        }

        NSInteger index = (i / 3) * 4;
        output[index + 0] =                    table[(value >> 18) & 0x3F];
        output[index + 1] =                    table[(value >> 12) & 0x3F];
        output[index + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';
        output[index + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';
    }

    return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];
}
Run Code Online (Sandbox Code Playgroud)

您可以在处理SKPaymentTransactionObserver消息的类上创建这些Internal方法:

@interface YourStoreClass (Internal)
- (BOOL)verifyReceipt:(SKPaymentTransaction *)transaction;
- (NSString *)encode:(const uint8_t *)input length:(NSInteger)length;
@end
Run Code Online (Sandbox Code Playgroud)

注意:你可以使用像libcrypto这样的东西来处理base64编码,但是你会在app批准时查看导出限制和额外步骤.但我离题了......

然后,无论您打算在远程服务器上开始记录事务,请在事务中调用verifyReceipt:并确保它恢复正常.

同时,在你的服务器上,这里有一些超级精简的PHP来处理事情:

$receipt = json_encode(array("receipt-data" => $_GET["receipt"]));
// NOTE: use "buy" vs "sandbox" in production.
$url = "https://sandbox.itunes.apple.com/verifyReceipt";
$response_json = call-your-http-post-here($url, $receipt);
$response = json_decode($response_json);

// Save the data here!

echo $response->status;
Run Code Online (Sandbox Code Playgroud)

呼叫您的-HTTP-POST,这里是你最喜欢的HTTP发布机制.(cURL是一种可能的选择.YMMV.PHP.net有独家新闻!)

我有点担心的一件事是从应用程序到服务器的URL中的有效负载的长度(通过GET).如果每个RFC都存在长度问题,我会忘记.也许它没问题,或者可能是服务器特定的.(读者:对此部分的建议表示欢迎!)

可能还有一些因为要求同步请求而烦恼.您可能想要异步发布它并放置ol'UIActivityIndi​​catorView或其他一些HUD.例证:initWithData:encoding: call对我来说需要一段时间.几秒钟,这是iPhone版本中的一个小小的永恒(或者其他任何在线的事情).显示某种不确定的进度指标可能是可取的.

  • 您应该注意,这很容易受到使用其他人收据的重播攻击.此外,您的iPhone应用程序容易受到服务器恶意攻击.有关如何修复这些漏洞的信息,请参阅此答案:http://stackoverflow.com/questions/1581246/how-can-my-server-securely-authenticate-iphone-in-in-app-purchase/1794470#1794470 (6认同)

Chr*_*ern 7

完整的源代码以及PHP实现的托管示例位于:http://www.chrismaddern.com/validate-app-store-iap-receipt-codes-online-tool/

希望它能帮到你!