我正在为应用内购买实施收据验证服务器端,如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;
}
有什么想法吗?
答案 0 :(得分:12)
我正在写下完整的方法来帮助初学者。
从iTunes帐户生成共享密钥。
- (void)paymentQueue:(SKPaymentQueue *)队列 updatedTransactions:(NSArray *)交易
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)
String 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());