Base64编码古怪的iOS7应用程序内购买收据服务器验证

Seo*_*ras 8 base64 objective-c in-app-purchase ios7

我发现iOS7收据的base64编码有一些非常奇怪的问题.

目前(Xcode5/iOS7)有两种获取应用内购买收据的方法:

  1. 不推荐使用的返回单个收据的方法. [SKPaymentTransaction transactionReceipt]
  2. 一捆来自位置的所有收据 appStoreReceiptURL

我的应用程序使用信用系统销售基于网站的服务,该系统使服务器收据验证成为必要.该应用程序还出售可下载的扩展.所以消耗品和非消耗品的混合物.非消耗品是从Apple下载的,因此无需验证.消耗品是用于在网站上购买服务的信用包.

当iOS7和XCode5推出时,我更新了我的应用程序,但在appStoreReceiptURL的新捆绑收据上遇到了困难.使用新样式,所有收据捆绑在一起,我的服务器从Apple的verifyReceipt沙箱中找回了这个错误

[status] => 21002
[exception] => java.lang.IllegalArgumentException
Run Code Online (Sandbox Code Playgroud)

在看过stackoverflow上的帖子后,我放弃了说其他人遇到了同样的问题,当时的意见是苹果公司的一个错误,或者尚未添加功能.但是我一直在看到使用旧的弃用方法的问题,这迫使我重新尝试.在经过大量的调试和搜索之后,我终于解决了一些出错的问题 - 以及让它工作但是以一种非常丑陋的方式,我对自己的生活没有信心.

我原以为NSData(普通字节缓冲区)编码输出不会有太大差别.这是我看到的奇怪部分.

原始弃用的单个收据可以是base64编码为64个字符行,末尾为\ r \n或者没有.Apple验证服务器不关心.无论哪种方式都很开心.

对于新的收据包,除非做了两件事,否则它将无法工作.首先,base64编码不能有换行符.我注意到Apple已将自己的base64编码器添加到iOS7中.这就是我用来获取适用于两种收据类型的编码输出.

NSString *receiptDataString = [transactionReceipt base64EncodedStringWithOptions:0];
Run Code Online (Sandbox Code Playgroud)

需要做的第二件事是搜索并替换服务器上收到的编码收据包中的所有空格字符.即

$receiptdata = str_replace(' ', '+', $receiptdata);
Run Code Online (Sandbox Code Playgroud)

我碰巧注意到这是我的服务器收到的收据之间的差异.为什么我不知道?我正在使用AFNetworking-1.3.2的JSONRequestOperationWithRequest

    NSMutableArray *pairs = [[NSMutableArray alloc] initWithCapacity:0];
    for (NSString *key in parameters) {
        [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, [parameters objectForKey:key]]];
    }
    postData = [[pairs componentsJoinedByString:@"&"] dataUsingEncoding:NSUTF8StringEncoding];
    request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://myserver.com/index.php"]];
    [request setHTTPMethod:@"POST"];
    [request setValue:[NSString stringWithFormat:@"%d", postData.length] forHTTPHeaderField:@"Content-Length"];
    [request setValue:@"application/x-www-form-urlencoded charset=utf-8" forHTTPHeaderField:@"Content-Type"];
    [request setHTTPBody:postData];
    operation = [AFJSONRequestOperation JSONRequestOperationWithRequest:request
Run Code Online (Sandbox Code Playgroud)

克里斯·普林斯声称在回答这个问题时让它与AFNetworking 2合作

为什么这两个NSData收据会导致像我看到的编码/解码问题?我已经尽可能详细而清晰地帮助其他人了,因为我看到有很多人在这里感受到同样的痛苦,Apple推出了这种新的收据方法.

Seo*_*ras 9

答案结果证明是由于

stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding
Run Code Online (Sandbox Code Playgroud)

没有逃避所有特殊字符,如:/?#[] @!$&'()*+ ,; =等.一旦base64编码,Apple提供的新收据包含需要转义但不被上述iOS lib转义的字符逃生编码器.环顾四周,我发现这里有一个效果很好.请参阅下面的工作代码.(服务器现在不需要解析收据代码,可以直接使用$ _POST)

// Lifted from:
// http://stackoverflow.com/questions/2159341/nsstring-method-to-percent-escape-for-url
//
- (NSString *)urlEncodeValue:(NSString *)str {
    NSString *result = (NSString *)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)str, NULL, CFSTR(":/?#[]@!$&’()*+,;="), kCFStringEncodingUTF8));
    return result;
}

    // Encode and pair basic parameters
    NSMutableArray *pairs = [[NSMutableArray alloc] initWithCapacity:0];
    NSString *part;
    for (NSString *key in parameters) {
        NSString *encodedValue = [[parameters objectForKey:key] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        NSString *encodedKey = [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
        part = [NSString stringWithFormat: @"%@=%@", encodedKey, encodedValue];
        [pairs addObject:part];
        [pairs addObject:[NSString stringWithFormat:@"%@=%@", key, [parameters objectForKey:key]]];
    }

    // Receipt encoded and paired separately
    receiptDataString = [self urlEncodeValue:receiptDataString];
    part = [NSString stringWithFormat: @"receipt=%@", receiptDataString];
    [pairs addObject:part];

    // Post data.
    postData = [[pairs componentsJoinedByString:@"&"] dataUsingEncoding:NSUTF8StringEncoding];
Run Code Online (Sandbox Code Playgroud)