优化:启动速度优化

This commit is contained in:
ivan 2026-03-30 14:29:55 +08:00
parent 42d9cf3fd2
commit 79d4e32e3e
9 changed files with 139 additions and 33 deletions

View File

@ -13,7 +13,7 @@
<application
android:usesCleartextTraffic="${usesCleartextTraffic}"
android:label="PetsHero AI"
android:name="${applicationName}"
android:name=".PetsHeroApplication"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"

View File

@ -8,9 +8,8 @@ import io.flutter.embedding.android.FlutterActivity
class MainActivity : FlutterActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// 必须在 super.onCreate 之前初始化,否则 facebook_app_events 插件注册时会因 SDK 未初始化而崩溃
FacebookSdk.sdkInitialize(applicationContext)
// Facebook SDK 调试日志:需 buildConfigField FACEBOOK_DEBUG_LOGS=true
super.onCreate(savedInstanceState)
// Facebook SDK 调试日志SDK 已在 [PetsHeroApplication] 中初始化)
if (BuildConfig.FACEBOOK_DEBUG_LOGS) {
try {
FacebookSdk.setIsDebugEnabled(true)
@ -19,6 +18,5 @@ class MainActivity : FlutterActivity() {
FacebookSdk.addLoggingBehavior(LoggingBehavior.DEVELOPER_ERRORS)
} catch (_: Exception) { /* ignore */ }
}
super.onCreate(savedInstanceState)
}
}

View File

@ -0,0 +1,15 @@
package com.petsheroai.app
import android.app.Application
import com.facebook.FacebookSdk
/**
* Facebook SDK 初始化从 [MainActivity] 挪到 Application避免阻塞 Activity.onCreate
* Flutter 引擎与首帧更早开始减轻一直停在原生启动屏的概率
*/
class PetsHeroApplication : Application() {
override fun onCreate() {
super.onCreate()
FacebookSdk.sdkInitialize(applicationContext)
}
}

View File

@ -1,5 +1,8 @@
import 'dart:async';
import 'package:facebook_app_events/facebook_app_events.dart';
import 'package:flutter/material.dart';
import 'package:flutter_native_splash/flutter_native_splash.dart';
import 'core/auth/auth_service.dart';
import 'core/nav/app_route_observer.dart';
@ -41,6 +44,8 @@ class _AppState extends State<App> with WidgetsBindingObserver {
WidgetsBinding.instance.addObserver(this);
// resumeddidChangeAppLifecycleState resumed
WidgetsBinding.instance.addPostFrameCallback((_) {
// +Logo Flutter
FlutterNativeSplash.remove();
_reportFacebookActivateApp('first_frame');
});
}
@ -96,18 +101,7 @@ class _AppState extends State<App> with WidgetsBindingObserver {
if (snapshot.connectionState == ConnectionState.done) {
return const SizedBox.shrink();
}
return Positioned.fill(
child: AbsorbPointer(
child: Container(
color: Colors.black.withValues(alpha: 0.2),
child: const Center(
child: CircularProgressIndicator(
color: AppColors.primary,
),
),
),
),
);
return const _StartupLoginOverlay();
},
),
],
@ -144,6 +138,78 @@ class _AppState extends State<App> with WidgetsBindingObserver {
}
}
/// [AuthService.loginComplete]/
class _StartupLoginOverlay extends StatefulWidget {
const _StartupLoginOverlay();
@override
State<_StartupLoginOverlay> createState() => _StartupLoginOverlayState();
}
class _StartupLoginOverlayState extends State<_StartupLoginOverlay> {
static const _longWaitAfter = Duration(seconds: 22);
Timer? _longWaitTimer;
bool _showNetworkHint = false;
@override
void initState() {
super.initState();
_longWaitTimer = Timer(_longWaitAfter, () {
if (mounted) setState(() => _showNetworkHint = true);
});
}
@override
void dispose() {
_longWaitTimer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Positioned.fill(
child: AbsorbPointer(
child: Container(
color: Colors.black.withValues(alpha: 0.22),
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 28),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const CircularProgressIndicator(color: AppColors.primary),
if (_showNetworkHint) ...[
const SizedBox(height: 22),
Text(
'网络较慢或暂时无法连接',
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.surface.withValues(alpha: 0.96),
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const SizedBox(height: 10),
Text(
'请检查 WiFi 或移动数据,稍候片刻。若网络正常,可能是服务器繁忙,请过一会再试。',
textAlign: TextAlign.center,
style: TextStyle(
color: AppColors.surface.withValues(alpha: 0.78),
fontSize: 14,
height: 1.4,
),
),
],
],
),
),
),
),
),
);
}
}
class _MainScaffold extends StatefulWidget {
const _MainScaffold({
required this.currentTab,

View File

@ -37,4 +37,7 @@ abstract final class ApiConfig {
/// URL
static String get proxyUrl => '$baseUrl$proxyPath';
/// HTTP /
static const Duration httpRequestTimeout = Duration(seconds: 20);
}

View File

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/foundation.dart';
@ -282,11 +283,22 @@ class ProxyClient {
final url = '$_baseUrl${ApiConfig.proxyPath}';
_log('真实请求URL: $url');
final response = await http.post(
Uri.parse(url),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(proxyBody),
);
http.Response response;
try {
response = await http
.post(
Uri.parse(url),
headers: {'Content-Type': 'application/json'},
body: jsonEncode(proxyBody),
)
.timeout(ApiConfig.httpRequestTimeout);
} on TimeoutException {
_proxyLog.d('HTTP 超时 (${ApiConfig.httpRequestTimeout.inSeconds}s): $path');
return ApiResponse(
code: -1,
msg: 'Request timed out. Check your network and try again.',
);
}
return _parseResponse(response);
}

View File

@ -290,12 +290,8 @@ class AuthService {
UserState.setNavigate(countryCode);
}
// 3. android_adjustgg common_infoextConfig /
try {
await _reportBothReferrersAndRefreshCommonInfo(uid!, deviceId);
} catch (e) {
_logMsg('referrer/common_info 流程异常: $e');
}
// 3. common_info loginComplete/
unawaited(_runPostLoginReferrerWork(uid!, deviceId));
} else {
_logMsg('init: 登录失败');
}
@ -371,4 +367,12 @@ class AuthService {
'common_info 失败: code=${commonRes.code} msg=${commonRes.msg}');
}
}
static Future<void> _runPostLoginReferrerWork(String uid, String deviceId) async {
try {
await _reportBothReferrersAndRefreshCommonInfo(uid, deviceId);
} catch (e, _) {
_logMsg('referrer/common_info 后台任务失败: $e');
}
}
}

View File

@ -21,6 +21,12 @@ class ReferrerService {
/// [AuthService.init] getReferrer Adjust Play Install Referrer fallback
static const int _adjustTimeoutMs = 4500;
/// [Future.any] Future
static const Duration _adjustRaceTimeout = Duration(seconds: 6);
/// Play Install Referrer /
static const Duration _playInstallReferrerTimeout = Duration(seconds: 10);
/// Adjust attributionCallback getAttributionWithTimeout
static void receiveAttributionFromCallback(AdjustAttribution attribution) {
if (!_attributionCallbackCompleter.isCompleted) {
@ -79,7 +85,7 @@ class ReferrerService {
}
})(),
_attributionCallbackCompleter.future,
]);
]).timeout(_adjustRaceTimeout, onTimeout: () => null);
if (attribution != null) {
final raw = _attributionToDigest(attribution);
if (raw.isNotEmpty) {
@ -95,7 +101,8 @@ class ReferrerService {
_referrerSource = 'gg';
if (defaultTargetPlatform == TargetPlatform.android) {
try {
final details = await PlayInstallReferrer.installReferrer;
final details = await PlayInstallReferrer.installReferrer
.timeout(_playInstallReferrerTimeout);
digest = details.installReferrer ?? '';
} catch (_) {
digest = '';
@ -129,7 +136,8 @@ class ReferrerService {
static Future<String> getGgReferrerDigest() async {
if (defaultTargetPlatform != TargetPlatform.android) return '';
try {
final details = await PlayInstallReferrer.installReferrer;
final details = await PlayInstallReferrer.installReferrer
.timeout(_playInstallReferrerTimeout);
return details.installReferrer ?? '';
} catch (_) {
return '';

View File

@ -24,9 +24,9 @@ void main() async {
statusBarBrightness: Brightness.light,
),
);
// Adjust
AuthService.init();
// Flutter
runApp(const App());
AuthService.init();
// purchaseStream queryPastPurchases
if (defaultTargetPlatform == TargetPlatform.android) {
GooglePlayPurchaseService.startPendingPurchaseListener();