客户端IAP二次验证
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二次验证的更多相关文章
- In-App Purchase iap 内付费 二次验证代码 (java 服务器端)
参考网址:https://blog.csdn.net/a351945755/article/details/22919533 package com.yichangmao.buyVerify.Comm ...
- ios IAP 内购验证
参考我之前的笔记 苹果内购笔记,在客户端向苹果购买成功之后,我们需要进行二次验证. 二次验证 IOS在沙箱环境下购买成功之后,向苹果进行二次验证,确认用户是否购买成功. 当应用向Apple服务器请求购 ...
- PHP设置谷歌验证器(Google Authenticator)实现操作二步验证
使用说明:开启Google的登陆二步验证(即Google Authenticator服务)后用户登陆时需要输入额外由手机客户端生成的一次性密码.实现Google Authenticator功能需要服务 ...
- Force.com微信企业号开发系列(一) - 启用二次验证
微信于9月份推出企业号后引起了业界不小的反响,许多企业都在思索企业号将如何影响企业的运营,从本文开始,我将详细阐述微信企业号开发的相关知识,而本文将着重介绍如何实现更高安全机制的二次验证. 申请企业体 ...
- jQuery.qrcode.js客户端生成二维码,支持中文并且可以生成LOGO
描述: jquery.qrcode.js 是一个能够在客户端生成矩阵二维码QRCode 的jquery插件 ,使用它可以很方便的在页面上生成二维条码.此插件是能够独立使用的,体积也比较 ...
- destoon 深度整合discuz x2 UC 之免邮箱二次验证
destoon中member/my.php,信息发布入口处判断是否已在dx中做了验证,如果已经验证,则不再提示验证,否则其中dt的验证页面. 在home.php.php. group.php. for ...
- 【转】Android手机客户端关于二维码扫描的源码--不错
原文网址:https://github.com/SkillCollege/QrCodeScan QrCodeScan 这是Android手机客户端关于二维码扫描的源码,使用了高效的ZBar解码库,并修 ...
- 基于RSA securID的Radius二次验证java实现(PAP验证方式)
基于rsa SecurID的二次验证.RSA server自身可以作为Radius服务器,RSA也可以和其他的软件集合,使用其他的server作为Radius服务器. radius的验证的一般流程如下 ...
- 【HELLO WAKA】WAKA iOS客户端 之二 架构设计与实现篇
上一篇主要做了MAKA APP的需求分析,功能结构分解,架构分析,API分析,API数据结构分析. 这篇主要讲如何从零做iOS应用架构. 全系列 [HELLO WAKA]WAKA iOS客户端 之一 ...
随机推荐
- 拾遗:Go 代码结构
#define @ $ 概述 Go 编码通常将所有代码放置在同一个工作区 一个工作区包含多个版本仓库,使用 Git 等工具控制 每个仓库包含一个或多个包 每个包由同一目录中的一份或多份源代码组成 包的 ...
- 剑指offer——61平衡二叉树
题目描述 输入一棵二叉树,判断该二叉树是否是平衡二叉树. 题解: 方法一:使用深度遍历,判断每个节点是不是平衡二叉树,这种从上至下的方法会导致底层的节点重复判断多次 方法二:使用后序遍历判断,这种 ...
- redis 配置文件aof配置
redis 配置文件aof配置: bind 127.0.0.1 port 6379 daemonize yes dbfilename dump.rdb dir /new_renpeng/redis/ ...
- Django框架(十二)—— 补充:inclusion_tag、defer、only、choice、事务、创建多对多的第三张表
目录 补充:inclusion_tag.defer.only.choice.事务.创建多对多的第三张表 一.inclusion_tag 1.作用 2.使用 二.defer与only 1.定义 2.使用 ...
- java MySQl数据库连接
<%@ page import="java.sql.Connection" %> <%@ page import="java.sql.DriverMan ...
- 随笔-ansible-5
1.Includes的使用场景 A项目要用重启PHP B项目要用重启PHP C项目要用重启PHP 可以将重启PHP这个task独立成一个playbook文件,供他人引用即可. 首先编写重启PHP的文件 ...
- 关于print()里面的sep和end参数的使用
print('hello', 'world') #默认用空格隔开 #hello world print('hello', 'world', sep='wuli') #sep=''可以用来设置连接的字符 ...
- 47. List中特有的方法
集合的体系:--------------| Collection 单列集合的根接口----------| List 如果实现了List接口的集合类,该类具备的特点是:有序,可重复---------- ...
- Sql Server 小知识不断扩充中
1. char.varchar.nvarchar 区别 char 定长字符数据长度8000字符,小于8000字符时以空格填充. varchar 变长字符数据最大长度8000,小于8000字符时不会以 ...
- vscode编程nodejs初始安装
nodejs官网 http://nodejs.cn/ 1.安装nodejs,记得安装时勾选配置路径 在cmd中输入node,进去node环境即为安装成功. 2.安装vscode,并安装插件node e ...