9

如Receipt Validation Programming guide所述,我正在为应用内购买实现收据验证服务器端。

每当我尝试将收据编码为 Base64 并将其发送到我的服务器时,我都会收到来自 Apple 的错误消息。但是,如果我手动将未编码的 base64 复制粘贴到服务器上,在那里对其进行编码并触发对 Apple 的 REST 调用,他们的 iTunes 服务器会正​​确响应。

我不确定我在做什么错误的客户端。代码非常简单:

-(NSString*) retrieveReceiptFromCompletedTransaction:(SKPaymentTransaction*)transaction
{
  NSData *receiptData;
  NSString *receiptString;
  NSBundle *bundle = [NSBundle mainBundle];

  if ([bundle respondsToSelector:@selector(appStoreReceiptURL)]) {
    NSURL *receiptURL = [bundle performSelector:@selector(appStoreReceiptURL)];
    receiptData= [NSData dataWithContentsOfURL:receiptURL];
  }
  else {
    receiptData = transaction.transactionReceipt;
  }

  receiptString = [receiptData base64EncodedStringWithOptions:0];
  return receiptString;
}

有任何想法吗?

4

1 回答 1

12
  • 实施的方法适用于可再生类型,未尝试其他类型的方法(可能或可能对其他类型没有帮助)。
  • 第 5 点(将字符串直接发送到服务器端(JAVA)是我实施解决此问题的方式(我面临的类似问题)
  • 我也在写下完整的方法来帮助初学者。

  • 从您的 iTunes 帐户生成共享密钥。

  • 比在您的代码(ios 端)中使用 shared_secret #define SHARED_SECRET @"XXXXXX6666555XXXXXXx"

-(void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions

  • SKPaymentTransactionStatePurchased

    {
    .....
    
    case SKPaymentTransactionStatePurchased:
                        if ([transaction.payment.productIdentifier
                             isEqualToString:PRICEPLAN1]) {
    
                            //[server PurchasedClinicalToDoList];
    
                            [self completeTransaction: transaction];
    
                        }
                        [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
                        break;
    }
    

5:验证收据

- (void) completeTransaction: (SKPaymentTransaction *)transaction
{
   // NSString* receiptString = [[NSString alloc] initWithString:transaction.payment.productIdentifier];



    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];

    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];

    NSString *jsonObjectString = [receipt base64EncodedStringWithOptions:0];


        [self validateViaOwnServer:jsonObjectString];
        [self validateDirectly: receipt];



}

6.ValidateViaServerSideCodes:

     -(void)validateViaOwnServer  :(NSString*)receipt
    {
         NSString* BASEURl = @"XXXXXXXXX/XXX/XXXX";
        NSString *TestReceipt= [BASEURl stringByAppendingString:@"/InApp/iOS/updatePurchase"];


        NSDictionary *params = @ {@"receipt" :receipt]};

        AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
        manager.responseSerializer.acceptableContentTypes = [NSSet setWithObject:@"text/html"];
        manager.responseSerializer = [AFHTTPResponseSerializer serializer];

        [manager TestReceipt
           parameters:params
              success:^(AFHTTPRequestOperation *operation, id responseData) {



              } failure:^(AFHTTPRequestOperation *operation, NSError *error) {


              }];
    }

7.直接验证:

-(void) validateDirectly :(NSData*)receipt
{
  // Sent to the server by the device
    // Create the JSON object that describes the request
    NSError *error;
       // NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents                                                          options:0 error:&error];
    NSData *requestData = [NSJSONSerialization dataWithJSONObject:[NSDictionary dictionaryWithObjectsAndKeys:
                                                                [receipt base64EncodedStringWithOptions:0],@"receipt-data",
                                                                SHARED_SECRET,@"password",
                                                                nil]
                                                       options:NSJSONWritingPrettyPrinted
                                                         error:&error
                        ];
    if(!requestData) {

    /* ... Handle error ... */ }
    // Create a POST request with the receipt data.
    NSURL *storeURL = [NSURL URLWithString:@"https://buy.itunes.apple.com/verifyReceipt"];
    //@"https://sandbox.itunes.apple.com/verifyReceipt"
NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL]; [storeRequest setHTTPMethod:@"POST"];
    [storeRequest setHTTPBody:requestData];
    // Make a connection to the iTunes Store on a background queue.
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
                                                  completionHandler:^(NSURLResponse *response, NSData *data, NSError
                                                                      *connectionError) {

    if (connectionError) {
/* ... Handle error ... */
//   NSLog(@"CONNECTION ERROR");
    } else {
    NSError *error;
NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data                                                                                                                       options:0 error:&error];
    if (!jsonResponse) { // NSLog(@"NOT JSON");

    /* ... Handle error ...*/ }
    else{

          /* ... YES VALIDATED ...*/
     }/* ... Send a response back to the device ... */
                                                      }
    }];
}

8:服务器端代码(JAVA)

字符串 URL = " https://buy.itunes.apple.com/verifyReceipt ";

            try {

                URL url = new URL(URL);
                HttpURLConnection conn = (HttpURLConnection) url.openConnection();
                conn.setDoOutput(true);
                conn.setRequestMethod("POST");
                //conn.setRequestProperty("Content-Type", "text/plain");
                conn.setRequestProperty("Accept", "application/json");
                conn.setRequestProperty("Content-Type", "application/json");


                String input = "{\"receipt-data\": \""+receiptData+"\", \"password\": \"69744THESECRETKEYXXX\"}";
                OutputStream os = conn.getOutputStream();
                os.write(input.getBytes());
                os.flush();

                if (conn.getResponseCode() != 200) {
                    throw new RuntimeException("Failed : HTTP error code : "
                            + conn.getResponseCode());
                }

                BufferedReader br = new BufferedReader(new InputStreamReader(
                        (conn.getInputStream())));

                String output;
                System.out.println("Output from Server .... \n");
                while ((output = br.readLine()) != null) {
                    appleJson += output;
//                  System.out.println(output);
                }

                conn.disconnect();

                appleReceipt = gson.fromJson(appleJson, AppleReceipt.class);
                purchaseStartDate = appleReceipt.getReceipt().getIn_app().get(1).getOriginal_purchase_date_ms();
                expiryDate = appleReceipt.getReceipt().getIn_app().get(1).getExpires_date_ms();
//              System.out.println("Apple receipt expiry date="+appleReceipt.getReceipt().getIn_app().get(1).getExpires_date_ms());

//              System.out.println("Apple receipt expiry date="+appleReceipt.getReceipt().getIn_app().get(1).getExpires_date_ms());
于 2014-11-18T08:14:07.057 回答