我正在使用以下方法来获取收据数据:
// 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:
方法为NSDictionary
返回的数据返回正确的transactionReceipt
对象,但它使用nil
返回的数据返回appStoreReceiptURL
- 并且我很自然地没有收到有效的收据!
- (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:
正确转换NSData
返回的transaction.transactionReceipt
。
答案 0 :(得分:4)
iOS 7改变了收据验证的方式。我经历了你失败的确切路径并获得了相同的结果。我发现来自[[NSBundle mainBundle] appStoreReceiptURL]
的收据需要使用与之前的transaction.transactionReceipt
不同的解码方法。
以下是Apple's docs的摘要:
最外面的部分是PKCS#7 容器,由RFC 2315定义,其有效负载使用编码 ASN.1(抽象语法表示法一),由ITU-T X.690定义。该 有效负载由一组接收属性组成。每张收据 attribute包含类型,版本和值。
如果您正在寻找快速解决方案,我在这里看到了成功:https://github.com/rmaddy/VerifyStoreReceiptiOS