【问题标题】:Invalid transaction receipt returned by appStoreReceiptURL (NSData), in iOS 7在 iOS 7 中 appStoreReceiptURL (NSData) 返回的交易收据无效
【发布时间】:2013-11-26 03:31:43
【问题描述】:

我正在使用以下方法获取收据数据:

// Use this method instead of accessing transaction.transactionReceipt directly!
- (NSData *)appStoreReceiptForPaymentTransaction:(SKPaymentTransaction *)transaction {
    NSData *receiptData = nil;

    // This is just a quick/dummy implementation!
    if (kiOS7) {
        NSURL *receiptFileURL = [[NSBundle mainBundle] appStoreReceiptURL];
        receiptData = [NSData dataWithContentsOfURL:receiptFileURL]; // Returns valid NSData object

    } else {
        receiptData = transaction.transactionReceipt; // Returns valid NSData object
    }        

    return receiptData;
}

我正在使用以下代码读取 JSON 收据:

NSData *receipt = [self appStoreReceiptForPaymentTransaction:transaction];

NSError *error = nil;
NSDictionary *receiptDict = [receipt dictionaryFromPlistData:&error];
NSString *transactionPurchaseInfo = [receiptDict objectForKey:@"purchase-info"];
NSString *decodedPurchaseInfo = [NSString stringWithUTF8String:[[NSData dataFromBase64String:transactionPurchaseInfo] bytes]];
NSDictionary *purchaseInfoDict = [[decodedPurchaseInfo dataUsingEncoding:NSUTF8StringEncoding] dictionaryFromPlistData:&error];

NSString *transactionID = [purchaseInfoDict objectForKey:@"transaction-id"];
NSString *purchaseDateString = [purchaseInfoDict objectForKey:@"purchase-date"];
NSString *signature = [receiptDict objectForKey:@"signature"];
NSString *signatureDecoded = [NSString stringWithUTF8String:[[NSData dataFromBase64String:signature] bytes]];

// Convert the string into a date
NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init];
[dateFormat setDateFormat:@"yyyy-MM-dd HH:mm:ss z"];

NSDate *purchaseDate = [dateFormat dateFromString:[purchaseDateString stringByReplacingOccurrencesOfString:@"Etc/" withString:@""]];

NSLog(@"Raw receipt content: \n%@", [NSString stringWithUTF8String:[receipt bytes]]);
NSLog(@"Purchase Info: %@", purchaseInfoDict);
NSLog(@"Transaction ID: %@", transactionID);
NSLog(@"Purchase Date: %@", purchaseDate);
NSLog(@"Signature: %@", signatureDecoded);

dictionaryFromPlistData: 方法为transactionReceipt 返回的数据返回正确的NSDictionary 对象,但它使用使用appStoreReceiptURL 返回的数据返回nil——因此我没有得到有效的收据!

- (NSDictionary *)dictionaryFromPlistData:(NSError **)outError {
    NSError *error;
    NSDictionary *dictionaryParsed = [NSPropertyListSerialization propertyListWithData:self
                                                                               options:NSPropertyListImmutable
                                                                                format:nil
                                                                                 error:&error];

    if (!dictionaryParsed) {

        if (error) {
            *outError = error;
        }

        return nil;
    }

    return dictionaryParsed;
}

为什么上面的代码在 iOS 7 中不起作用?

重申一下,dictionaryFromPlistData: 正确转换了transaction.transactionReceipt 返回的NSData

【问题讨论】:

    标签: ios in-app-purchase receipt


    【解决方案1】:

    iOS 7 更改了收据验证的完成方式。我经历了你失败的确切路径并得到了相同的结果。我发现来自[[NSBundle mainBundle] appStoreReceiptURL] 的收据需要与之前的transaction.transactionReceipt 不同的解码方法。

    这是来自Apple's docs的sn-p:

    最外面的部分是 PKCS #7 RFC 2315 定义的容器,其有效负载使用编码 ASN.1(抽象语法符号一),由 ITU-T X.690 定义。这 有效负载由一组收据属性组成。每张收据 属性包含类型、版本和值。

    如果您正在寻找快速解决方案,我在这里看到了成功:https://github.com/rmaddy/VerifyStoreReceiptiOS

    【讨论】:

    • 是的。我在几个应用程序中使用了 VerifyStoreReceiptiOS,它运行良好。自己实现所有这些东西将是一个痛苦的世界。请注意,您需要在项目中包含 OpenSSL(静态链接),并且还需要在捆绑包中包含 Apple's Root certificate。我会强烈推荐你观看相关的 WWDC 视频:developer.apple.com/wwdc/videos/#308
    猜你喜欢
    • 1970-01-01
    • 2016-02-13
    • 2012-07-20
    • 2017-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多