iOS游戏开发三:苹果内支付实现 In-app

iOS游戏开发三:苹果内支付实现 In-app

首先你必须熟悉内支付的流程,可以到网上搜搜看。

前几天因为需要做了个苹果的内支付,当中遇到了不少苦头,感觉网上的各种博客对内支付这一块都是点到即止,没有真真正正实现自己的需求。正所谓辛苦就有所得,通过东接西搬,终于内力小成,特与大家分享一下自己的经验。这里我假设你已经把商品的ID什么的都已经注册成功了,测试账号也有了。

下面直接贴代码了~~~~

[objc]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. //  
  2. //  IAPHelperViewController.h  
  3. //    
  4.   
  5. #import <UIKit/UIKit.h>  
  6. #import <StoreKit/StoreKit.h>  
  7.   
  8. @interface IAPHelperViewController : UIViewController<SKProductsRequestDelegate,SKPaymentTransactionObserver>  
  9. {  
  10.     NSString* kMyInAppIdentifier;  
  11.     BOOL receiptValid;  
  12.     UIActivityIndicatorView* spinner;  
  13. }  
  14.   
  15. + (IAPHelperViewController *) sharedIAPHelper;  
  16.   
  17. - (void) requestProUpgradeProductData;  
  18.   
  19. - (void) requestProductData;  
  20.   
  21. - (void) buyGolds:(int)buyType;  
  22.   
  23. - (BOOL) canInAppPayment;  
  24.   
  25. - (void) paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions;  
  26.   
  27. - (void) purchasedTransaction:(SKPaymentTransaction *)transaction;  
  28.   
  29. - (void) completeTransaction:(SKPaymentTransaction *)transaction;  
  30.   
  31. - (void) failedTransaction:(SKPaymentTransaction *)transaction;  
  32.   
  33. - (void) paymentQueueRestoreCompletedTransactionsFinished: (SKPaymentTransaction *)transaction;  
  34.   
  35. - (void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error;  
  36.   
  37. - (void) restoreTransaction:(SKPaymentTransaction *)transaction;  
  38.   
  39. - (void) recordTransaction:(SKPaymentTransaction *)product;  
  40.   
  41. - (void) verifyReceiptFromMyServer:(SKPaymentTransaction *)transaction;  
  42.   
  43. @end  

[objc]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. //  
  2. //  IAPHelperViewController.m  
  3. //    
  4.   
  5. #import "IAPHelperViewController.h"  
  6. #include "cocos2d.h"  
  7. using namespace cocos2d;  
  8.   
  9. const static int IAP1p99 = flag1;//主要是标记用户点击了那个商品  
  10. const static int IAP2p99 = flag2;  
  11. const static int IAP3p99 = flag3;  
  12. const static int IAP4p99 = flag4;  
  13. const static int IAP5p99 = flag5;  
  14. #define MyServerURL        @"your server address , not apple"  
  15. #define ProductOne         @"product  1 id"  
  16. #define ProductThree       @".......  2 .."  
  17. #define ProductFive        @".......  3 .."  
  18. #define ProductFifteen     @".......  4 .."  
  19. #define ProductFifty       @"......   5 .."  
  20. #define MyFrint            NSLog(@"\n%s %d\n",__FUNCTION__, __LINE__)  
  21.   
  22.   
  23. @interface IAPHelperViewController ()  
  24.   
  25. @end  
  26.   
  27. @implementation IAPHelperViewController  
  28.   
  29. //定义单例变量  
  30. static IAPHelperViewController* singleton = nil;  
  31. //单例模式  
  32. + (IAPHelperViewController *) sharedIAPHelper  
  33. {  
  34.     MyFrint;  
  35.     if (singleton == nil) {  
  36.         singleton = [[IAPHelperViewController alloc] initWithNibName:nil bundle:nil];  
  37.     }  
  38.     return singleton;  
  39. }  
  40. //初始化 这里应该根据自己的情况初始化 我用的是C++写的界面 OC不鸟~~~~~~  
  41. - (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil  
  42. {  
  43.     MyFrint;    
  44.     self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];  
  45.     if (self) {  
  46.         receiptValid = NO;  
  47.     }  
  48.     return self;  
  49. }  
  50. //加载视图  
  51. - (void) viewDidLoad  
  52. {  
  53.     MyFrint;  
  54.     [super viewDidLoad];  
  55.     self.view.backgroundColor = [UIColor orangeColor];  
  56. }  
  57. //请求升级数据  
  58. - (void) requestProUpgradeProductData  
  59. {  
  60.     MyFrint;  
  61.     NSSet* productIdentifiers = [NSSet setWithObjects:ProductOne, ProductThree, ProductFive, ProductFifteen, ProductFifty, nil nil];  
  62.     SKProductsRequest* request = [[SKProductsRequest alloc] initWithProductIdentifiers:productIdentifiers];  
  63.     request.delegate = self;  
  64.     [request start];  
  65. }  
  66. //点击商品按钮  
  67. - (void) buyGolds:(int)buyType  
  68. {  
  69.     MyFrint;//根据点击标记 找到对应的商品IDs  
  70.     switch (buyType) {  
  71.         case IAP1p99: { kMyInAppIdentifier = ProductOne;     break; }  
  72.         case IAP2p99: { kMyInAppIdentifier = ProductThree;   break; }  
  73.         case IAP3p99: { kMyInAppIdentifier = ProductFive;    break; }  
  74.         case IAP4p99: { kMyInAppIdentifier = ProductFifteen; break; }  
  75.         case IAP5p99: { kMyInAppIdentifier = ProductFifty;   break; }  
  76.         defaultbreak;  
  77.     }  
  78.     [[SKPaymentQueue defaultQueue] addTransactionObserver:self];  
  79.     if ([self canInAppPayment]) {  
  80.         NSLog(@"允许应用内支付");  
  81.         //首先向AppStore请求恢复交易  
  82.         [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];  
  83.     } else {  
  84.         NSLog(@"不允许应用内支付");  
  85.     }  
  86. }  
  87. //判断是否可以应用内支付  
  88. - (BOOL) canInAppPayment  
  89. {  
  90.     MyFrint;//你应该根据是否想让越狱的iOS设备允许内支付   
  91.     if ([[NSFileManager defaultManager] fileExistsAtPath:@"/Applications/Cydia.app"]){  
  92.         NSLog(@"Jailbroken detected!");  
  93.         return NO;  
  94.     }  
  95.     if ([SKPaymentQueue canMakePayments]) {  
  96.         return YES;  
  97.     } else {  
  98.         return NO;  
  99.     }  
  100. }  
  101. //输入正确的帐号后进入 (如果是测试 必须必须使用你注册的沙河账号和密码)  
  102. - (void) paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentTransaction *)transaction  
  103. {  
  104.     MyFrint;  
  105.     [self requestProductData];  
  106. }  
  107. //请求购买的商品信息  
  108. - (void) requestProductData  
  109. {  
  110.     MyFrint;  
  111.     NSSet * set = [NSSet setWithObjects:kMyInAppIdentifier, nil nil];//可以添加多个商品ID  
  112.     SKProductsRequest* request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];  
  113.     request.delegate = self;  
  114.     [request start];  
  115. }  
  116. #pragma mark SKProductsRequestDelegate 请求协议 ----------------------------------------------------------  
  117. //收到产品信息  
  118. - (void) productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response  
  119. {  
  120.     //    NSArray *myProduct = response.products;  
  121.     //    NSLog(@"产品付费数量: %d", [myProduct count]);  
  122.     //    NSLog(@"产品Product ID:%@",response.invalidProductIdentifiers);  
  123.     //    SKPayment *payment = nil;  
  124.     //    // populate UI  
  125.     //    for(SKProduct *product in myProduct)  
  126.     //    {  
  127.     //        NSLog(@"\n\nproduct info");  
  128.     //        NSLog(@"SKProduct 描述信息%@", [product description]);  
  129.     //        NSLog(@"产品标题 %@" , product.localizedTitle);  
  130.     //        NSLog(@"产品描述信息: %@" , product.localizedDescription);  
  131.     //        NSLog(@"价格: %@" , product.price);  
  132.     //        NSLog(@"Product id: %@\n\n" , product.productIdentifier);  
  133.     //        payment = [SKPayment paymentWithProduct:product];  
  134.     //    }  
  135.     MyFrint;  
  136.     SKPayment* payment = [SKPayment paymentWithProduct:[response.products lastObject]];  
  137.     NSLog(@"\nPayment:\n productIdentifier=%@, \nrequestData=%@, \nquanlity=%d, \n",payment.productIdentifier,[payment.requestData description],payment.quantity);  
  138.     [[SKPaymentQueue defaultQueue] addPayment:payment];  
  139.     [request release];//请求已经生效  
  140. }  
  141. //请求错误信息  
  142. - (void) request:(SKRequest *)request didFailWithError:(NSError *)error  
  143. {  
  144.     MyFrint;  
  145.     UIAlertView *alerView =  [[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Alert",NULL)  
  146.                                                         message:[error localizedDescription]  
  147.                                                        delegate:nil  
  148.                                               cancelButtonTitle:NSLocalizedString(@"Close",nil)  
  149.                                               otherButtonTitles:nil];  
  150.     [alerView show];  
  151.     [alerView release];  
  152.     [request release];//请求失效  
  153. }  
  154. - (void) purchasedTransaction:(SKPaymentTransaction *)transaction  
  155. {  
  156.     MyFrint;  
  157. }  
  158. - (void) requestDidFinish:(SKRequest *)request  
  159. {  
  160.     MyFrint;  
  161. }  
  162. //然后当用户输入正确的appStore帐号密码后进入(再次说明 如果是测试 必须是你注册的测试账号 不能使用真实的AppleID 否则后果~~~~)  
  163. //方法在新交易被创建或更新时都会被调用  
  164. - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions  
  165. {  
  166.     MyFrint;  
  167.     for ( SKPaymentTransaction* transaction in transactions )  
  168.     {  
  169.         switch (transaction.transactionState)  
  170.         {  
  171.             case SKPaymentTransactionStatePurchased:  
  172.             {//交易完成  
  173.                 [self completeTransaction:transaction];  
  174.             }  
  175.                 break;  
  176.             case SKPaymentTransactionStateFailed:  
  177.             {//交易失败  
  178.                 [self failedTransaction:transaction];  
  179.             }  
  180.                 break;  
  181.             case SKPaymentTransactionStateRestored:  
  182.             {//已经购买过该商品  
  183.                 [self restoreTransaction:transaction];  
  184.             }  
  185.             case SKPaymentTransactionStatePurchasing:  
  186.             {//商品添加进列表  
  187.                 NSLog(@"商品添加进列表==");  
  188.                 break;  
  189.             }  
  190.             default:  
  191.                 break;  
  192.         }  
  193.     }  
  194. }  
  195. //玩家等待 这里我想加个转动条 但没成功OC不鸟呀  
  196. - (void) activityIndicatorRun  
  197. {  
  198.     spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];  
  199.     spinner.color = [UIColor whiteColor];  
  200.     spinner.frame = CGRectMake(100180.0f137.0f137.0f);  
  201.     [spinner startAnimating];  
  202. }  
  203. //玩家结束等待  
  204. - (void) activityIndicatorStop  
  205. {  
  206.     [spinner stopAnimating];  
  207. }  
  208. //observer在用户成功购买后提供相应的product  
  209. - (void)completeTransaction:(SKPaymentTransaction *)transaction  
  210. {  
  211.     MyFrint;  
  212.     [self activityIndicatorRun];  
  213.     [self verifyReceiptFromMyServer:transaction];//这个方法是内支付最重要的方法  
  214.     [self activityIndicatorStop];  
  215.     if (receiptValid) {  
  216.         [self recordTransaction:transaction];  
  217.         //提示服务器刷新数据  ---  
  218.         CCNotificationCenter::sharedNotificationCenter()->postNotification(kGNetworkNotificationName_Shop_BuyCredit_Successed, NULL);  
  219.     } else {  
  220.         [self failedTransaction:transaction];  
  221.     }  
  222.     [[SKPaymentQueue defaultQueue] finishTransaction:transaction];  
  223. }  
  224. //处理还原购买  结束交易  
  225. - (void) restoreTransaction: (SKPaymentTransaction *)transaction  
  226. {  
  227.     MyFrint;  
  228.     [[SKPaymentQueue defaultQueue] finishTransaction:transaction];  
  229. }  
  230. //处理失败购买 结束交易  
  231. - (void) failedTransaction: (SKPaymentTransaction *)transaction  
  232. {  
  233.     MyFrint;  
  234.     if (transaction.error.code != SKErrorPaymentCancelled) {  
  235.         NSLog(@"购买失败");  
  236.     }   
[objc]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <span style="white-space:pre">    </span>//根据项目的实际运行情况看 下面的完全多余.  
[objc]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1. <pre code_snippet_id="105137" snippet_file_name="blog_20131209_2_9929406" name="code" class="objc">    //else {  
  2.     //    NSLog(@"用户取消购买");  
  3.     //}  

 
[objc]  view plain  copy
 print ? 在CODE上查看代码片 派生到我的代码片
  1.     [[SKPaymentQueue defaultQueue] finishTransaction:transaction];  
  2. }  
  3. //取消登陆帐号密码操作  
  4. - (void) paymentQueue:(SKPaymentQueue *) paymentQueue restoreCompletedTransactionsFailedWithError:(NSError *)error  
  5. {  
  6.     MyFrint;  
  7. }  
  8. //用户成功购买  
  9. - (void) recordTransaction:(SKPaymentTransaction *)product  
  10. {  
  11.     MyFrint;  
  12.     UIAlertView* view = [[UIAlertView alloc] initWithTitle:@"购买结果" message:@"购买成功" delegate:nil cancelButtonTitle:@"确定" otherButtonTitles: nil nil];  
  13.     [view show];  
  14.     [view release];  
  15. }  
  16. //向服务器请求验证  
  17. - (void) verifyReceiptFromMyServer:(SKPaymentTransaction *)transaction  
  18. {  
  19.     MyFrint;  
  20.     //初始化为合法  
  21.     if ([transaction.payment.productIdentifier isEqualToString:kMyInAppIdentifier]) {  
  22.         //base64 encode the receipt data for sending  
  23.         if ([transaction.transactionReceipt base64Encoding] != nil) {  
  24.             //将数据http post请求发送到我的服务器  
  25.             //data=base64(json(post))  
  26.               
  27.             //字典内容  
  28.             NSDictionary* postDict = [[NSDictionary alloc] initWithObjectsAndKeys:@"ios",@"mode",  
  29.                                       @"verify",@"method",  
  30.                                       [NSDictionary dictionaryWithObjectsAndKeys:[self base64Encode:transaction.transactionReceipt],@"receipt",@"YES",@"test", nil nil],@"params",  
  31.                                       @"1136",@"uid", nil nil];  
  32.             //字典转化为json数据  
  33.             NSError* error = nil;  
  34.             NSData* jsonData = [NSJSONSerialization dataWithJSONObject:postDict options:NSJSONWritingPrettyPrinted error:&error];  
  35.             if([jsonData length]>0 && error == nil){  
  36.                   
  37.             }else if([jsonData length] == 0 && error == nil){  
  38.                 NSLog(@"No data returned after serialization.");  
  39.                 receiptValid = NO;  
  40.             }else if(error != nil){  
  41.                 NSLog(@"An error happened = %@",error);  
  42.                 receiptValid = NO;  
  43.             }  
  44.             //json数据base64  
  45.             NSString* base64 = [self base64Encode:jsonData];  
  46.             if ([base64 length]==0 || [base64 isEqualToString:@""]) {  
  47.                 NSLog(@"Base64 error");  
  48.                 receiptValid = NO;  
  49.             }  
  50.               
  51.             NSURL* url = [NSURL URLWithString:MyServerURL];  
  52.             NSMutableURLRequest* theRequest = [NSMutableURLRequest requestWithURL:url];  
  53.               
  54.             [theRequest setHTTPMethod:@"POST"];  
  55.             [theRequest setValue:[NSString stringWithFormat:@"%d", [jsonData length]] forHTTPHeaderField:@"Content-Length"];  
  56.             [theRequest setHTTPBody:[[NSString stringWithFormat:@"data=%@", base64] dataUsingEncoding:NSUTF8StringEncoding]];  
  57.               
  58.               
  59.             //发送同步请求  因为你将使用自己的服务器返回的数据来判断是否成功  
  60.             NSURLResponse* response = [[NSURLResponse alloc] init];  
  61.             NSError*       myerror =  [[NSError alloc] init];  
  62.             NSMutableData* receiveData = (NSMutableData *)[NSURLConnection sendSynchronousRequest:theRequest returningResponse:&response error:&myerror];  
  63.               
  64.             //NSURLConnection* theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];  
  65.               
  66.             //接收到服务器返回的数据  
  67.             NSString *receiptStatus = [[NSString alloc] initWithBytes: [receiveData mutableBytes] length:[receiveData length] encoding:NSUTF8StringEncoding];  
  68.             NSLog(@"\nreceiptStatus=%@",receiptStatus);  
  69.             NSString* str = @"\"status\":0";  
  70.               
  71.             if ([receiptStatus length]==0 || [receiptStatus isEqualToString:@""]) {  
  72.                 receiptValid = NO;  
  73.             }  
  74.               
  75.             if ([receiptStatus rangeOfString:str].location != NSNotFound) {  
  76.                 NSLog(@"Yes Yes Yes!!!");  
  77.                 receiptValid = YES;  
  78.             } else {  
  79.                 receiptValid = NO;  
  80.             }  
  81.             [receiptStatus release];  
  82.             [myerror release];  
  83.             [response release];  
  84.             [postDict release];  
  85.         } else {  
  86.             NSLog(@"当向服务器发送验证数据时出错!!!");  
  87.             receiptValid = NO;  
  88.         }  
  89.     }  
  90.     else  
  91.     {  
  92.         NSLog(@"无效的商品ID");  
  93.         receiptValid = NO;  
  94.     }  
  95. }  
  96. //将NSData64位编码  
  97. - (NSString*) base64Encode:(NSData *)theData  
  98. {  
  99.     const uint8_t* input = (const uint8_t*)[theData bytes];  
  100.     NSInteger length = [theData length];  
  101.       
  102.     static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";  
  103.       
  104.     NSMutableData* data = [NSMutableData dataWithLength:((length + 2) / 3) * 4];  
  105.     uint8_t* output = (uint8_t*)data.mutableBytes;  
  106.       
  107.     NSInteger i;  
  108.     for (i=0; i < length; i += 3) {  
  109.         NSInteger value = 0;  
  110.         NSInteger j;  
  111.         for (j = i; j < (i + 3); j++) {  
  112.             value <<= 8;  
  113.               
  114.             if (j < length) {  
  115.                 value |= (0xFF & input[j]);  
  116.             }  
  117.         }  
  118.           
  119.         NSInteger theIndex = (i / 3) * 4;  
  120.         output[theIndex + 0] =                    table[(value >> 18) & 0x3F];  
  121.         output[theIndex + 1] =                    table[(value >> 12) & 0x3F];  
  122.         output[theIndex + 2] = (i + 1) < length ? table[(value >> 6)  & 0x3F] : '=';  
  123.         output[theIndex + 3] = (i + 2) < length ? table[(value >> 0)  & 0x3F] : '=';  
  124.     }  
  125.       
  126.     return [[[NSString alloc] initWithData:data encoding:NSASCIIStringEncoding] autorelease];  
  127. }  
  128. //收到内存警告释放资源  
  129. - (void) didReceiveMemoryWarning  
  130. {  
  131.     [super didReceiveMemoryWarning];  
  132.     // Dispose of any resources that can be recreated.  
  133. }  
  134. //回收内存  
  135. -(void) dealloc  
  136. {  
  137.     [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];//解除监听  
  138.     [spinner release]; spinner = nil;  
  139.     [super dealloc];  
  140. }  
  141. @end  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值