diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 6eef413..0ed668c 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -4,7 +4,6 @@
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
-
diff --git a/assets/skin_config.json b/assets/skin_config.json
index 7b3a3e3..7584e71 100644
--- a/assets/skin_config.json
+++ b/assets/skin_config.json
@@ -54,7 +54,7 @@
]
},
"analytics": {
- "debugLogs": false,
+ "debugLogs": true,
"adjust": {
"appToken": "chflzzr4x5hc",
"environment": "sandbox",
diff --git a/lib/features/purchase/purchase_screen.dart b/lib/features/purchase/purchase_screen.dart
index af4b806..07f9710 100644
--- a/lib/features/purchase/purchase_screen.dart
+++ b/lib/features/purchase/purchase_screen.dart
@@ -27,7 +27,8 @@ class PurchaseScreen extends StatefulWidget {
State createState() => _PurchaseScreenState();
}
-class _PurchaseScreenState extends State {
+class _PurchaseScreenState extends State
+ with WidgetsBindingObserver {
List _products = [];
bool _loading = true;
String? _loadError;
@@ -35,8 +36,17 @@ class _PurchaseScreenState extends State {
int? _selectedIndex;
ThirdPartyPaymentWatch? _thirdPartyWatch;
+ void _resetPayingState() {
+ if (!mounted) return;
+ setState(() {
+ _paying = false;
+ _selectedIndex = null;
+ });
+ }
+
@override
void dispose() {
+ WidgetsBinding.instance.removeObserver(this);
_thirdPartyWatch?.dispose();
super.dispose();
}
@@ -44,6 +54,7 @@ class _PurchaseScreenState extends State {
@override
void initState() {
super.initState();
+ WidgetsBinding.instance.addObserver(this);
// Defer network + setState until after first frame so the route can paint and
// the main isolate stays responsive (avoids input ANR when opening this screen).
WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -53,6 +64,14 @@ class _PurchaseScreenState extends State {
});
}
+ @override
+ void didChangeAppLifecycleState(AppLifecycleState state) {
+ // 对齐 app_client:从 Google Play 返回时先解锁支付按钮,避免取消/失败后长时间转圈等待超时。
+ if (state == AppLifecycleState.resumed && _paying && mounted) {
+ _resetPayingState();
+ }
+ }
+
Future _loadProducts({bool isInitial = false}) async {
if (!isInitial) {
setState(() {
@@ -243,7 +262,10 @@ class _PurchaseScreenState extends State {
});
final picked = await _pickPaymentMethod(methods);
- if (!mounted || picked == null) return;
+ if (!mounted || picked == null) {
+ _resetPayingState();
+ return;
+ }
final pm = picked.paymentMethod?.trim() ?? '';
if (pm.isEmpty) {
@@ -339,6 +361,7 @@ class _PurchaseScreenState extends State {
createResponse: created,
createPaymentApp: currentBackendAppType(),
);
+ _resetPayingState();
return;
}
@@ -418,18 +441,16 @@ class _PurchaseScreenState extends State {
analyticsProduct: item,
);
- await NativeIapCoordinator.purchaseGooglePlay(
- sink: sink,
- userId: uid,
- activityId: aid,
- storeProductId: pid,
- createPaymentApp: currentBackendAppType(),
- );
-
- if (mounted) {
- setState(() {
- _paying = false;
- });
+ try {
+ await NativeIapCoordinator.purchaseGooglePlay(
+ sink: sink,
+ userId: uid,
+ activityId: aid,
+ storeProductId: pid,
+ createPaymentApp: currentBackendAppType(),
+ );
+ } finally {
+ _resetPayingState();
}
}
diff --git a/pubspec.yaml b/pubspec.yaml
index 3f462b8..fdbb3be 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -2,7 +2,7 @@ name: funymee_ai
description: "FunyMee AI Application."
publish_to: 'none'
-version: 1.0.0+1
+version: 1.0.14+14
environment:
sdk: ^3.11.1