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

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

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

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

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

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

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

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

让我们开始吧

一 Apple开发者平台添加内购商品

首先使用苹果开发者账户登录苹果开发者平台

Sign In - Apple

点击【App】 

 

添加新的苹果内购商品

 

添加的时候页面的指引很清晰,就不赘述了,苹果添加内购商品比较简单,加完就可以了。

然后去创建沙盒账户用来做苹果支付测试,回到首页,点击【用户和访问】

点击沙盒,然后添加一个苹果测试账户,这个账户可以是个假的邮箱,不需要是正式的Apple id,比如你可以设置为88888@qq.com类似之类的账户

 

添加完点击创建即可

二 flutter 代码集成

使用到的第三方插件:

in_app_purchase: ^3.1.5

插件官网地址:in_app_purchase | Flutter package

将插件添加至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就是你在APP Store Connect配置的应用内购买商品的product ID

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

源码地址:GitHub - TheRuningAnt/FGTALogin: 使用Flutter 去集成海外平台第三方登录,包含Google、Tiktok、Facebook、Apple登录 

(注:直接调用该demo的苹果支付无法支付成功,因为该demo使用的bundle ID是测试ID,并未正式上线,但是功能是经过使用真实上线的bundle ID支付验证过的,如需使用该demo进行苹果支付测试,可将IOS工程下的bundlle ID替换为你自己的包名然后进行测试)

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

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

相关文章

《Java 简易速速上手小册》第2章:面向对象的 Java(2024 最新版)

文章目录 2.1 类和对象 - 构建你的小宇宙2.1.1 基础知识2.1.2 重点案例&#xff1a;设计一个简单的图书类2.1.3 拓展案例 1&#xff1a;学生管理系统2.1.4 拓展案例 2&#xff1a;账户管理系统 2.2 继承与多态 - 让一切变得更有趣2.2.1 基础知识2.2.2 重点案例&#xff1a;动物…

【51单片机】蜂鸣器(江科大)

11.1蜂鸣器 1.蜂鸣器介绍 蜂鸣器是一种将电信号转换为声音信号的器件,常用来产生设备的按键音、报警音等提示信号 蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器 有源蜂鸣器:内部自带振荡源,将正负极接上直流电压即可持续发声,频率固定 无源蜂鸣器:内部不带振荡源,需…

C语言strlen和sizeof的区别

strlen和sizeof没有联系 前者是库函数&#xff0c;统计长度的标志是是否有\0 后者是操作符。计算长度的标志是字节数量。

Linux_线程

线程与进程 多级页表 线程控制 线程互斥 线程同步 生产者消费者模型 常见概念 下面选取32位系统举例。 一.线程与进程 上图是曾经我们认为进程所占用的资源的集合。 1.1 线程概念 线程是一个执行分支&#xff0c;执行粒度比进程细&#xff0c;调度成本比进程低线程是cpu…

本地部署 Stable Cascade

本地部署 Stable Cascade 0. 引言1. 事前准备2. 本地部署 Stable Cascade3. 使用 Stable Cascade 生成图片4. Stable Cascade Github 地址 0. 引言 Stable Cascade 模型建立在 Wrstchen 架构之上&#xff0c;它与 Stable Diffusion 等其他模型的主要区别在于它的工作潜在空间要…

软考27-上午题-查找

一、基本概念 1-1、查找表&#xff1a; 同一类型的数据元素构成的集合。 对查找表常用的操作&#xff1a; 从查找表中查询某个特定的元素&#xff1b;检索某个特定的元素的各种属性。 通常只进行这两种操作的查找表&#xff1a;静态查找表 1-1-2、静态查找表&#xff1a; 顺…

B2科目二考试项目笔记

B2科目二考试项目笔记 1 桩考1.1 右起点倒库1.2 移库&#xff08;左→右&#xff09;1.3 驶向左起点1.4 左起点倒库1.5 驶向右起点 2 侧方停车考试阶段&#xff08;从路边开始&#xff09;&#xff1a; 3 直角转弯4 坡道定点停车和起步5 单边桥6 通过限速限宽门7 曲线行驶8 连续…

[OPEN SQL] 删除数据

DELETE语句用于删除数据库表中的数据 本次操作使用的数据库表为SCUSTOM&#xff0c;其字段内容如下所示 航班用户(SCUSTOM) 需要删除以下数据 1.删除单条数据 语法格式 DELETE <dbtab> FROM <wa>. DELETE <dbtab> FROM TABLE <itab>. DELETE FROM &…

Linux makefile 大型多文件的处理

最简单的例子是 main.cpp test.cpp test.h 首先将这三个写好 然后的话 test.cpp 上面输出 helloworld 首先我们在同一个目录下创建一个makefile 文件 然后用vim 编辑它 如下图&#xff08;使用的c&#xff09; mybin 是我们的可执行程序 gcc是编译的命令 gcc 前面必…

人形机器人专题:准直驱执行器深度:人形机器人执行器技术的前沿

今天分享的是人形机器人系列深度研究报告&#xff1a;《人形机器人专题&#xff1a;准直驱执行器深度&#xff1a;人形机器人执行器技术的前沿》。 &#xff08;报告出品方&#xff1a;招商证券&#xff09; 报告共计&#xff1a;34页 准直驱执行器具备独特优势 刚性执行器…

ArcgisForJS基础

文章目录 0.引言1.第一个ArcgisForJS应用程序1.1.安装部署ArcgisForJS1.2.实现ArcgisForJS应用程序 2.开发与调试工具2.1.集成开发环境2.2.调试工具2.3.Firebug 0.引言 ArcGIS API for JavaScript是一款由Esri公司开发的用于创建WebGIS应用的JavaScript库。它允许开发者通过调…

UI文件原理

使用UI文件创建界面很轻松很便捷&#xff0c;他的原理就是每次我们保存UI文件的时候&#xff0c;QtCreator就自动帮我们将UI文件翻译成C的图形界面创建代码。可以通过以下步骤查看代码 到工程编译目录&#xff0c;一般就是工程同级目录下会生成另一个编译目录&#xff0c;会找到…

Stable Diffusion主流UI详细介绍

Stable Diffusion目前主流的操作界面有WebUI、ComfyUI以及Fooocus 这里webui和fooocus在人机交互上的逻辑是一样的&#xff0c;fooocus界面更加简洁。 comfyui是在人机交互上是采用流程节点的交互逻辑&#xff0c;和上面略有区别。 界面分别如下&#xff1a; WebUI界面如下 we…

Spring 用法学习总结(二)之基于注解注入属性

Spring学习 5 基于注解方式创建对象6 基于注解注入属性 5 基于注解方式创建对象 注解是代码的特殊标记&#xff0c;可以简化xml配置&#xff0c;格式&#xff1a;注解名称(属性名称属性值&#xff09;&#xff0c;可以作用在类、方法、属性上 以下注解都可以创建bean实例 Com…

LeetCode 每日一题 Day 62 - 75

1686. 石子游戏 VI Alice 和 Bob 轮流玩一个游戏&#xff0c;Alice 先手。 一堆石子里总共有 n 个石子&#xff0c;轮到某个玩家时&#xff0c;他可以 移出 一个石子并得到这个石子的价值。Alice 和 Bob 对石子价值有 不一样的的评判标准 。双方都知道对方的评判标准。 给你…

提前部署游戏业务防护,为何如此重要?

现在做网络游戏的企业都知道服务器的安全对于我们来说很重要&#xff01;互联网上面的DDoS攻击和CC攻击等等无处不在&#xff0c;而游戏服务器对服务器的防御能力和处理能力要求更高&#xff0c;普通的服务器则是比较注重各方面能力的均衡。 随着游戏行业的壮大&#xff0c;网络…

Shell 学习笔记(一)-Shell脚本编程简介

一 什么是shell&#xff1f; shell是一个用 C 语言编写的程序&#xff0c;它是用户使用 Linux 的桥梁。Shell 既是一种命令语言&#xff0c;又是一种程序设计语言。 Shell 是指一种应用程序&#xff0c;这个应用程序提供了一个界面&#xff0c;用户通过这个界面访问操作系统内…

【学网攻】 第(28)节 -- OSPF虚链路

系列文章目录 目录 系列文章目录 文章目录 前言 一、什么是OSPF虚链路&#xff1f; 二、实验 1.引入 实验目标 实验背景 技术原理 实验步骤 实验设备 实验拓扑图 实验配置 扩展 实验拓扑图 实验配置 实验验证 文章目录 【学网攻】 第(1)节 -- 认识网络【学网攻…

winprop二次开发

winprop二次开发 前言工具1——整合多个天线结果用途代码实现 工具2——wallman辅助工具需求代码实现 前言 工作需求&#xff0c;对该软件进行简单地二次开发&#xff0c;都是一些挺简单的代码&#xff0c;单纯是为了上传之后将其从本地删除 工具1——整合多个天线结果 用途…

鲁南制药“健康幸福中国年”主题航班,开启探寻健康与幸福的旅程

“小年&#xff0c;小年&#xff0c;过了今天就是年。”提到过年&#xff0c;北方人的“过年”是从腊月二十三的“小年”开始的&#xff0c;而南方地区是在明天。虽然时间不同&#xff0c;但是浓浓的年味是一样的&#xff0c;红彤彤是主色调&#xff0c;喜洋洋是主乐曲&#xf…