mobile v1.0.3:登录卡死定位增强(B-58)
- SDK 初始化与登录拆成两步分别超时,提示语区分卡在哪一步 - 登录失败时读取并展示 OpenIM SDK 日志文件结尾(去 ANSI 颜色码),用户拍照即可回传诊断信息 - 模拟器实测(Android 15 x86_64):initSDK+login 对 192.168.200.11 全流程正常,排除服务端与代码逻辑问题 - libgojni arm64 已验证 16KB 页对齐,排除新机型兼容性问题
This commit is contained in:
@@ -80,7 +80,12 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
password: password,
|
||||
platformID: IMService.instance.platformID,
|
||||
);
|
||||
// 2. 登录 OpenIM SDK(服务器连不上时这一步可能长时间不返回,加超时兜底)
|
||||
// 2. 初始化消息组件(分两步超时,方便定位卡在哪一步)
|
||||
await IMService.instance.init().timeout(
|
||||
const Duration(seconds: 15),
|
||||
onTimeout: () => throw AuthException('消息组件初始化超时'),
|
||||
);
|
||||
// 3. 登录 OpenIM SDK
|
||||
await IMService.instance.login(userID: result.userID, token: result.token).timeout(
|
||||
const Duration(seconds: 20),
|
||||
onTimeout: () => throw AuthException('连不上消息服务器,请确认手机连着公司内网 WiFi'),
|
||||
@@ -102,7 +107,7 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
}
|
||||
}
|
||||
|
||||
/// 登录失败:在提示下方附上服务器自检结果,方便远程定位是哪一段不通
|
||||
/// 登录失败:在提示下方附上服务器自检结果和 SDK 日志结尾,方便远程定位是哪一段不通
|
||||
Future<void> _fail(String msg) async {
|
||||
final parts = [msg];
|
||||
try {
|
||||
@@ -113,6 +118,15 @@ class _LoginScreenState extends State<LoginScreen> {
|
||||
final sdkErr = IMService.instance.lastConnectError;
|
||||
if (sdkErr != null && sdkErr.isNotEmpty) parts.add('消息组件报告:$sdkErr');
|
||||
if (mounted) setState(() => _error = parts.join('\n'));
|
||||
// SDK 日志可能较大,异步读完后再补一行提示用户拍照
|
||||
try {
|
||||
final tail = await IMService.instance.sdkLogTail();
|
||||
if (tail.isNotEmpty && mounted) {
|
||||
setState(() => _error = '${parts.join('\n')}\n—— SDK 日志结尾(拍照发给我)——\n$tail');
|
||||
}
|
||||
} catch (_) {
|
||||
// 读日志失败不影响原提示
|
||||
}
|
||||
}
|
||||
|
||||
/// 逐个探测三个服务端口:能拿到任何 HTTP 响应就算通
|
||||
|
||||
@@ -39,6 +39,41 @@ class IMService extends ChangeNotifier {
|
||||
/// 最近一次连接失败的原始错误(诊断展示用)
|
||||
String? lastConnectError;
|
||||
|
||||
/// SDK 数据/日志目录(_doInit 时记录)
|
||||
String? _dataDir;
|
||||
|
||||
/// 读 SDK 日志文件的结尾部分(定位「SDK 卡在哪」用)。读不到返回空串。
|
||||
Future<String> sdkLogTail() async {
|
||||
try {
|
||||
final dataDir = _dataDir ?? '${(await getApplicationDocumentsDirectory()).path}/openim';
|
||||
final dir = Directory(dataDir);
|
||||
if (!dir.existsSync()) return '';
|
||||
final files = dir
|
||||
.listSync(recursive: true)
|
||||
.whereType<File>()
|
||||
.where((f) => f.path.endsWith('.log'))
|
||||
.toList()
|
||||
..sort((a, b) => b.lastModifiedSync().compareTo(a.lastModifiedSync()));
|
||||
if (files.isEmpty) return '';
|
||||
final file = files.first;
|
||||
final len = file.lengthSync();
|
||||
final start = len > 2048 ? len - 2048 : 0;
|
||||
final raf = file.openSync();
|
||||
try {
|
||||
raf.setPositionSync(start);
|
||||
final bytes = raf.readSync(len - start);
|
||||
// 去掉日志里的 ANSI 颜色码,免得截图里出现乱码
|
||||
return String.fromCharCodes(bytes)
|
||||
.replaceAll(RegExp(r'\x1B\[[0-9;]*m'), '')
|
||||
.trim();
|
||||
} finally {
|
||||
raf.closeSync();
|
||||
}
|
||||
} catch (_) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/// 是否已登录
|
||||
bool loggedIn = false;
|
||||
|
||||
@@ -98,6 +133,7 @@ class IMService extends ChangeNotifier {
|
||||
Future<void> _doInit() async {
|
||||
final dir = await getApplicationDocumentsDirectory();
|
||||
final dataDir = '${dir.path}/openim';
|
||||
_dataDir = dataDir;
|
||||
await Directory(dataDir).create(recursive: true);
|
||||
final ok = await OpenIM.iMManager.initSDK(
|
||||
platformID: platformID,
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
name: changlian
|
||||
description: 畅联 —— 公司内部通讯 App(手机端)
|
||||
publish_to: "none"
|
||||
version: 1.0.2+3
|
||||
version: 1.0.3+4
|
||||
|
||||
environment:
|
||||
sdk: ">=3.6.0 <4.0.0"
|
||||
|
||||
Reference in New Issue
Block a user