| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- import 'dart:async';
- import 'package:flutter/material.dart';
- import 'package:get/get.dart';
- import 'package:in_app_purchase/in_app_purchase.dart';
- import 'package:video_player/video_player.dart';
- import '../../../../config/theme/dark_theme_colors.dart';
- import '../../../../config/translations/strings_enum.dart';
- import '../../../../utils/in_app_purchase_util.dart';
- import '../../../components/ix_snackbar.dart';
- import '../../../constants/assets.dart';
- class SubscriptionController extends GetxController {
- // 内购工具实例
- final InAppPurchaseUtil _iapUtil = InAppPurchaseUtil.instance;
- // 视频播放器控制器
- late VideoPlayerController videoController;
- final isVideoInitialized = false.obs;
- // 产品加载状态
- final isLoadingProducts = false.obs;
- // 购买处理中状态
- final isPurchasing = false.obs;
- // 产品列表
- final productDetails = <ProductDetails>[].obs;
- // 当前选中的订阅计划索引 (0: 年度, 1: 终身, 2: 月度, 3: 周度)
- final selectedPlanIndex = 0.obs;
- // 产品ID配置
- // iOS 测试: 使用 StoreKit Configuration 文件中配置的 ID
- // Android 测试: 需要在 Google Play Console 中创建对应的测试产品
- // 生产环境: 替换为你在 App Store Connect 和 Google Play Console 中创建的真实产品 ID
- final Map<String, String> productIds = {
- 'yearly': 'com.test.yearly', // 年度订阅
- 'lifetime': 'com.test.lifetime', // 终身会员
- 'monthly': 'com.test.monthly', // 月度订阅
- 'weekly': 'com.test.weekly', // 周度订阅
- };
- // 订阅计划列表
- List<Map<String, dynamic>> get plans => [
- {
- 'productId': productIds['yearly'],
- 'price': _getProductPrice(productIds['yearly']!) ?? '\$40.00',
- 'period': Strings.perYear.tr,
- 'title': Strings.yearlyPlan.tr,
- 'badge': Strings.mostlyChoose.tr,
- 'badgeBgColor': DarkThemeColors.bg1,
- 'badgeTextColor': DarkThemeColors.subscriptionColor,
- 'badgeBorderColor': DarkThemeColors.dividerColor,
- },
- {
- 'productId': productIds['lifetime'],
- 'price': _getProductPrice(productIds['lifetime']!) ?? '\$58.00',
- 'period': Strings.once.tr,
- 'title': Strings.lifeTime.tr,
- 'badge': null,
- },
- {
- 'productId': productIds['monthly'],
- 'price': _getProductPrice(productIds['monthly']!) ?? '\$58.00',
- 'period': Strings.perYear.tr,
- 'title': Strings.monthPlan.tr,
- 'badge': null,
- },
- {
- 'productId': productIds['weekly'],
- 'price': _getProductPrice(productIds['weekly']!) ?? '\$1.00',
- 'period': Strings.perWeek.tr,
- 'title': Strings.weekPlan.tr,
- 'badge': Strings.limitedTime.tr,
- 'badgeBgColor': DarkThemeColors.primaryColor,
- 'badgeTextColor': Colors.white,
- 'badgeBorderColor': null,
- },
- ];
- // 获取产品价格
- String? _getProductPrice(String productId) {
- final product = _iapUtil.getProductById(productId);
- return product?.price;
- }
- @override
- void onInit() {
- super.onInit();
- _initializeVideoPlayer();
- _initializeInAppPurchase();
- }
- @override
- void onClose() {
- videoController.dispose();
- // 注意: 不要在这里调用 _iapUtil.dispose()
- // 因为它是单例,可能在其他地方还在使用
- super.onClose();
- }
- /// 初始化内购
- Future<void> _initializeInAppPurchase() async {
- try {
- // 初始化内购
- final success = await _iapUtil.initialize(
- onSuccess: _handlePurchaseSuccess,
- onError: _handlePurchaseError,
- onCancelled: _handlePurchaseCancelled,
- onPending: _handlePurchasePending,
- onRestore: _handleRestoreSuccess,
- );
- if (success) {
- // 加载产品信息
- await _loadProducts();
- } else {
- IXSnackBar.showIXSnackBar(title: Strings.error.tr, message: '内购功能不可用');
- }
- } catch (e) {
- debugPrint('初始化内购失败: $e');
- }
- }
- /// 加载产品信息
- Future<void> _loadProducts() async {
- isLoadingProducts.value = true;
- try {
- final productIdSet = productIds.values.toSet();
- final success = await _iapUtil.loadProducts(productIdSet);
- if (success) {
- productDetails.value = _iapUtil.products;
- debugPrint('加载了 ${productDetails.length} 个产品');
- } else {
- IXSnackBar.showIXSnackBar(title: Strings.error.tr, message: '加载产品信息失败');
- }
- } catch (e) {
- debugPrint('加载产品失败: $e');
- } finally {
- isLoadingProducts.value = false;
- }
- }
- /// 处理购买成功
- void _handlePurchaseSuccess(PurchaseDetails purchaseDetails) {
- isPurchasing.value = false;
- IXSnackBar.showIXSnackBar(
- title: Strings.success.tr,
- message: '购买成功: ${purchaseDetails.productID}',
- );
- // TODO: 这里添加你的业务逻辑
- // 1. 更新用户订阅状态到服务器
- // 2. 更新本地存储
- // 3. 刷新 UI 显示
- }
- /// 处理购买失败
- void _handlePurchaseError(PurchaseDetails purchaseDetails) {
- isPurchasing.value = false;
- IXSnackBar.showIXSnackBar(
- title: Strings.error.tr,
- message: '购买失败: ${purchaseDetails.error?.message ?? "未知错误"}',
- );
- }
- /// 处理购买取消
- void _handlePurchaseCancelled(PurchaseDetails purchaseDetails) {
- isPurchasing.value = false;
- IXSnackBar.showIXSnackBar(title: Strings.info.tr, message: '购买已取消');
- }
- /// 处理购买等待中
- void _handlePurchasePending(PurchaseDetails purchaseDetails) {
- isPurchasing.value = true;
- IXSnackBar.showIXSnackBar(title: Strings.info.tr, message: '购买处理中...');
- }
- /// 处理恢复购买成功
- void _handleRestoreSuccess(PurchaseDetails purchaseDetails) {
- IXSnackBar.showIXSnackBar(
- title: Strings.success.tr,
- message: '恢复购买成功: ${purchaseDetails.productID}',
- );
- // TODO: 更新用户订阅状态
- }
- /// 发起购买
- Future<void> _requestPurchase(String productId) async {
- if (isPurchasing.value) {
- debugPrint('已有购买正在进行中');
- return;
- }
- isPurchasing.value = true;
- try {
- final success = await _iapUtil.purchaseProductById(productId);
- if (!success) {
- isPurchasing.value = false;
- IXSnackBar.showIXSnackBar(
- title: Strings.error.tr,
- message: '发起购买失败,请重试',
- );
- }
- } catch (e) {
- isPurchasing.value = false;
- debugPrint('购买异常: $e');
- IXSnackBar.showIXSnackBar(title: Strings.error.tr, message: '购买异常: $e');
- }
- }
- /// 恢复购买
- Future<void> _restorePurchases() async {
- try {
- final success = await _iapUtil.restorePurchases();
- if (success) {
- IXSnackBar.showIXSnackBar(
- title: Strings.info.tr,
- message: Strings.restoringPurchases.tr,
- );
- } else {
- IXSnackBar.showIXSnackBar(title: Strings.error.tr, message: '恢复购买失败');
- }
- } catch (e) {
- debugPrint('恢复购买异常: $e');
- IXSnackBar.showIXSnackBar(title: Strings.error.tr, message: '恢复购买异常: $e');
- }
- }
- // 初始化视频播放器
- void _initializeVideoPlayer() {
- videoController = VideoPlayerController.asset(Assets.subscriptionBg)
- ..initialize()
- .then((_) {
- isVideoInitialized.value = true;
- videoController.setLooping(true);
- videoController.setVolume(0); // 静音播放
- videoController.play();
- })
- .catchError((error) {
- print('视频初始化失败: $error');
- });
- }
- // 选择订阅计划
- void selectPlan(int index) {
- selectedPlanIndex.value = index;
- }
- // 确认变更/购买
- void confirmChange() {
- final plan = plans[selectedPlanIndex.value];
- final productId = plan['productId'] as String?;
- if (productId == null) {
- IXSnackBar.showIXSnackBar(title: Strings.error.tr, message: '产品ID未配置');
- return;
- }
- _requestPurchase(productId);
- }
- // 恢复购买
- void restorePurchases() {
- _restorePurchases();
- }
- // 支付问题
- void handlePaymentIssue() {
- // TODO: 实现支付问题处理逻辑
- IXSnackBar.showIXSnackBar(
- title: Strings.info.tr,
- message: Strings.openingPaymentSupport.tr,
- );
- }
- }
|