使用 AFNetworking objective-c 进行自动续订的应用内购买收据验证

In-app purchase receipt verification for auto renewal using AFNetworking objective-c

我正在使用 AFNetworking 编写以下代码进行收据验证,它给了我 status=210002 虽然它在 NSMutableURLRequest

中给了我 status=0

请帮我解决问题

 NSString *strurl = @"https://sandbox.itunes.apple.com/verifyReceipt";   
 NSData *receipt = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] appStoreReceiptURL]];

 NSDictionary *parameter=@{
                          @"receipt-data" : [receipt base64EncodedStringWithOptions:0],
                          @"password" : @"xxxxxxxxxxxxxxxxxxxx",
                         };


 NSData *jsonParam = [NSJSONSerialization dataWithJSONObject:parameter options:NSJSONWritingPrettyPrinted error:nil];

 AFHTTPRequestOperationManager *manager =  [AFHTTPRequestOperationManager manager];
 manager.responseSerializer.acceptableContentTypes = [manager.responseSerializer.acceptableContentTypes setByAddingObject:@"text/plain"];
 [manager POST:strurl parameters:jsonParam success:^(AFHTTPRequestOperation *oprtation, id responseObject){
    NSLog(@"JSON: %@", responseObject);

 }failure:^(AFHTTPRequestOperation *operation, NSError *error){
    NSLog(@"Error: %@", error);

 }];

谢谢

这是我在我的应用程序中使用的收据验证代码,但我在 swift 中有实现。

我也在使用 NSMutableURLRequest 来调用 iTunes 服务器的 Web 服务。

    func verifyPaymentReceipt(){

    let mainBundle = NSBundle.mainBundle() as NSBundle;
    let receiptUrl = mainBundle.appStoreReceiptURL;
    let isPresent = receiptUrl?.checkResourceIsReachableAndReturnError(NSErrorPointer());

    if(isPresent == true){

        let data = NSData(contentsOfURL: receiptUrl! );

        // Create the JSON object that describes the request

        let requestContents  = NSMutableDictionary();
        //            let encodeddata = data!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions());
        let encodeddata = data!.base64EncodedString();

        print("encodeddata = \(encodeddata)");

        requestContents.setObject(encodeddata, forKey: "receipt-data");
        requestContents.setObject("xxxxxxxxxxxxxxxxxxxxxxx", forKey: "password");
        var requestData : NSData?
        do{
            requestData = try NSJSONSerialization.dataWithJSONObject(requestContents, options: NSJSONWritingOptions());
        }catch{
            NSLog("Error in json data creation at verifyPaymentReceipt");
        }

        let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString
        let file = "\(documentsPath)/requestData"

        if(NSFileManager.defaultManager().createFileAtPath(file, contents: data, attributes: nil)){
            NSLog("File %@ ",file);
        }
        else{
            NSLog("error File %@ ",file);
        }



        if(requestData != nil){

            let strRequestData = NSString(data: requestData!, encoding: NSUTF8StringEncoding);
            print(" strRequestData = \(strRequestData)");
            // Create a POST request with the receipt data.

            let storeURL = NSURL(string: "https://sandbox.itunes.apple.com/verifyReceipt");
            let storeRequest = NSMutableURLRequest(URL: storeURL!);
            storeRequest.HTTPMethod = "POST";
            storeRequest.HTTPBody = requestData;

            // Make a connection to the iTunes Store on a background queue.

            let queue = NSOperationQueue();
            NSURLConnection.sendAsynchronousRequest(storeRequest, queue: queue, completionHandler: { (response : NSURLResponse?, data : NSData?, error : NSError?) -> Void in

                if(error != nil){
                    //Handle Error
                }
                else{
                    let d = NSString(data: data!, encoding: NSUTF8StringEncoding);
                    NSLog("DATA:%@", d!);

                    var jsonResponse: NSMutableDictionary?
                    do{
                        jsonResponse = try NSJSONSerialization.JSONObjectWithData(data!,
                            options: NSJSONReadingOptions.AllowFragments) as? NSMutableDictionary;
                        print(jsonResponse);

                    }catch{
                        NSLog("Parsing issue : verifyPaymentReceipt");
                    }

                    if(jsonResponse != nil){

                        let expirationDate: NSDate? = self.expirationDateFromResponse(jsonResponse!);
                        NSLog("Expiration Date: %@", expirationDate!);

                    }
                }
            });

        }

    }

}

As you mention that your code works fine with NSMutableURLRequest but it returns 21002 with AFNetworking.

21002 - 收据数据 属性 中的数据格式错误或丢失。

这意味着您在使用 AFNetworking 时编码收据数据格式错误。所以我认为这是使用 AFNetworking 进行编码的问题。

在 iOS7 中,Apple 在 NSData 上引入了新的 base64 方法,因此无需使用第三方 base 64 解码库,但我仍然建议您尝试使用 Base64 编码用于收据编码。我希望这会解决您的 AFNetworkig 问题。当我验证来自服务器端的收据并且此编码库在这种情况下有效时,我也面临同样的 21002 问题。不知道如何,但它解决了我在服务器端的收据验证调用问题。希望它也对你有用。

这是我在 objective C 中使用的 iOS 收据验证代码的片段,用于在应用启动时检查续订。这有助于我在应用启动时从 App Store 获取订阅续订收据数据。

- (void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction isTestServer:(BOOL)flag{
    NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
    NSData *receipt = [NSData dataWithContentsOfURL:receiptURL];
    [self handleActionWithType:kIAPPurchSuccess data:receipt];

    NSError *error;
    NSDictionary *requestContents = @{
                                      @"receipt-data": [receipt base64EncodedStringWithOptions:0],
                                      @"password": @"INSERT_PASSWORD_HERE",
                                      @"exclude-old-transactions": @"true"
                                      };
    NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents
                                                          options:0
                                                            error:&error];

    NSString *serverString = @"https://buy.itunes.apple.com/verifyReceipt";
    NSURL *storeURL = [NSURL URLWithString:serverString];
    NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL];
    [storeRequest setHTTPMethod:@"POST"];
    [storeRequest setHTTPBody:requestData];

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [NSURLConnection sendAsynchronousRequest:storeRequest queue:queue
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
                               if (connectionError) {
                                   [self handleActionWithType:KIAPPurchVerFailed data:nil];
                               } else {
                                   NSError *error;
                                   NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error];
                                   if (!jsonResponse) {
                                       [self handleActionWithType:KIAPPurchVerFailed data:nil];
                                   }
                                   NSString *status = [NSString stringWithFormat:@"%@",jsonResponse[@"status"]];
                                   if (status && [status isEqualToString:@"21007"]) {
                                       [self verifyPurchaseWithPaymentTransaction:transaction isTestServer:YES];
                                   }else if(status && [status isEqualToString:@"0"]){
                                       [self handleActionWithType:KIAPPurchVerSuccess data:nil];
                                   }
#if DEBUG
                                   NSLog(@"log-IAP> jsonResults: %@",jsonResponse);
#endif
                               }
                           }];
    [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}

希望这对您有所帮助。最好尽快将 Objective C 项目转换为 swift,因为越来越难找到关于 Objective C 的教程,尤其是对于较新的实施。