zoukankan      html  css  js  c++  java
  • 苹果开发——App内购以及验证store的收据(二)

    原地址:http://zengwu3915.blog.163.com/blog/static/2783489720137605156966?suggestedreading

    三、 客户端使用StoreKit完成内购
    添加Storekit.Framework,编写自己的storeObsever,用于处理交易,代码如下,其中completeTransaction和failedTransaction两个函数是自定义的用来处理交易成功与失败其它的就都是SKPaymentTransactionObserver这个代理要求的。

    //
    // StoreObserver.h
    // HelloStore
    //
    // Created by guoke on 13-8-4.
    // Copyright (c) 2013年 guoke. All rights reserved.
    //

    #import <Foundation/Foundation.h>

    #import <StoreKit/StoreKit.h>
    #import <StoreKit/SKPaymentTransaction.h>
    @interface StoreObserver : NSObject <SKPaymentTransactionObserver, SKProductsRequestDelegate>
    {
    int buyType;
    }

    -(void)Create;
    -(void)Destroy;

    -(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;
    -(void)PurchasedTransaction: (SKPaymentTransaction *)transaction;
    -(void)completeTransaction: (SKPaymentTransaction *)transaction;
    -(void)failedTransaction: (SKPaymentTransaction *)transaction;
    -(void)paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;
    -(void)paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error;

    -(void)Buy:(int)type;
    -(bool)CanMakePay;
    -(void)RequestProductData;
    -(void)restoreTransaction: (SKPaymentTransaction *)transaction;

    @end

    //
    // StoreObserver.m
    // HelloStore
    //
    // Created by guoke on 13-8-4.
    // Copyright (c) 2013年 guoke. All rights reserved.
    //
    #import "StoreObserver.h"
    #define ProductID @"com.HelloStorTest.TestItem" // 产品ID,对应iTunes Connect中设置的产品ID

    @implementation StoreObserver

    -(void)Create
    {
    //---------------------
    //----监听购买结果
    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
    }

    -(void)Destroy
    {
    //解除监听
    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
    }

    -(void)Buy:(int)type
    {
    buyType = type;
    if ([self CanMakePay])
    {
    NSLog(@"允许程序内付费购买");
    [self RequestProductData];
    }
    else
    {
    NSLog(@"不允许程序内付费购买");
    }
    }

    -(bool)CanMakePay
    {
    return [SKPaymentQueue canMakePayments];
    }

    -(void)RequestProductData
    {
    NSLog(@"---------请求对应的产品信息------------");
    NSArray *product = nil;

    // 这时可以根据buyType不同选择不同的商品,这个只是测试,只用了一种
    product=[[NSArray alloc] initWithObjects:ProductID,nil];

    NSSet *nsset = [NSSet setWithArray:product];
    SKProductsRequest *request=[[SKProductsRequest alloc] initWithProductIdentifiers: nsset];
    request.delegate=self;
    [request start];
    [product release];
    }

    //<SKProductsRequestDelegate> 请求协议
    //收到的产品信息
    - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
    {

    NSLog(@"-----------收到产品反馈信息--------------");
    NSArray *myProduct = response.products;
    NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers);
    NSLog(@"产品付费数量: %d", [myProduct count]);
    // populate UI
    for(SKProduct *product in myProduct){
    NSLog(@"product info");
    NSLog(@"SKProduct 描述信息%@", [product description]);
    NSLog(@"产品标题 %@" , product.localizedTitle);
    NSLog(@"产品描述信息: %@" , product.localizedDescription);
    NSLog(@"价格: %@" , product.price);
    NSLog(@"Product id: %@" , product.productIdentifier);
    }
    SKPayment *payment = nil;

    payment = [SKPayment paymentWithProductIdentifier:ProductID];
    NSLog(@"---------发送购买请求------------");
    [[SKPaymentQueue defaultQueue] addPayment:payment];
    [request autorelease];
    }
    - (void)requestProUpgradeProductData
    {
    NSLog(@"------请求升级数据---------");
    NSSet *productIdentifiers = [NSSet setWithObject:@"com.productid"];
    SKProductsRequest* productsRequest = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];
    productsRequest.delegate = self;
    [productsRequest start];

    }
    //弹出错误信息
    - (void)request:(SKRequest *)request didFailWithError:(NSError *)error
    {
    NSLog(@"-------弹出错误信息----------");
    }

    -(void) requestDidFinish:(SKRequest *)request
    {
    NSLog(@"----------反馈信息结束--------------");
    }

    -(void) PurchasedTransaction: (SKPaymentTransaction *)transaction
    {
    NSLog(@"-----PurchasedTransaction----");
    NSArray *transactions =[[NSArray alloc] initWithObjects:transaction, nil];
    [self paymentQueue:[SKPaymentQueue defaultQueue] updatedTransactions:transactions];
    [transactions release];
    }

    //<SKPaymentTransactionObserver> 千万不要忘记绑定,代码如下:
    //----监听购买结果
    //[[SKPaymentQueue defaultQueue] addTransactionObserver:self];

    - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray*)transactions//交易结果
    {
    NSLog(@"-----paymentQueue--------");
    for(SKPaymentTransaction*transaction in transactions)
    {
    switch(transaction.transactionState)
    {
    caseSKPaymentTransactionStatePurchased://交易完成
    [self completeTransaction:transaction];
    NSLog(@"-----交易完成 --------");
    break;
    caseSKPaymentTransactionStateFailed://交易失败
    [self failedTransaction:transaction];
    NSLog(@"-----交易失败 --------");
    break;
    caseSKPaymentTransactionStateRestored://已经购买过该商品
    [self restoreTransaction:transaction];
    NSLog(@"-----已经购买过该商品 --------");
    caseSKPaymentTransactionStatePurchasing://商品添加进列表
    NSLog(@"-----商品添加进列表 --------");
    break;
    default:
    break;
    }
    }
    }
    -(void) completeTransaction:(SKPaymentTransaction*)transaction
    {
    NSLog(@"-----completeTransaction--------");

    // 接受到的App Store验证字符串,这里需要经过JSON编码
    NSString* jsonObjectString =[self encode:(uint8_t*)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];

    // 将jsonObjectString字符串发给服务器,由服务器POST到iTunes上验证


    // Remove the transaction from the payment queue.
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];
    }

    - (void) failedTransaction: (SKPaymentTransaction *)transaction
    {
    NSLog(@"失败");
    if (transaction.error.code != SKErrorPaymentCancelled)
    {
    }
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

    }
    -(void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction
    {
    }

    - (void) restoreTransaction: (SKPaymentTransaction *)transaction
    {
    NSLog(@" 交易恢复处理");
    }

    -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error
    {
    NSLog(@"-------paymentQueue----");
    }

    // 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] autorelease];
    }
    @end

    在ViewController.m中创建和释放

    - (void)viewDidLoad
    {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    self.observer = [[StoreObserver alloc] init];
    [self.observer Create];

    // test
    [self.observer Buy:0];
    }
    - (void)viewDidUnload
    {
    [self.observer Destroy];
    [self.observer release];
    }

     
    编译运行,将会看到以下Log信息
    苹果开发——App内购以及验证store的收据(二) - 过☆客 - 过☆客
     
    苹果开发——App内购以及验证store的收据(二) - 过☆客 - 过☆客
     
    苹果开发——App内购以及验证store的收据(二) - 过☆客 - 过☆客
     
    苹果开发——App内购以及验证store的收据(二) - 过☆客 - 过☆客

    2013-08-04 19:15:39.776 HelloStoreTest[9839:c07] 允许程序内付费购买
    2013-08-04 19:15:39.777 HelloStoreTest[9839:c07] ---------请求对应的产品信息------------
    2013-08-04 19:15:39.780 HelloStoreTest[9839:c07] -----paymentQueue--------
    2013-08-04 19:15:39.781 HelloStoreTest[9839:c07] -----商品添加进列表 --------
    2013-08-04 19:15:39.989 HelloStoreTest[9839:c07] -----------收到产品反馈信息--------------
    2013-08-04 19:15:39.990 HelloStoreTest[9839:c07] 产品Product ID:(
    )
    2013-08-04 19:15:39.990 HelloStoreTest[9839:c07] 产品付费数量: 1
    2013-08-04 19:15:39.990 HelloStoreTest[9839:c07] product info
    2013-08-04 19:15:39.991 HelloStoreTest[9839:c07] SKProduct 描述信息<SKProduct: 0x8b4e5a0>
    2013-08-04 19:15:39.991 HelloStoreTest[9839:c07] 产品标题 测试商品
    2013-08-04 19:15:39.991 HelloStoreTest[9839:c07] 产品描述信息: 这里是一个store测试商品
    2013-08-04 19:15:39.992 HelloStoreTest[9839:c07] 价格: 6
    2013-08-04 19:15:39.992 HelloStoreTest[9839:c07] Product id: com.HelloStorTest.TestItem
    2013-08-04 19:15:39.992 HelloStoreTest[9839:c07] ---------发送购买请求------------
    2013-08-04 19:15:39.993 HelloStoreTest[9839:c07] -----paymentQueue--------
    2013-08-04 19:15:39.993 HelloStoreTest[9839:c07] -----商品添加进列表 --------
    2013-08-04 19:15:39.994 HelloStoreTest[9839:c07] ----------反馈信息结束--------------

    四、验证store收据
    交易完成后,服务器需要向Apple验证交易是否成功,不然,自己买的产品给别人了就亏了。
    在上面的客户端代码中,我们监听函数中在交易成功时调用了completeTransaction函数,购买成功之后,我们会收到反馈的收据,其中在transactionReceipt中存验证信息。将字打印出来格式为:

    {
    "signature" = "Arcf6xlj4B3XqosYqFrhSNltW+HZS1UOLTh30CLb2AXTW5GABZRK52j1B8eyOynXUqlqhpZCjCk51pWyiO59JCukrz9ktQeaVCha2xgqjzasqz6x8Ulsm+VeA4bDs3eakq5xcMgogRDUOBg5sJauPwMQA30PnLV+ruypva91JAS2AAADVzCCA1MwggI7oAMCAQICCGUUkU3ZWAS1MA0GCSqGSIb3DQEBBQUAMH8xCzAJBgNVBAYTAlVTMRMwEQYDVQQKDApBcHBsZSBJbmMuMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEzMDEGA1UEAwwqQXBwbGUgaVR1bmVzIFN0b3JlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA5MDYxNTIyMDU1NloXDTE0MDYxNDIyMDU1NlowZDEjMCEGA1UEAwwaUHVyY2hhc2VSZWNlaXB0Q2VydGlmaWNhdGUxGzAZBgNVBAsMEkFwcGxlIGlUdW5lcyBTdG9yZTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMrRjF2ct4IrSdiTChaI0g8pwv/cmHs8p/RwV/rt/91XKVhNl4XIBimKjQQNfgHsDs6yju++DrKJE7uKsphMddKYfFE5rGXsAdBEjBwRIxexTevx3HLEFGAt1moKx509dhxtiIdDgJv2YaVs49B0uJvNdy6SMqNNLHsDLzDS9oZHAgMBAAGjcjBwMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUNh3o4p2C0gEYtTJrDtdDC5FYQzowDgYDVR0PAQH/BAQDAgeAMB0GA1UdDgQWBBSpg4PyGUjFPhJXCBTMzaN+mV8k9TAQBgoqhkiG92NkBgUBBAIFADANBgkqhkiG9w0BAQUFAAOCAQEAEaSbPjtmN4C/IB3QEpK32RxacCDXdVXAeVReS5FaZxc+t88pQP93BiAxvdW/3eTSMGY5FbeAYL3etqP5gm8wrFojX0ikyVRStQ+/AQ0KEjtqB07kLs9QUe8czR8UGfdM1EumV/UgvDd4NwNYxLQMg4WTQfgkQQVy8GXZwVHgbE/UC6Y7053pGXBk51NPM3woxhd3gSRLvXj+loHsStcTEqe9pBDpmG5+sk4tw+GK3GMeEN5/+e1QT9np/Kl1nj+aBw7C0xsy0bFnaAd1cSS6xdory/CUvM6gtKsmnOOdqTesbp0bs8sn6Wqs0C9dgcxRHuOMZ2tm8npLUm7argOSzQ==";
    "purchase-info" = "ewoJIm9yaWdpbmFsLXB1cmNoYXNlLWRhdGUtcHN0IiA9ICIyMDEzLTA4LTA0IDA0OjE1OjQ1IEFtZXJpY2EvTG9zX0FuZ2VsZXMiOwoJInVuaXF1ZS1pZGVudGlmaWVyIiA9ICIwMDAwYjAzMWM3YjgiOwoJIm9yaWdpbmFsLXRyYW5zYWN0aW9uLWlkIiA9ICIxMDAwMDAwMDgyODY4NjY0IjsKCSJidnJzIiA9ICIxLjAiOwoJInRyYW5zYWN0aW9uLWlkIiA9ICIxMDAwMDAwMDgyODY4NjY0IjsKCSJxdWFudGl0eSIgPSAiMSI7Cgkib3JpZ2luYWwtcHVyY2hhc2UtZGF0ZS1tcyIgPSAiMTM3NTYxNDk0NTI3NSI7CgkidW5pcXVlLXZlbmRvci1pZGVudGlmaWVyIiA9ICI2Q0Y4ODg1Ni1FRjZGLTRGN0UtOTJGOC1BNUEwMjJFNzdERUIiOwoJInByb2R1Y3QtaWQiID0gImNvbS5IZWxsb1N0b3JUZXN0LlRlc3RJdGVtIjsKCSJpdGVtLWlkIiA9ICI2ODM5MTkxNjIiOwoJImJpZCIgPSAiY29tLmd1b2tlLkhlbGxvU3RvcmVUZXN0IjsKCSJwdXJjaGFzZS1kYXRlLW1zIiA9ICIxMzc1NjE0OTQ1Mjc1IjsKCSJwdXJjaGFzZS1kYXRlIiA9ICIyMDEzLTA4LTA0IDExOjE1OjQ1IEV0Yy9HTVQiOwoJInB1cmNoYXNlLWRhdGUtcHN0IiA9ICIyMDEzLTA4LTA0IDA0OjE1OjQ1IEFtZXJpY2EvTG9zX0FuZ2VsZXMiOwoJIm9yaWdpbmFsLXB1cmNoYXNlLWRhdGUiID0gIjIwMTMtMDgtMDQgMTE6MTU6NDUgRXRjL0dNVCI7Cn0=";
    "environment" = "Sandbox";
    "pod" = "100";
    "signing-status" = "0";
    }

    将这个字符串发给服务器,然后用服务器去POST到App上去验证。
    验证过程:( 原本是在服务器上验证的,为了测试,我们不弄太复杂,直接在当前程序做一个验证测试 )
    1. 先取出transactionReceipt属性中的收据数据。并以base64方式编码

    NSString* ObjectString = [self encode:(uint8_t *)transaction.transactionReceipt.bytes length:transaction.transactionReceipt.length];

    // 其中encode就是base64编码转换函数,编码后的数据为类似:

    ewoJInNpZ25hdHVyZSIgPSAiQXJjZjZ4bGo0QjNYcW9zWXFGcmhTTmx0VytIWlMxVU9MVGgzMENMYjJBWFRXNUdBQlpSSzUyajFCOGV5T3luWFVxbHFocFpDakNrNTFwV3lpTzU5SkN1a3J6OWt0UWVhVkNoYTJ4Z3FqemFzcXo2eDhVbHNtK1ZlQTRiRHMzZWFrcTV4Y01nb2dSRFVPQmc1c0phdVB3TVFBMzBQbkxWK3J1eXB2YTkxSkFTMkFBQURWekNDQTFNd2dnSTdvQU1DQVFJQ0NHVVVrVTNaV0FTMU1BMEdDU3FHU0liM0RRRUJCUVVBTUg4eEN6QUpCZ05WQkFZVEFsVlRNUk13RVFZRFZRUUtEQXBCY0hCc1pTQkpibU11TVNZd0pBWURWUVFMREIxQmNIQnNaU0JEWlhKMGFXWnBZMkYwYVc5dUlFRjFkR2h2Y21sMGVURXpNREVHQTFVRUF3d3FRWEJ3YkdVZ2FWUjFibVZ6SUZOMGIzSmxJRU5sY25ScFptbGpZWFJwYjI0Z1FYVjBhRzl5YVhSNU1CNFhEVEE1TURZeE5USXlNRFUxTmxvWERURTBNRFl4TkRJeU1EVTFObG93WkRFak1DRUdBMVVFQXd3YVVIVnlZMmhoYzJWU1pXTmxhWEIwUTJWeWRHbG1hV05oZEdVeEd6QVpCZ05WQkFzTUVrRndjR3hsSUdsVWRXNWxjeUJUZEc5eVpURVRNQkVHQTFVRUNnd0tRWEJ3YkdVZ1NXNWpMakVMTUFrR0ExVUVCaE1DVlZNd2daOHdEUVlKS29aSWh2Y05BUUVCQlFBRGdZMEFNSUdKQW9HQkFNclJqRjJjdDRJclNkaVRDaGFJMGc4cHd2L2NtSHM4cC9Sd1YvcnQvOTFYS1ZoTmw0WElCaW1LalFRTmZnSHNEczZ5anUrK0RyS0pFN3VLc3BoTWRkS1lmRkU1ckdYc0FkQkVqQndSSXhleFRldngzSExFRkdBdDFtb0t4NTA5ZGh4dGlJZERnSnYyWWFWczQ5QjB1SnZOZHk2U01xTk5MSHNETHpEUzlvWkhBZ01CQUFHamNqQndNQXdHQTFVZEV3RUIvd1FDTUFBd0h3WURWUjBqQkJnd0ZvQVVOaDNvNHAyQzBnRVl0VEpyRHRkREM1RllRem93RGdZRFZSMFBBUUgvQkFRREFnZUFNQjBHQTFVZERnUVdCQlNwZzRQeUdVakZQaEpYQ0JUTXphTittVjhrOVRBUUJnb3Foa2lHOTJOa0JnVUJCQUlGQURBTkJna3Foa2lHOXcwQkFRVUZBQU9DQVFFQUVhU2JQanRtTjRDL0lCM1FFcEszMlJ4YWNDRFhkVlhBZVZSZVM1RmFaeGMrdDg4cFFQOTNCaUF4dmRXLzNlVFNNR1k1RmJlQVlMM2V0cVA1Z204d3JGb2pYMGlreVZSU3RRKy9BUTBLRWp0cUIwN2tMczlRVWU4Y3pSOFVHZmRNMUV1bVYvVWd2RGQ0TndOWXhMUU1nNFdUUWZna1FRVnk4R1had1ZIZ2JFL1VDNlk3MDUzcEdYQms1MU5QTTN3b3hoZDNnU1JMdlhqK2xvSHNTdGNURXFlOXBCRHBtRzUrc2s0dHcrR0szR01lRU41LytlMVFUOW5wL0tsMW5qK2FCdzdDMHhzeTBiRm5hQWQxY1NTNnhkb3J5L0NVdk02Z3RLc21uT09kcVRlc2JwMGJzOHNuNldxczBDOWRnY3hSSHVPTVoydG04bnBMVW03YXJnT1N6UT09IjsKCSJwdXJjaGFzZS1pbmZvIiA9ICJld29KSW05eWFXZHBibUZzTFhCMWNtTm9ZWE5sTFdSaGRHVXRjSE4wSWlBOUlDSXlNREV6TFRBNExUQTBJREEwT2pFMU9qUTFJRUZ0WlhKcFkyRXZURzl6WDBGdVoyVnNaWE1pT3dvSkluVnVhWEYxWlMxcFpHVnVkR2xtYVdWeUlpQTlJQ0l3TURBd1lqQXpNV00zWWpnaU93b0pJbTl5YVdkcGJtRnNMWFJ5WVc1ellXTjBhVzl1TFdsa0lpQTlJQ0l4TURBd01EQXdNRGd5T0RZNE5qWTBJanNLQ1NKaWRuSnpJaUE5SUNJeExqQWlPd29KSW5SeVlXNXpZV04wYVc5dUxXbGtJaUE5SUNJeE1EQXdNREF3TURneU9EWTROalkwSWpzS0NTSnhkV0Z1ZEdsMGVTSWdQU0FpTVNJN0Nna2liM0pwWjJsdVlXd3RjSFZ5WTJoaGMyVXRaR0YwWlMxdGN5SWdQU0FpTVRNM05UWXhORGswTlRJM05TSTdDZ2tpZFc1cGNYVmxMWFpsYm1SdmNpMXBaR1Z1ZEdsbWFXVnlJaUE5SUNJMlEwWTRPRGcxTmkxRlJqWkdMVFJHTjBVdE9USkdPQzFCTlVFd01qSkZOemRFUlVJaU93b0pJbkJ5YjJSMVkzUXRhV1FpSUQwZ0ltTnZiUzVJWld4c2IxTjBiM0pVWlhOMExsUmxjM1JKZEdWdElqc0tDU0pwZEdWdExXbGtJaUE5SUNJMk9ETTVNVGt4TmpJaU93b0pJbUpwWkNJZ1BTQWlZMjl0TG1kMWIydGxMa2hsYkd4dlUzUnZjbVZVWlhOMElqc0tDU0p3ZFhKamFHRnpaUzFrWVhSbExXMXpJaUE5SUNJeE16YzFOakUwT1RRMU1qYzFJanNLQ1NKd2RYSmphR0Z6WlMxa1lYUmxJaUE5SUNJeU1ERXpMVEE0TFRBMElERXhPakUxT2pRMUlFVjBZeTlIVFZRaU93b0pJbkIxY21Ob1lYTmxMV1JoZEdVdGNITjBJaUE5SUNJeU1ERXpMVEE0TFRBMElEQTBPakUxT2pRMUlFRnRaWEpwWTJFdlRHOXpYMEZ1WjJWc1pYTWlPd29KSW05eWFXZHBibUZzTFhCMWNtTm9ZWE5sTFdSaGRHVWlJRDBnSWpJd01UTXRNRGd0TURRZ01URTZNVFU2TkRVZ1JYUmpMMGROVkNJN0NuMD0iOwoJImVudmlyb25tZW50IiA9ICJTYW5kYm94IjsKCSJwb2QiID0gIjEwMCI7Cgkic2lnbmluZy1zdGF0dXMiID0gIjAiOwp9

    2. 创建JSON对象,字典格式,单键值对,键名为”receipt-data“,值为上一步编码的数据
    {”recipt-data“:"编码后数据"}

    NSString* sendString = [[NSString alloc] initWithFormat:@"{"receipt-data":"%@"}",ObjectString ];

    3. 发送HTTP POS 的请求,将数据发送到App Store,其地址为 https://buy.itunes.apple.com/verifyReceipt
    sandbox测试地址为:https://sandbox.itunes.apple.com/verifyReceipt

    NSURL *sandboxStoreURL = [[NSURL alloc] initWithString: @"https://sandbox.itunes.apple.com/verifyReceipt"];
    NSData *postData = [NSData dataWithBytes:[sendString UTF8String] length:[sendString length]];
    NSMutableURLRequest *connectionRequest = [NSMutableURLRequest requestWithURL:sandboxStoreURL];
    [connectionRequest setHTTPMethod:@"POST"];
    [connectionRequest setTimeoutInterval:120.0];
    [connectionRequest setCachePolicy:NSURLRequestUseProtocolCachePolicy];
    [connectionRequest setHTTPBody:postData];
    [[SKPaymentQueue defaultQueue] finishTransaction: transaction];

    NSURLConnection *connection = [[NSURLConnection alloc]
    initWithRequest:connectionRequest
    delegate:self];
    [connection release];

    4. App Store的返回值也是一个JSON格式的对象,包含两个键值对, status和receipt:
    {
    “status” : 0,
    “receipt” : { … }
    }

    {"receipt":{"original_purchase_date_pst":"2013-08-04 04:15:45 America/Los_Angeles", "purchase_date_ms":"1375614945275", "unique_identifier":"0000b031c7b8", "original_transaction_id":"1000000082868664", "bvrs":"1.0", "transaction_id":"1000000082868664", "quantity":"1", "unique_vendor_identifier":"6CF88856-EF6F-4F7E-92F8-A5A022E77DEB", "item_id":"683919162", "product_id":"com.HelloStorTest.TestItem", "purchase_date":"2013-08-04 11:15:45 Etc/GMT", "original_purchase_date":"2013-08-04 11:15:45 Etc/GMT", "purchase_date_pst":"2013-08-04 04:15:45 America/Los_Angeles", "bid":"com.guoke.HelloStoreTest", "original_purchase_date_ms":"1375614945275"}, "status":0}

    如果status的值为0, 就说明该receipt为有效的。 否则就是无效的。
     
    App Store的收据
    发送给App Store的收据数据是通过对transaction中对应的信息编码而创建的。 当App Store验证收据时, 将从其中解码出数据,并以”receipt”的键返回。 返回的响应信息是JSON格式,被包含在SKPaymentTransaction的对象中(transactionReceipt属性)。Server可通过这些值来了解交易的详细信息。 Apple建议只发送receipt数据到服务器并使用receipt数据验证和获得交易详情。 因为App Store可验证收据信息,返回信息,保证信息不被篡改,这种方式比同时提交receipt和transaction的数据要安全。
     
    购买信息的键,很多的键都对应SKPaymentTransaction的属性。
    键名  描述
    quantity  购买商品的数量。对应SKPayment对象中的quantity属性
    product_id  商品的标识,对应SKPayment对象的productIdentifier属性。
    transaction_id  交易的标识,对应SKPaymentTransaction的transactionIdentifier属性
    purchase_date  交易的日期,对应SKPaymentTransaction的transactionDate属性
    original_-transaction_id  对于恢复的transaction对象,该键对应了原始的transaction标识
    original_purchase_-date  对于恢复的transaction对象,该键对应了原始的交易日期
    app_item_id  App Store用来标识程序的字符串。一个服务器可能需要支持多个server的支付功能,可以用这个标识来区分程序。链接sandbox用来测试的程序的不到这个值,因此该键不存在。
    version_external_-identifier  用来标识程序修订数。该键在sandbox环境下不存在
    bid iPhone 程序的bundle标识
    bvrs iPhone 程序的版本号
     
    参考文献:
     
    附件为本文测试程序,直接改名为zip解压即可(因网易不支持zip)
     
     
    HelloStore.rar(39.45K)   
    下载
  • 相关阅读:
    clear:both其实是有瑕疵的
    CSS3不遥远,几个特性你要知道
    JavaScript使用数组拼接字符串性能如何?
    CSS网页宽度怎么定比较合适
    浅析JavaScript的垃圾回收机制
    淡入淡出效果的js原生实现
    非阻塞式JavaScript脚本及延伸知识
    HTML5 Canvas圣诞树
    Ubuntu查看和自动挂载硬盘
    正则表达式批量重命名
  • 原文地址:https://www.cnblogs.com/123ing/p/3790443.html
Copyright © 2011-2022 走看看