android amazon 支付接入
流程:
申请 Amazon 开发者帐号 ---> 在 amazon 控制台添加应用 ---> 添加应用内商品(消费类商品,授权类商品,订阅类商品)---> 导出 JSON 文件 --->集成 Amazon 支付 ---> 将导出的 JSON 文件 copy 到 /mnt/sdcard/目录下---> 沙河模式下测试支付 ---> 上传发布
注意:亚马逊目前使用 V1 签名;2.targetSdkVersion 版本必须小于等于29
SDK运行模式一共三种:
①:SANDBOX 沙河模式,用于测试,与 Amazon App Tester 测试工具交互
②:PRODUCTION 提交到亚马逊应用商店才可测试
③:UNKNOWN 尚未通过调用verifyLicense()初始化SDK。
步骤一:集成亚马逊内购SDK
implementation 'com.amazon.device:amazon-appstore-sdk:3.0.4'
步骤二:在 AndroidManifest.xml 文件中添加 ResponseReceiver 配置,如果应用 targetSdkVersion 设置的是 31 或更高版本,必须显式地将 android:exported 设置 ResponseReceiver 中android:exported 设置为true。
<receiver android:name="com.amazon.device.iap.ResponseReceiver" android:exported="true"android:permission="com.amazon.inapp.purchasing.Permission.NOTIFY" ><intent-filter><actionandroid:name="com.amazon.inapp.purchasing.NOTIFY" /></intent-filter></receiver>
步骤三:实现并注册PurchasingListener (onCreate 生命周期方法中调用)
purchasingListener = new PurchasingListener() {/*** 确定当前登录用户的UserId和marketplace。* @param response*/@Overridepublic void onUserDataResponse(final UserDataResponse response) {Log.d(LOG_TAG, "onUserDataResponse: requestId (" + response.getRequestId()+ ") userIdRequestStatus: "+ response.getRequestStatus()+ ")");//当前用户相关信息(用户ID和市场final UserDataResponse.RequestStatus status = response.getRequestStatus();switch (status) {case SUCCESSFUL:Log.d(LOG_TAG, "onUserDataResponse: get user id " + response.getUserData().getUserId()+ ", marketplace "+ response.getUserData().getMarketplace());currentUserId = response.getUserData().getUserId();currentMarketplace = response.getUserData().getMarketplace();break;case FAILED:Log.d(LOG_TAG, "onUserDataResponse FAILED failed, status code is " + status);case NOT_SUPPORTED:Log.d(LOG_TAG, "onUserDataResponse NOT_SUPPORTED failed, status code is " + status);break;}}/*** 检索应用中销售的SKU的信息* 使用来自ProductDataResponse对象的有效SKU。** @param response*/@Overridepublic void onProductDataResponse(final ProductDataResponse response) {final ProductDataResponse.RequestStatus status = response.getRequestStatus();Log.d(LOG_TAG, "onProductDataResponse: RequestStatus (" + status + ")");switch (status) {case SUCCESSFUL:Log.d(LOG_TAG, "onProductDataResponse: successful. The item data map in this response includes the valid SKUs");final Set<String> unavailableSkus = response.getUnavailableSkus();for (final String s : response.getUnavailableSkus()) {Log.v(LOG_TAG, unavailableSkus.size() + " 不可用SKU:" + s);}final Map<String, Product> products = response.getProductData();for (final String key : products.keySet()) {Product product = products.get(key);Log.v(LOG_TAG, String.format("可购买的产品:%s\n 类型:%s\n SKU:%s\n 价格:%s\n 描述:%s\n", product.getTitle(), product.getProductType(), product.getSku(), product.getPrice(), product.getDescription()));// 处理产品}break;case FAILED:case NOT_SUPPORTED:Log.d(LOG_TAG, "onProductDataResponse: failed, should retry request");break;}}/*** 检索自上次调用该方法之后用户完成的所有购买交易* 仅可检索未履行和已取消的消费品购买* @param response*/@Overridepublic void onPurchaseUpdatesResponse(final PurchaseUpdatesResponse response) {Log.d(LOG_TAG, "PurchaseUpdatesResponse: requestId (" + response.getRequestId()+ ") Status ("+ response.getRequestStatus()+ ") userId ("+ response.getUserData().getUserId()+ ")");//获取请求状态final PurchaseUpdatesResponse.RequestStatus status = response.getRequestStatus();switch (status) {case SUCCESSFUL:Log.e(LOG_TAG, "========no consumeProduct==========" + response.getReceipts());//PurchasingService.getProductDatafor (final Receipt receipt : response.getReceipts()) {LogD("购买收据 + receipt " + receipt.isCanceled() + "\n" + "收据:" + receipt.getReceiptId());if (!receipt.isCanceled()) {String localReceipt = SharedPreferencesUtil.getString(mContext, receipt.getReceiptId(), "");Gson gson = new Gson();Type type = new TypeToken<Hashtable<String, String>>(){}.getType();Hashtable<String, String> localPurchase= gson.fromJson(localReceipt, type);if(null!=localPurchase){myProductInfo = localPurchase;}receiptID = receipt.getReceiptId();Log.e(LOG_TAG, "----------myProductInfo------------: " + myProductInfo);consumeProduct(receipt,"2");}}// if (response.hasMore()) {
// //如果不启用“待定购买”,则在每次getPurchaseUpdates(false)调用中只返回未履行的消费品收据
// PurchasingService.getPurchaseUpdates(false);
// return;
// }break;case NOT_SUPPORTED:Log.d(LOG_TAG, "onProductDataResponse: failed, should retry request");break;}}/*** purchase()用户拉起支付后,用于确定购买状态。** @param response*/@Overridepublic void onPurchaseResponse(final PurchaseResponse response) {final String requestId = response.getRequestId().toString();final String userId = response.getUserData().getUserId();final PurchaseResponse.RequestStatus status = response.getRequestStatus();Log.d(LOG_TAG, "支付成功回调 onPurchaseResponse: requestId (" + requestId+ ") userId ("+ userId+ ") purchaseRequestStatus ("+ status+ ")");switch (status) {case SUCCESSFUL://交易成功final Receipt receipt = response.getReceipt();Log.d(LOG_TAG, "onPurchaseResponse: receipt json:" + receipt.toJSON());receiptID = receipt.getReceiptId();Log.d(LOG_TAG, "onPurchaseResponse: receipt receiptID:" + receipt.getReceiptId());//请求服务端跟amazon校验//校验成功去消耗PurchasingService.notifyFulfillment(receiptID, FulfillmentResult.FULFILLED);break;
// case PENDING:
// Log.d(LOG_TAG, "onPurchaseResponse: 等待远程批准——如果获得批准,购买将在 getPurchaseUpdates 中返回");
// break;case ALREADY_PURCHASED://已经授权过的,属于成功,此时将道具给玩家即可Log.d(LOG_TAG, "onPurchaseResponse: 已经授权过的,属于成功,此时将道具给玩家即可");break;case INVALID_SKU:Log.d(LOG_TAG, "onPurchaseResponse: invalid SKU!无效SKU,无法识别");break;case FAILED:case NOT_SUPPORTED:Log.e(LOG_TAG, "支付失败 用户在完成之前取消了购买");break;}}};
步骤四:注册监听(onCreate 生命周期方法中调用)
PurchasingService.registerListener(mContext, purchasingListener);
步骤五:通过 getUserData() 当前用户相关(用户ID和市场),我这边是放在了onCreate 生命周期方法中
PurchasingService.getUserData();(onCreate 生命周期方法中调用)
步骤六:检索自上次调用该方法之后用户完成的所有购买交易,以确保获取最新的更新
PurchasingService.getPurchaseUpdates(true);(onCreate 生命周期方法中调用)
-
false- 返回自上次调用getPurchaseUpdates()之后的购买记录的分页响应。检索用户的未履行消费品、权利和订阅购买的收据。亚马逊应用商店建议在大部分情况下使用此方法。注意: 如果您的应用启用了待定购买,则亚马逊应用商店会在每次
getPurchaseUpdates(false)调用中为用户返回所有未履行的消费品和权利收据,直到您的应用调用notifyFulfillment()为止。如果不启用“待定购买”,则在每次getPurchaseUpdates(false)调用中只返回未履行的消费品收据。 -
true- 检索用户的完整购买记录。需要将数据存储在某个位置(例如服务器端数据缓存),或将所有数据保留在内存中。
步骤七:验证SKU,购买中不会因 SKU 无效而意外失败。
Set<String> productSkus = new HashSet<>();productSkus.add("skus1");productSkus.add("skus12");productSkus.add("skus3");....PurchasingService.getProductData(productSkus);// 触发PurchasingListener.onProductDataResponse()
步骤八:拉起支付弹框支付
final RequestId requestId = PurchasingService.purchase("Product_Id");
注意:在消耗商品前,先完成后端服务器通过亚马逊的Receipt Verification Service (RVS)验证receiptId,从而验证购买所产生的收据。验证后再去消耗。
测试流程:
1:从亚马逊应用商店将Amazon App Tester下载到手机上。App Tester模拟生产环境,下载链接
2:下载后台的amazon.sdktester.json 文件复制到手机的/sdcard/文件夹中,在Amazon App Tester应用中找到 IAP items in JSON File,看下是否有数据
adb push F:/download/amazon.sdktester.json /mnt/sdcard/
3:adb shell setprop debug.amazon.sandboxmode debug 设置为沙盒模式
//检查应用是否处于测试模式
Log.d(TAG, "Appstore SDK Mode: " + LicensingService.getAppstoreSDKMode());
以上就是 Amazon 支付的接入流程,发布到 Amazon 后才可以正式付费,但正式付费跟测试付费显示效果是一样的.
相关文章:
android amazon 支付接入
流程: 申请 Amazon 开发者帐号 ---> 在 amazon 控制台添加应用 ---> 添加应用内商品(消费类商品,授权类商品,订阅类商品)---> 导出 JSON 文件 --->集成 Amazon 支付 ---> 将导出的 JSON 文件 copy 到 …...
Vue2-快速搭建pc端后台管理系统
一.推荐二次开发框架 vue-element-admin Star(84k)vue-antd-admin Star(3.5k) 二.vue-element-admin 官网链接:https://panjiachen.github.io/vue-element-admin-site/zh/ 我这里搭建的是基础模版vue-admin-template(推荐) # 克隆项目 git clone https://github.com/PanJi…...
【产品文档】团队介绍PPT模板
今天和大家免费分享团队介绍的PPT模板。团队介绍是向他人展示团队的实力、专业性和能力的重要方式。通过一个有力的团队介绍,您可以突出团队的成员、经验、技能和取得的成就,从而增加信任、吸引合作伙伴、客户或投资者的兴趣 【模板预览】 动态演示效果…...
组件库的使用和自定义组件
目录 一、组件库介绍 1、什么是组件 2、组件库介绍 3、arco.design 二、组件库的使用 1、快速上手 2、主题定制 3、暗黑模式 4、语言国际化 5、业务常见问题 三、自定义组件 2、组件开发规范 3、示例实践guide-tip 4、业务组件快速托管 一、组件库介绍 1、什么是…...
网站和API支持HTTPS,最好在Nginx上配置
随着我们网站用户的增多,我们会逐渐意识到HTTPS加密的重要性。在不修改现有代码的情况下,要从HTTP升级到HTTPS,让Nginx支持HTTPS是个很好的选择。今天我们来讲下如何从Nginx入手,从HTTP升级到HTTPS,同时支持静态网站和…...
UnitTest笔记: 拓展库DDT的使用
DDT (Data-Drivers- Tests) 允许使用不同的测试数据运行同一个测试用例,展示为不同的测试用例。 第一步: pip安装 ddt 第二步: 创建test_baidu_ddt.py 1. 测试类要使用ddt 修饰 2. 不同形式的参数化: 列表,字典&a…...
裂缝检测,只依赖OPENCV,基于YOLO8S
裂缝检测,只依赖OPENCV,YOLOV8S 现在YOLOV8S训练目标非常方便,可以直接转换成ONNX让OPENCV调用,支持C/PYTHON,原理很简单,自己找博客,有兴趣相互交流...
python编程环境使用技巧3-程序打包pyinstaller
前言 在Python中,打包指的是将Python代码和相关资源(如配置文件、图像等)整合到一个可执行的文件或安装包中,以便于在其他环境中使用。 下面是使用pyinstaller进行打包的简要步骤: 1-安装pyinstaller:在命…...
Go 自学:defer关键字
我们可以使用defer关键字延迟代码的执行,相当于我们把代码放入一个stack中,遵循last in first out的原则输出代码。 package mainimport ("fmt" )func myDefer() {for i : 0; i < 5; i {defer fmt.Print(i)} }func main() {defer fmt.Prin…...
【云计算】Docker特别版——前端一篇学会
docker学习 文章目录 一、下载安装docker(一)Windows桌面应用安装(二)Linux命令安装 二、windows注册登录docker三、Docker的常规操作(一)、基本的 Docker 命令(二)、镜像操作(三)、容器的配置(四)、登录远程仓库 四、镜像管理(一…...
.net使用RabbitMQ小记
使用RabbitMQ的优点 1.性能全面,rabbitmq性能比较全面,是消息中间件的首选 2.高并发,rabbitmq实现语言是天生就具备高并发高可用的erlang语言 3.任务异步处理,将不需要同步处理的并且耗时长的操作由消息队列通知消息接受方进行异步…...
layUI 中 穿梭框无法获取值的细节问题
初始化的时候一定要指定id,不然就会出现无法调用 获得右侧数据和实例重载的方法...
Kaggle回归问题Mercedes——Benz Greener Manufacturing
目录 前言1 题目介绍2 数据清洗3 数据可视化分析4 模型训练5 源码 前言 这是我在大三选修课的课程设计,内容参考了Kaggle上高赞的代码,有详细批注,整体比较基础,结构相对完整,便于初学者学习。这个是一个回归问题&…...
天润融通「微藤大语言模型平台2.0」以知识驱动企业高速增长
8月23日,天润融通(又称“天润云”,2167.HK),正式发布「微藤大语言模型平台2.0」。 “大模型企业知识企业知识工程”。 “不能有效记录和管理知识的企业是不能持续进步的。在企业的生产流程中,相比于其他场景࿰…...
【BUG】解决安装oracle11g或12C中无法访问临时位置的问题
项目场景: 安装oracle时,到第二步出现oracle11g或12C中无法访问临时位置的问题。 解决方案: 针对客户端安装,在cmd中执行命令:前面加实际路径setup.exe -ignorePrereq -J"-Doracle.install.client.validate.cli…...
2. 使用IDEA创建Spring Boot Hello项目并管理依赖——Maven入门指南
前言:本文将介绍如何使用IDEA创建一个Spring Boot Hello项目,并通过Maven来管理项目的依赖。我们从项目的创建到代码的编写,再到项目的构建和运行,一步步演示了整个过程。 🚀 作者简介:作为某云服务提供商的…...
Python在电路课程中的应用
1 需求 课程中有大量的计算,电路方程、复数计算,之前都是用的MATLAB online,可现在要过期了,只能更换平台。 2 工具 https://www.online-python.com/ Python3 在线工具 | 菜鸟工具 (runoob.com) 3 Sinusoid 章节 涉及到复数计…...
Spark SQL join的三种实现方式
引言 join是SQL中的常用操作,良好的表结构能够将数据分散到不同的表中,使其符合某种规范(mysql三大范式),可以最大程度的减少数据冗余,更新容错等,而建立表和表之间关系的最佳方式就是join操作。 对于Spark来说有3种…...
wazuh环境配置和漏洞复现
1.wazuh配置 虚拟机 (OVA) - 替代安装 (wazuh.com)在官方网页安装ova文件 打开VMware选择打开虚拟机,把下载好的ova文件放入在设置网络改为NAT模式 账号:wazuh-user 密码:wazuh ip a 查看ip 启动小皮 远程连接 账号admin …...
九五从零开始的运维之路(其三十六)
文章目录 前言一、集群概述1.负载均衡技术类型(一)四层负载均衡器(二)七层负载均衡器 2.负载均衡实现方式(一)硬件负载均衡产品:(二)软件负载均衡产品: 二、L…...
SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
网站指纹识别
网站指纹识别 网站的最基本组成:服务器(操作系统)、中间件(web容器)、脚本语言、数据厍 为什么要了解这些?举个例子:发现了一个文件读取漏洞,我们需要读/etc/passwd,如…...
基于PHP的连锁酒店管理系统
有需要请加文章底部Q哦 可远程调试 基于PHP的连锁酒店管理系统 一 介绍 连锁酒店管理系统基于原生PHP开发,数据库mysql,前端bootstrap。系统角色分为用户和管理员。 技术栈 phpmysqlbootstrapphpstudyvscode 二 功能 用户 1 注册/登录/注销 2 个人中…...
Kubernetes 网络模型深度解析:Pod IP 与 Service 的负载均衡机制,Service到底是什么?
Pod IP 的本质与特性 Pod IP 的定位 纯端点地址:Pod IP 是分配给 Pod 网络命名空间的真实 IP 地址(如 10.244.1.2)无特殊名称:在 Kubernetes 中,它通常被称为 “Pod IP” 或 “容器 IP”生命周期:与 Pod …...
AxureRP-Pro-Beta-Setup_114413.exe (6.0.0.2887)
Name:3ddown Serial:FiCGEezgdGoYILo8U/2MFyCWj0jZoJc/sziRRj2/ENvtEq7w1RH97k5MWctqVHA 注册用户名:Axure 序列号:8t3Yk/zu4cX601/seX6wBZgYRVj/lkC2PICCdO4sFKCCLx8mcCnccoylVb40lP...
GeoServer发布PostgreSQL图层后WFS查询无主键字段
在使用 GeoServer(版本 2.22.2) 发布 PostgreSQL(PostGIS)中的表为地图服务时,常常会遇到一个小问题: WFS 查询中,主键字段(如 id)莫名其妙地消失了! 即使你在…...
CSP信奥赛C++常用系统函数汇总
# CSP信奥赛C常用系统函数汇总## 一、输入输出函数### 1. cin / cout(<iostream>) cpp int x; cin >> x; // 输入 cout << x << endl;// 输出 优化:ios::sync_with_stdio(false); 可提升速度 2. scanf() /…...
Python网页自动化测试,DrissonPage库入门说明文档
🛰️ 基本逻辑 操作浏览器的基本逻辑如下: 创建浏览器对象,用于启动或接管浏览器获取一个 Tab 对象使用 Tab 对象访问网址使用 Tab 对象获取标签页内需要的元素对象使用元素对象进行交互 除此以外,还能执行更为复杂的操作&am…...
