提交 d6302c91 authored 作者: 王鹏飞's avatar 王鹏飞

feat: migrate from flutter_inapp_purchase to official in_app_purchase plugin

Replace deprecated flutter_inapp_purchase (StoreKit 1 only) with the official in_app_purchase plugin supporting StoreKit 2 on iOS 15+. Update all IAP-related controllers (recharge, order awaiting/cancel/completed) to use InAppPurchase.instance, purchaseStream, and buyConsumable API.
上级 70946588
......@@ -7,8 +7,6 @@ PODS:
- Flutter (1.0.0)
- flutter_app_update (0.0.1):
- Flutter
- flutter_inapp_purchase (0.0.1):
- Flutter
- flutter_inappwebview_ios (0.0.1):
- Flutter
- flutter_inappwebview_ios/Core (= 0.0.1)
......@@ -30,6 +28,9 @@ PODS:
- WechatOpenSDK-XCFramework (~> 2.0.4)
- image_picker_ios (0.0.1):
- Flutter
- in_app_purchase_storekit (0.0.1):
- Flutter
- FlutterMacOS
- just_audio (0.0.1):
- Flutter
- FlutterMacOS
......@@ -57,12 +58,12 @@ DEPENDENCIES:
- connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`)
- Flutter (from `Flutter`)
- flutter_app_update (from `.symlinks/plugins/flutter_app_update/ios`)
- flutter_inapp_purchase (from `.symlinks/plugins/flutter_inapp_purchase/ios`)
- flutter_inappwebview_ios (from `.symlinks/plugins/flutter_inappwebview_ios/ios`)
- flutter_sound (from `.symlinks/plugins/flutter_sound/ios`)
- flutter_tts (from `.symlinks/plugins/flutter_tts/ios`)
- fluwx (from `.symlinks/plugins/fluwx/ios`)
- image_picker_ios (from `.symlinks/plugins/image_picker_ios/ios`)
- in_app_purchase_storekit (from `.symlinks/plugins/in_app_purchase_storekit/darwin`)
- just_audio (from `.symlinks/plugins/just_audio/darwin`)
- package_info_plus (from `.symlinks/plugins/package_info_plus/ios`)
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
......@@ -86,8 +87,6 @@ EXTERNAL SOURCES:
:path: Flutter
flutter_app_update:
:path: ".symlinks/plugins/flutter_app_update/ios"
flutter_inapp_purchase:
:path: ".symlinks/plugins/flutter_inapp_purchase/ios"
flutter_inappwebview_ios:
:path: ".symlinks/plugins/flutter_inappwebview_ios/ios"
flutter_sound:
......@@ -98,6 +97,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/fluwx/ios"
image_picker_ios:
:path: ".symlinks/plugins/image_picker_ios/ios"
in_app_purchase_storekit:
:path: ".symlinks/plugins/in_app_purchase_storekit/darwin"
just_audio:
:path: ".symlinks/plugins/just_audio/darwin"
package_info_plus:
......@@ -116,13 +117,13 @@ SPEC CHECKSUMS:
connectivity_plus: 481668c94744c30c53b8895afb39159d1e619bdf
Flutter: cabc95a1d2626b1b06e7179b784ebcf0c0cde467
flutter_app_update: 816fdb2e30e4832a7c45e3f108d391c42ef040a9
flutter_inapp_purchase: 722da12971a50f306f37e62fc1aaf576b1cbecf6
flutter_inappwebview_ios: b89ba3482b96fb25e00c967aae065701b66e9b99
flutter_sound: d95194f6476c9ad211d22b3a414d852c12c7ca44
flutter_sound_core: 7f2626d249d3a57bfa6da892ef7e22d234482c1a
flutter_tts: b88dbc8655d3dc961bc4a796e4e16a4cc1795833
fluwx: 49b4472b54762abde51daa0bc348ba05520016ac
image_picker_ios: e0ece4aa2a75771a7de3fa735d26d90817041326
in_app_purchase_storekit: 22cca7d08eebca9babdf4d07d0baccb73325d3c8
just_audio: 4e391f57b79cad2b0674030a00453ca5ce817eed
OrderedSet: e539b66b644ff081c73a262d24ad552a69be3a94
package_info_plus: 566e1b7a2f3900e4b0020914ad3fc051dcc95596
......
......@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_book/apis/index.dart';
import 'package:flutter_book/models/index.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:fluwx/fluwx.dart';
import 'package:get/get.dart';
......@@ -24,4 +24,4 @@ import 'dart:io';
part 'view.dart';
part 'controller.dart';
\ No newline at end of file
part 'controller.dart';
......@@ -56,8 +56,11 @@ class _CoinRechargePageState extends State<CoinRechargePage>
Container(
margin: EdgeInsets.symmetric(horizontal: 15.w),
child: CustomGradientButton(
text: '立即充值${controller.rechargeModel.priceName ?? ''}',
isEnabled: true,
text: controller.isSubmitting
? '正在充值...'
: '立即充值${controller.rechargeModel.priceName ?? ''}',
isEnabled: controller.rechargeModel.identifying != null &&
!controller.isSubmitting,
onPressed: () {
controller.createRechargeOrder();
},
......
......@@ -20,14 +20,10 @@ class UserOrderCoinAwaitingController extends GetxController {
// 微信
Fluwx fluwx = Fluwx();
late PayOrderModel payOrderModel;
dynamic _purchaseUpdatedSubscription;
dynamic _purchaseErrorSubscription;
dynamic _connectionSubscription;
PurchasedItem? _resultItem;
StreamSubscription<List<PurchaseDetails>>? _purchaseUpdatedSubscription;
PurchaseDetails? _resultItem;
List<IAPItem> _items = [];
///未完成的订单
final List<PurchasedItem> _pendingPurchases = [];
List<ProductDetails> _items = [];
// 紫荆币数据
List<CoinModel> data = [];
......@@ -37,7 +33,6 @@ class UserOrderCoinAwaitingController extends GetxController {
if(Platform.isIOS){
_getProduct();
initPlatformState();
_getPendingPurchase();
}
super.onInit();
}
......@@ -50,42 +45,27 @@ class UserOrderCoinAwaitingController extends GetxController {
@override
void onClose() {
// controller.onRefresh();
if (_connectionSubscription != null) {
_connectionSubscription.cancel();
_connectionSubscription = null;
}
if (_purchaseUpdatedSubscription != null) {
_purchaseUpdatedSubscription.cancel();
_purchaseUpdatedSubscription!.cancel();
_purchaseUpdatedSubscription = null;
}
if (_purchaseErrorSubscription != null) {
_purchaseErrorSubscription.cancel();
_purchaseErrorSubscription = null;
}
super.onClose();
}
/// 初始化
Future<void> initPlatformState() async{
await FlutterInappPurchase.instance.initialize();
_connectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
});
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
CustomToast.dismiss();
if(productItem != null){
_resultItem = productItem;
requestOrderStatus();
}
});
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
CustomToast.dismiss();
Toast.show(purchaseError!.message.toString());
});
final available = await InAppPurchase.instance.isAvailable();
_iapLog('IAP store available: $available');
_purchaseUpdatedSubscription =
InAppPurchase.instance.purchaseStream.listen(
_listenToPurchaseUpdated,
onError: (error) {
CustomToast.dismiss();
_iapLog('IAP purchase stream error: $error');
Toast.show('内购发生错误,请稍后重试');
},
);
}
......@@ -130,14 +110,20 @@ class UserOrderCoinAwaitingController extends GetxController {
.map((coinModel) => coinModel.identifying!)
.toList();
List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(productList);
for (var item in items) {
_items.add(item);
if (productList.isEmpty) return;
_iapLog('IAP productList: $productList');
try {
final response =
await InAppPurchase.instance.queryProductDetails(productList.toSet());
_items = response.productDetails;
_iapLog('IAP query error: ${response.error}');
_iapLog('IAP not found ids: ${response.notFoundIDs}');
_iapLog('IAP loaded items: ${_items.map((item) => item.id).toList()}');
} catch (error) {
_items = [];
_iapLog('IAP getProducts failed: $error');
}
_items = items;
// update();
}
/// 支付订单
......@@ -145,8 +131,8 @@ class UserOrderCoinAwaitingController extends GetxController {
// 苹果支付
if (model.payType ==3){
// 发起苹果支付
IAPItem targetItem = _items.firstWhere(
(item) => item.productId == model.goodsId,
ProductDetails targetItem = _items.firstWhere(
(item) => item.id == model.goodsId,
);
_requestPurchase(targetItem);
}
......@@ -178,10 +164,19 @@ class UserOrderCoinAwaitingController extends GetxController {
}
/// 苹果支付
void _requestPurchase(IAPItem item) {
void _requestPurchase(ProductDetails item) {
CustomToast.loading();
FlutterInappPurchase.instance
.requestPurchase(item.productId!);
try {
final purchaseParam = PurchaseParam(productDetails: item);
InAppPurchase.instance.buyConsumable(
purchaseParam: purchaseParam,
autoConsume: true,
);
} catch (error) {
CustomToast.dismiss();
_iapLog('IAP request purchase failed: $error');
Toast.show('内购发起失败,请稍后重试');
}
}
/// 支付宝支付
......@@ -220,7 +215,7 @@ class UserOrderCoinAwaitingController extends GetxController {
/// 获取订单状态
void requestOrderStatus() async {
final result = await ShopAPI.orderStatus(orderNumber: model.ordersnum??'',receipt:_resultItem != null?_resultItem!.transactionReceipt.toString():'');
final result = await ShopAPI.orderStatus(orderNumber: model.ordersnum??'',receipt:_resultItem != null?_resultItem!.verificationData.serverVerificationData.toString():'');
if (result.paySuccess == 1){
Toast.show('订单支付完成');
if(context.mounted){
......@@ -239,7 +234,6 @@ class UserOrderCoinAwaitingController extends GetxController {
}
StorageService.to.setObject(kFailOrder, temp);
}
FlutterInappPurchase.instance.finishTransactionIOS(_resultItem!.transactionId!);
}
}
else{
......@@ -248,8 +242,8 @@ class UserOrderCoinAwaitingController extends GetxController {
// 保存未支付的订单
Map<String,String> failOrder = {
'orderNum':payOrderModel.ordersnum??'',
'transactionReceipt':_resultItem!.transactionReceipt.toString(),
'transactionId':_resultItem!.transactionId.toString()
'transactionReceipt':_resultItem!.verificationData.serverVerificationData.toString(),
'transactionId':_resultItem!.purchaseID.toString()
};
List<Map> failOrderList = [];
failOrderList.add(failOrder);
......@@ -259,23 +253,33 @@ class UserOrderCoinAwaitingController extends GetxController {
}
///获取未完成的购买
Future _getPendingPurchase() async {
List<PurchasedItem>? items = await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items!) {
_pendingPurchases.add(item);
}
if(StorageService.to.getObject(kFailOrder) !=null){
List<Map<String,String>> failOrderList = StorageService.to.getObject(kFailOrder) as List<Map<String, String>>;
for (var item in _pendingPurchases) {
for (var element in failOrderList) {
if(element['transactionId'] == item.transactionId){
requestOrderStatus();
}
}
void _iapLog(String message) {
Console.log(message);
debugPrint(message);
}
Future<void> _listenToPurchaseUpdated(
List<PurchaseDetails> purchaseDetailsList) async {
for (final purchaseDetails in purchaseDetailsList) {
_iapLog(
'IAP purchase update: ${purchaseDetails.productID}, ${purchaseDetails.status}, ${purchaseDetails.error}');
if (purchaseDetails.status == PurchaseStatus.pending) {
continue;
}
CustomToast.dismiss();
if (purchaseDetails.status == PurchaseStatus.error) {
Toast.show(purchaseDetails.error?.message ?? '内购发生错误,请稍后重试');
} else if (purchaseDetails.status == PurchaseStatus.canceled) {
Toast.show('支付已取消');
} else if (purchaseDetails.status == PurchaseStatus.purchased ||
purchaseDetails.status == PurchaseStatus.restored) {
_resultItem = purchaseDetails;
requestOrderStatus();
}
if (purchaseDetails.pendingCompletePurchase) {
await InAppPurchase.instance.completePurchase(purchaseDetails);
}
}
}
}
library user_order_coin_awaiting;
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_book/utils/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:fluwx/fluwx.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
......
......@@ -20,14 +20,10 @@ class UserOrderCoinCancelController extends GetxController {
// 微信
Fluwx fluwx = Fluwx();
late PayOrderModel payOrderModel;
dynamic _purchaseUpdatedSubscription;
dynamic _purchaseErrorSubscription;
dynamic _connectionSubscription;
PurchasedItem? _resultItem;
StreamSubscription<List<PurchaseDetails>>? _purchaseUpdatedSubscription;
PurchaseDetails? _resultItem;
List<IAPItem> _items = [];
///未完成的订单
final List<PurchasedItem> _pendingPurchases = [];
List<ProductDetails> _items = [];
List<CoinModel> data = [];
......@@ -37,7 +33,6 @@ class UserOrderCoinCancelController extends GetxController {
if(Platform.isIOS){
_getProduct();
initPlatformState();
_getPendingPurchase();
}
super.onInit();
}
......@@ -50,43 +45,27 @@ class UserOrderCoinCancelController extends GetxController {
@override
void onClose() {
// controller.onRefresh();
if (_connectionSubscription != null) {
_connectionSubscription.cancel();
_connectionSubscription = null;
}
if (_purchaseUpdatedSubscription != null) {
_purchaseUpdatedSubscription.cancel();
_purchaseUpdatedSubscription!.cancel();
_purchaseUpdatedSubscription = null;
}
if (_purchaseErrorSubscription != null) {
_purchaseErrorSubscription.cancel();
_purchaseErrorSubscription = null;
}
super.onClose();
}
/// 初始化
Future<void> initPlatformState() async{
await FlutterInappPurchase.instance.initialize();
_connectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
});
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
CustomToast.dismiss();
if(productItem != null){
_resultItem = productItem;
requestOrderStatus();
}
});
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
CustomToast.dismiss();
Toast.show(purchaseError!.message.toString());
});
final available = await InAppPurchase.instance.isAvailable();
_iapLog('IAP store available: $available');
_purchaseUpdatedSubscription =
InAppPurchase.instance.purchaseStream.listen(
_listenToPurchaseUpdated,
onError: (error) {
CustomToast.dismiss();
_iapLog('IAP purchase stream error: $error');
Toast.show('内购发生错误,请稍后重试');
},
);
}
......@@ -131,13 +110,20 @@ class UserOrderCoinCancelController extends GetxController {
.map((coinModel) => coinModel.identifying!)
.toList();
List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(productList);
for (var item in items) {
_items.add(item);
if (productList.isEmpty) return;
_iapLog('IAP productList: $productList');
try {
final response =
await InAppPurchase.instance.queryProductDetails(productList.toSet());
_items = response.productDetails;
_iapLog('IAP query error: ${response.error}');
_iapLog('IAP not found ids: ${response.notFoundIDs}');
_iapLog('IAP loaded items: ${_items.map((item) => item.id).toList()}');
} catch (error) {
_items = [];
_iapLog('IAP getProducts failed: $error');
}
_items = items;
// update();
}
/// 支付订单
......@@ -145,8 +131,8 @@ class UserOrderCoinCancelController extends GetxController {
// 苹果支付
if (model.payType ==3){
// 发起苹果支付
IAPItem targetItem = _items.firstWhere(
(item) => item.productId == model.goodsId,
ProductDetails targetItem = _items.firstWhere(
(item) => item.id == model.goodsId,
);
_requestPurchase(targetItem);
}
......@@ -178,10 +164,19 @@ class UserOrderCoinCancelController extends GetxController {
}
/// 苹果支付
void _requestPurchase(IAPItem item) {
void _requestPurchase(ProductDetails item) {
CustomToast.loading();
FlutterInappPurchase.instance
.requestPurchase(item.productId!);
try {
final purchaseParam = PurchaseParam(productDetails: item);
InAppPurchase.instance.buyConsumable(
purchaseParam: purchaseParam,
autoConsume: true,
);
} catch (error) {
CustomToast.dismiss();
_iapLog('IAP request purchase failed: $error');
Toast.show('内购发起失败,请稍后重试');
}
}
/// 支付宝支付
......@@ -220,7 +215,7 @@ class UserOrderCoinCancelController extends GetxController {
/// 获取订单状态
void requestOrderStatus() async {
final result = await ShopAPI.orderStatus(orderNumber: model.ordersnum??'',receipt:_resultItem != null?_resultItem!.transactionReceipt.toString():'');
final result = await ShopAPI.orderStatus(orderNumber: model.ordersnum??'',receipt:_resultItem != null?_resultItem!.verificationData.serverVerificationData.toString():'');
if (result.paySuccess == 1){
Toast.show('订单支付完成');
if(context.mounted){
......@@ -239,7 +234,6 @@ class UserOrderCoinCancelController extends GetxController {
}
StorageService.to.setObject(kFailOrder, temp);
}
FlutterInappPurchase.instance.finishTransactionIOS(_resultItem!.transactionId!);
}
}
else{
......@@ -248,8 +242,8 @@ class UserOrderCoinCancelController extends GetxController {
// 保存未支付的订单
Map<String,String> failOrder = {
'orderNum':payOrderModel.ordersnum??'',
'transactionReceipt':_resultItem!.transactionReceipt.toString(),
'transactionId':_resultItem!.transactionId.toString()
'transactionReceipt':_resultItem!.verificationData.serverVerificationData.toString(),
'transactionId':_resultItem!.purchaseID.toString()
};
List<Map> failOrderList = [];
failOrderList.add(failOrder);
......@@ -259,25 +253,33 @@ class UserOrderCoinCancelController extends GetxController {
}
///获取未完成的购买
Future _getPendingPurchase() async {
List<PurchasedItem>? items = await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items!) {
_pendingPurchases.add(item);
}
if(StorageService.to.getObject(kFailOrder) !=null){
List<Map<String,String>> failOrderList = StorageService.to.getObject(kFailOrder) as List<Map<String, String>>;
for (var item in _pendingPurchases) {
for (var element in failOrderList) {
if(element['transactionId'] == item.transactionId){
requestOrderStatus();
}
}
void _iapLog(String message) {
Console.log(message);
debugPrint(message);
}
Future<void> _listenToPurchaseUpdated(
List<PurchaseDetails> purchaseDetailsList) async {
for (final purchaseDetails in purchaseDetailsList) {
_iapLog(
'IAP purchase update: ${purchaseDetails.productID}, ${purchaseDetails.status}, ${purchaseDetails.error}');
if (purchaseDetails.status == PurchaseStatus.pending) {
continue;
}
CustomToast.dismiss();
if (purchaseDetails.status == PurchaseStatus.error) {
Toast.show(purchaseDetails.error?.message ?? '内购发生错误,请稍后重试');
} else if (purchaseDetails.status == PurchaseStatus.canceled) {
Toast.show('支付已取消');
} else if (purchaseDetails.status == PurchaseStatus.purchased ||
purchaseDetails.status == PurchaseStatus.restored) {
_resultItem = purchaseDetails;
requestOrderStatus();
}
if (purchaseDetails.pendingCompletePurchase) {
await InAppPurchase.instance.completePurchase(purchaseDetails);
}
}
}
}
library user_order_coin_cancel;
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_book/utils/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:fluwx/fluwx.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
......
......@@ -20,13 +20,9 @@ class UserOrderCoinCompletedController extends GetxController {
// 微信
Fluwx fluwx = Fluwx();
late PayOrderModel payOrderModel;
dynamic _purchaseUpdatedSubscription;
dynamic _purchaseErrorSubscription;
dynamic _connectionSubscription;
PurchasedItem? _resultItem;
List<IAPItem> _items = [];
///未完成的订单
final List<PurchasedItem> _pendingPurchases = [];
StreamSubscription<List<PurchaseDetails>>? _purchaseUpdatedSubscription;
PurchaseDetails? _resultItem;
List<ProductDetails> _items = [];
List<CoinModel> data = [];
......@@ -36,7 +32,6 @@ class UserOrderCoinCompletedController extends GetxController {
if(Platform.isIOS){
_getProduct();
initPlatformState();
_getPendingPurchase();
}
super.onInit();
}
......@@ -49,43 +44,27 @@ class UserOrderCoinCompletedController extends GetxController {
@override
void onClose() {
// controller.onRefresh();
if (_connectionSubscription != null) {
_connectionSubscription.cancel();
_connectionSubscription = null;
}
if (_purchaseUpdatedSubscription != null) {
_purchaseUpdatedSubscription.cancel();
_purchaseUpdatedSubscription!.cancel();
_purchaseUpdatedSubscription = null;
}
if (_purchaseErrorSubscription != null) {
_purchaseErrorSubscription.cancel();
_purchaseErrorSubscription = null;
}
super.onClose();
}
/// 初始化
Future<void> initPlatformState() async{
await FlutterInappPurchase.instance.initialize();
_connectionSubscription = FlutterInappPurchase.connectionUpdated.listen((connected) {
});
_purchaseUpdatedSubscription = FlutterInappPurchase.purchaseUpdated.listen((productItem) {
CustomToast.dismiss();
if(productItem != null){
_resultItem = productItem;
requestOrderStatus();
}
});
_purchaseErrorSubscription = FlutterInappPurchase.purchaseError.listen((purchaseError) {
CustomToast.dismiss();
Toast.show(purchaseError!.message.toString());
});
final available = await InAppPurchase.instance.isAvailable();
_iapLog('IAP store available: $available');
_purchaseUpdatedSubscription =
InAppPurchase.instance.purchaseStream.listen(
_listenToPurchaseUpdated,
onError: (error) {
CustomToast.dismiss();
_iapLog('IAP purchase stream error: $error');
Toast.show('内购发生错误,请稍后重试');
},
);
}
......@@ -131,13 +110,20 @@ class UserOrderCoinCompletedController extends GetxController {
.map((coinModel) => coinModel.identifying!)
.toList();
List<IAPItem> items = await FlutterInappPurchase.instance.getProducts(productList);
for (var item in items) {
_items.add(item);
if (productList.isEmpty) return;
_iapLog('IAP productList: $productList');
try {
final response =
await InAppPurchase.instance.queryProductDetails(productList.toSet());
_items = response.productDetails;
_iapLog('IAP query error: ${response.error}');
_iapLog('IAP not found ids: ${response.notFoundIDs}');
_iapLog('IAP loaded items: ${_items.map((item) => item.id).toList()}');
} catch (error) {
_items = [];
_iapLog('IAP getProducts failed: $error');
}
_items = items;
// update();
}
/// 支付订单
......@@ -145,8 +131,8 @@ class UserOrderCoinCompletedController extends GetxController {
// 苹果支付
if (model.payType ==3){
// 发起苹果支付
IAPItem targetItem = _items.firstWhere(
(item) => item.productId == model.goodsId,
ProductDetails targetItem = _items.firstWhere(
(item) => item.id == model.goodsId,
);
_requestPurchase(targetItem);
}
......@@ -178,10 +164,19 @@ class UserOrderCoinCompletedController extends GetxController {
}
/// 苹果支付
void _requestPurchase(IAPItem item) {
void _requestPurchase(ProductDetails item) {
CustomToast.loading();
FlutterInappPurchase.instance
.requestPurchase(item.productId!);
try {
final purchaseParam = PurchaseParam(productDetails: item);
InAppPurchase.instance.buyConsumable(
purchaseParam: purchaseParam,
autoConsume: true,
);
} catch (error) {
CustomToast.dismiss();
_iapLog('IAP request purchase failed: $error');
Toast.show('内购发起失败,请稍后重试');
}
}
/// 支付宝支付
......@@ -220,7 +215,7 @@ class UserOrderCoinCompletedController extends GetxController {
/// 获取订单状态
void requestOrderStatus() async {
final result = await ShopAPI.orderStatus(orderNumber: model.ordersnum??'',receipt:_resultItem != null?_resultItem!.transactionReceipt.toString():'');
final result = await ShopAPI.orderStatus(orderNumber: model.ordersnum??'',receipt:_resultItem != null?_resultItem!.verificationData.serverVerificationData.toString():'');
if (result.paySuccess == 1){
Toast.show('订单支付完成');
if(context.mounted){
......@@ -239,7 +234,6 @@ class UserOrderCoinCompletedController extends GetxController {
}
StorageService.to.setObject(kFailOrder, temp);
}
FlutterInappPurchase.instance.finishTransactionIOS(_resultItem!.transactionId!);
}
}
else{
......@@ -248,8 +242,8 @@ class UserOrderCoinCompletedController extends GetxController {
// 保存未支付的订单
Map<String,String> failOrder = {
'orderNum':payOrderModel.ordersnum??'',
'transactionReceipt':_resultItem!.transactionReceipt.toString(),
'transactionId':_resultItem!.transactionId.toString()
'transactionReceipt':_resultItem!.verificationData.serverVerificationData.toString(),
'transactionId':_resultItem!.purchaseID.toString()
};
List<Map> failOrderList = [];
failOrderList.add(failOrder);
......@@ -259,25 +253,33 @@ class UserOrderCoinCompletedController extends GetxController {
}
///获取未完成的购买
Future _getPendingPurchase() async {
List<PurchasedItem>? items = await FlutterInappPurchase.instance.getPurchaseHistory();
for (var item in items!) {
_pendingPurchases.add(item);
}
if(StorageService.to.getObject(kFailOrder) !=null){
List<Map<String,String>> failOrderList = StorageService.to.getObject(kFailOrder) as List<Map<String, String>>;
for (var item in _pendingPurchases) {
for (var element in failOrderList) {
if(element['transactionId'] == item.transactionId){
requestOrderStatus();
}
}
void _iapLog(String message) {
Console.log(message);
debugPrint(message);
}
Future<void> _listenToPurchaseUpdated(
List<PurchaseDetails> purchaseDetailsList) async {
for (final purchaseDetails in purchaseDetailsList) {
_iapLog(
'IAP purchase update: ${purchaseDetails.productID}, ${purchaseDetails.status}, ${purchaseDetails.error}');
if (purchaseDetails.status == PurchaseStatus.pending) {
continue;
}
CustomToast.dismiss();
if (purchaseDetails.status == PurchaseStatus.error) {
Toast.show(purchaseDetails.error?.message ?? '内购发生错误,请稍后重试');
} else if (purchaseDetails.status == PurchaseStatus.canceled) {
Toast.show('支付已取消');
} else if (purchaseDetails.status == PurchaseStatus.purchased ||
purchaseDetails.status == PurchaseStatus.restored) {
_resultItem = purchaseDetails;
requestOrderStatus();
}
if (purchaseDetails.pendingCompletePurchase) {
await InAppPurchase.instance.completePurchase(purchaseDetails);
}
}
}
}
library user_order_coin_completed;
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_book/theme.dart';
import 'package:flutter_book/utils/index.dart';
import 'package:flutter_book/widgets/index.dart';
import 'package:flutter_inapp_purchase/flutter_inapp_purchase.dart';
import 'package:in_app_purchase/in_app_purchase.dart';
import 'package:fluwx/fluwx.dart';
import 'package:get/get.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
......
差异被折叠。
......@@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.1+5
version: 1.0.1+6
environment:
sdk: '>=3.0.0 <4.0.0'
......@@ -95,7 +95,7 @@ dependencies:
# 支付宝
tobias: ^3.3.0
# 内购
flutter_inapp_purchase: ^5.6.1
in_app_purchase: ^3.2.1
encrypt: ^5.0.3
# 阿里oss直传
flutter_oss_aliyun: ^6.4.1
......
Markdown 格式
0% 或
您添加了 0 人 到此讨论。请谨慎行事。
请先完成此评论的编辑!
请 注册 或者 后发表评论