- 启动页先读本地凭证:无凭证(首次打开)直接进登录页,不再先等 SDK 初始化 - SDK init/login 加 20s 超时;init 用共享 Future 防止超时后重复触发 initSDK - 登录页对 IM 登录超时给出明确提示(确认手机连着公司内网 WiFi) - 修复 flutter create 模板遗留的 widget_test(引用不存在的 MyApp),改为登录页渲染冒烟测试 - 版本号 1.0.1+2
120 lines
3.7 KiB
Dart
120 lines
3.7 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:flutter_localizations/flutter_localizations.dart';
|
|
|
|
import 'nav.dart';
|
|
import 'screens/call_screen.dart';
|
|
import 'screens/home_screen.dart';
|
|
import 'screens/login_screen.dart';
|
|
import 'services/call_service.dart';
|
|
import 'services/im_service.dart';
|
|
import 'theme.dart';
|
|
|
|
void main() {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
runApp(const ChanglianApp());
|
|
}
|
|
|
|
class ChanglianApp extends StatefulWidget {
|
|
const ChanglianApp({super.key});
|
|
|
|
@override
|
|
State<ChanglianApp> createState() => _ChanglianAppState();
|
|
}
|
|
|
|
class _ChanglianAppState extends State<ChanglianApp> {
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
// 被踢下线 / token 失效:清凭证、回登录页
|
|
IMService.instance.onForceLogout = () async {
|
|
await LoginScreen.clearCredential();
|
|
navigatorKey.currentState?.pushAndRemoveUntil(
|
|
MaterialPageRoute(builder: (_) => const LoginScreen()),
|
|
(route) => false,
|
|
);
|
|
};
|
|
// 来电时弹出通话界面
|
|
CallService.instance.onIncomingCall = () {
|
|
navigatorKey.currentState?.push(
|
|
MaterialPageRoute(builder: (_) => const CallScreen(), fullscreenDialog: true),
|
|
);
|
|
};
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
title: '畅联',
|
|
navigatorKey: navigatorKey,
|
|
theme: buildAppTheme(),
|
|
debugShowCheckedModeBanner: false,
|
|
localizationsDelegates: const [
|
|
GlobalMaterialLocalizations.delegate,
|
|
GlobalWidgetsLocalizations.delegate,
|
|
GlobalCupertinoLocalizations.delegate,
|
|
],
|
|
supportedLocales: const [Locale('zh', 'CN')],
|
|
locale: const Locale('zh', 'CN'),
|
|
home: const SplashGate(),
|
|
);
|
|
}
|
|
}
|
|
|
|
/// 启动页:初始化 SDK,有本地凭证则自动登录进主页,否则进登录页
|
|
class SplashGate extends StatefulWidget {
|
|
const SplashGate({super.key});
|
|
|
|
@override
|
|
State<SplashGate> createState() => _SplashGateState();
|
|
}
|
|
|
|
class _SplashGateState extends State<SplashGate> {
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
_boot();
|
|
}
|
|
|
|
Future<void> _boot() async {
|
|
final im = IMService.instance;
|
|
// 先读本地凭证:没有凭证(首次打开)直接去登录页,
|
|
// 不在启动页等 SDK 初始化——服务器连不上时 initSDK 可能长时间不返回,
|
|
// 不能让启动页一直转圈。
|
|
final credential = await LoginScreen.readCredential();
|
|
if (credential == null) {
|
|
if (!mounted) return;
|
|
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => const LoginScreen()));
|
|
return;
|
|
}
|
|
try {
|
|
await im.init().timeout(const Duration(seconds: 20));
|
|
await im.login(userID: credential.$1, token: credential.$2).timeout(const Duration(seconds: 20));
|
|
CallService.instance.start();
|
|
if (!mounted) return;
|
|
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => const HomeScreen()));
|
|
return;
|
|
} catch (_) {
|
|
// 自动登录失败(token 失效、服务器连不上等):清凭证回登录页
|
|
await LoginScreen.clearCredential();
|
|
}
|
|
if (!mounted) return;
|
|
Navigator.of(context).pushReplacement(MaterialPageRoute(builder: (_) => const LoginScreen()));
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const Scaffold(
|
|
body: Center(
|
|
child: Column(
|
|
mainAxisSize: MainAxisSize.min,
|
|
children: [
|
|
Text('畅联', style: TextStyle(fontSize: 32, fontWeight: FontWeight.w600, color: AppColors.primary)),
|
|
SizedBox(height: AppGap.x6),
|
|
SizedBox(width: 28, height: 28, child: CircularProgressIndicator(strokeWidth: 3, color: AppColors.primary)),
|
|
],
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|