101 lines
3.0 KiB
Dart
101 lines
3.0 KiB
Dart
import 'dart:convert';
|
||
|
||
import 'package:crypto/crypto.dart';
|
||
import 'package:device_info_plus/device_info_plus.dart';
|
||
import 'package:flutter/foundation.dart';
|
||
|
||
import '../api/api_client.dart';
|
||
import '../api/proxy_client.dart';
|
||
import '../api/services/user_api.dart';
|
||
|
||
/// 认证服务:APP 启动时执行快速登录
|
||
class AuthService {
|
||
AuthService._();
|
||
|
||
static const _tag = '[AuthService]';
|
||
|
||
static void _log(String msg) {
|
||
debugPrint('$_tag $msg');
|
||
}
|
||
|
||
/// 获取设备 ID(Android: androidId, iOS: identifierForVendor, Web: fallback)
|
||
static Future<String> _getDeviceId() async {
|
||
final deviceInfo = DeviceInfoPlugin();
|
||
switch (defaultTargetPlatform) {
|
||
case TargetPlatform.android:
|
||
final android = await deviceInfo.androidInfo;
|
||
return android.id;
|
||
case TargetPlatform.iOS:
|
||
final ios = await deviceInfo.iosInfo;
|
||
return ios.identifierForVendor ?? 'ios-unknown';
|
||
default:
|
||
return 'device-${DateTime.now().millisecondsSinceEpoch}';
|
||
}
|
||
}
|
||
|
||
/// 计算 sign:MD5(deviceId) 大写 32 位
|
||
static String _computeSign(String deviceId) {
|
||
final bytes = utf8.encode(deviceId);
|
||
final digest = md5.convert(bytes);
|
||
return digest.toString().toUpperCase();
|
||
}
|
||
|
||
/// APP 启动时调用快速登录
|
||
/// 启动时网络可能未就绪,会延迟后重试
|
||
static Future<void> init() async {
|
||
_log('init: 开始快速登录');
|
||
const maxRetries = 3;
|
||
const retryDelay = Duration(seconds: 2);
|
||
|
||
try {
|
||
// 等待网络就绪(浏览器能访问但 App 报错时,多为启动时网络未初始化)
|
||
await Future<void>.delayed(const Duration(seconds: 2));
|
||
|
||
final deviceId = await _getDeviceId();
|
||
_log('init: deviceId=$deviceId');
|
||
|
||
final sign = _computeSign(deviceId);
|
||
_log('init: sign=$sign');
|
||
|
||
ApiResponse? res;
|
||
for (var i = 0; i < maxRetries; i++) {
|
||
if (i > 0) {
|
||
_log('init: 第 ${i + 1} 次重试,等待 ${retryDelay.inSeconds}s...');
|
||
await Future<void>.delayed(retryDelay);
|
||
}
|
||
try {
|
||
res = await UserApi.fastLogin(
|
||
origin: deviceId,
|
||
resolution: sign,
|
||
digest: '',
|
||
);
|
||
break;
|
||
} catch (e) {
|
||
_log('init: 第 ${i + 1} 次请求失败: $e');
|
||
if (i == maxRetries - 1) rethrow;
|
||
}
|
||
}
|
||
|
||
if (res == null) return;
|
||
|
||
_log('init: 登录结果 code=${res.code} msg=${res.msg}');
|
||
|
||
if (res.isSuccess && res.data != null) {
|
||
final data = res.data as Map<String, dynamic>?;
|
||
final token = data?['reevaluate'] as String?;
|
||
if (token != null && token.isNotEmpty) {
|
||
ApiClient.instance.setUserToken(token);
|
||
_log('init: 已设置 userToken');
|
||
} else {
|
||
_log('init: 响应中无 reevaluate (userToken)');
|
||
}
|
||
} else {
|
||
_log('init: 登录失败');
|
||
}
|
||
} catch (e, st) {
|
||
_log('init: 异常 $e');
|
||
_log('init: 堆栈 $st');
|
||
}
|
||
}
|
||
}
|