很早之前想写一写这个,但是因为写起来太繁琐,所以就一直没有写下去的欲望。今天一天坐着发呆,刚好抽空把这个总结一下。
这里主要以单机应用为例来开发,因为如果是和服务器交互的话,也就是多了服务器的验证过程,当然都有服务器了,为什么不去做个开关去用支付宝微信呢?O(∩_∩)O哈哈~
想使用In-App Purchase(以下简称IAP)完成App内付费前,先去看看是必须要用IAP支付,还是需要用支付宝或者微信支付
在苹果制定的游戏规则中,所有在App内提供的服务需要付费时,都应当使用IAP,比如软件功能、游戏道具;所有在App外提供的服务需要付费时,都应使用其他支付方式,比如支付宝
在IAP里,可以出售:
- 数字内容:比如游戏关卡解锁、游戏道具等;
- 软件功能:如各种扩展features;
而比如实物,例如美团外卖的饭、公司的玩偶等都是不可以使用IAP支付,而需要去接入支付宝、微信支付这类支付服务。
当然如果你非要想去用IAP去兑换实物,那可以先用IAP去兑换虚拟货币,比如QQ币,然后再用QQ币去购买。
顺便说一下如果你想用线下自己的兑换码去兑换购买的那些东西,这如果被审核发现会被拒的。
一、准备工作
首先去iTunes Connect,点击Agreements, Tax, and Banking,填写Contact Info, Bank Info, Tax Info。如果填过就不用再填了。
然后去对应的app详情
,选择功能
标签,然后添加需要的支付类型。
每个类型区别说明的很清楚。
- 消耗品(Consumable products):比如游戏内金币等。
- 不可消耗品(Non-consumable products):简单来说就是一次购买,终身可用(用户可随时从App Store restore)。
- 自动更新订阅品(Auto-renewable subscriptions):和不可消耗品的不同点是有失效时间。比如一整年的付费周刊。在这种模式下,开发者定期投递内容,用户在订阅期内随时可以访问这些内容。订阅快要过期时,系统将自动更新订阅(如果用户同意)。
- 非自动更新订阅品(Non-renewable subscriptions):一般使用场景是从用户从IAP购买后,购买信息存放在自己的开发者服务器上。失效日期/可用是由开发者服务器自行控制的,而非由App Store控制,这一点与自动更新订阅品有差异。
- 免费订阅品(Free subscriptions):在Newsstand中放置免费订阅的一种方式。免费订阅永不过期。只能用于Newsstand-enabled apps。
最常用的就是消耗品
,创建名字,id唯一,然后下面填写介绍就行了。
而单机用户如果想可以让账号换设备了恢复,而自己又不想搭建服务器,并且一次买断的就可以创建不可消耗品
,如果不是买断服务,那就可以创建自动更新订阅品
。
二、内容托管上传In-app purchase content
托管内容仅限于针对不可消耗品,如果你不需要这个功能,可以跳过这部分。如果你想使用换账号恢复功能,自己又不想搭建服务器,那可以开启苹果的内容托管。开启后,会显示等待上传。
在项目创建新的target
类型选择In-app purchase content
创建好之后可以修改product id,修改为自己在后台创建的产品ID
然后可以选择这个target 》 archive打包之后上传到App Store,上传的时候会让你选择上传到哪个app,选择之后上传即可
上传完成之后,去对应的那个详情,在托管选项里面就会多出来一个pkg的包
三、代码使用
封装了一下支付和不可消耗品
的恢复,没有服务器验证的步骤。如果是搭建的服务器的话,那最好就是去服务器验证,可以参考这个文章:In-App Purchase Walk Through
.h文件
#import <Foundation/Foundation.h>
typedef void(^paySuccess)(BOOL paySuccess);
typedef void(^restoreSuccess)(BOOL restoreSuccess);
@interface HDPayTools : NSObject
///支付对应的productID
- (void)startPayWithProductID:(NSString *)productID withCompleteHandler:(paySuccess)paySuccessHandler;
///恢复
- (void)restoreWithCompleteHandler:(restoreSuccess)restoreSuccessHandler;
@end
.m文件
#import "HDPayTools.h"
#import <StoreKit/StoreKit.h>
#import <SVProgressHUD.h>
@interface HDPayTools() <SKProductsRequestDelegate,SKPaymentTransactionObserver>
@property (copy, nonatomic) NSString *m_productID;
@property (copy, nonatomic) paySuccess paySuccessHandler;
@property (copy, nonatomic) restoreSuccess restoreSuccessHandler;
@end
@implementation HDPayTools
-(void)dealloc{
[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
- (instancetype)init {
self = [super init];
if (self) {
[[SKPaymentQueue defaultQueue] addTransactionObserver: self];
}
return self;
}
- (void)startPayWithProductID:(NSString *)productID withCompleteHandler:(paySuccess)paySuccessHandler {
//下单
[SVProgressHUD showWithStatus:nil];
self.paySuccessHandler = paySuccessHandler;
self.m_productID = productID;
NSSet *productIDs = [NSSet setWithObject:_m_productID];
SKProductsRequest *request= [[SKProductsRequest alloc] initWithProductIdentifiers:productIDs];
request.delegate = self;
[request start];
}
- (void)restoreWithCompleteHandler:(restoreSuccess)restoreSuccessHandler {
self.restoreSuccessHandler = restoreSuccessHandler;
[SVProgressHUD showWithStatus:nil];
[[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
}
- (void)p_startPayWithProduct:(SKProduct *)product {
SKPayment *payment = [SKPayment paymentWithProduct:product];
[[SKPaymentQueue defaultQueue] addPayment:payment];
}
- (void)p_finishedTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"支付成功");
if (self.paySuccessHandler) {
self.paySuccessHandler(true);
}
[SVProgressHUD showSuccessWithStatus:@"购买成功"];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)p_failedTransaction:(SKPaymentTransaction *)transaction {
NSLog(@"支付失败");
if (self.paySuccessHandler) {
self.paySuccessHandler(false);
}
[SVProgressHUD showErrorWithStatus:@"操作失败"];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
- (void)p_alreadyBuyWithTransaction:(SKPaymentTransaction *)transaction {
[SVProgressHUD showSuccessWithStatus:@"恢复成功"];
[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}
#pragma mark -
#pragma mark - SKProductsRequestDelegate
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response {
NSArray *myProducts = response.products;
if (myProducts.count == 0) {
SKMutablePayment *mPayment = [[SKMutablePayment alloc] init];
mPayment.productIdentifier = _m_productID;
[[SKPaymentQueue defaultQueue] addPayment:mPayment];
} else {
for (SKProduct *product in myProducts)
{
//product
[self p_startPayWithProduct:product];
break;
}
}
}
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error
{
NSLog(@"%@",error);
}
#pragma mark -
#pragma mark - SKPaymentTransactionObserver
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray<SKPaymentTransaction *> *)transactions {
for (SKPaymentTransaction *transaction in transactions) {
switch (transaction.transactionState) {
case SKPaymentTransactionStatePurchasing:
{
NSLog(@"商品加入列表,正在购买中...");
}
break;
case SKPaymentTransactionStatePurchased:// 购买完成
{
NSLog(@"购买完成");
[self p_finishedTransaction:transaction];
}
break;
case SKPaymentTransactionStateFailed:// 交易失败
{
[self p_failedTransaction:transaction];
}
break;
case SKPaymentTransactionStateRestored: //已经购买过该商品
{
NSLog(@"已经购买过该商品");
[self p_alreadyBuyWithTransaction:transaction];
}
break;
default:
break;
}
}
}
- (void)paymentQueue:(SKPaymentQueue *)queue restoreCompletedTransactionsFailedWithError:(NSError *)error {
NSLog(@"%@",error);
[SVProgressHUD showErrorWithStatus:error.localizedDescription];
}
- (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue {
NSLog(@"成功");
if (self.restoreSuccessHandler) {
self.restoreSuccessHandler(true);
}
}
@end
然后可以使用沙盒账号测试。
四、提交审核上线
第一次提交付费需要苹果审核,等包提交到App Store的时候,选择需要审核的包,然后往下拉选择要提交审核的付费项目。
然后提交送审即可。
版权属于:东哥笔记 - DongGe.org
本文链接:https://dongge.org/blog/868.html
自2017年12月26日起,『转载以及大段采集进行后续编辑』须注明本文标题和链接!否则禁止所有转载和采集行为!