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. jeecg随笔-3.X的生成后配置

    生成后按以上步骤进行配置即可.

  2. (转)VS2015基础 指定一个或多个项目执行 - 心少朴的博客

           慈心积善融学习,技术愿为有情学.善心速造多好事,前人栽树后乘凉.我今于此写经验,愿见文者得启发. 这个解决方案下,有两个项目, 看到黑体的project了吗?它就是指定执行的项目. 这两 ...

  3. 剑指offer第二版面试题7:二叉树的下一个节点(JAVA版本)

    题目:给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针. 分析: 根据中序遍历的特点,要找到一个节点的下一个节点无非 ...

  4. script标签的defer、async属性

    之前一直对script标签的defer.async属性一知半解,直到看到了论坛上某大神发的图片,茅塞顿开!!!!!

  5. python库argparse中type的新奇指定方法

    最近在看一些项目的源码,总是能学到好多东西. 关于arparse中type的类型指定 不止可以指定常规类型,还可以加一些自己类型判断,具体用法如下(来源): def str2bool(v): &quo ...

  6. 2-数据分析-matplotlib-1-概述

    1.matplotlib: 最流行的Python底层绘图库,主要做数据可视化图表,名字取材于MATLAB,模仿MATLAB构建. 2.学习matplotlib的意义: (1)能将数据进行可视化,更直观 ...

  7. JS 将对象转换成字符 字符串转换成json对象

    //js对象 var user = { "name": "张学友", "address": "中国香港" }; //将对 ...

  8. 软工-五月心得体会 PB16110698

    伴随着愈发红润的骄阳,火热而紧张刺激的五月悄然而至.这一个月以来,曾经让同学们“废寝忘食”的软工课大作业终于告一段落,每周一篇的读书笔记也缓到半月一篇,着实令人长吐一口气.但这一份表面的余裕当然没有看 ...

  9. 随笔记录 重置root密码 2019.8.7

    方法1:进入单用户模式 1.开机进入以下界面选择要启动的系统按e 2.找到星号行在后面添加上init=/bin/sh 3.按住Ctrl+x执行 4.进入单用户模式 5.如果passwd命令失败,可以直 ...

  10. thrift 的一些相关知识

    thrift是一个很好用的跨语言的rpc框架. 但是其也有一些需要注意的问题: 第一: 发现其对于类型检查没有那么严格:    最近工作中发现是可以把一个int类型直接付给string,而没有任何wa ...