-
Notifications
You must be signed in to change notification settings - Fork 38
2019/05/01 - iOS内购填坑之旅 #37
Description
开发前准备
1.付费应用协议
因为内购都是和钱相关的,所以我们在开发之前,需要itunes Connect账号的owner,也就是所有者针对未配置过内购的新项目,签署 Paid Applications agreement(《付费应用程序协议》),这个页面一般我们也进不去。。。
- 配置内购项目
我们需要设置一个app secret(App专用共享秘钥),对于自动续期订阅的内购项目,我们需要这个秘钥去苹果做票据验证,其它模式不需要。
- Xcode工程配置
开启此选项App Store中APP的介绍界面显示内购的相关项目,关闭则不显示
项目应用
实现步骤主要包括三步:
- 首先在项目工程中加入StoreKit.framework
- 加入头文件#import <StoreKit/StoreKit.h>
- 遵守代理SKPaymentTransactionObserver,SKProductsRequestDelegate
App内请求内购项
在创建购买订单之前要向app store请求内购项,建议在购买之前完成,以减少购买时查询订单的时间
- 判断用户是否具备权限
if([SKPaymentQueue canMakePayments]) {
self.progressHUD.label.text = @"购买中,请等待...";
[self requestProductData];
}else{
self.progressHUD.label.text = @"您没有允许程序内付费...";
[self.progressHUD hideAnimated:YES afterDelay:1];
}
- 创建商品查询请求
(void)requestProductData{
SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:
[NSSet setWithObject:self.itemId]];
request.delegate = self;
[request start];
}
注意:这里的ProductIdentifiers可以查询多个商品,只需传一个product id的集合。
查询的结果我们可以在SKProductsRequestDelegate得到结果
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
{
NSArray *myProducts = response.products;
if ([myProducts count] > 0) {
SKProduct *selectedProduct = [myProducts objectAtIndex:0];
SKMutablePayment *payment = [SKMutablePayment paymentWithProduct:selectedProduct];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}else{
if (self.progressHUD) {
self.progressHUD.label.text = @"无效的产品";
[self.progressHUD hideAnimated:YES afterDelay:1];
}
}
}
请求完成和请求失败可以调用
- (void)requestDidFinish:(SKRequest *)request NS_AVAILABLE_IOS(3_0);
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error NS_AVAILABLE_IOS(3_0);
项目里面请求产品和支付还是放在一起的,可以在点击购买之前先完成商品信息的查询,然后保存下来,后面用户点击购买的时候可以节省一些请求时间,毕竟苹果的服务器确实是有些慢的。。 也可以缩短加载loading的时间。
构建支付请求
- 创建支付
SKPayment * payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
- 添加支付交易的回调的SKPaymentTransactionObserver
这个是内购项目的最重要的一个方法,我们创建了支付项之后,剩下的就看苹果服务器的了,我们就靠这个observer来接收购买过程状态。
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions NS_AVAILABLE_IOS(3_0);
switch (transaction.transactionState)
{
case SKPaymentTransactionStatePurchased://交易完成
[self completeTransaction:transaction];
break;
case SKPaymentTransactionStateFailed://交易失败
[self failedTransaction:transaction];
break;
case SKPaymentTransactionStateRestored://已经购买过该商品
[self restoreTransaction:transaction];
break;
case SKPaymentTransactionStatePurchasing: //商品添加进列表
NSLog(@"商品添加进列表");
break;
default:
break;
}
注意:我们需要在适时的时候调用[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
否则苹果会以为这个事务一直没有完成,每次启动都会重复执行updatedTransactions方法。
对于自动订阅模式,我们需要给后端提供SKPaymentTransaction里面的一些信息,来做唯一标识,对于首次购买的用户SKPaymentTransaction里面的originalTransaction是空的,对于续费的用户才会有值,这样我们就可以区分首次购买和续费。
验证票据
我们app采用的服务器验证,获取票据信息后,通过base64编码以后上传至信任的服务器,由服务器完成与App Store的验证,
验证地址
沙盒环境 https://sandbox.itunes.apple.com/verifyReceipt;
正式环境 https://buy.itunes.apple.com/verifyReceipt;
NSURL *receiptUrl = [[NSBundle mainBundle] appStoreReceiptURL];
NSData *receiptData = [NSData dataWithContentsOfURL:receiptUrl];
NSString *encodingStr = [receiptData base64EncodedString];
沙盒账号是什么
iOS应用里面用到了苹果应用内付费(IAP)功能,在项目上线前一定要进行功能测试。测试肯定是需要的,何况这个跟money有关。。。不仅仅是要测试,我们还要进行大量的测试,这样才能发现内购存在的一些问题,比如漏单,支付失败等问题。开发完成了之后,如何进行测试呢?难道我测试个内购功能要自己掏钱?就算是公司掏钱,但是苹果要抽掉30%,想想点下购买的时候都会手抖。。。
苹果当然没这么坑了,测试内购,苹果提供了沙盒账号的方式。这个沙盒账号其实是虚拟的AppleID,在开发者账号后台的iTune Connect上配置了之后就能使用沙盒账号测试内购,有了沙盒账号,我们就可以任性挥霍啦。
IAP内购的一些坑
对于自动订阅模式,要在每次启动的时候都要添加observer [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
这主要是为了防止漏单的问题,在每次启动的时候会去检测是否有未完成的事务,然后再把相关信息上传到服务器。所以我们需要把orderId本地化,之后无论是首次购买还是续费,还有服务器续费未收到通知的情况,都可以防止漏单的问题。



