1、首先苹果IAP把每次购买抽象成了一个事务(SKPaymentTransaction),

- (void)productsRequest:(SKProductsRequest *)request didReceiveResponse:(SKProductsResponse *)response;
每次在上述方法中收到反馈信息之后添加的[[SKPaymentQueue defaultQueue] addPayment:payment];
就相当于在事务管理中添加了一个事务,只有事务被正常结束(finishTransaction:)该次支付行为才算完成。
即使一次支付中途被中断,这次事务也并没有丢失。假设支付没有完成App就退出了(比如突然崩溃了),那么当下次App重启之后(调用了addTransactionObserver:),之前被中断的事务会接着进行。
这个的缺点就是中间等待重启的时间可能会很长,影响用户体验。

2、在购买成功后的客户端二次验证。

每次购买成功之后都会把encodeStr存到本地,验证成功再进行删除。以后每次打开应用或打开充值会先查看是否有未完成的验证

//交易结果
- (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions{
NSLog(@"5.交易结果");
for (SKPaymentTransaction *transaction in transactions){
switch (transaction.transactionState){
case SKPaymentTransactionStatePurchased:{//交易完成
NSLog(@"交易完成");
[self completeTransaction:transaction];
} break;
case SKPaymentTransactionStateFailed://交易失败
{ [self failedTransaction:transaction];
NSLog(@"-----交易失败 --------");
[SVProgressHUD dismiss];
UIAlertView *alerView2 = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"购买失败,请重新尝试购买"
delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
[alerView2 show]; }break;
case SKPaymentTransactionStateRestored://已经购买过该商品
[self restoreTransaction:transaction];
NSLog(@"-----已经购买过该商品 --------");
case SKPaymentTransactionStatePurchasing: //商品添加进列表
NSLog(@"-----商品添加进列表 --------");
break;
default:
break;
}
}
}
- (void)completeTransaction: (SKPaymentTransaction *)transaction{
NSString * productIdentifier = transaction.payment.productIdentifier;
if ([productIdentifier length] > 0) {
[SVProgressHUD dismiss];
//添加IAPModel到本地
//获取验证凭证
NSURL *receiptURL = [[NSBundle mainBundle] appStoreReceiptURL];
//从沙盒中获取购买凭证
NSData *receiptData = [NSData dataWithContentsOfURL:receiptURL];
//进行Base64加密
NSString *encodeStr = [receiptData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
WekeIAPModel *model = [[WekeIAPModel alloc]initWithReceiptStr:encodeStr user_id:[AppSingle sharedAppSingle].user_id];
[[AppSingle sharedAppSingle].IAPArray addObject:model];
[SaveCachesFile saveDataList:[AppSingle sharedAppSingle].IAPArray fileName:WekeIAP];
[self verifyPruchaseWithEncodeStr:encodeStr];
[[SKPaymentQueue defaultQueue] finishTransaction: transaction];
}else{
[SVProgressHUD dismiss];
UIAlertView *alerView2 = [[UIAlertView alloc] initWithTitle:@"提示"
message:@"购买失败,未能连接到苹果服务器"
delegate:nil cancelButtonTitle:NSLocalizedString(@"关闭",nil) otherButtonTitles:nil];
[alerView2 show];
}
}
//验证购买凭证
- (void)verifyPruchaseWithEncodeStr :(NSString *)encodeStr{
//验证URL POST请求
NSURL *url = [NSURL URLWithString:Buy_Verify_Receipt_Url];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0f];
request.HTTPMethod = @"POST";
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(@"验证失败");
}else{
NSDictionary *dict = [NSJSONSerialization JSONObjectWithData:result options:NSJSONReadingAllowFragments error:nil];
NSLog(@"线上环境验证结果%@",dict);
if ([[dict objectForKey:@"status"] integerValue] == 21007) {
//如果是沙盒环境
[self verifyPruchaseInSANDBOXWithEncodeStr:encodeStr];
}else if ([[dict objectForKey:@"status"] integerValue] == 0){
NSLog(@"线上环境验证成功,进行增加积分等操作");
//验证成功 删除IAP数组中的该Model
for (WekeIAPModel *model in self.IAPArray) {
if ([model.encodeStr isEqualToString:encodeStr]) {
[[AppSingle sharedAppSingle].IAPArray removeObject:model];
[self.IAPArray removeObject:model];
[SaveCachesFile saveDataList:[AppSingle sharedAppSingle].IAPArray fileName:WekeIAP];
}
}
[self postGrede]; }else{
NSLog(@"线上环境验证失败");
UIAlertController *alertCT = [UIAlertController alertControllerWithTitle:@"提示" message:@"充值验证失败,请重试" preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消"style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction *care = [UIAlertAction actionWithTitle:@"重试"style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self verifyPruchaseWithEncodeStr:encodeStr];
}];
[alertCT addAction:cancel];
[alertCT addAction:care];
[self presentViewController:alertCT animated:YES completion:nil];
}
}
} //在沙盒中验证
- (void)verifyPruchaseInSANDBOXWithEncodeStr:(NSString *)encodeStr{ //验证URL POST请求
NSURL *url = [NSURL URLWithString:SANDBOX_VERIFY_RECEIPT_URL];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:20.0f];
request.HTTPMethod = @"POST";
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(@"沙盒验证失败");
UIAlertController *alertCT = [UIAlertController alertControllerWithTitle:@"提示" message:@"充值验证失败,请重试" preferredStyle:(UIAlertControllerStyleAlert)];
UIAlertAction *cancel = [UIAlertAction actionWithTitle:@"取消"style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
}];
UIAlertAction *care = [UIAlertAction actionWithTitle:@"重试"style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
[self verifyPruchaseInSANDBOXWithEncodeStr:encodeStr];
}];
[alertCT addAction:cancel];
[alertCT addAction:care];
[self presentViewController:alertCT animated:YES completion:nil];
}else{
NSLog(@"沙盒验证成功");
[self postGrede];
//验证成功 删除IAP数组中的该Model
for (WekeIAPModel *model in self.IAPArray) {
if ([model.encodeStr isEqualToString:encodeStr]) {
[[AppSingle sharedAppSingle].IAPArray removeObject:model];
[self.IAPArray removeObject:model];
[SaveCachesFile saveDataList:[AppSingle sharedAppSingle].IAPArray fileName:WekeIAP];
}
} }
}

客户端IAP二次验证的更多相关文章

  1. In-App Purchase iap 内付费 二次验证代码 (java 服务器端)

    参考网址:https://blog.csdn.net/a351945755/article/details/22919533 package com.yichangmao.buyVerify.Comm ...

  2. ios IAP 内购验证

    参考我之前的笔记 苹果内购笔记,在客户端向苹果购买成功之后,我们需要进行二次验证. 二次验证 IOS在沙箱环境下购买成功之后,向苹果进行二次验证,确认用户是否购买成功. 当应用向Apple服务器请求购 ...

  3. PHP设置谷歌验证器(Google Authenticator)实现操作二步验证

    使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码.实现Google Authenticator功能需要服务 ...

  4. Force.com微信企业号开发系列(一) - 启用二次验证

    微信于9月份推出企业号后引起了业界不小的反响,许多企业都在思索企业号将如何影响企业的运营,从本文开始,我将详细阐述微信企业号开发的相关知识,而本文将着重介绍如何实现更高安全机制的二次验证. 申请企业体 ...

  5. jQuery.qrcode.js客户端生成二维码,支持中文并且可以生成LOGO

    描述: jquery.qrcode.js 是一个能够在客户端生成矩阵二维码QRCode 的jquery插件 ,使用它可以很方便的在页面上生成二维条码.此插件是能够独立使用的,体积也比较         ...

  6. destoon 深度整合discuz x2 UC 之免邮箱二次验证

    destoon中member/my.php,信息发布入口处判断是否已在dx中做了验证,如果已经验证,则不再提示验证,否则其中dt的验证页面. 在home.php.php. group.php. for ...

  7. 【转】Android手机客户端关于二维码扫描的源码--不错

    原文网址:https://github.com/SkillCollege/QrCodeScan QrCodeScan 这是Android手机客户端关于二维码扫描的源码,使用了高效的ZBar解码库,并修 ...

  8. 基于RSA securID的Radius二次验证java实现(PAP验证方式)

    基于rsa SecurID的二次验证.RSA server自身可以作为Radius服务器,RSA也可以和其他的软件集合,使用其他的server作为Radius服务器. radius的验证的一般流程如下 ...

  9. 【HELLO WAKA】WAKA iOS客户端 之二 架构设计与实现篇

    上一篇主要做了MAKA APP的需求分析,功能结构分解,架构分析,API分析,API数据结构分析. 这篇主要讲如何从零做iOS应用架构. 全系列 [HELLO WAKA]WAKA iOS客户端 之一 ...

随机推荐

  1. ssh 登陆免 known_hosts 提示

    修改配置文件 “~/.ssh/config”,加上这两行,重启服务器: StrictHostKeyChecking no UserKnownHostsFile /dev/null

  2. testNG官方文档翻译-3 testng.xml

    你可以通过以下几种不同的方法触发TestNG: 用一个testng.xml文件 使用ant 从命令行触发 这个章节将会介绍testng.xml的格式(你也可以在下面找到关于ant和命令行的内容). 关 ...

  3. 在linux 下查询某个进程被那个程序占用

    ps -ef|grep pid ps -aux | grep pid 清除linux 缓存: echo 1 > /proc/sys/vm/drop_caches

  4. vue中记录页面的滚动距离

    业务需求:pageOne页面是一个商品列表页面,在这个页面点击商品,就会跳转到pageTwo商品详细页面.此时再从pageTwo页面返回到pageOne页面时,pageOne页面需要做到:1.记录pa ...

  5. touchWX使用 echarts

    <button bindtap="init" wx:if="{{!isLoaded}}">加载图表</button> <butto ...

  6. 基于OpenResty与Consul实现服务网格ServiceMesh

    一.逻辑架构 1.基于OpenResty开发智能代理: 利用其动态可编程特性,动态化配置nginx服务路由: 2.需要向OpenResty添加weibo开源的upsync服务发现模块: 3.基于con ...

  7. ros语音交互(五)移植科大讯飞语音识别到ros

    将以前下载的的语音包的 samples/iat_record/的iat_record.c speech_recognizer.c speech_recognizer.c 拷贝到工程src中, linu ...

  8. kubectl 使用token的方式连接到集群

    首先得有一个账户 kubectl create serviceaccount dashboard-admin -n kube-system #创建一个名叫dashboard-admin 命名空间在ku ...

  9. rest framework之APIView

    一.rest framework配置 1.安装rest framework 在django环境中安装rest-framework框架: (automatic) C:\Users\Administrat ...

  10. Maven pom配置(Spring+SpringMvc+mybaties)

    <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven ...