From f1f442be2c521d3637e6b287b073a8e61e4520fb Mon Sep 17 00:00:00 2001 From: lxm <1274844347@qq.com> Date: Wed, 29 Apr 2026 17:37:58 +0800 Subject: [PATCH] =?UTF-8?q?feat(feedback):=20=E5=9C=A8=E8=AF=84=E8=AE=BA?= =?UTF-8?q?=E9=A1=B5URL=E4=B8=AD=E6=B7=BB=E5=8A=A0=E8=AE=BE=E5=A4=87?= =?UTF-8?q?=E4=BF=A1=E6=81=AF=E5=8F=82=E6=95=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 添加 device_marketing_names 依赖,用于获取设备市售名称 创建 device_info_helper 模块统一读取设备品牌、型号、操作系统信息 扩展 buildCommentUrl 函数,支持传入设备信息参数,便于后台按设备维度筛选 --- lib/modules/feedback/comment_url.dart | 19 +++++- lib/modules/feedback/device_info_helper.dart | 61 +++++++++++++++++++ .../feedback/views/comment_webview.dart | 6 ++ pubspec.yaml | 1 + 4 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 lib/modules/feedback/device_info_helper.dart diff --git a/lib/modules/feedback/comment_url.dart b/lib/modules/feedback/comment_url.dart index 303468e55..2e880ad55 100644 --- a/lib/modules/feedback/comment_url.dart +++ b/lib/modules/feedback/comment_url.dart @@ -8,7 +8,8 @@ import '../../data/models/appconfig.dart'; /// 生成加密评论页 URL(与 App Comment 服务端 SIGN_SECRET 一致) /// -/// [userId]、[packageName]、[appName]、[appVersion] 必填;[userName]、[lang] 可选。 +/// [userId]、[packageName]、[appName]、[appVersion] 必填;其余可选。 +/// [deviceBrand]/[deviceModel]/[osType]/[osVersion] 用于评论后台按设备维度筛选。 Future buildCommentUrl({ required String userId, String? userName, @@ -16,6 +17,10 @@ Future buildCommentUrl({ required String appName, required String appVersion, String lang = 'en', + String? deviceBrand, + String? deviceModel, + String? osType, + String? osVersion, }) async { final signSecret = _commentSignSecret(); var commentServer = _commentServerUrl(); @@ -29,7 +34,7 @@ Future buildCommentUrl({ commentServer = commentServer.trim().replaceAll(RegExp(r'/$'), ''); - final payload = { + final payload = { 'userId': userId, 'userName': userName ?? userId, 'packageName': packageName, @@ -39,6 +44,16 @@ Future buildCommentUrl({ 'ts': DateTime.now().millisecondsSinceEpoch ~/ 1000, 'nonce': _randomHex(8), }; + if (deviceBrand != null && deviceBrand.isNotEmpty) { + payload['deviceBrand'] = deviceBrand; + } + if (deviceModel != null && deviceModel.isNotEmpty) { + payload['deviceModel'] = deviceModel; + } + if (osType != null && osType.isNotEmpty) payload['osType'] = osType; + if (osVersion != null && osVersion.isNotEmpty) { + payload['osVersion'] = osVersion; + } final algo = AesGcm.with256bits(); final key = await algo.newSecretKeyFromBytes(_hexDecode(signSecret)); diff --git a/lib/modules/feedback/device_info_helper.dart b/lib/modules/feedback/device_info_helper.dart new file mode 100644 index 000000000..c4236cc74 --- /dev/null +++ b/lib/modules/feedback/device_info_helper.dart @@ -0,0 +1,61 @@ +import 'dart:io' show Platform; + +import 'package:device_info_plus/device_info_plus.dart'; +import 'package:device_marketing_names/device_marketing_names.dart'; + +import '../../core/utils/logger.dart'; + +/// 反馈系统上报到评论后台的设备信息。 +class CommentDeviceInfo { + final String? brand; + final String? model; + final String? osType; + final String? osVersion; + + const CommentDeviceInfo({ + this.brand, + this.model, + this.osType, + this.osVersion, + }); +} + +/// 读取设备信息:`model` 优先取 `device_marketing_names` 的市售名, +/// 命中失败时退化为 "品牌 + 内部型号",不影响功能。 +Future readCommentDeviceInfo() async { + try { + final plugin = DeviceInfoPlugin(); + final marketingNames = DeviceMarketingNames(); + + if (Platform.isIOS) { + final info = await plugin.iosInfo; + final code = info.utsname.machine; + final marketing = await marketingNames.getSingleName(); + return CommentDeviceInfo( + brand: 'Apple', + model: marketing.isNotEmpty ? marketing : code, + osType: 'ios', + osVersion: info.systemVersion, + ); + } + + if (Platform.isAndroid) { + final info = await plugin.androidInfo; + final brand = _capitalize(info.brand); + final marketing = await marketingNames.getSingleName(); + final fallback = '$brand ${info.model}'; + return CommentDeviceInfo( + brand: brand, + model: marketing.isNotEmpty ? marketing : fallback, + osType: 'android', + osVersion: info.version.release, + ); + } + } catch (e) { + Logger.error('读取设备信息失败: $e'); + } + return const CommentDeviceInfo(); +} + +String _capitalize(String s) => + s.isEmpty ? s : s[0].toUpperCase() + s.substring(1).toLowerCase(); diff --git a/lib/modules/feedback/views/comment_webview.dart b/lib/modules/feedback/views/comment_webview.dart index e71a2bc4c..e908ee7fe 100644 --- a/lib/modules/feedback/views/comment_webview.dart +++ b/lib/modules/feedback/views/comment_webview.dart @@ -10,6 +10,7 @@ import '../../../core/theme/app_colors.dart'; import '../../../core/utils/logger.dart'; import '../../../data/models/user_Info.dart'; import '../comment_url.dart'; +import '../device_info_helper.dart'; /// 用户反馈:加载加密后的 App Comment 评论页(每次进入重新生成 URL) class CommentWebView extends StatefulWidget { @@ -35,6 +36,7 @@ class _CommentWebViewState extends State { Future _loadUrl() async { try { final packageInfo = await PackageInfo.fromPlatform(); + final device = await readCommentDeviceInfo(); final lang = Get.locale?.languageCode ?? 'en'; final String userId; @@ -56,6 +58,10 @@ class _CommentWebViewState extends State { appName: packageInfo.appName, appVersion: '${packageInfo.version}+${packageInfo.buildNumber}', lang: lang, + deviceBrand: device.brand, + deviceModel: device.model, + osType: device.osType, + osVersion: device.osVersion, ); Logger.debug('评论页 URL 已生成'); diff --git a/pubspec.yaml b/pubspec.yaml index 78847cec1..7bad91fa4 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -60,6 +60,7 @@ dependencies: ref: 6c66ad23ee79749f30a8eece542cf54eaf157ed8 flutter_local_notifications: ^18.0.1 device_info_plus: ^11.5.0 + device_marketing_names: ^1.0.0 uuid: ^4.3.3 record: ^6.0.0 share_plus: ^12.0.1