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. 利用爬虫爬取指定用户的CSDN博客文章转为md格式,目的是完成博客迁移博文到Hexo等静态博客

    文章目录 功能 爬取的方式: 设置生成的md文件命名规则: 设置md文件的头部信息 是否显示csdn中的锚点"文章目录"字样,以及下面具体的锚点 默认false(因为csdn中是集 ...

  2. ThinkPHP5实用的数据库操作方法

    1.update方法总结 /** * 设置记录的某个字段值 * 支持使用数据库字段和方法 * @access public * @param string|array $field 字段名 * @pa ...

  3. 36-Ubuntu-用户管理-01-新建用户useradd

    创建用户/设置密码/删除用户/确认用户信息 序号 命令 作用 说明 01 sudo useradd -m -g 组名 新建用户名 添加新用户 -m 自动建立用户家目录 -g 指定用户所在的组,否则会建 ...

  4. (数据科学学习手札57)用ggplotly()美化ggplot2图像

    一.简介 经常利用Python进行数据可视化的朋友一定用过或听说过plotly这样的神器,我在(数据科学学习手札43)Plotly基础内容介绍中也曾做过非常详细的介绍,其渲染出的图像以浏览器为载体,非 ...

  5. JS window对象 计时器setTimeout() setTimeout()计时器,在载入后延迟指定时间后,去执行一次表达式,仅执行一次。 语法: setTimeout(代码,延迟时间);

    计时器setTimeout() setTimeout()计时器,在载入后延迟指定时间后,去执行一次表达式,仅执行一次. 语法: setTimeout(代码,延迟时间); 参数说明: 1. 要调用的函数 ...

  6. Shell中整数自增的几种方式

    Shell中整数自增的几种方式 2016年08月27日 19:07:40 杰瑞26 阅读数:2816    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.n ...

  7. python 打印出水仙花数

    打印出三位水仙花数方法及解释 num = 100while num <= 999: #这里num 小于等于999 则运行 填1000也可以 a = num % 10 #num对10取余 b = ...

  8. leetcood学习笔记-39-组合总和

    题目描述: 方法一: class Solution: def combinationSum(self, candidates, target): """ :type ca ...

  9. parseFloat 和 Number isNaN 转换

    parseFloat(true) // NaN Number( parseFloat(null) // NaN Number( parseFloat('') // NaN Number('') par ...

  10. php上传(三)

    关于一些上传插件的运用 JQuery上传插件Uploadify使用详解 http://www.cnblogs.com/oec2003/archive/2010/01/06/1640027.html