iOS内购详解 您所在的位置:网站首页 ios订阅破解 iOS内购详解

iOS内购详解

2023-11-07 01:50| 来源: 网络整理| 查看: 265

概述

iOS内购是指苹果 App Store 的应用内购买,即In-App Purchase,简称IAP(以下本文关于内购都简称为IAP),是苹果为 App 内购买虚拟商品或服务提供的一套交易系统。为什么我们需要掌握IAP这套流程呢,因为App Store审核指南规定:

如果您想要在 app 内解锁特性或功能 (解锁方式有:订阅、游戏内货币、游戏关卡、优质内容的访问 限或解锁完整版等),则必须使用 App 内购买项目。App 不得使用自身机制来解锁内容或功能, 如许可证密钥、增强现实标记、二维码等。App 及其元数据不得包含按钮、外部链接或其他行动号 召用语,以指引用户使用非 App 内购买项目机制进行购买。

这段话的大概意思就是APP内的虚拟商品或服务,必须使用 IAP 进行购买支付,不允许使用支付宝、微信支付等其它第三方支付方式(包括Apple Pay),也不允许以任何方式(包括跳出App、提示文案等)引导用户通过应用外部渠道购买。如果违反此规定,apple审核人员不会让你的APP上架!!!

内购前准备

APP内集成IAP代码之前需要先去开发账号的ITunes Connect进行以下三步操作:

1,后台填写银行账户信息

2,配置商品信息,包括产品ID,产品价格等

3,配置用于测试IAP支付功能的沙箱账户。

填写银行账户信息一般交由产品管理人员负责,开发者不需要关注,开发者需要关注的是第二步和第三步。

配置内购商品

IAP 是一套商品交易系统,而非简单的支付系统,每一个购买项目都需要在开发者后台的Itunes Connect后台为 App 创建一个对应的商品,提交给苹果审核通过后,购买项目才会生效。内购商品有四种类型:

消耗型项目:只可使用一次的产品,使用之后即失效,必须再次购买,如:游戏币、一次性虚拟道具等 非消耗型项目:只需购买一次,不会过期或随着使用而减少的产品。如:电子书 自动续期订阅:允许用户在固定时间段内购买动态内容的产品。除非用户选择取消,否则此类订阅会自动续期,如:Apple Music这类按月订阅的商品(有些鸡贼的开发者以此收割对IAP商品不熟悉的用户,参考App Store“流氓”软件) 非续期订阅:允许用户购买有时限性服务的产品,此 App 内购买项目的内容可以是静态的。此类订阅不会自动续期

配置商品信息需要注意产品ID和产品价格

1,产品 ID 具有唯一性,建议使用项目的 Bundle Identidier 作为前缀后面拼接自定义的唯一的商品名或者 ID(字母、数字),这里有个坑:一旦新建一个内购商品,它的产品ID将永远被占用,即使该商品已经被删除,已创建的内购商品除了产品 ID 之外的所有信息都可以修改,如果删除了一个内购商品,将无法再创建一个相同产品 ID 的商品,也意味着该产品 ID 永久失效!!!

2,在创建IAP项目的时候,需要设定价格,产品价格只能从苹果提供的价格等级去选择,这个价格等级是固定的,同一价格等级会对应各个国家的货币,比如等级1对应1美元、6元人民币,等级2对应2美元、12元人民币……最高等级87对应999.99美元、6498元人民币。另外可能是为了照顾某些货币区的开发者和用户,还有一些特殊的等级,比如备用等级A对应1美元、1元人民币,备用等级B对应1美元、3元人民币这样。除此之外,IAP项目不能定一个9.9元人民币这样不符合任何等级的价格。详细价格等级表可以看苹果的官方价格等级文档

苹果的价格等级表通常是不会调整的,但也不排除在某些货币汇率发生巨大变化的情况下,对该货币的定价进行调整,调整前苹果会发邮件通知开发者。

3,商品分成

App Store上的付费App和App内购,苹果与开发者默认是3/7分成。但实际上,在某些地区苹果与开发者分成之前需要先扣除交易税,开发者的实际分成不一定是70%。从2015年10月开始,苹果对中国地区的App Store购买扣除了2%的交易税,对于中国区帐号购买的IAP,开发者的实际分成在68%~69%之间。而且中国以外不同地区的交易税标准也存在差异,如苹果的官方价格等级文档

,如果需要严格计算实际收入,可能需要把这个部分也考虑进来。

针对不同地区的内购,内购价格和对应的开发者实际收入在苹果的价格等级表中有详细列举。

另外,根据苹果在2016年6月的新规则,针对Auto-Renewable Subscription类型的IAP,如果用户购买的订阅时间超过1年,那么从第二年开始,开发者可以获得85%的分成。详情可查看苹果的订阅产品价格说明

沙箱账户

新的内购产品上线之前,测试人员一般需要对内购产品进行测试,但是内购涉及到钱,所以苹果为内购测试提供了 沙箱测试账号 的功能,Apple Pay 推出之后 沙箱测试账号`也可以用于 Apple Pay 支付的测试,沙箱测试账号 简单理解就是:只能用于内购和 Apple Pay 测试功能的 Apple ID,它并不是真实的 Apple ID。

填写沙箱测试账号信息需要注意以下几点:

电子邮件不能是别人已经注册过 AppleID 的邮箱 电子邮箱可以不是真实的邮箱,但是必须符合邮箱格式 App Store 地区的选择,测试的时候弹出的提示框以及结算的价格会按照沙箱账号选择的地区来,建议测试的时候新建几个不同地区的账号进行测试!!!

沙箱账号测试的使用:

首先沙箱测试账号必须在真机环境下进行测试,并且是 adhoc 证书或者 develop 证书签名的安装包,沙盒账号不支持直接从 App Store 下载的安装包 去真机的 App Store 退出真实的 Apple ID 账号,退出之后并不需要在App Store 里面登录沙箱测试账号 然后去 App 里面测试购买商品,会弹出登录框,选择 使用现有的 Apple ID,然后登录沙箱测试账号,登录成功之后会弹出购买提示框,点击 购买,然后会弹出提示框完成购买。 内购流程

IAP的支付流程分为客户端和服务端,客户端的工作如下:

获取内购产品列表(从App内读取或从自己服务器读取),向用户展示内购列表 用户选择某个内购产品后,先请求可用的内购产品的本地化信息列表,此次调用Apple的StoreKit库的代码 得到内购产品的本地化信息后,根据用户选择的内购产品的ID得到内购产品 根据内购产品发起IAP购买请求,收到购买完成的回调 购买流程结束后, 向服务器发起验证凭证以及支付结果的请求 自己的服务器将支付结果信息返回给前端并发放虚拟产品

前端支付流程图如下:

------------------------------ IAPManager.h ----------------------------- #import NS_ASSUME_NONNULL_BEGIN typedef enum { IAPPurchSuccess = 0, // 购买成功 IAPPurchFailed = 1, // 购买失败 IAPPurchCancel = 2, // 取消购买 IAPPurchVerFailed = 3, // 订单校验失败 IAPPurchVerSuccess = 4, // 订单校验成功 IAPPurchNotArrow = 5, // 不允许内购 }IAPPurchType; typedef void (^IAPCompletionHandle)(IAPPurchType type,NSData *data); @interface IAPManager : NSObject + (instancetype)shareIAPManager; - (void)startPurchaseWithID:(NSString *)purchID completeHandle:(IAPCompletionHandle)handle; @end NS_ASSUME_NONNULL_END ------------------------------ IAPManager.m ----------------------------- #import "IAPManager.h" #import #import @interface IAPManager(){ NSString *_currentPurchasedID; IAPCompletionHandle _iAPCompletionHandle; } @end @implementation IAPManager + (instancetype)shareIAPManager{ static IAPManager *iAPManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken,^{ iAPManager = [[IAPManager alloc] init]; }); return iAPManager; } - (instancetype)init{ self = [super init]; if (self) { [[SKPaymentQueue defaultQueue] addTransactionObserver:self]; } return self; } - (void)dealloc{ [[SKPaymentQueue defaultQueue] removeTransactionObserver:self]; } - (void)startPurchaseWithID:(NSString *)purchID completeHandle:(IAPCompletionHandle)handle{ if (purchID) { if ([SKPaymentQueue canMakePayments]) { _currentPurchasedID = purchID; _iAPCompletionHandle = handle; //从App Store中检索关于指定产品列表的本地化信息 NSSet *nsset = [NSSet setWithArray:@[purchID]]; SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:nsset]; request.delegate = self; [request start]; }else{ [self handleActionWithType:IAPPurchNotArrow data:nil]; } } } - (void)handleActionWithType:(IAPPurchType)type data:(NSData *)data{ #if DEBUG switch (type) { case IAPPurchSuccess: NSLog(@"购买成功"); break; case IAPPurchFailed: NSLog(@"购买失败"); break; case IAPPurchCancel: NSLog(@"用户取消购买"); break; case IAPPurchVerFailed: NSLog(@"订单校验失败"); break; case IAPPurchVerSuccess: NSLog(@"订单校验成功"); break; case IAPPurchNotArrow: NSLog(@"不允许程序内付费"); break; default: break; } #endif if(_iAPCompletionHandle){ _iAPCompletionHandle(type,data); } } - (void)verifyPurchaseWithPaymentTransaction:(SKPaymentTransaction *)transaction{ //交易验证 NSURL *recepitURL = [[NSBundle mainBundle] appStoreReceiptURL]; NSData *receipt = [NSData dataWithContentsOfURL:recepitURL]; if(!receipt){ // 交易凭证为空验证失败 [self handleActionWithType:IAPPurchVerFailed data:nil]; return; } // 购买成功将交易凭证发送给服务端进行再次校验 [self handleActionWithType:IAPPurchSuccess data:receipt]; NSError *error; NSDictionary *requestContents = @{ @"receipt-data": [receipt base64EncodedStringWithOptions:0] }; NSData *requestData = [NSJSONSerialization dataWithJSONObject:requestContents options:0 error:&error]; if (!requestData) { // 交易凭证为空验证失败 [self handleActionWithType:IAPPurchVerFailed data:nil]; return; } NSString *serverString = @"https:xxxx"; NSURL *storeURL = [NSURL URLWithString:serverString]; NSMutableURLRequest *storeRequest = [NSMutableURLRequest requestWithURL:storeURL]; [storeRequest setHTTPMethod:@"POST"]; [storeRequest setHTTPBody:requestData]; [[NSURLSession sharedSession] dataTaskWithRequest:storeRequest completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { if (error) { // 无法连接服务器,购买校验失败 [self handleActionWithType:IAPPurchVerFailed data:nil]; } else { NSError *error; NSDictionary *jsonResponse = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (!jsonResponse) { // 服务器校验数据返回为空校验失败 [self handleActionWithType:IAPPurchVerFailed data:nil]; } NSString *status = [NSString stringWithFormat:@"%@",jsonResponse[@"status"]]; if(status && [status isEqualToString:@"0"]){ [self handleActionWithType:IAPPurchVerSuccess data:nil]; } else { [self handleActionWithType:IAPPurchVerFailed data:nil]; } #if DEBUG NSLog(@"----验证结果 %@",jsonResponse); #endif } }]; // 验证成功与否都注销交易,否则会出现虚假凭证信息一直验证不通过,每次进程序都得输入苹果账号 [[SKPaymentQueue defaultQueue] finishTransaction:transaction]; } #pragma mark - SKProductsRequestDelegate - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response{ NSArray *product = response.products; if([product count]


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

      专题文章
        CopyRight 2018-2019 实验室设备网 版权所有