In App Purchase 个人使用总结


转载自:http://www.cocoachina.com/bbs/read.php?tid=17158


上一个项目用到了In App Purchase,发现现在大家对这个挺关注的,把上次写的总结贴出来给大家看一下,希望对大家有点帮助!

一 有关如何在程序中加入In APP Purchase 的内容参考下面的连接
http://developer.apple.com/iphone/library/documentation/NetworkingInternet/Conceptual/StoreKitGuide/Introduction/Introduction.html#//apple_ref/doc/uid/TP40008267-CH1-SW1

二 我的程序具体步骤
1 添加Storekit.Framework,编写自己的storeObsever,用于处理交易,代码如下,其中completeTransaction和failedTransaction两个函数是自定义的用来处理交易成功与失败其它的就都是SKPaymentTransactionObserver这个代理要求的。

代码
 #import  
#import  
 #import  
@interface MyStoreObserver : NSObject < SKPaymentTransactionObserver > {
}
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransacti*****:(NSArray *)transacti*****; 
-(void) PurchasedTransaction: (SKPaymentTransaction *)transaction; 
- (void) completeTransaction: (SKPaymentTransaction *)transaction; 
- (void) failedTransaction: (SKPaymentTransaction *)transaction;
 -(void) paymentQueueRestoreCompletedTransacti*****Finished: (SKPaymentTransaction *)transaction;
 -(void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransacti*****FailedWithError:(NSError *)error; 
@end 

- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransacti*****:(NSArray *)transacti*****函数用来更新transacti*****的状态
 - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransacti*****:(NSArray *)transacti***** { 
 for (SKPaymentTransaction* transaction in transacti*****)  {  
switch (transaction.transacti*****tate)  {  
case SKPaymentTransacti*****tatePurchased:  
[self completeTransaction:transaction];  
break;  
case SKPaymentTransacti*****tateFailed: 
 [self failedTransaction:transaction];  
break;  
case SKPaymentTransacti*****tateRestored: 
 break;  
default:  
break;  
}  
2 在程序中添加storeObsever,最好在applicationDidFinishLaunching中添加
MyStoreObserver *tempObserver = [[MyStoreObserver alloc] init];  
self.observer = tempObserver;  
[tempObserver release];
[[SKPaymentQueue defaultQueue] addTransactionObserver:self.observer]; 

3 发送付费请求,在相应的类中实现SKProductsRequestDelegate,别忘记定义自己产品的identifier
//请求产品信息 
 #define kMyFeatureIdentifier  yourProductIdentifiers   (你自己的产品identifiers)
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers: 
 [NSSet setWithObject: kMyFeatureIdentifier]]; 
 request.delegate = self; 
[request start];  
代理方法相关代码,如果请求成功的话就可以发送付费请求  
#pragma mark request delegate
 //!收到产品的消息 
- (void)productsRequest:(SKProductsRequest *)request didReceiveResp*****e:(SKProductsResp*****e *)resp*****e{  
SKPayment *payment = [SKPayment paymentWithProductIdentifier:kMyFeatureIdentifier]; 
 [[SKPaymentQueue defaultQueue] addPayment:payment]; 
[request autorelease];
  }
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{  
UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:@"Alert" message:[error localizedDescription]  delegate:nil c
ancelButtonTitle:NSLocalizedString(@"Close",nil)  otherButtonTitles:nil];  [alerView show]; [alerView release]; 
}

4  接下来就是Apple自己的付费相关处理了,需要做是就是点击按钮来确定付费
5 交易完成后需要向Apple验证这次交易是否成功,要不然没成功就把产品给别人的话,那就亏了,在1中可以看到当交易成功时会调用自定义的completeTransaction函数,在该函数中我们需要验证transactionReceipt 关于验证SKPaymentTransaction的transactionReceipt transactionReceipt是只有当SKPaymentTransaction完成时,即transacti*****tate 被设置为SKPaymentTransacti*****tatePurchased 或 SKPaymentTransacti*****tateRestored时才被创建,因此只有这两种状态下能去验证transactionReceipt

原始思路及具体步骤如下:  
a 从SKPaymentTranscation的实例中将transactionReceipt转化为NSString   
 NSString *temptransactionReceipt  = [[NSString alloc] initWithData:[mytransaction transactionReceipt] encoding:NSUTF8StringEncoding];

如果用NSLog的方法将其写出来显示如下,里边有很多的‘+’ { "signature" = 
"AZNZdoggtjbU/wMqZ4SSd3lgkxbWr+/zcV7Oez4io7f5oPMliKlQzWW4vj+FLsVyhjyyuPyTSugJ6m4Hrp+CjdAptGZg4iWExoyE6stltg0EfD8Ezggjg5q04ws74pMZ/0aRgjedua8dCMMqR7C8ZjojfOYU6LrFiK7qbUUiV+inMIIDUzCCAjugAwIBAgIIZRSRTdlYBLUwDQYJKoZIhvcNAQEFBQAwfzELMAkGA1UEBhMCVVMxEzARBgNVBAoMCkFwcGxlIEluYy4xJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MTMwMQYDVQQDDCpBcHBsZSBpVHVuZXMgU3RvcmUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDkwNjE1MjIwNTU2WhcNMTQwNjE0MjIwNTU2WjBkMSMwIQYDVQQDDBpQdXJjaGFzZVJlY2VpcHRDZXJ0aWZpY2F0ZTEbMBkGA1UECwwSQXBwbGUgaVR1bmVzIFN0b3JlMRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAytGMXZy3gitJ2JMKFojSDynC/9yYezyn9HBX+u3/3VcpWE2XhcgGKYqNBA1+AewOzrKO774OsokTu4qymEx10ph8UTmsZewB0ESMHBEjF7FN6/HccsQUYC3WagrHnT12HG2Ih0OAm/ZhpWzj0HS4m813LpIyo00sewMvMNL2hkcCAwEAAaNyMHAwDAYDVR0TAQH/BAIwADAfBgNVHSMEGDAWgBQ2HejinYLSARi1MmsO10MLkVhDOjAOBgNVHQ8BAf8EBAMCB4AwHQYDVR0OBBYEFKmDg/IZSMU+ElcIFMzNo36ZXyT1MBAGCiqGSIb3Y2QGBQEEAgUAMA0GCSqGSIb3DQEBBQUAA4IBAQARpJs+O2Y3gL8gHdASkrfZHFpwINd1VcB5VF5LkVpnFz63zylA/3cGIDG91b/d5NIwZjkVt4Bgvd62o/mCbzCsWiNfSKTJVFK1D78BDQoSO2oHTuQuz1BR7xzNHxQZ90zUS6ZX9SC8N3g3A1jEtAyDhZNB+CRBBXLwZdnBUeBsT9QLpjvTnekZcGTnU08zfCjGF3eBJEu9eP6WgexK1xMSp72kEOmYbn6yTi3D4YrcYx4Q3n/57VBP2en8qXWeP5oHDsLTGzLRsWdoB3VxJLrF2ivL8JS8zqC0qyac452pN6xunRuzyyfpaqzQL12BzFEe44xna2byektSbtquA5LNAAAAAA=="; "purchase-info" = "ewoJIml0ZW0taWQiID0gIjMzMDU5OTg4MCI7Cgkib3JpZ2luYWwtdHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDAwMDAwOTEyNTgiOwoJInB1cmNoYXNlLWRhdGUiID0gIjIwMDktMTAtMTQgMDY6MDY6NTQgRXRjL0dNVCI7CgkicHJvZHVjdC1pZCIgPSAiY29tLnNlbnNreS5jbmFtZXNpZ3B1cmNoYXNlY29uc3VtYWJsZSI7CgkidHJhbnNhY3Rpb24taWQiID0gIjEwMDAwMDAwMDAwOTEyNTgiOwoJInF1YW50aXR5IiA9ICIxIjsKCSJvcmlnaW5hbC1wdXJjaGFzZS1kYXRlIiA9ICIyMDA5LTEwLTE0IDA2OjA2OjU0IEV0Yy9HTVQiOwoJImJpZCIgPSAiY29tLnNlbnNreS5jc2lnbmF0dXJlYXBwIjsKCSJidnJzIiA9ICIxLjAiOwp9"; "pod" = "100"; "signing-status" = "0";}    
b然后通过Post的方法将其提交给服务器,在这里只是将transactionReceipt传给服务器,验证由服务器完成。代码如下,    
 NSString *requestStirng =[NSString stringWithFormat: @"receipt_data=%@",temptransactioReceipt];  

requestStirng = [requestStirng stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 

 NSData *postData = [NSData dataWithBytes:[requestStirng UTF8String] length:[requestStirng length]]; 
NSMutableURLRequest *connectionRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:[kURL          stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]]; 
 [connectionRequest setHTTPMethod:@"POST"];  
[connectionRequest setTimeoutInterval:120.0]; 
 [connectionRequest setCachePolicy:NSURLRequestUseProtocolCachePolicy]; 
 [connectionRequest setHTTPBody:postData];  
出现的错误,服务器用传过去的receipt_data向Apple验证,通不过,但将用NSLog的方法在后台写出的temptransactionreceipt向Apple验证能通过  错误原因  对比发现通过URL传给服务器的字符串不能很好的完成urlEncode,在里边出现的+不能自动进行编码转化,因为在Objective-C 中不能将NSString 真正的实现URL encode , 
解决方法可参考下面的地址  
http://simonwoodside.com/weblog/2009/4/22/how_to_really_url_encode/ 
 但当我用上面地址给出的方法进行编码后仍不能解决该问题,原因不明 
 解决办法:
在将transactionReceipt转化成的NSString传给服务器之前先进行转化,将里边的+转换为%2B , 将步骤a中的代码改为 
 NSString *temptransactionReceipt  = [[NSString alloc] initWithData:[mytransaction transactionReceipt] encoding:NSUTF8StringEncoding]; 
 temptransactionReceipt =  [temptransactionReceipt stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];  


6 服务器端验证相关代码 其中XML为自定义的一个类,getHeader所做的工作就是把receipt数据Post给Apple然后得到返回的结果返回  
$url = "https://buy.itunes.apple.com/verifyReceipt";/ $receipt = json_encode(array("receipt-data" => base64_encode($receipt_data)));     
$resp*****e_json = $Xml->getHeader($url, $receipt);    
 $resp*****e = json_decode($resp*****e_json['content'], true);

getHeader的代码如下  public function getHeader($url, $data)         { 
                   $ch = curl_init(); 
                    $timeout = 300; // set to zero for no timeout  
                 curl_setopt($ch, CURLOPT_URL, $url); 
         //       curl_setopt($ch, CURLOPT_ENCODING, 'gzip'); 
                  curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 1); //post到https 
                  curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                   curl_setopt($ch, CURLOPT_POST, true); 
                  curl_setopt($ch, CURLOPT_POSTFIELDS, $data);  
                 curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);  
                 curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);//跟随页面的跳转
         //       curl_setopt($ch, CURLOPT_HEADER, true); 
                  curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout); 
                   $handles = curl_exec($ch); 
                  $header = curl_getinfo($ch);
                   curl_close($ch); 
                  $header['content'] = $handles; 
                  return $header; 
        } 


把自己写的测试的例子传上来供大家参考下

你可能感兴趣的:(iPhone)