为什么80%的码农都做不了架构师?>>>   

1.概念介绍

<1>苹果内购:

App内购买是指在苹果的 App Store 中购买应用程序的方式。
在玩一些游戏类应用软件,这些应用都可以免费下载,但是在玩的过程中就会需要在应用内付费,否则就只能玩几关之类的。有时候会不小心点击到一些内购按钮,或是小孩乱点导致扣费的情况。
另外苹果手机系统默认的 Apple ID 的密码时效为 15 分钟,意思就是当输入了一次 Apple ID 之后,在接下来的 15 分钟内,若是点击一些付费项目的话,系统就会直接使用 Apple ID 来购买了。

2.登录iTunes Connect,进入具体的app,点击右上角的功能,创建以供测试的内购产品

3.登录iTunes Connect,进入用户职能,点击沙箱技术测试员,创建测试员账号

注意:

<1>将要创建的测试员账号必须是之前没有注册过App Store的,所以要谨慎注册,谨慎删除。

<2>创建成功之后,我们必须得登录这个邮箱,完成App Store的邮箱验证。

<3>退出当前iPhone的iCloud,App Store的所有账号。

完成以上的操作,即可开始苹果内购的测试。

4.打开Xcode运行项目,开始代码层的编写;

我们先理一下内购的逻辑:

<1>定义好正式和测试的环境;

#if DEBUG
//沙盒测试环境验证
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"#else
//正式环境验证
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"#endif

<2>检查当前iPhone是否支持苹果内购;

-(void)startUserIAP{[[SKPaymentQueue defaultQueue] addTransactionObserver:self];_currentProId = @"yearmoneytest";if([SKPaymentQueue canMakePayments]){[self requestProductData:@"yearmoneytest"];}else{NSLog(@"不允许程序内付费");}
}

<3>去苹果服务器请求当前app里面的内购产品,如果请求成功,找到自己要购买的产品,并开始支付;

//去苹果服务器请求商品
- (void)requestProductData:(NSString *)type{NSLog(@"-------------请求对应的产品信息----------------");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(@"产品付费数量:%lu",(unsigned long)[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:_currentProId]){p = pro;}}SKPayment *payment = [SKPayment paymentWithProduct:p];NSLog(@"发送购买请求");[[SKPaymentQueue defaultQueue] addPayment:payment];
}//请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{NSLog(@"------------------错误-----------------:%@", error);
}- (void)requestDidFinish:(SKRequest *)request{NSLog(@"------------反馈信息结束-----------------");
}

<4>监听购买的结果,如果购买成功,我们再去苹果服务器验证凭证;

//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{for(SKPaymentTransaction *tran in transaction){switch (tran.transactionState) {case SKPaymentTransactionStatePurchased:{NSLog(@"交易完成");// 发送到苹果服务器验证凭证[self verifyPurchaseWithPaymentTransaction];[[SKPaymentQueue defaultQueue] finishTransaction:tran];}break;case SKPaymentTransactionStatePurchasing:NSLog(@"商品添加进列表");break;case SKPaymentTransactionStateRestored:{NSLog(@"已经购买过商品");[[SKPaymentQueue defaultQueue] finishTransaction:tran];}break;case SKPaymentTransactionStateFailed:{NSLog(@"交易失败");[[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentFailed" object:nil];[[SKPaymentQueue defaultQueue] finishTransaction:tran];}break;default:break;}}
}//交易结束
- (void)completeTransaction:(SKPaymentTransaction *)transaction{NSLog(@"交易结束");[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}- (void)dealloc{[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}
/***  验证购买,避免越狱软件模拟苹果请求达到非法购买问题**/
-(void)verifyPurchaseWithPaymentTransaction{//从沙盒中获取交易凭证并且拼接成请求体数据NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//转化为base64字符串NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接请求数据NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];//创建请求到苹果官方进行购买验证NSURL *url=[NSURL URLWithString:SANDBOX];NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];requestM.HTTPBody=bodyData;requestM.HTTPMethod=@"POST";//创建连接并发送同步请求[[NSURLSession sharedSession] dataTaskWithRequest:requestM completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {if (error) {NSLog(@"验证购买过程中发生错误,错误信息:%@",error.localizedDescription);return;}NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];NSLog(@"%@",dic);if([dic[@"status"] intValue]==0){NSLog(@"购买成功!");[[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentSuccess" object:nil];NSDictionary *dicReceipt= dic[@"receipt"];NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject];NSString *productIdentifier= dicInApp[@"product_id"];//读取产品标识//如果是消耗品则记录购买数量,非消耗品则记录是否购买过NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];if ([productIdentifier isEqualToString:@"yearmoneytest"]) {NSInteger purchasedCount=[defaults integerForKey:productIdentifier];//已购买数量[defaults setInteger:(purchasedCount+1) forKey:productIdentifier];}else{[defaults setBool:YES forKey:productIdentifier];}[defaults synchronize];//在此处对购买记录进行存储,可以存储到开发商的服务器端}else{[[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentFailed" object:nil];NSLog(@"购买失败,未通过验证!");}}];}

以上即是我分享的苹果内购总结,感谢阅读,欢迎指正。为方便大家使用,封装好了一套代码,一句话调用即可,下面是文件代码。

//
//  IAPManager.h
//  traffic
//
//  Created by Tommy on 2017/6/10.
//  Copyright © 2017年 Mqch295. All rights reserved.
//#import <Foundation/Foundation.h>@interface IAPManager : NSObject/***该类的对象必须在内存中一直存在,才可以执行完整个内购的流程***/
-(void)startUserIAP;@end
//
//  IAPManager.m
//  traffic
//
//  Created by Tommy on 2017/6/10.
//  Copyright © 2017年 Mqch295. All rights reserved.
//#if DEBUG
//沙盒测试环境验证
#define SANDBOX @"https://sandbox.itunes.apple.com/verifyReceipt"#else
//正式环境验证
#define AppStore @"https://buy.itunes.apple.com/verifyReceipt"#endif#import "IAPManager.h"
#import <StoreKit/StoreKit.h>@interface IAPManager()<SKPaymentTransactionObserver,SKProductsRequestDelegate>@property (nonatomic,copy) NSString *currentProId;@end@implementation IAPManager#pragma mark 公有方法-(void)startUserIAP{[[SKPaymentQueue defaultQueue] addTransactionObserver:self];_currentProId = @"yearmoneytest";if([SKPaymentQueue canMakePayments]){[self requestProductData:@"yearmoneytest"];}else{NSLog(@"不允许程序内付费");}
}#pragma mark 私有方法//去苹果服务器请求商品
- (void)requestProductData:(NSString *)type{NSLog(@"-------------请求对应的产品信息----------------");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(@"产品付费数量:%lu",(unsigned long)[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:_currentProId]){p = pro;}}SKPayment *payment = [SKPayment paymentWithProduct:p];NSLog(@"发送购买请求");[[SKPaymentQueue defaultQueue] addPayment:payment];
}//请求失败
- (void)request:(SKRequest *)request didFailWithError:(NSError *)error{NSLog(@"------------------错误-----------------:%@", error);
}- (void)requestDidFinish:(SKRequest *)request{NSLog(@"------------反馈信息结束-----------------");
}/***  验证购买,避免越狱软件模拟苹果请求达到非法购买问题**/
-(void)verifyPurchaseWithPaymentTransaction{//从沙盒中获取交易凭证并且拼接成请求体数据NSURL *receiptUrl=[[NSBundle mainBundle] appStoreReceiptURL];NSData *receiptData=[NSData dataWithContentsOfURL:receiptUrl];NSString *receiptString=[receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];//转化为base64字符串NSString *bodyString = [NSString stringWithFormat:@"{\"receipt-data\" : \"%@\"}", receiptString];//拼接请求数据NSData *bodyData = [bodyString dataUsingEncoding:NSUTF8StringEncoding];//创建请求到苹果官方进行购买验证NSURL *url=[NSURL URLWithString:SANDBOX];NSMutableURLRequest *requestM=[NSMutableURLRequest requestWithURL:url];requestM.HTTPBody=bodyData;requestM.HTTPMethod=@"POST";//创建连接并发送同步请求[[NSURLSession sharedSession] dataTaskWithRequest:requestM completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {if (error) {NSLog(@"验证购买过程中发生错误,错误信息:%@",error.localizedDescription);return;}NSDictionary *dic=[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingAllowFragments error:nil];NSLog(@"%@",dic);if([dic[@"status"] intValue]==0){NSLog(@"购买成功!");[[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentSuccess" object:nil];NSDictionary *dicReceipt= dic[@"receipt"];NSDictionary *dicInApp=[dicReceipt[@"in_app"] firstObject];NSString *productIdentifier= dicInApp[@"product_id"];//读取产品标识//如果是消耗品则记录购买数量,非消耗品则记录是否购买过NSUserDefaults *defaults=[NSUserDefaults standardUserDefaults];if ([productIdentifier isEqualToString:@"yearmoneytest"]) {NSInteger purchasedCount=[defaults integerForKey:productIdentifier];//已购买数量[defaults setInteger:(purchasedCount+1) forKey:productIdentifier];}else{[defaults setBool:YES forKey:productIdentifier];}[defaults synchronize];//在此处对购买记录进行存储,可以存储到开发商的服务器端}else{[[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentFailed" object:nil];NSLog(@"购买失败,未通过验证!");}}];}
//监听购买结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transaction{for(SKPaymentTransaction *tran in transaction){switch (tran.transactionState) {case SKPaymentTransactionStatePurchased:{NSLog(@"交易完成");// 发送到苹果服务器验证凭证[self verifyPurchaseWithPaymentTransaction];[[SKPaymentQueue defaultQueue] finishTransaction:tran];}break;case SKPaymentTransactionStatePurchasing:NSLog(@"商品添加进列表");break;case SKPaymentTransactionStateRestored:{NSLog(@"已经购买过商品");[[SKPaymentQueue defaultQueue] finishTransaction:tran];}break;case SKPaymentTransactionStateFailed:{NSLog(@"交易失败");[[NSNotificationCenter defaultCenter] postNotificationName:@"PaymentFailed" object:nil];[[SKPaymentQueue defaultQueue] finishTransaction:tran];}break;default:break;}}
}//交易结束
- (void)completeTransaction:(SKPaymentTransaction *)transaction{NSLog(@"交易结束");[[SKPaymentQueue defaultQueue] finishTransaction:transaction];
}- (void)dealloc{[[SKPaymentQueue defaultQueue] removeTransactionObserver:self];
}@end

QQ:2799569272,不定时更新。

转载于:https://my.oschina.net/Atoman/blog/967726

iOS开发 IAP苹果内购相关推荐

  1. iOS开发支付篇——内购(IAP)详解

    iOS开发支付篇--内购(IAP)详解 苹果客户端购买虚拟商品是需要走内购 先看gif图 具体步骤: 协议.税务和银行业务 信息填写 内购商品的添加 添加沙盒测试账号 内购代码的具体实现 内购的注意事 ...

  2. ios 内购正式环境_iOS开发-2017苹果内购最新教程

    公司项目中有虚拟产品,所以要使用苹果内购.自此记录一下苹果内购的流程.前提是已有开发者账号 协议,税务和银行业务 协议,税务和银行业务 协议,税务和银行业务 申请合同 这里提示地址太长,按照要求重新填 ...

  3. 苹果app商品定价_iOS 开发_2017苹果内购价格表

    [作者前言]:13年入圈,分享些本人工作中遇到的点点滴滴那些事儿,17年刚开始写博客,高手勿喷!以分享交流为主,欢迎各路豪杰点评改进! 1.应用场景: 使用苹果内购的APP/游戏 2.实现目标: 了解 ...

  4. iOS开发——高级技术内购服务

    内购服务 大家都知道做iOS开发本身的收入有三种来源:出售应用.内购和广告.国内用户通常很少直接 购买应用,因此对于开发者而言(特别是个人开发者),内购和广告收入就成了主要的收入来源.内购营销模式,通 ...

  5. java(jfinal) 接入ios苹果内购(连续包月订阅),服务端将二次验证。

    大致流程: 1.ios端进行支付,然后收到苹果的一串数据(也叫收据),然后ios端将其转码为BASE64编码的字符串. 2.ios端请求服务端接口,将数据传给服务端,服务端拿到数据后,通过一系列处理后 ...

  6. 苹果内购IAP记录-1

    这段时间做了苹果内购IAP,做一个整理记录,主要是开发层面. 一.前期工作:在开发者账号中添加银行信息同意协议等,添加沙盒账号,添加内购商品 二.项目开发,因为项目需要支持iOS15一下的版本所以使用 ...

  7. uni app ios 苹果内购

    app ios 苹果内购 的步骤 1,准备工作先要uniapp 开发ios 内购需要准备的沙盒 测试账号,在苹果手机登录沙盒账号 也就是把自己的Apple ID退出登录沙盒账号,manifest.js ...

  8. 【iOS内购支付】Uniapp拉起苹果内购支付注意事项、实现步骤以及踩过的坑(手把手教程)

    前言 Hello!又是很长时间没有写博客了,因为最近又开始从事新项目,也是第一次接触关于uniapp开发原生IOS应用的项目,在这里做一些关于我在项目中使用苹果内购支付所实现的方式以及要注意的事项,希 ...

  9. 【iOS】苹果内购调研

    参考文章 官方文档 iOS开发内购全套图文教程 App Store上架指导 苹果不允许 iOS 应用内置购买(IAP)使用第三方支付方式,那么跨平台的电子书阅读器怎么解决这个问题? 应用内购(In-A ...

最新文章

  1. css3 高度最小100%,100%最小高度CSS布局
  2. Turbo C 3.0安装及使用说明
  3. s3c2440arm裸机编程之ADC触摸屏
  4. 兴业银行与第四范式开启AI平台加速模式 毫秒级信用卡反欺诈系统上线
  5. ORACLE OMF介绍
  6. JVM 性能调优监控工具 jps、jstack、jmap、jhat、jstat、hprof 使用详解
  7. Lambda 表达式详解~Lambda与集合
  8. createsamples.cpp中生成vec文件的实现及详细注释、图解——人脸识别的尝试系列(三)
  9. linux管道学习资料
  10. 2021-08-25Prompt
  11. 【机器学习系列】变分推断第一讲:Variational Inference背景和用途
  12. 快速查看是哪个文件占用空间大
  13. UE4_Shader Compile 停在某一帧或者新建材质出现卡死
  14. no algorithm found for: 08000000h - 0800275bhno algorithm found for: 08000000h - XXXXXXXXH
  15. (vant新手坑)引入Vant组件并改变其样式
  16. larkplayer视频播放器: 同时支持PC、移动端 插件化的HTML5视频播放器。
  17. CentOS 7下的软件安装方法总结
  18. Lesson 4.2 逻辑回归参数估计:极大似然估计、相对熵与交叉熵损失函数
  19. C盘不够了怎么办!将其他盘空间怎么分给C盘!
  20. Android SDK工具链清单

热门文章

  1. Android NDK开发Crash错误定位
  2. 一朵落地中国的“智能云”是如何飘到你身边的!
  3. LintCode_514 Paint Fence
  4. HDFS体系结构详解
  5. Behavior Targeting - 技术研究
  6. Web前端开发之“常见模块你真的很了解吗?”
  7. vf省计算机考试题库,计算机二级VF上机题库及答案
  8. 自动驾驶初创公司Nuro获软银9.4亿美元投资
  9. Python关于File学习过程
  10. python之UnittTest模块