当前位置: 首页 > 工具软件 > product-app > 使用案例 >

iOS开发--In-app Purchase内购验证方法

孟昆
2023-12-01

IOS7开始:AppStore增加了验证内购(In App Purchasement)的方法, 以确保此次支付是有效地.

下面是苹果提供的验证地址:

开发测试用:

https://sandbox.itunes.apple.com/verifyReceipt

产品用:

https://buy.itunes.apple.com/verifyReceipt


当购买成功时,会得到苹果返回的一个收据(receipt), 苹果推荐的方法是将收据发给开发者的server,server像上述地址post http消息,进行验证, 苹果将结果返回.用来判断到底是真正的购买还是虚假的购买.

当然,我们也可以在客户端来验证,代码如下:

#define ITMS_SANDBOX_VERIFY_RECEIPT_URL     @"https://sandbox.itunes.apple.com/verifyReceipt"

#pragma mark - VerifyFinishedTransaction
-(void)verifyFinishedTransaction:(SKPaymentTransaction *)transaction{
    if(transaction.transactionState == SKPaymentTransactionStatePurchased){
        NSData *transactionReceipt  = transaction.transactionReceipt;
        //将transactionIdentifer和加密后的transactionReceipt数据发送给server端
//        NSString* receipent = [NSString stringWithFormat:@"%s", transactionReceipt.bytes];//用来POST给server
        NSDictionary *requestContents = @{
                                          @"receipt-data": [self encode:(uint8_t *)transactionReceipt.bytes length:transactionReceipt.length]};
        
        NSLog(@"receipent = %@", requestContents);
        
        // 在app上做验证, 仅用于测试
        NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
                                                              options:0
                                                                error:nil];
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:ITMS_SANDBOX_VERIFY_RECEIPT_URL]];
        [request setHTTPMethod:@"POST"];
        [request setHTTPBody:requestData];
        NSError* err;
        NSURLResponse *theResponse = nil;
        NSData *data=[NSURLConnection sendSynchronousRequest:request
                                           returningResponse:&theResponse
                                                       error:&err];
        NSError *jsonParsingError = nil;
        NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonParsingError];
        NSLog(@"requestDict: %@", dict);
    }
}
//Base64加密
- (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];
}


正确地返回数据应该是:

{

    receipt =     {

        bid = APPBundleID

        bvrs = AppVersion

        "item_id" = 1011063440;

        "original_purchase_date" = "2015-06-25 02:40:46 Etc/GMT";

        "original_purchase_date_ms" = 1435200046685;

        "original_purchase_date_pst" = "2015-06-24 19:40:46 America/Los_Angeles";

        "original_transaction_id" = 1000000160740781;

        "product_id" = ProductID

        "purchase_date" = "2015-06-25 02:40:46 Etc/GMT";

        "purchase_date_ms" = 1435200046685;

        "purchase_date_pst" = "2015-06-24 19:40:46 America/Los_Angeles";

        quantity = 1;

        "transaction_id" = 1000000160740781;

        "unique_identifier" = bea76003f25d87d1572ac452f600ef2575af0c7f;

        "unique_vendor_identifier" = "7C4CE200-847F-4F5C-BE32-04FAEE6C64E7";

    };

    status = 0;

}


其中: status=0,表示支付有效.


下面是其他的一些状态码:

Status Code

Description

21000

The App Store could not read the JSON object you provided.

21002

The data in the receipt-data property was malformed or missing.

21003

The receipt could not be authenticated.

21004

The shared secret you provided does not match the shared secret on file for your account.

Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.

21005

The receipt server is not currently available.

21006

This receipt is valid but the subscription has expired. When this status code is returned to your server, the receipt data is also decoded and returned as part of the response.

Only returned for iOS 6 style transaction receipts for auto-renewable subscriptions.

21007

This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.

21008

This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.


 类似资料: