【原创 附源码】Flutter集成谷歌支付详细流程(附源码)

最近有时间,特意整理了一下之前使用过的Flutter平台的海外支付,附源码及demo可供参考

这篇文章只记录Google支付的详细流程,相关Flutter文章链接如下:

【原创 附源码】Flutter集成Apple支付详细流程(附源码)

【原创 附源码】Flutter安卓及iOS海外登录--Google登录最详细流程​​​​​​​

【原创 附源码】Flutter安卓及iOS海外登录--Tiktok登录最详细流程

【原创 附源码】Flutter安卓及iOS海外登录--Facebook登录最详细流程

【原创 附源码】Flutter安卓及iOS海外登录--Apple登录最详细流程

让我们开始吧

一 google平台配置

首先进入谷歌开发者平台(记得科学上网)

https://developers.google.com/?hl=zh-cn

进入开发者平台之后,点击google play,创建我们的APP

点击登录管理中心

创建完我们的APP之后,就可以开始配置支付的功能。需要注意的是,在进行谷歌支付测试的时候,需要先提交一个封闭测试版本及以上等级(例如公开版本)的包,然后才可以去创建应用内支付的商品,等这个包提交审核通过之后才可以开始进行谷歌支付的测试。

点击创建轨道

点击创建新的发布版本

签名选择Google管理签名,然后上传aab格式的release版本的包,aab版本的包在这里生成
点开Build,选择Generate Signed Bundle/APK

 然后选择app bundle

然后一路next,最后选择release版本,然后finish

然后在输出控制台的build选项卡,即可找到刚刚打出来的aab包

然后上传就可以了。

上传完成之后,此时就可以配置应用内商品了,点击这里进行添加配置:

添加完成后记得激活,不然即使审核通过之后测试的时候也获取不到该商品

点击这里激活商品

这个时候商品的配置就完成了。

接下来添加测试账户,进入封闭测试页面,切换到【测试用户选项卡】,然后创建测试群组,在群组里添加测试人员账户即可

当你的APP审核通过之后,这个页面下方的测试人员参与方式便会生效,如下所示:

就可以将这些链接发给测试人员,让他们去安装进行测试购买。

最后修改一下测试政策状态

选中测试群组,然后将政策状态改为LICENSED

OK,配置完成

二 flutter 代码集成

使用到的第三方插件:

in_app_purchase: ^3.1.5

插件官网地址:https://pub.dev/packages/in_app_purchase

将插件添加至yaml文件,然后执行flutter pub get

执行完了记得去IOS和安卓端分别执行pod install 和 gradle sync同步一下第三方插件

然后在项目中新建dart文件,命名为:BuyEngine.dart

然后将以下代码放入:

import 'dart:async';
import 'dart:io';import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:in_app_purchase_storekit/in_app_purchase_storekit.dart';
import 'package:in_app_purchase_android/in_app_purchase_android.dart';class BuyEngin{StreamSubscription<List<PurchaseDetails>> _subscription;InAppPurchase _inAppPurchase;List<ProductDetails> _products; //内购的商品对象集合//初始化购买组件void initializeInAppPurchase() {// 初始化in_app_purchase插件_inAppPurchase = InAppPurchase.instance;//监听购买的事件final Stream<List<PurchaseDetails>> purchaseUpdated = _inAppPurchase.purchaseStream;_subscription = purchaseUpdated.listen((purchaseDetailsList) {_listenToPurchaseUpdated(purchaseDetailsList);}, onDone: () {_subscription.cancel();}, onError: (error) {error.printError();print("购买失败了");});}void resumePurchase(){_inAppPurchase.restorePurchases();}/// 加载全部的商品void buyProduct(String productId) async {print("请求商品id " + productId);List<String> _outProducts = [productId];final bool available = await _inAppPurchase.isAvailable();if (!available) {// ToastUtil.showToast("无法连接到商店");print("无法连接到商店");return;}//开始购买// ToastUtil.showToast("连接成功-开始查询全部商品");print("连接成功-开始查询全部商品");List<String> _kIds = _outProducts;final ProductDetailsResponse response = await _inAppPurchase.queryProductDetails(_kIds.toSet());print("商品获取结果  " + response.productDetails.toString());if (response.notFoundIDs.isNotEmpty) {// ToastUtil.showToast("无法找到指定的商品");print("无法找到指定的商品");// ToastUtil.showToast("无法找到指定的商品 数量 " + response.productDetails.length.toString());return;}// 处理查询到的商品列表List<ProductDetails> products = response.productDetails;print("products ==== " + products.length.toString());if (products.isNotEmpty) {//赋值内购商品集合_products = products;}print("全部商品加载完成了,可以启动购买了,总共商品数量为:${products.length}");//先恢复可重复购买// await _inAppPurchase. ();startPurchase(productId);}// 调用此函数以启动购买过程void startPurchase(String productId) async {print("购买的商品id为" + productId);if (_products != null && _products.isNotEmpty) {// ToastUtil.showToast("准备开始启动购买流程");try {ProductDetails productDetails = _getProduct(productId);print("一切正常,开始购买,信息如下:title: ${productDetails.title}  desc:${productDetails.description} ""price:${productDetails.price}  currencyCode:${productDetails.currencyCode}  currencySymbol:${productDetails.currencySymbol}");_inAppPurchase.buyConsumable(purchaseParam: PurchaseParam(productDetails: productDetails));} catch (e) {e.printError();print("购买失败了");}} else {print("当前没有商品无法调用购买逻辑");}}// 根据产品ID获取产品信息ProductDetails _getProduct(String productId) {return _products.firstWhere((product) => product.id == productId);}/// 内购的购买更新监听void _listenToPurchaseUpdated(List<PurchaseDetails> purchaseDetailsList) async {for (PurchaseDetails purchase in purchaseDetailsList) {if (purchase.status == PurchaseStatus.pending) {// 等待支付完成_handlePending();} else if (purchase.status == PurchaseStatus.canceled) {// 取消支付_handleCancel(purchase);} else if (purchase.status == PurchaseStatus.error) {// 购买失败_handleError(purchase.error);} else if (purchase.status == PurchaseStatus.purchased || purchase.status == PurchaseStatus.restored) {// ToastUtil.showToast(DataConfig.getShowName("Pay_Success_Tip"));//完成购买, 到服务器验证if (Platform.isAndroid) {var googleDetail = purchase as GooglePlayPurchaseDetails;checkAndroidPayInfo(googleDetail);} else if (Platform.isIOS) {var appstoreDetail = purchase as AppStorePurchaseDetails;checkApplePayInfo(appstoreDetail);}}}}/// 购买失败void _handleError(IAPError iapError) {// ToastUtil.showToast("${DataConfig.getShowName("Purchase_Failed")}:${iapError?.code} message${iapError?.message}");}/// 等待支付void _handlePending() {print("等待支付");}/// 取消支付void _handleCancel(PurchaseDetails purchase) {_inAppPurchase.completePurchase(purchase);}/// Android支付成功的校验void checkAndroidPayInfo(GooglePlayPurchaseDetails googleDetail) async {_inAppPurchase.completePurchase(googleDetail);print("安卓支付交易ID为" + googleDetail.purchaseID);print("安卓支付验证收据为" + googleDetail.verificationData.serverVerificationData);}/// Apple支付成功的校验void  checkApplePayInfo(AppStorePurchaseDetails appstoreDetail) async {_inAppPurchase.completePurchase(appstoreDetail);print("Apple支付交易ID为" + appstoreDetail.purchaseID);print("Apple支付验证收据为" + appstoreDetail.verificationData.serverVerificationData);}@overridevoid onClose() {if (Platform.isIOS) {final InAppPurchaseStoreKitPlatformAddition iosPlatformAddition =_inAppPurchase.getPlatformAddition<InAppPurchaseStoreKitPlatformAddition>();iosPlatformAddition.setDelegate(null);}_subscription.cancel();}}

至此集成完毕,开始测试谷歌支付

三 支付测试 

在调用谷歌支付的地方提前初始化购买插件:

BuyEngin _buyEngin = BuyEngin();
_buyEngin.initializeInAppPurchase();

然后调用即可:

_buyEngin.buyProduct("应用内商品ID");

应用内商品ID就是你在google开发者中心配置的应用内购买商品的product ID

如果一切正常,则会正常唤醒谷歌支付(记得是在科学上网的环境下测试)

支付完成后可以看到可以正常获取到交易的ID和交易的验证收据,为了避免被第三方恶意刷购买接口来进行非法购买,建议将该收据上传后端服务器进行验证,验证通过之后再去更新用户的购买信息

Ok ,集成完毕,功德+1
源码地址: GitHub - TheRuningAnt/FGTALogin: 使用Flutter 去集成海外平台第三方登录,包含Google、Tiktok、Facebook、Apple登录 
(注:直接调用该demo的谷歌支付无法支付成功,因为该demo使用的安卓包名是测试包名,并未正式上线,但是功能是经过使用真实上线的包名支付验证过的,如上截图所示。如需使用该demo进行谷歌支付测试,可将安卓包名替换为你自己的审核通过的包名然后进行测试)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/682162.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【大数据Hive】hive 表设计常用优化策略

目录 一、前言 二、hive 普通表查询原理 2.1 操作演示说明 2.1.1 创建一张表&#xff0c;并加载数据 2.1.2 统计3月24号的登录人数 2.1.3 查询原理过程总结 2.2 普通表结构带来的问题 三、hive分区表设计 3.1 区表结构 - 分区设计思想 3.2 操作演示 3.2.1 创建分区表…

解决MAC连上wifi或热点却不能上网问题

解决MAC连上wifi或热点却不能上网问题 #新换的mac昨天还能连上wifi&#xff0c;今天就不好使了。 找到连接的wifi点击详细信息&#xff0c;选择TCP/IP 中的配置IPV4 选择关闭

Python Matplotlib 的学习笔记

Python Matplotlib 的学习笔记 0. Python Matplotlib 简介1. 为什么要用 Matplotlib&#xff1f;2. Matplotlib 基础类详解2-1. Line&#xff08;线&#xff09;2-2. Marker&#xff08;标记&#xff09;2-3. Text&#xff08;文本&#xff09;2-4. Legend&#xff08;图例&…

中国电子学会2023年12月份青少年软件编程Scratch图形化等级考试试卷一级真题(含答案)

2023-12 Scratch一级真题 分数&#xff1a;100 题数&#xff1a;37 测试时长&#xff1a;60min 一、单选题(共25题&#xff0c;共50分) 1.观察下列每个圆形中的四个数&#xff0c;找出规律&#xff0c;在括号里填上适当的数&#xff1f;&#xff08;C&#xff09;&#xf…

预处理详解(下)

1.#运算符 #运算符将宏的一个参数转换为字符串字面量。它仅允许出现在带参数的宏的替换列表中。 #运算符所执行的操作可以理解为”字符串化“。 例如&#xff1a; 我们将打印的字符串中的n改为参数n,这样在传参的时候就也会随着变化。假如我们不将其改为参数n的话会发生什么呢…

C++ Qt框架开发 | 基于Qt框架开发实时成绩显示排序系统(3) 保存表格数据

对上两篇篇的工作C Qt框架开发| 基于Qt框架开发实时成绩显示排序系统&#xff08;1&#xff09;-CSDN博客和C Qt框架开发 | 基于Qt框架开发实时成绩显示排序系统&#xff08;2&#xff09;折线图显示-CSDN博客继续优化&#xff0c;增加一个保存按钮&#xff0c;用于保存成绩数据…

论文阅读-面向机器学习的云工作负载预测模型的性能分析

论文名称&#xff1a;Performance Analysis of Machine Learning Centered Workload Prediction Models for Cloud 摘要 由于异构服务类型和动态工作负载的高变异性和维度&#xff0c;资源使用的精确估计是一个复杂而具有挑战性的问题。在过去几年中&#xff0c;资源使用和流…

给定n个结点的树,其中有k个结点是特殊结点(未知),定义好结点:该结点到k个特殊结点的距离之和最小。若随机k个结点为特殊结点,求好结点个数的期望值

题目 思路: 举例: 其中黑色结点为特殊结点,可以看出,每种情况都有一个结点的s值不等于k / 2,但是是好结点,所以最后答案加一。 #include <bits/stdc++.h> using namespace std; #define int long long #define pb push_back #define fi first #define se second …

【北邮鲁鹏老师计算机视觉课程笔记】10 Classification 分类

【北邮鲁鹏老师计算机视觉课程笔记】10 Classification 分类 1 图像识别的基本范式 检测问题&#xff1a;不仅要知道有没有&#xff0c;还要知道在哪里 分类是整图级标签&#xff0c;检测是区域级标签&#xff0c;分割是像素级标签 2 检测任务的应用 3 单实例识别与类别识别…

【5G NR】【一文读懂系列】移动通讯中使用的信道编解码技术-Turbo编码原理

目录 Turbo码&#xff1a;无线通信中的革命性技术 引言 一、Turbo码的基本原理 1.1 卷积码基础&#xff1a; 1.2 Turbo码的构造&#xff1a; 1.2.1 分量编码器 1.2.2 随机交织器 1.2.3 穿刺和复接单元 1.3 编码器结构的重要性和影响 1.4 迭代解码&#xff1a; 1.4.1 …

接口测试怎么进行,如何做好接口测试

一、什么是接口&#xff1f; 接口测试主要用于外部系统与系统之间以及内部各个子系统之间的交互点&#xff0c;定义特定的交互点&#xff0c;然后通过这些交互点来&#xff0c;通过一些特殊的规则也就是协议&#xff0c;来进行数据之间的交互。 二、 常用接口采用方式&#x…

AI少女/HS2甜心选择2 仿剑三剑灵人物卡全合集打包

AI少女/HS2甜心选择2 仿剑三剑灵人物卡全合集打包 内含&#xff1a;菩提禅音[剑网3]明教晓天喵姐[剑3]明教晓天喵姐无帽版[剑3]茱莉亚[剑灵] 下载地址&#xff1a; https://www.changyouzuhao.cn/12492.html

配置DNS正反向解析服务!!!!

一.准备工作 #关闭防火墙和selinux,或者允许服务通过 [rootnode ~]# nmcli c mod ens32 ipv4.method manual ipv4.address 192.168.32.133/24 ipv4.gateway 192.168.32.2 ipv4.dns 192.168.32.132 [rootnode ~]# nmcli c reload [rootnode ~]# nmcli c up ens32[rootnode ~]# …

three.js 细一万倍教程 从入门到精通(三)

目录 五、详解PBR材质纹理 5.1、详解PBR物理渲染 5.2、标准网格材质与光照物理效果 5.3、置换贴图与顶点细分设置 5.4、设置粗糙度与粗糙度贴图 5.5、设置金属度与金属贴图 5.6、法线贴图应用 5.7、如何获取各种类型纹理贴图 5.8、纹理加载进度情况 单张图片加载 多…

数据结构-并查集

并查集原理 在一些应用问题中&#xff0c;需要将n个不同的元素划分成一些不相交的集合。开始时&#xff0c;每个元素自成一个 单元素集合&#xff0c;然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询一 个元素归属于那个集合的运算。适合于描述这类…

Matplotlib Figure与Axes速成:核心技能一网打尽

Matplotlib Figure与Axes速成&#xff1a;核心技能一网打尽 &#x1f335;文章目录&#x1f335; &#x1f333;引言&#x1f333;&#x1f333; 一、Figure&#xff08;图形&#xff09;&#x1f333;&#x1f341;1. 创建Figure&#x1f341;&#x1f341;2. 添加Axes&#…

NARF关键点提取原理简介

一、NARF2D边缘点探测的矩形平面的边长s和计算点p和上邻域的距离所用的k值 二、障碍物边缘和阴影边缘 三、NARF边缘点探测 四、NARF借助边缘点信息进行关键点检测 本人也是参考其他博主&#xff0c;以及这份英文文献写的(毕竟是英文文献&#xff0c;部分翻译肯定有些误差&…

一探Lepton Search究竟

2024年1月25日&#xff0c;阿里巴巴原技术副总裁在 Twitter 上称用不到 500 行 Python 代码实现了 AI 对话搜索引擎&#xff0c;并在27日附上了开源地址&#xff1a;https://github.com/leptonai/search_with_lepton&#xff0c;截止春节期间已经5.8K的Star。 Twitter截图 Comm…

Spring Security学习(四)——登陆认证(包括自定义登录页)

前言 和前面的文章隔了很长时间才更新Spring Security系列&#xff0c;主要原因一个是之前太忙了&#xff0c;把项目都忙完了&#xff0c;赶上春节假期&#xff0c;就慢慢研究。Spring Security的体系非常复杂&#xff0c;一口吃不了热豆腐&#xff0c;没办法速成&#xff0c;…

仰暮计划|“​他们艰苦半生,但真的希望祖国安祥,山河无恙”

自述&#xff0c;自赎 我没有在那个年代生活过&#xff0c;我一出生就是盛世中国&#xff0c;看遍了祖国的大好河山。但我没想到&#xff0c;走了这么远的路&#xff0c;吃了这么多的苦的爷爷会一直跟我说“不是国家不好&#xff0c;只是中国的钱拿去还债了&#xff0c;过了那…