最近有时间,特意整理了一下之前使用过的Flutter平台的海外支付,附源码及demo可供参考
这篇文章只记录Apple支付的详细流程,其他相关Flutter文章链接如下:
【原创 附源码】Flutter集成谷歌支付详细流程(附源码)
【原创 附源码】Flutter安卓及iOS海外登录--Google登录最详细流程
【原创 附源码】Flutter安卓及iOS海外登录--Tiktok登录最详细流程
【原创 附源码】Flutter安卓及iOS海外登录--Facebook登录最详细流程
【原创 附源码】Flutter安卓及iOS海外登录--Apple登录最详细流程
让我们开始吧
首先使用苹果开发者账户登录苹果开发者平台
Sign In - Apple
添加的时候页面的指引很清晰,就不赘述了,苹果添加内购商品比较简单,加完就可以了。
然后去创建沙盒账户用来做苹果支付测试,回到首页,点击【用户和访问】
点击沙盒,然后添加一个苹果测试账户,这个账户可以是个假的邮箱,不需要是正式的Apple id,比如你可以设置为[email protected]类似之类的账户
添加完点击创建即可
使用到的第三方插件:
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> _subscription;
InAppPurchase _inAppPurchase;
List _products; //内购的商品对象集合
//初始化购买组件
void initializeInAppPurchase() {
// 初始化in_app_purchase插件
_inAppPurchase = InAppPurchase.instance;
//监听购买的事件
final Stream> 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 _outProducts = [productId];
final bool available = await _inAppPurchase.isAvailable();
if (!available) {
// ToastUtil.showToast("无法连接到商店");
print("无法连接到商店");
return;
}
//开始购买
// ToastUtil.showToast("连接成功-开始查询全部商品");
print("连接成功-开始查询全部商品");
List _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 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 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);
}
@override
void onClose() {
if (Platform.isIOS) {
final InAppPurchaseStoreKitPlatformAddition iosPlatformAddition =
_inAppPurchase.getPlatformAddition();
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替换为你自己的包名然后进行测试)