iOS- 给App添加内购& 验证购买iOS7新特性
http://blog.csdn.net/tspangle/article/details/39315355
1.内购——应用内购买
我所说的内购——也可以说是应用内购买
大家都知道通过苹果应用程序商店有三种主要赚钱的方式:
1.直接收费(与国内大部分用户的消费习惯相悖,如果要收费,直接收高的,别收6块钱)
2.广告(降低用户体验 应用程序名称带Lite可以添加广告)
3.内购
至于设计哪些卖钱?产品经理需要认真考虑和调研的。记录用户行为是可以帮助产品经理确认哪些收费!
所以要做好游戏,一定要研究心理,要研究哲学,哈哈。
2.内购的类别有哪几种呢?
在游戏中我们经常用到的主要由分两种:
非消耗品(Nonconsumable)买了就有,头衔,功能
指的是在游戏中一次性购买并拥有永久访问权的物品或服务。非消耗品物品可以被用户再次下载,并且能够在用户的所有设备上使用
消耗品(Consumable),买了就用,用了就没
专为支持可消耗的物品或服务设计的,消耗品购买不可被再次下载,根据其特点,消耗品不能在用户的设备之间跨设备使用,除非自定义服务在用户的账号之间共享这些信息
3.添加内购功能
3.1在iTunes Connect中给自己的应用添加消耗品定义
3.3要使用内购,需要导入StoreKit框架
定义好的商品
#define kIAPBomb @"airplay.10bombs"
#define kIAPBullet @"airplay.laserBullet"
1. 实例化请求时,必须指定有效的identifiers集合,之所以如此处理,主要是为了确保提交的内购商品真的通过了苹果的审批,处于可用状态!
2. 要想获取到准确的可用产品集合,需要通过代理方法实现
- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
3. 越狱用户无法测试内购,但是可以购买
- @interface ITViewController () <SKProductsRequestDelegate, SKPaymentTransactionObserver>
- {
- // 产品字典
- NSMutableDictionary *_productDict;
- }
- - (void)viewDidLoad
- {
- [super viewDidLoad];
- [self requestProducts];
- // 设置购买队列的监听器
- [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
- }
3.4.询问苹果的服务器能够销售哪些商品
- #pragma mark 询问苹果的服务器能够销售哪些商品
- - (void)requestProducts
- {
- // 能够销售的商品
- NSSet *set = [[NSSet alloc] initWithObjects:kIAPBomb, kIAPBullet, nil nil];
- // "异步"询问苹果能否销售
- SKProductsRequest *request = [[SKProductsRequest alloc] initWithProductIdentifiers:set];
- request.delegate = self;
- // 启动请求
- [request start];
- }
3.5.获取询问结果,成功采取操作把商品加入可售商品字典里
- - (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response
- {
- if (_productDict == nil) {
- _productDict = [NSMutableDictionary dictionaryWithCapacity:response.products.count];
- }
- for (SKProduct *product in response.products) {
- // 激活了对应的销售操作按钮,相当于商店的商品上架允许销售
- NSLog(@"%@", product.productIdentifier);
- if ([product.productIdentifier isEqualToString:kIAPBullet]) {
- _bulletButton.enabled = YES;
- }
- if ([product.productIdentifier isEqualToString:kIAPBomb]) {
- _bombButton.enabled = YES;
- }
- // 填充商品字典
- [_productDict setObject:product forKey:product.productIdentifier];
- }
- }
3.6.用户决定购买商品
- #pragma mark - 用户决定购买商品
- - (void)buyProduct:(SKProduct *)product
- {
- // 要购买产品(店员给用户开了个小票)
- SKPayment *payment = [SKPayment paymentWithProduct:product];
- // // 设置购买队列的监听器
- // [[SKPaymentQueue defaultQueue] addTransactionObserver:self];
- // 去收银台排队,准备购买(异步网络)
- [[SKPaymentQueue defaultQueue] addPayment:payment];
- }
- - (IBAction)purchaseProducts
- {
- [self buyProduct:_productDict[kIAPBullet]];
- }
- - (IBAction)purchaseBomb:(id)sender
- {
- [self buyProduct:_productDict[kIAPBomb]];
- }
3.7.判断购买状态是否成功
- #pragma mark - SKPaymentTransaction Observer
- #pragma mark 购买队列状态变化
- - (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions
- {
- // 调试
- for (SKPaymentTransaction *transaction in transactions) {
- NSLog(@"队列状态变化 %@", transaction);
- // 如果小票状态是购买完成
- if (SKPaymentTransactionStatePurchased == transaction.transactionState) {
- NSLog(@"购买完成 %@", transaction.payment.productIdentifier);
- // 更新界面或者数据,把用户购买得商品交给用户
- // ...
- // 验证购买凭据
- [self verifyPruchase];
- // 将交易从交易队列中删除
- [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
- } else if (SKPaymentTransactionStateRestored == transaction.transactionState) {
- NSLog(@"恢复成功 %@", transaction.payment.productIdentifier);
- // 更新界面或者数据,把用户购买得商品交给用户
- // ...
- // 将交易从交易队列中删除
- [[SKPaymentQueue defaultQueue] finishTransaction:transaction];
- }
- }
- }
3.8.给用户提供恢复功能(因为在不同设备上永久性商品可能会出现需要恢复购买的情况)
- #pragma mark - 恢复商品
- - (void)restorePurchase
- {
- // 恢复已经完成的所有交易.(仅限永久有效商品)
- [[SKPaymentQueue defaultQueue] restoreCompletedTransactions];
- }
3.9.验证购买(防止第三方插件漏洞)iOS7新特性
提示:虽然苹果在iOS7提升了购买凭据的安全性,但是处于金钱考虑,购买完成后,一定要做凭据的验证工作。
- #pragma mark 验证购买凭据
- - (void)verifyPruchase
- {
- // 验证凭据,获取到苹果返回的交易凭据
- // appStoreReceiptURL iOS7.0增加的,购买交易完成后,会将凭据存放在该地址
- NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
- // 从沙盒中获取到购买凭据
- NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
- // 发送网络POST请求,对购买凭据进行验证
- NSURL *url = [NSURL URLWithString:ITMS_SANDBOX_VERIFY_RECEIPT_URL];
- // 国内访问苹果服务器比较慢,timeoutInterval需要长一点
- NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];
- request.HTTPMethod = @"POST";
- // 在网络中传输数据,大多情况下是传输的字符串而不是二进制数据
- // 传输的是BASE64编码的字符串
- /**
- BASE64 常用的编码方案,通常用于数据传输,以及加密算法的基础算法,传输过程中能够保证数据传输的稳定性
- BASE64是可以编码和解码的
- */
- NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
- NSString *payload = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", encodeStr];
- NSData *payloadData = [payload dataUsingEncoding:NSUTF8StringEncoding];
- request.HTTPBody = payloadData;
- // 提交验证请求,并获得官方的验证JSON结果
- NSData *result = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
- // 官方验证结果为空
- if (result == nil) {
- NSLog(@"验证失败");
- }
- NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
- NSLog(@"%@", dict);
- if (dict != nil) {
- // 比对字典中以下信息基本上可以保证数据安全
- // bundle_id&application_version&product_id&transaction_id
- NSLog(@"验证成功");
- }
- }
3.10.说说整个购买流程结构
1.苹果APP(商家)——— 2.告诉苹果Store服务器要卖的商品 ——— 3.苹果审核完(告诉你是否可以卖)
4.用户(买商品)——— 5.苹果APP(商家)——— 6.开发票给(用户)————
7.用户(拿着发票去苹果Store服务器付款)——8.付款成功(用户在APP里获得服务商品)
(注意:如果要模拟测试内购,需要用真机才可以测试)
转自:http://www.cnblogs.com/qingche/p/3561424.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具