refactor(core): 平台上报收敛为单个请求头

去掉 device_info_plus 依赖与机型/系统版本,只保留 X-Client-Platform。
This commit is contained in:
Vicky authored and trae-solo-agent committed 2026-10-27 14:00:19 +08:00
1 parent 01a3b0101e
commit 935de13343
6 files changed
+19 -113

No files matched your search

+4 -5
View File
@@ -5,7 +5,6 @@ import 'package:dio/dio.dart';
import '../../config/app_config.dart';
import 'api_exception.dart';
import 'api_interceptors.dart';
import 'device_profile.dart';
import 'network_log_interceptor.dart';
/// `ApiException` 从这里也能拿到:历史调用方一律 `import 'api_client.dart'`,不必改 import。
@@ -25,7 +24,7 @@ class ApiClient {
this.tokenRefresher,
this.onUnauthorized,
this.deviceIdReader,
this.deviceProfileReader,
this.platformReader,
}) : _fixedBaseUrl = baseUrl {
_dio = Dio(
BaseOptions(
@@ -42,7 +41,7 @@ class ApiClient {
AuthHeaderInterceptor(
accessTokenReader: accessTokenReader,
deviceIdReader: deviceIdReader,
deviceProfileReader: deviceProfileReader,
platformReader: platformReader,
),
const EnvelopeInterceptor(),
NetworkLogInterceptor(),
@@ -70,8 +69,8 @@ class ApiClient {
/// 设备号(`X-Device-Id`):注册风控、后续下载绑定都要用
final Future<String> Function()? deviceIdReader;
/// 设备画像(系统/机型版本):后台列表展示客户端系统用
final Future<DeviceProfile> Function()? deviceProfileReader;
/// 客户端平台(`X-Client-Platform`):后台区分 iOS / Android
final String Function()? platformReader;
Future<Object?> get(String path, {Map<String, String>? query}) {
return _request('GET', path, query: query);
+6 -7
View File
@@ -5,7 +5,6 @@ import 'dart:convert';
import 'package:dio/dio.dart';
import 'api_exception.dart';
import 'device_profile.dart';
import 'network_log_interceptor.dart';
/// 请求级开关:放在 `RequestOptions.extra` 里,由 `ApiClient` 写入、拦截器读取。
@@ -36,7 +35,7 @@ class AuthHeaderInterceptor extends Interceptor {
AuthHeaderInterceptor({
this.accessTokenReader,
this.deviceIdReader,
this.deviceProfileReader,
this.platformReader,
});
/// 当前 access token;未登录返回 null 或空串。
@@ -45,8 +44,8 @@ class AuthHeaderInterceptor extends Interceptor {
/// 设备号(`X-Device-Id`):注册风控、下载绑定都用它。
final Future<String> Function()? deviceIdReader;
/// 设备画像(系统/机型):后台判断客户端系统用,匿名请求同样要带。
final Future<DeviceProfile> Function()? deviceProfileReader;
/// 客户端平台(`X-Client-Platform`):后台区分 iOS / Android,匿名请求同样要带。
final String Function()? platformReader;
@override
Future<void> onRequest(
@@ -62,9 +61,9 @@ class AuthHeaderInterceptor extends Interceptor {
if (deviceId != null && deviceId.isNotEmpty) {
options.headers['X-Device-Id'] = deviceId;
}
final profile = await deviceProfileReader?.call();
if (profile != null) {
options.headers.addAll(profile.headers);
final platform = platformReader?.call() ?? '';
if (platform.isNotEmpty) {
options.headers['X-Client-Platform'] = platform;
}
handler.next(options);
}
+7 -61
View File
@@ -2,68 +2,14 @@
import 'dart:io' show Platform;
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
/// 设备画像:随每个请求以请求头上报,供后台列表识别客户端系统。
/// 客户端平台,后台只用来区分 iOS / Android。
///
/// 之前只有登录接口在 body 里带 `platform` / `osVersion`,匿名互动没有任何系统信息,
/// 后台只能显示「—」。改成请求头后,点赞、收藏、评论、观看等接口都能带上。
class DeviceProfile {
const DeviceProfile({
this.platform = '',
this.osVersion = '',
this.model = '',
});
/// ANDROID / IOS / WEB;桌面端等无法归类时为空。
final String platform;
/// 系统版本,Android 取 release(如 14),iOS 取 systemVersion(如 17.2)。
final String osVersion;
/// 机型,Android 取 model(如 SM-G991B),iOS 取 utsname.machine(如 iPhone15,2)。
final String model;
Map<String, String> get headers => {
if (platform.isNotEmpty) 'X-Client-Platform': platform,
if (osVersion.isNotEmpty) 'X-Client-Os': osVersion,
if (model.isNotEmpty) 'X-Client-Model': model,
};
}
/// 读取一次并缓存设备画像:插件调用有开销,且整个进程内不会变。
class DeviceProfileReader {
DeviceProfileReader({DeviceInfoPlugin? plugin})
: _plugin = plugin ?? DeviceInfoPlugin();
final DeviceInfoPlugin _plugin;
Future<DeviceProfile>? _cached;
Future<DeviceProfile> read() => _cached ??= _load();
Future<DeviceProfile> _load() async {
if (kIsWeb) return const DeviceProfile(platform: 'WEB');
try {
if (Platform.isAndroid) {
final info = await _plugin.androidInfo;
return DeviceProfile(
platform: 'ANDROID',
osVersion: info.version.release,
model: info.model,
);
}
if (Platform.isIOS) {
final info = await _plugin.iosInfo;
return DeviceProfile(
platform: 'IOS',
osVersion: info.systemVersion,
model: info.utsname.machine,
);
}
} catch (_) {
// 插件不可用(widget 测试没有原生通道)时退化为 dart:io 能拿到的信息
}
return const DeviceProfile();
}
/// 系统版本、机型一律不上报:后台列表需要的只是「这台设备是安卓还是苹果」。
String clientPlatform() {
if (kIsWeb) return 'WEB';
if (Platform.isAndroid) return 'ANDROID';
if (Platform.isIOS) return 'IOS';
return '';
}