博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
iOS开发之应用内支付IAP全部流程
阅读量:4562 次
发布时间:2019-06-08

本文共 6261 字,大约阅读时间需要 20 分钟。

应用内支付:

大致的业务逻辑是这样的。

1.向服务器请求商品订单号码以及ituns配置的商品ID

2.发起IAP购买请求
3.购买流程结束后, 向服务器发起验证凭证以及支付结果的请求
4.验证流程结束完成购买流程。

流程

  1. 首先打开itunesconnect看一下有没有配置用户账户等信息, 点击 『协议, 税务与银行卡业务』进去配置就可以。
  2. 创建App或者选择已经有的App, 点击进入详情之后, 点击App内购项目这一选项
    屏幕快照 2015-09-24 上午11.53.06.png
    进入, 点击右上角的CreateNew按钮进行创建。 如果已经有的话可以点击进详情编辑内容。
    消耗型项目
    对于消耗型 App 内购买项目,用户每次下载时都必须进行购买。一次性服务通常属于消耗型项目,例如钓鱼 App 中的鱼饵。
    非消耗型项目
    对于非消耗型 App 内购买项目,用户仅需要购买一次。不会过期或随使用而减少的服务通常为非消耗型项目,例如游戏 App 的新跑道。
    自动续订订阅
    通过自动续订订阅,用户可以购买指定时间期限内的更新和动态内容。除非用户取消选择,否则订阅(例如杂志订阅等)会自动续订。
    免费订阅
    免费订阅是开发人员在“报刊杂志”中推广其内容的绝佳方式。用户注册免费订阅后,此订阅内容在与该用户 Apple ID 相关联的所有设备上可用。免费订阅不会过期,并且仅能在位于“报刊杂志”类别中的 App 中提供。
    非续订订阅
    非续订订阅允许有时限性的营销服务。对于 App 内购买项目中的限时访问内容,就需使用非续订订阅。例如,导航 App 中语音导航功能的一周订阅,或者年度订阅已存档的视频或音频的在线目录。

通常我们都选择消耗形项目, 如果你要按月付费之类的就要选择非续订订阅之类的喽。

选择消耗形项目, 然后继续,输入商品的名称, 产品的ID(自定义), 在下边添加语言的地方添加一下商品的描述信息, 然后上传一张商品界面的截图(这里可以随便, 影响不是很大)保存就可以了。

屏幕快照 2015-09-24 上午11.57.16.png

这是我们创建的结果, 右边的准备好去提交的提示是用于你提交App审核的时候同时提交一下内购项目的审核, 在应用程序的附加信息里边。必须要提交- - 。 这里的产品ID就是后期用于请求商品的商品ID。这时候就可以开始测试了。

代码

  1. 导入 StoreKit.Framework 这个框架

    并在VC中

    #import 
  2. 实现SKPaymentTransactionObserver, SKProductsRequestDelegate这两个代理

3.在ViewDidLoad中添加购买监听

// 添加购买监听    [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
  1. 开始模拟购买, 要先检测是否允许内购。
// 检测是否允许内购        if([SKPaymentQueue canMakePayments]){            [self requestProductData:productID];        }else{            NSLog(@"不允许程序内付费"); }
//请求商品- (void)requestProductData:(NSString *)type{    NSLog(@"请求商品"); [SVProgressHUD showWithStatus:@"正在请求商品信息" maskType:SVProgressHUDMaskTypeGradient]; NSArray *product = [[NSArray alloc] initWithObjects:type, nil]; NSSet *nsset = [NSSet setWithArray:product]; // 请求动作 SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset]; request.delegate = self; [request start]; }
//收到产品返回信息- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{    NSLog(@"收到了请求反馈");    NSArray *product = response.products; if([product count] == 0){ NSLog(@"没有这个商品"); return; } NSLog(@"productID:%@", response.invalidProductIdentifiers); NSLog(@"产品付费数量:%ld",[product count]); SKProduct *p = nil; // 所有的商品, 遍历招到我们的商品 for (SKProduct *pro in product) { NSLog(@"%@", [pro description]); NSLog(@"%@", [pro localizedTitle]); NSLog(@"%@", [pro localizedDescription]); NSLog(@"%@", [pro price]); NSLog(@"%@", [pro productIdentifier]); if([pro.productIdentifier isEqualToString:productID]) { p = pro; } } SKPayment * payment = [SKPayment paymentWithProduct:p]; NSLog(@"发送购买请求"); [SVProgressHUD showWithStatus:@"正在发送购买请求" maskType:SVProgressHUDMaskTypeGradient]; [[SKPaymentQueue defaultQueue] addPayment:payment]; }
//请求失败- (void)request:(SKRequest *)request didFailWithError:(NSError *)error {    NSLog(@"商品信息请求错误:%@", error); [SVProgressHUD showErrorWithStatus:[error localizedDescription]]; } - (void)requestDidFinish:(SKRequest *)request { NSLog(@"请求结束"); [SVProgressHUD dismiss]; }
//监听购买结果- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction {    for(SKPaymentTransaction *tran in transaction){ switch (tran.transactionState) { case SKPaymentTransactionStatePurchased: NSLog(@"交易完成"); [SVProgressHUD showSuccessWithStatus:@"交易完成"]; break; case SKPaymentTransactionStatePurchasing: NSLog(@"商品添加进列表"); [SVProgressHUD showWithStatus:@"正在请求付费信息" maskType:SVProgressHUDMaskTypeGradient]; break; case SKPaymentTransactionStateRestored: NSLog(@"已经购买过商品"); [SVProgressHUD showErrorWithStatus:@"已经购买过商品"]; break; case SKPaymentTransactionStateFailed: NSLog(@"交易失败"); [SVProgressHUD showErrorWithStatus:@"交易失败, 请重试"]; break; default: [SVProgressHUD dismiss]; break; } } }

在交易结束的时候, 要向服务器做凭证的验证, 因为要链接苹果的服务器, 所以这里的网络请求可能稍慢一点。 所以建议做一下本地化。

//交易结束- (void)completeTransaction:(SKPaymentTransaction *)transaction{    NSLog(@"交易结束");    [SVProgressHUD dismiss];    NSString * productIdentifier = [[NSString alloc] initWithData:transaction.transactionReceipt encoding:NSUTF8StringEncoding]; NSString * receipt = [[productIdentifier dataUsingEncoding:NSUTF8StringEncoding] base64EncodedString]; if ([productIdentifier length] > 0) { // 向自己的服务器验证购买凭证 // https://sandbox.itunes.apple.com/verifyReceipt // receipt-data } [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; }

最后在dealloc中移除监听

- (void)dealloc{    // 移除监听    [[SKPaymentQueue defaultQueue] removeTransactionObserver:self];}

自己了解一下流程很重要, 顺便附上服务器端的验证代码

$receipt) ); $ch = curl_init($endpoint); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $postData); curl_setopt ($ch, CURLOPT_SSL_VERIFYPEER, 0); //这两行一定要加,不加会报SSL 错误 curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0); $response = curl_exec($ch); $errno = curl_errno($ch); $errmsg = curl_error($ch); curl_close($ch); //判断时候出错,抛出异常 if ($errno != 0) { throw new Exception($errmsg, $errno); } $data = json_decode($response); //判断返回的数据是否是对象 if (!is_object($data)) { throw new Exception('Invalid response data'); } //判断购买时候成功 if (!isset($data->status) || $data->status != 0) { throw new Exception('Invalid receipt'); } //返回产品的信息 return array( 'quantity' => $data->receipt->quantity, 'product_id' => $data->receipt->product_id, 'transaction_id' => $data->receipt->transaction_id, 'purchase_date' => $data->receipt->purchase_date, 'app_item_id' => $data->receipt->app_item_id, 'bid' => $data->receipt->bid, 'bvrs' => $data->receipt->bvrs ); } //获取 App 发送过来的数据,设置时候是沙盒状态 $receipt = $_GET['data']; $isSandbox = true; //开始执行验证 try { $info = getReceiptData($receipt, $isSandbox); // 通过product_id 来判断是下载哪个资源 switch($info['product_id']){ case 'com.application.xxxxx.xxxx': Header("Location:xxxx.zip"); break; } } //捕获异常 catch(Exception $e) { echo 'Message: ' .$e->getMessage(); } ?>

在我们公司的测试服务器中,我们会连接苹果的测试服务器https://sandbox.itunes.apple.com/verifyReceipt验证。

在我们部署在线上的正式服务器中,我们会连接苹果的正式服务器https://buy.itunes.apple.com/verifyReceipt验证。
我们提交给苹果审核的是正式版,我们以为苹果审核时,我们应该连接苹果的线上验证服务器来验证购买凭证。结果我理解错了,苹果在审核App时,只会在sandbox环境购买,其产生的购买凭证,也只能连接苹果的测试验证服务器。但是审核的app又是连接的我们的线上服务器。所以我们这边的服务器无法验证通过IAP购买,造成我们app的又一次审核被拒。
解决方法是判断苹果正式验证服务器的返回code,如果是21007,则再一次连接测试服务器进行验证即可。苹果的上有对返回的code的详细说明 (引自 唐巧, 上边有文章地址).

文/WildDylan(简书作者)
原文链接:http://www.jianshu.com/p/e9ae4cece800
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。

转载于:https://www.cnblogs.com/lys-iOS-study/p/5684435.html

你可能感兴趣的文章
Maven多模块项目搭建
查看>>
redis列表list
查看>>
雷林鹏分享: C# 简介
查看>>
ORA-12505: TNS: 监听程序当前无法识别连接描述符中所给出的SID等错误解决方法
查看>>
实用类-<Math类常用>
查看>>
构建之法阅读笔记之四
查看>>
10.15习题2
查看>>
Windows Server 2008 R2 备份与恢复详细实例
查看>>
Ubuntu上kubeadm安装Kubernetes集群
查看>>
关于java学习中的一些易错点(基础篇)
查看>>
MFC的多国语言界面的实现
查看>>
四则运算个人项目 最终版
查看>>
java线程系列---java5中的线程池
查看>>
SQL表连接
查看>>
新秀系列C/C++经典问题(四)
查看>>
memset函数具体说明
查看>>
经常使用的android弹出对话框
查看>>
确保新站自身站点设计的合理性的六大注意点
查看>>
promise
查看>>
Go 网络编程笔记
查看>>