-
Notifications
You must be signed in to change notification settings - Fork 250
Description
OpenIM Server Version
3.8.3+3
Operating System and CPU Architecture
macOS (AMD)
Deployment Method
第二次的初始化SDK,监听器 onConnectFailed报错,错误码:10000,返回的错误信息还是 错误信息: dial tcp xxx.xxx.xxx.xxx:10001: i/o timeout
第二次初始化SDK的监听器报错,提示的IP,是首次初始化SDK填写的IP,已经调用了反初始化,然后重新初始化更换了IP了,为啥第二次SDK,还是报错的首次初始化SDK的IP。
然后第二次初始化 监听器 onConnectFailed会一直报错,说连接不上第一次初始化SDK的ip, 不过关闭了app之后,重新打开。第二次初始化就成功了。这里就很奇怪。
是反初始化的时候,没有把首次初始化SDK里面的数据清理完整吗?
Bug Description and Steps to Reproduce
import 'dart:convert';
import 'dart:io';
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_openim_sdk/flutter_openim_sdk.dart';
import 'package:get/get.dart';
import 'package:openim_common/openim_common.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:openim_live/openim_live.dart';
import 'package:dio/dio.dart' as dio;
import '../config/domain_config.dart';
import '../../utils/AESUtils.dart' as LocalAESUtils;
import '../im_callback.dart';
class IMController extends GetxController with IMCallback, OpenIMLive {
late Rx userInfo;
late String atAllTag;
// 重连相关变量
int _reconnectAttempts = 0;
static const int _maxReconnectAttempts = 0; // 最大重连次数
static const Duration _reconnectDelay = Duration(seconds: 0);
bool _isReconnecting = false;
@OverRide
void onClose() {
super.close();
onCloseLive();
super.onClose();
}
@OverRide
void onInit() async {
super.onInit();
onInitLive();
WidgetsBinding.instance.addPostFrameCallback((_) => initOpenIM());
}
void initOpenIM() async {
// 打印初始化参数
print('=== SDK初始化参数 ===');
print('platformID: ${IMUtils.getPlatform()}');
print('apiAddr: ${Config.imApiUrl}');
print('wsAddr: ${Config.imWsUrl}');
print('dataDir: ${Config.cachePath}');
print('logLevel: ${Config.logLevel}');
print('logFilePath: ${Config.cachePath}');
print('====================');
final initialized = await OpenIM.iMManager.initSDK(
platformID: IMUtils.getPlatform(),
apiAddr: Config.imApiUrl,
wsAddr: Config.imWsUrl,
dataDir: Config.cachePath,
logLevel: Config.logLevel,
logFilePath: Config.cachePath,
listener: OnConnectListener(
onConnecting: () {
print("重新连接-init");
imSdkStatus(IMSdkStatus.connecting);
},
onConnectFailed: (code, error) {
print("连接失败-init");
imSdkStatus(IMSdkStatus.connectionFailed);
_handleConnectionFailedWithRetry(code ?? 0, error ?? 'Unknown error');
},
onConnectSuccess: () {
imSdkStatus(IMSdkStatus.connectionSucceeded);
_resetReconnectState();
},
onKickedOffline: kickedOffline,
onUserTokenExpired: kickedOffline,
onUserTokenInvalid: userTokenInvalid,
),
);
OpenIM.iMManager
..setUploadLogsListener(OnUploadLogsListener(onUploadProgress: uploadLogsProgress))
..userManager.setUserListener(OnUserListener(
onSelfInfoUpdated: (u) {
selfInfoUpdated(u);
userInfo.update((val) {
val?.nickname = u.nickname;
val?.faceURL = u.faceURL;
val?.remark = u.remark;
val?.ex = u.ex;
val?.globalRecvMsgOpt = u.globalRecvMsgOpt;
});
},
onUserStatusChanged: userStausChanged))
..messageManager.setAdvancedMsgListener(OnAdvancedMsgListener(
onRecvC2CReadReceipt: recvC2CMessageReadReceipt,
onRecvNewMessage: recvNewMessage,
onNewRecvMessageRevoked: recvMessageRevoked,
onRecvOfflineNewMessage: recvOfflineMessage,
onRecvOnlineOnlyMessage: (msg) {
print('onRecvOnlineOnlyMessage');
if (msg.isCustomType) {
final data = msg.customElem!.data;
final map = jsonDecode(data!);
final customType = map['customType'];
if (customType == CustomMessageType.callingInvite ||
customType == CustomMessageType.callingAccept ||
customType == CustomMessageType.callingReject ||
customType == CustomMessageType.callingCancel ||
customType == CustomMessageType.callingHungup) {
final signaling = SignalingInfo(invitation: InvitationInfo.fromJson(map['data']));
signaling.userID = signaling.invitation?.inviterUserID;
switch (customType) {
case CustomMessageType.callingInvite:
receiveNewInvitation(signaling);
break;
case CustomMessageType.callingAccept:
inviteeAccepted(signaling);
break;
case CustomMessageType.callingReject:
inviteeRejected(signaling);
break;
case CustomMessageType.callingCancel:
invitationCancelled(signaling);
break;
case CustomMessageType.callingHungup:
beHangup(signaling);
break;
}
}
}
},
))
..messageManager.setMsgSendProgressListener(OnMsgSendProgressListener(
onProgress: progressCallback,
))
..messageManager.setCustomBusinessListener(OnCustomBusinessListener(
onRecvCustomBusinessMessage: recvCustomBusinessMessage,
))
..friendshipManager.setFriendshipListener(OnFriendshipListener(
onBlackAdded: blacklistAdded,
onBlackDeleted: blacklistDeleted,
onFriendApplicationAccepted: friendApplicationAccepted,
onFriendApplicationAdded: friendApplicationAdded,
onFriendApplicationDeleted: friendApplicationDeleted,
onFriendApplicationRejected: friendApplicationRejected,
onFriendInfoChanged: friendInfoChanged,
onFriendAdded: friendAdded,
onFriendDeleted: friendDeleted,
))
..conversationManager.setConversationListener(OnConversationListener(
onConversationChanged: conversationChanged,
onNewConversation: newConversation,
onTotalUnreadMessageCountChanged: totalUnreadMsgCountChanged,
onInputStatusChanged: inputStateChanged,
onSyncServerFailed: (reInstall) {
imSdkStatus(IMSdkStatus.syncFailed, reInstall: reInstall ?? false);
_handleSyncFailedWithRetry(reInstall);
},
onSyncServerFinish: (reInstall) {
imSdkStatus(IMSdkStatus.syncEnded, reInstall: reInstall ?? false);
_resetReconnectState();
if (Platform.isAndroid) {
Permissions.request([Permission.systemAlertWindow]);
}
},
onSyncServerStart: (reInstall) {
imSdkStatus(IMSdkStatus.syncStart, reInstall: reInstall ?? false);
},
onSyncServerProgress: (progress) {
imSdkStatus(IMSdkStatus.syncProgress, progress: progress);
}))
..groupManager.setGroupListener(OnGroupListener(
onGroupApplicationAccepted: groupApplicationAccepted,
onGroupApplicationAdded: groupApplicationAdded,
onGroupApplicationDeleted: groupApplicationDeleted,
onGroupApplicationRejected: groupApplicationRejected,
onGroupInfoChanged: groupInfoChanged,
onGroupMemberAdded: groupMemberAdded,
onGroupMemberDeleted: groupMemberDeleted,
onGroupMemberInfoChanged: groupMemberInfoChanged,
onJoinedGroupAdded: joinedGroupAdded,
onJoinedGroupDeleted: joinedGroupDeleted,
));
Logger().sdkIsInited = initialized;
initializedSubject.sink.add(initialized);
}
Future login(String userID, String token) async {
try {
var user = await OpenIM.iMManager.login(
userID: userID,
token: token,
defaultValue: () async => UserInfo(userID: userID),
);
userInfo = UserFullInfo.fromJson(user.toJson()).obs;
_queryMyFullInfo();
_queryAtAllTag();
} catch (e, s) {
print('e: $e s:$s');
await _handleLoginRepeatError(e);
return Future.error(e, s);
}
}
Future logout() {
return OpenIM.iMManager.logout();
}
void _queryAtAllTag() async {
atAllTag = OpenIM.iMManager.conversationManager.atAllTag;
}
void _queryMyFullInfo() async {
final data = await Apis.queryMyFullInfo();
if (data is UserFullInfo) {
userInfo.update((val) {
val?.allowAddFriend = data.allowAddFriend;
val?.allowBeep = data.allowBeep;
val?.allowVibration = data.allowVibration;
val?.nickname = data.nickname;
val?.faceURL = data.faceURL;
val?.phoneNumber = data.phoneNumber;
val?.email = data.email;
val?.birth = data.birth;
val?.gender = data.gender;
});
}
}
_handleLoginRepeatError(e) async {
if (e is PlatformException && (e.code == "13002" || e.code == '1507')) {
await logout();
await DataSp.removeLoginCertificate();
}
}
/// 处理连接失败并尝试重连
void _handleConnectionFailedWithRetry(int code, String error) async {
if (_isReconnecting) {
print('正在重连中,忽略新的连接失败事件');
return;
}
_reconnectAttempts++;
print('连接失败,第 $_reconnectAttempts 次重连尝试,错误码: $code, 错误信息: $error');
if (_reconnectAttempts <= _maxReconnectAttempts) {
// 尝试重连
await _attemptReconnect();
} else {
// 重连次数已达上限,反初始化SDK并重新初始化
print('重连次数已达上限 ($_maxReconnectAttempts 次),开始反初始化SDK并重新初始化');
await _restartSDKWithLatestConfig();
}
}
/// 处理同步失败并尝试重连
void _handleSyncFailedWithRetry(bool? reInstall) async {
if (_isReconnecting) {
print('正在重连中,忽略新的同步失败事件');
return;
}
_reconnectAttempts++;
print('同步失败,第 $_reconnectAttempts 次重连尝试');
if (_reconnectAttempts <= _maxReconnectAttempts) {
// 尝试重连
await _attemptReconnect();
} else {
// 重连次数已达上限,反初始化SDK并重新初始化
print('重连次数已达上限 ($_maxReconnectAttempts 次),开始反初始化SDK并重新初始化');
await _restartSDKWithLatestConfig();
}
}
/// 尝试重连
Future _attemptReconnect() async {
if (_isReconnecting) {
return;
}
_isReconnecting = true;
print('等待 $_reconnectDelay.inSeconds 秒后进行第 $_reconnectAttempts 次重连...');
await Future.delayed(_reconnectDelay);
print('开始第 $_reconnectAttempts 次重连...');
try {
// 由于不需要重新初始化SDK,我们只需要等待一段时间
// 让SDK有机会自动重连,或者等待网络状态变化
// 等待一段时间让重连有机会发生
await Future.delayed(Duration(seconds: 5));
// 检查当前连接状态
// 这里我们可以通过检查SDK状态来判断是否重连成功
// 或者等待下一次连接状态回调
print('第 $_reconnectAttempts 次重连等待完成,检查连接状态...');
// 重连尝试完成,重置状态
// 如果连接成功,会在onConnectSuccess回调中重置状态
// 如果连接失败,会在onConnectFailed回调中继续重连
_isReconnecting = false;
} catch (e) {
print('第 $_reconnectAttempts 次重连失败: $e');
_isReconnecting = false;
}
}
/// 重置重连状态
void _resetReconnectState() {
_reconnectAttempts = 0;
_isReconnecting = false;
print('重连状态已重置');
}
/// 获取重连状态信息
Map<String, dynamic> getReconnectStatus() {
return {
'isReconnecting': _isReconnecting,
'reconnectAttempts': _reconnectAttempts,
'maxReconnectAttempts': _maxReconnectAttempts,
'reconnectDelay': _reconnectDelay.inSeconds,
};
}
/// 手动重置重连状态
void resetReconnectState() {
_resetReconnectState();
}
/// 反初始化SDK并重新初始化
Future _restartSDKWithLatestConfig() async {
try {
print('开始反初始化SDK...');
// // 反初始化SDK
// OpenIM.iMManager.unInitSDK();
// print('SDK反初始化成功');
// 重置重连状态
_resetReconnectState();
// 根据最新的appid重新请求服务器信息
print('开始获取最新的服务器配置...');
await _refreshServerConfig();
// 重新初始化SDK
print('开始重新初始化SDK...');
await _reinitializeSDK();
// 等待连接成功回调后再进行登录
print('等待连接成功回调...');
await _waitForConnectionSuccess();
// 重新登录
print('开始重新登录...');
await _relogin();
print('SDK重启和重新初始化完成');
} catch (e) {
print('SDK重启失败: $e');
// 如果重启失败,不再显示弹窗,而是记录错误日志
// 系统会继续尝试重连,直到达到最大重连次数
print('SDK重启失败,系统将继续尝试重连');
}
}
/// 刷新服务器配置
Future _refreshServerConfig() async {
try {
// 获取最新的appid
final latestAppId = await _getLatestAppId();
print('获取到最新appid: $latestAppId');
// 根据appid重新请求服务器信息
await _requestServerConfig(latestAppId);
print('服务器配置刷新成功');
} catch (e) {
print('刷新服务器配置失败: $e');
throw e;
}
}
/// 获取最新的appid
Future _getLatestAppId() async {
try {
// 从本地存储获取最新appid
final appId = await DataSp.getCurrentAppId();
if (appId != null && appId.isNotEmpty) {
print('获取到最新appid: $appId');
return appId;
}
// 如果没有找到appid,尝试从历史记录中获取
final appIdHistory = await DataSp.getAppIdHistory();
if (appIdHistory != null && appIdHistory.isNotEmpty) {
final latestAppId = appIdHistory.first;
print('从历史记录获取到appid: $latestAppId');
return latestAppId;
}
// 如果都没有找到,抛出异常
throw Exception('没有找到可用的appid');
} catch (e) {
print('获取最新appid失败: $e');
throw e;
}
}
/// 请求服务器配置
Future _requestServerConfig(String appId) async {
try {
print('使用appid $appId 请求服务器配置');
// 构造要加密的数据
final Map<String, dynamic> dataToEncrypt = {
'appid': appId,
// 可按需扩展更多字段
};
final String jsonString = jsonEncode(dataToEncrypt);
final String encryptedData = LocalAESUtils.AESUtils.encrypt(jsonString);
// 使用统一的域名配置
final List<String> domains = DomainConfig.domains;
final httpClient = dio.Dio();
// 设置超时时间
httpClient.options.connectTimeout = const Duration(seconds: 10);
httpClient.options.receiveTimeout = const Duration(seconds: 10);
dio.Response<dynamic>? response;
// 依次尝试每个域名
for (int i = 0; i < domains.length; i++) {
final domain = domains[i];
try {
print('尝试域名 ${i + 1}/${domains.length}: $domain');
response = await httpClient.post(
'$domain/api/imserver/getbyappid',
data: {
'updateInfo': encryptedData,
},
);
if (response.statusCode == 200) {
print('域名 $domain 请求成功');
break;
} else {
print('域名 $domain 返回错误状态码: ${response.statusCode}');
}
} catch (e) {
print('域名 $domain 请求失败: $e');
// 继续尝试下一个域名
continue;
}
}
if (response != null && response.statusCode == 200) {
// 解析数据并写入配置
final Map<String, dynamic> configData = response.data is String
? jsonDecode(response.data)
: response.data;
print('获取到服务器配置: ${configData['data']['baseUrl']}');
// 组装要存储的配置
final Map<String, String> serverConfig = {
'baseUrl': configData['data']['baseUrl'] ?? '',
'userAgreementUrl': configData['data']['userAgreementUrl'] ?? '',
'privacyPolicyUrl': configData['data']['privacyPolicyUrl'] ?? '',
'serverIP': configData['data']['host'] ?? '',
// 可以根据需要添加更多配置项
};
// 保存服务器配置到本地存储
await DataSp.putServerConfig(serverConfig);
// 保存当前使用的appid
await DataSp.putCurrentAppId(appId);
print('服务器配置更新成功');
// 更新Config中的连接信息(如果Config支持动态更新)
await _updateConnectionConfig(serverConfig);
} else {
// 所有域名都失败了
print('所有域名都请求失败');
throw Exception('所有服务器都无法访问,请检查网络连接');
}
} catch (e) {
print('请求服务器配置失败: $e');
throw e;
}
}
/// 更新连接配置
Future _updateConnectionConfig(Map<String, String> serverConfig) async {
try {
// 这里可以根据获取到的服务器配置更新Config中的连接信息
// 例如:更新API地址、WebSocket地址等
// 示例:如果Config支持动态更新
// Config.updateApiUrl(serverConfig['baseUrl']);
// Config.updateWsUrl(serverConfig['wsUrl']);
print('连接配置更新完成');
} catch (e) {
print('更新连接配置失败: $e');
// 不抛出异常,因为主要配置已经保存成功
}
}
/// 重新初始化SDK
Future _reinitializeSDK() async {
try {
// 反初始化SDK
OpenIM.iMManager.unInitSDK();
print('SDK反初始化成功');
// 打印重新初始化参数
print('=== SDK重新初始化参数 ===');
print('platformID2222: ${IMUtils.getPlatform()}');
print('apiAddr11111: ${Config.imApiUrl}');
print('wsAddr3333: ${Config.imWsUrl}');
print('dataDir444: ${Config.cachePath}');
print('logLevel5555: ${Config.logLevel}');
print('logFilePath66666: ${Config.cachePath}');
print('====================');
// 重新初始化SDK,设置新的连接信息
final initialized = await OpenIM.iMManager.initSDK(
platformID: IMUtils.getPlatform(),
apiAddr: Config.imApiUrl,
wsAddr: Config.imWsUrl,
dataDir: Config.cachePath,
logLevel: Config.logLevel,
logFilePath: Config.cachePath,
listener: OnConnectListener(
onConnecting: () {
print("重新连接-re");
imSdkStatus(IMSdkStatus.connecting);
},
onConnectFailed: (code, error) {
print("连接失败-re");
imSdkStatus(IMSdkStatus.connectionFailed);
// 重新初始化后,如果连接失败,仍然遵循2次重连限制
_handleConnectionFailedWithRetry(code ?? 0, error ?? 'Unknown error');
},
onConnectSuccess: () {
imSdkStatus(IMSdkStatus.connectionSucceeded);
print('重新初始化后连接成功');
// 通知连接成功,可以继续执行登录
_notifyConnectionSuccess();
},
onKickedOffline: kickedOffline,
onUserTokenExpired: kickedOffline,
onUserTokenInvalid: userTokenInvalid,
),
);
if (!initialized) {
throw Exception('SDK重新初始化失败');
}
// 重新设置各种监听器
await _setupAllListeners();
print('SDK重新初始化成功,监听器设置完成');
// 显示服务器信息更新提示对话框
_showServerUpdateDialog();
} catch (e) {
print('SDK重新初始化失败: $e');
throw e;
}
}
/// 设置所有监听器
Future _setupAllListeners() async {
try {
// 设置上传日志监听器
OpenIM.iMManager.setUploadLogsListener(OnUploadLogsListener(
onUploadProgress: uploadLogsProgress,
));
// 设置用户监听器
OpenIM.iMManager.userManager.setUserListener(OnUserListener(
onSelfInfoUpdated: (u) {
selfInfoUpdated(u);
userInfo.update((val) {
val?.nickname = u.nickname;
val?.faceURL = u.faceURL;
val?.remark = u.remark;
val?.ex = u.ex;
val?.globalRecvMsgOpt = u.globalRecvMsgOpt;
});
},
onUserStatusChanged: userStausChanged,
));
// 设置消息监听器
OpenIM.iMManager.messageManager.setAdvancedMsgListener(OnAdvancedMsgListener(
onRecvC2CReadReceipt: recvC2CMessageReadReceipt,
onRecvNewMessage: recvNewMessage,
onNewRecvMessageRevoked: recvMessageRevoked,
onRecvOfflineNewMessage: recvOfflineMessage,
onRecvOnlineOnlyMessage: (msg) {
print('onRecvOnlineOnlyMessage');
if (msg.isCustomType) {
final data = msg.customElem!.data;
final map = jsonDecode(data!);
final customType = map['customType'];
if (customType == CustomMessageType.callingInvite ||
customType == CustomMessageType.callingAccept ||
customType == CustomMessageType.callingReject ||
customType == CustomMessageType.callingCancel ||
customType == CustomMessageType.callingHungup) {
final signaling = SignalingInfo(invitation: InvitationInfo.fromJson(map['data']));
signaling.userID = signaling.invitation?.inviterUserID;
switch (customType) {
case CustomMessageType.callingInvite:
receiveNewInvitation(signaling);
break;
case CustomMessageType.callingAccept:
inviteeAccepted(signaling);
break;
case CustomMessageType.callingReject:
inviteeRejected(signaling);
break;
case CustomMessageType.callingCancel:
invitationCancelled(signaling);
break;
case CustomMessageType.callingHungup:
beHangup(signaling);
break;
}
}
}
},
));
// 设置消息发送进度监听器
OpenIM.iMManager.messageManager.setMsgSendProgressListener(OnMsgSendProgressListener(
onProgress: progressCallback,
));
// 设置自定义业务监听器
OpenIM.iMManager.messageManager.setCustomBusinessListener(OnCustomBusinessListener(
onRecvCustomBusinessMessage: recvCustomBusinessMessage,
));
// 设置好友关系监听器
OpenIM.iMManager.friendshipManager.setFriendshipListener(OnFriendshipListener(
onBlackAdded: blacklistAdded,
onBlackDeleted: blacklistDeleted,
onFriendApplicationAccepted: friendApplicationAccepted,
onFriendApplicationAdded: friendApplicationAdded,
onFriendApplicationDeleted: friendApplicationDeleted,
onFriendApplicationRejected: friendApplicationRejected,
onFriendInfoChanged: friendInfoChanged,
onFriendAdded: friendAdded,
onFriendDeleted: friendDeleted,
));
// 设置会话监听器
OpenIM.iMManager.conversationManager.setConversationListener(OnConversationListener(
onConversationChanged: conversationChanged,
onNewConversation: newConversation,
onTotalUnreadMessageCountChanged: totalUnreadMsgCountChanged,
onInputStatusChanged: inputStateChanged,
onSyncServerFailed: (reInstall) {
imSdkStatus(IMSdkStatus.syncFailed, reInstall: reInstall ?? false);
// 重新初始化后,如果同步失败,仍然遵循2次重连限制
_handleSyncFailedWithRetry(reInstall);
},
onSyncServerFinish: (reInstall) {
imSdkStatus(IMSdkStatus.syncEnded, reInstall: reInstall ?? false);
print('重新初始化后同步完成');
},
onSyncServerStart: (reInstall) {
imSdkStatus(IMSdkStatus.syncStart, reInstall: reInstall ?? false);
},
onSyncServerProgress: (progress) {
imSdkStatus(IMSdkStatus.syncProgress, progress: progress);
},
));
// 设置群组监听器
OpenIM.iMManager.groupManager.setGroupListener(OnGroupListener(
onGroupApplicationAccepted: groupApplicationAccepted,
onGroupApplicationAdded: groupApplicationAdded,
onGroupApplicationDeleted: groupApplicationDeleted,
onGroupApplicationRejected: groupApplicationRejected,
onGroupInfoChanged: groupInfoChanged,
onGroupMemberAdded: groupMemberAdded,
onGroupMemberDeleted: groupMemberDeleted,
onGroupMemberInfoChanged: groupMemberInfoChanged,
onJoinedGroupAdded: joinedGroupAdded,
onJoinedGroupDeleted: joinedGroupDeleted,
));
print('所有监听器设置完成');
} catch (e) {
print('设置监听器失败: $e');
throw e;
}
}
/// 重新登录
Future _relogin() async {
try {
// 获取保存的登录凭证
final loginCredentials = await _getSavedLoginCredentials();
if (loginCredentials == null) {
throw Exception('没有找到保存的登录凭证');
}
print('开始重新登录,用户ID: ${loginCredentials['userID']}');
// 执行登录
await login(loginCredentials['userID']!, loginCredentials['token']!);
print('重新登录成功');
} catch (e) {
print('重新登录失败: $e');
throw e;
}
}
/// 获取保存的登录凭证
Future<Map<String, String>?> _getSavedLoginCredentials() async {
try {
// 从本地存储获取保存的登录凭证
final loginCertificate = DataSp.getLoginCertificate();
if (loginCertificate != null &&
loginCertificate.userID.isNotEmpty &&
loginCertificate.imToken.isNotEmpty) {
print('获取到保存的登录凭证: userID=${loginCertificate.userID}');
return {
'userID': loginCertificate.userID,
'token': loginCertificate.imToken,
};
}
// 如果没有找到登录凭证,尝试从登录账户信息中获取
final loginAccount = DataSp.getLoginAccount();
if (loginAccount != null) {
print('找到登录账户信息,但缺少登录凭证');
print('登录账户信息: $loginAccount');
}
print('没有找到有效的登录凭证');
return null;
} catch (e) {
print('获取保存的登录凭证失败: $e');
return null;
}
}
// 连接成功等待的Completer
Completer? _connectionSuccessCompleter;
/// 等待连接成功回调
Future _waitForConnectionSuccess() async {
_connectionSuccessCompleter = Completer();
// 设置超时时间,避免无限等待
Timer(const Duration(seconds: 30), () {
if (!_connectionSuccessCompleter!.isCompleted) {
_connectionSuccessCompleter!.completeError(
TimeoutException('等待连接成功超时', const Duration(seconds: 30))
);
}
});
try {
await _connectionSuccessCompleter!.future;
print('连接成功回调已收到,可以继续执行登录');
} catch (e) {
print('等待连接成功失败: $e');
throw e;
}
}
/// 通知连接成功
void _notifyConnectionSuccess() {
if (_connectionSuccessCompleter != null && !_connectionSuccessCompleter!.isCompleted) {
_connectionSuccessCompleter!.complete();
print('已通知连接成功');
}
}
/// 显示服务器信息更新提示对话框
void _showServerUpdateDialog() {
final isAndroid = Platform.isAndroid;
Get.dialog(
PopScope(
canPop: false, // 禁止返回键关闭对话框
child: AlertDialog(
title: Text(
StrRes.appSsecurityPrompt,
style: TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
),
),
content: Text(
isAndroid
? StrRes.restartAppAndroid
: StrRes.restartAppiPhone,
style: TextStyle(fontSize: 16),
),
actions: [
if (isAndroid) ...[
TextButton(
onPressed: () {
Get.back(); // 关闭对话框
print('用户确认服务器信息更新,准备关闭应用');
// 延迟一下再关闭应用,确保对话框先关闭
Future.delayed(Duration(milliseconds: 300), () {
// 关闭当前应用
// SystemNavigator.pop();
if (Platform.isAndroid) {
// Android 上使用 exit(0) 更可靠
exit(0);
} else if (Platform.isIOS) {
// iOS 上使用 SystemNavigator.pop(),因为 exit(0) 可能被拒绝
exit(0);
SystemNavigator.pop();
} else {
// 其他平台(比如桌面版)
exit(0);
}
});
},
child: Text(
'确认',
style: TextStyle(
fontSize: 16,
color: Colors.blue,
),
),
),
],
],
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
),
),
barrierDismissible: false, // 禁止点击外部关闭对话框
);
print('显示服务器信息更新提示对话框 - 平台: ${isAndroid ? "Android" : "iOS"}');
}
}
Screenshots Link
No response