fix: 修改客服,增加sdk使用;增加邀请链接短链,升级flutter到3.35.0,Dart 3.9.0

This commit is contained in:
speakeloudest 2026-01-24 23:14:18 -08:00
parent 57a47874be
commit e59cbf8b60
20 changed files with 457 additions and 187 deletions

View File

@ -54,7 +54,9 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:extractNativeLibs="true"
tools:targetApi="31">
<meta-data
android:name="io.flutter.embedding.android.EnableImpeller"
android:value="false" />
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />

View File

@ -762,11 +762,9 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/HiddifyPacketTunnel.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
DEVELOPMENT_TEAM = NJRRF427XB;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXCLUDED_ARCHS = armv7;
GCC_C_LANGUAGE_STANDARD = gnu17;
@ -792,7 +790,6 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord-PacketTunnel";
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@ -818,11 +815,9 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/PacketTunnelRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
DEVELOPMENT_TEAM = NJRRF427XB;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXCLUDED_ARCHS = armv7;
GCC_C_LANGUAGE_STANDARD = gnu17;
@ -848,7 +843,6 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord-PacketTunnel";
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@ -872,11 +866,9 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = PacketTunnel/HiddifyPacketTunnel.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
DEVELOPMENT_TEAM = NJRRF427XB;
ENABLE_USER_SCRIPT_SANDBOXING = YES;
EXCLUDED_ARCHS = armv7;
GCC_C_LANGUAGE_STANDARD = gnu17;
@ -902,7 +894,6 @@
PRODUCT_BUNDLE_IDENTIFIER = "$(BASE_BUNDLE_IDENTIFIER).PacketTunnel";
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord-PacketTunnel";
SKIP_INSTALL = YES;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
@ -980,11 +971,9 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
DEVELOPMENT_TEAM = NJRRF427XB;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7;
INFOPLIST_FILE = Runner/Info.plist;
@ -1016,7 +1005,6 @@
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
@ -1212,11 +1200,9 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/Runner.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
DEVELOPMENT_TEAM = NJRRF427XB;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7;
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = "i386 arm64";
@ -1248,7 +1234,6 @@
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
@ -1270,11 +1255,9 @@
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Runner/RunnerRelease.entitlements;
CODE_SIGN_IDENTITY = "Apple Development";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
CODE_SIGN_STYLE = Manual;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_TEAM = "";
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = NJRRF427XB;
DEVELOPMENT_TEAM = NJRRF427XB;
ENABLE_BITCODE = NO;
"EXCLUDED_ARCHS[sdk=iphoneos*]" = armv7;
INFOPLIST_FILE = Runner/Info.plist;
@ -1306,7 +1289,6 @@
"PRODUCT_BUNDLE_IDENTIFIER[sdk=iphoneos*]" = com.taw.hifastvpn;
PRODUCT_NAME = "$(TARGET_NAME)";
PROVISIONING_PROFILE_SPECIFIER = "";
"PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = "HiFastVPN-iOS-Pord";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;

View File

@ -41,6 +41,12 @@ class KRAppRunData {
/// 使便 UI
final Rx<String?> kr_account = Rx<String?>(null);
/// 使便 UI
final Rx<String?> shareUrl = Rx<String?>(null);
/// 使便 UI
final Rx<String?> kr_authType = Rx<String?>(null);
/// ID使便 UI
final Rx<int?> kr_userId = Rx<int?>(null);
@ -633,14 +639,18 @@ class KRAppRunData {
tag: 'AppRunData');
KRLogUtil.kr_i('🆔 [AppRunData] id: ${userInfo.id}',
tag: 'AppRunData');
KRLogUtil.kr_i('🆔 [AppRunData] id: ${userInfo.shareUrl}',
tag: 'AppRunData');
//
kr_referCode.value = userInfo.referCode;
kr_refererId.value = userInfo.refererId;
kr_account.value =
authType == 'device' ? '9000${userInfo.id}' : authIdentifier;
authType == 'device' ? '${userInfo.id}' : authIdentifier;
kr_balance.value = userInfo.balance;
kr_commission.value = userInfo.commission;
shareUrl.value = userInfo.shareUrl;
kr_authType.value = authType;
KRLogUtil.kr_i('💾 [AppRunData] 用户信息已保存到全局状态:', tag: 'AppRunData');
KRLogUtil.kr_i(' - kr_referCode: "${kr_referCode.value}"',
@ -651,6 +661,8 @@ class KRAppRunData {
tag: 'AppRunData');
KRLogUtil.kr_i(' - kr_commission: ${kr_commission.value}',
tag: 'AppRunData');
KRLogUtil.kr_i(' - kr_commission: ${shareUrl.value}',
tag: 'AppRunData');
},
);
} catch (e, stackTrace) {

View File

@ -31,6 +31,7 @@ class KRUserInfo {
final int referralPercentage;
final bool onlyFirstPurchase;
final int giftAmount;
final String shareUrl;
// auth_methods
final List<KRAuthMethod> authMethods;
@ -48,6 +49,7 @@ class KRUserInfo {
this.referralPercentage = 0,
this.onlyFirstPurchase = false,
this.giftAmount = 0,
this.shareUrl = '',
this.authMethods = const [],
});
@ -65,6 +67,7 @@ class KRUserInfo {
referralPercentage: json['referral_percentage'] ?? 0,
onlyFirstPurchase: json['only_first_purchase'] ?? false,
giftAmount: json['gift_amount'] ?? 0,
shareUrl: json['share_link'] ?? '',
authMethods: (json['auth_methods'] as List<dynamic>?)
?.map((e) => KRAuthMethod.fromJson(e))
.toList() ??

View File

@ -79,13 +79,8 @@ class HIMenuView extends GetView<HIMenuController> implements HasSwipeConfig {
mainAxisSize: MainAxisSize.min, // Column
children: [
Obx(() {
final account =
KRAppRunData.getInstance().kr_account.value;
final isDeviceLogin =
account != null && account.startsWith('9000');
final accountText = (account == null || isDeviceLogin)
? '待绑定'
: '${KRAppRunData.getInstance().kr_account.value.toString()}';
final authType = KRAppRunData.getInstance().kr_authType.value;
final accountText = authType == 'email' ? '${KRAppRunData.getInstance().kr_account.value.toString()}' : '待绑定';
return UserInfoCard(
controller: controller,
userId: accountText,

View File

@ -1,21 +1,69 @@
import 'package:get/get.dart';
import 'package:chatwoot_flutter_sdk/chatwoot_sdk.dart';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart';
import 'package:flutter/foundation.dart';
import 'package:kaer_with_panels/app/common/app_run_data.dart';
/// 2Chatwoot
class KRChatwootController extends GetxController {
/// Chatwoot
final String kr_chatwootUrl = 'https://app.chatwoot.com/widget?website_token=YXQmh16ymNYW1SVybhnoQQ9w';
import 'package:kaer_with_panels/app/utils/kr_secure_storage.dart';
///
final RxBool kr_isLoading = true.obs;
class KRChatwootController {
//
final String baseUrl = 'https://app.chatwoot.com';
final String inboxIdentifier = 'YXQmh16ymNYW1SVybhnoQQ9w';
@override
void onInit() {
super.onInit();
KRChatwootController() {
KRSecureStorage().kr_readData(key: 'USER_INFO').then((value) {
print('KRSecureStorage_keyUserInfo: $value');
});
}
///
/// [loading]
void kr_setLoading(bool loading) {
kr_isLoading.value = loading;
///
/// UserState
ChatwootUser get chatUser {
final appRunData = KRAppRunData.getInstance();
final userId = appRunData.kr_userId.value?.toString();
final deviceId = appRunData.deviceId;
final account = appRunData.kr_account.value;
// 使 userId 使 deviceId
final identifier = userId ?? deviceId ?? 'unknown_user';
// 使 Guest
final name = account ?? 'Guest';
// 使
String email = '';
if (account != null && account.contains('@')) {
email = account;
} else {
email = '$identifier@hifastvpn.com';
}
return ChatwootUser(
identifier: identifier, //
name: name,
email: email,
);
}
/// /
Future<List<String>> onFilePicker() async {
try {
final result = await FilePicker.platform.pickFiles(
allowMultiple: true,
type: FileType.any,
);
if (result != null && result.paths.isNotEmpty) {
// null String
return result.paths.whereType<String>().toList();
}
} catch (e) {
debugPrint("KRChatwoot: 文件选择失败 - $e");
}
return [];
}
//
// void trackEvent(String eventName) { ... }
}

View File

@ -1,52 +1,71 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:kaer_with_panels/app/widgets/hi_base_scaffold.dart';
import 'package:kaer_with_panels/app/widgets/kr_simple_loading.dart';
import 'package:chatwoot_flutter_sdk/chatwoot_sdk.dart';
import '../controllers/kr_chatwoot_controller.dart';
import 'package:get/get.dart';
/// 2Chatwoot
class KRChatwootView extends GetView<KRChatwootController> {
class KRChatwootView extends StatefulWidget {
const KRChatwootView({super.key});
@override
State<KRChatwootView> createState() => _KRChatwootViewState();
}
class _KRChatwootViewState extends State<KRChatwootView> {
//
final KRChatwootController _controller = KRChatwootController();
//
bool _isPageLoading = true;
@override
Widget build(BuildContext context) {
return HIBaseScaffold(
showBack: true,
topContentAreaHeight: 0,
return Scaffold(
// 20px
backgroundColor: Colors.white,
body: Padding(
// 20px
padding: const EdgeInsets.only(top: 20.0),
child: Stack(
children: [
InAppWebView(
initialUrlRequest: URLRequest(
url: WebUri(controller.kr_chatwootUrl),
),
initialSettings: InAppWebViewSettings(
javaScriptEnabled: true,
domStorageEnabled: true,
allowsInlineMediaPlayback: true,
),
onLoadStart: (controller, url) {
this.controller.kr_setLoading(true);
ChatwootWidget(
baseUrl: _controller.baseUrl,
websiteToken: _controller.inboxIdentifier,
user: _controller.chatUser,
locale: "zh_CN",
onAttachFile: _controller.onFilePicker,
onLoadStarted: () {
debugPrint("KRChatwoot: 开始加载 SDK");
},
onLoadStop: (controller, url) {
this.controller.kr_setLoading(false);
closeWidget: () {
print('返回');
Get.back();
},
onReceivedError: (controller, request, error) {
this.controller.kr_setLoading(false);
},
),
Obx(() {
if (controller.kr_isLoading.value) {
return const Center(
child: KRSimpleLoading(
size: 40,
),
);
onLoadCompleted: () {
debugPrint("KRChatwoot: SDK 加载完毕");
if (mounted) {
setState(() => _isPageLoading = false);
}
return const SizedBox.shrink();
}),
},
),
//
if (_isPageLoading)
Container(
color: Colors.white,
child: const Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
CircularProgressIndicator(strokeWidth: 2),
const SizedBox(height: 16),
Text("正在连接客服...", style: TextStyle(color: Colors.grey)),
],
),
),
),
],
),
),
);
}
}

View File

@ -121,12 +121,8 @@ class KRDeleteAccountView extends GetView<KRDeleteAccountController> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() {
final account = KRAppRunData.getInstance().kr_account.value;
final isDeviceLogin =
account != null && account.startsWith('9000');
final accountText = (account ==null || isDeviceLogin)
? '待绑定'
: '${KRAppRunData.getInstance().kr_account.value.toString()}';
final authType = KRAppRunData.getInstance().kr_authType.value;
final accountText = authType == 'email' ? '${KRAppRunData.getInstance().kr_account.value.toString()}' : '待绑定';
return Text(
accountText,
style: TextStyle(

View File

@ -10,6 +10,7 @@ import 'package:share_plus/share_plus.dart';
import 'package:kaer_with_panels/app/utils/kr_common_util.dart';
import 'package:kaer_with_panels/app/widgets/hi_base_scaffold.dart';
import 'package:kaer_with_panels/app/widgets/hi_help_entrance.dart';
import 'package:kaer_with_panels/app/common/app_run_data.dart';
class KRInviteView extends GetView<KRInviteController> {
const KRInviteView({super.key});
@ -123,14 +124,14 @@ class KRInviteView extends GetView<KRInviteController> {
color: Colors.white,
),
onPressed: () {
if (controller.kr_referCode.value.isNotEmpty) {
final code = controller.kr_referCode.value;
final text = '#您的好友邀请您使用Hi快网络加速器\n'
'安装完毕后,在软件内<邀请好友>页面粘贴以下邀请码\n'
'$code\n'
'您和您的好友将会分别获得3天免费时长\n\n'
'点击此处进入下载页面\n'
'或在浏览器输入hifastvpn.com下载#';
'首次付款后您和您的好友将会分别获得3天免费时长\n'
'请在浏览器输入${KRAppRunData.getInstance().shareUrl.value}下载#';
if (GetPlatform.isIOS) {
Share.share(text, subject: '直接分享Hi快VPN邀请链接');
} else {

View File

@ -86,12 +86,8 @@ class KRLoginView extends GetView<KRLoginController> {
mainAxisAlignment: MainAxisAlignment.center,
children: [
Obx(() {
final account = KRAppRunData.getInstance().kr_account.value;
final isDeviceLogin =
account != null && account.startsWith('9000');
final accountText = (account == null || isDeviceLogin)
? '待绑定'
: '${KRAppRunData.getInstance().kr_account.value.toString()}';
final authType = KRAppRunData.getInstance().kr_authType.value;
final accountText = authType == 'email' ? '${KRAppRunData.getInstance().kr_account.value.toString()}' : '待绑定';
return Text(
accountText,

View File

@ -259,7 +259,7 @@ class HttpUtil {
/// HTTP
class _KRSimpleHttpInterceptor extends Interceptor {
///
static const bool KR_HTTP_PRINT = false;
static const bool KR_HTTP_PRINT = true;
final Dio _dio;
_KRSimpleHttpInterceptor(this._dio);
static String? _lastPath;

View File

@ -1,29 +1,42 @@
import 'package:flutter_keychain/flutter_keychain.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class IAPPendingOrderService {
static const _keyOrderNo = 'hi_iap_pending_order_no';
static const _keyJwsData = 'hi_iap_pending_jws_data'; // Key
//
static final _storage = FlutterSecureStorage(
aOptions: const AndroidOptions(
encryptedSharedPreferences: true, // Android
),
iOptions: const IOSOptions(
accessibility: KeychainAccessibility.first_unlock, // iOS Keychain
),
);
///
static Future<void> setPendingOrderNo(String orderNo) async {
await FlutterKeychain.put(key: _keyOrderNo, value: orderNo);
await _storage.write(key: _keyOrderNo, value: orderNo);
}
///
static Future<String?> getPendingOrderNo() async {
return await FlutterKeychain.get(key: _keyOrderNo);
return await _storage.read(key: _keyOrderNo);
}
/// JWS
static Future<void> setPendingJwsData(String jwsData) async {
await FlutterKeychain.put(key: _keyJwsData, value: jwsData);
await _storage.write(key: _keyJwsData, value: jwsData);
}
/// JWS
static Future<String?> getPendingJwsData() async {
return await FlutterKeychain.get(key: _keyJwsData);
return await _storage.read(key: _keyJwsData);
}
/// JWS
static Future<void> clearPendingOrderNo() async {
await FlutterKeychain.remove(key: _keyOrderNo);
await FlutterKeychain.remove(key: _keyJwsData);
await _storage.delete(key: _keyOrderNo);
await _storage.delete(key: _keyJwsData);
}
}

View File

@ -2,7 +2,7 @@ import 'dart:io';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter_udid/flutter_udid.dart';
import 'package:flutter_keychain/flutter_keychain.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import '../utils/kr_secure_storage.dart';
import '../utils/kr_log_util.dart';
import 'package:crypto/crypto.dart';
@ -140,54 +140,49 @@ class KRDeviceInfoService {
/// iOS设备ID - 使Keychain存储的UUID
/// iOS的identifierForVendor在所有同供应商应用卸载后会重置
/// 使flutter_keychain存储到iOS Keychain使ID也不会变化
/// 使flutter_secure_storage存储到iOS Keychain使ID也不会变化
Future<String> _getIOSDeviceId() async {
try {
const keychainKey = 'kr_ios_device_persistent_id';
// 1. iOS Keychain读取已存储的设备ID
String? storedId = await FlutterKeychain.get(key: keychainKey);
final storage = FlutterSecureStorage();
// 1. Keychain ID
String? storedId = await storage.read(key: keychainKey);
if (storedId != null && storedId.isNotEmpty) {
if (kDebugMode) {
print('📱 iOS: 从Keychain读取已存储的设备ID');
print('📱 iOS: 从 Keychain 读取已存储的设备ID');
}
KRLogUtil.kr_i('📱 iOS: 使用Keychain中的持久化设备ID', tag: 'KRDeviceInfoService');
KRLogUtil.kr_i('📱 iOS: 使用 Keychain 中的持久化设备ID', tag: 'KRDeviceInfoService');
return storedId;
}
// 2. Keychain中没有ID
// 2. Keychain ID
final iosInfo = await _deviceInfo.iosInfo;
// 使
String udid = await FlutterUdid.consistentUdid;
// 使identifierForVendor作为主要因子
final factors = [
udid,
iosInfo.utsname.machine, // "iPhone14,3"
iosInfo.model, //
iosInfo.systemName, //
// : iosInfo.identifierForVendor -
// : iosInfo.name -
// : iosInfo.systemVersion -
iosInfo.utsname.machine,
iosInfo.model,
iosInfo.systemName,
];
final combined = factors
.where((f) => f.isNotEmpty)
.join('|');
final combined = factors.where((f) => f.isNotEmpty).join('|');
final bytes = utf8.encode(combined);
final hash = sha256.convert(bytes);
final newDeviceId = hash.toString();
// 3. iOS Keychain使
await FlutterKeychain.put(key: keychainKey, value: newDeviceId);
// 3. Keychain
await storage.write(key: keychainKey, value: newDeviceId);
if (kDebugMode) {
print('📱 iOS: 生成新设备ID并保存到Keychain - 因子数: ${factors.where((f) => f.isNotEmpty).length}');
print('📱 iOS: 生成新设备ID并保存到 Keychain');
}
KRLogUtil.kr_i('📱 iOS: 生成并持久化新设备ID到Keychain', tag: 'KRDeviceInfoService');
KRLogUtil.kr_i('📱 iOS: 新设备ID已保存 Keychain', tag: 'KRDeviceInfoService');
return newDeviceId;
} catch (e) {

View File

@ -6,6 +6,7 @@
#include "generated_plugin_registrant.h"
#include <flutter_secure_storage_linux/flutter_secure_storage_linux_plugin.h>
#include <flutter_udid/flutter_udid_plugin.h>
#include <screen_retriever_linux/screen_retriever_linux_plugin.h>
#include <tray_manager/tray_manager_plugin.h>
@ -13,6 +14,9 @@
#include <window_manager/window_manager_plugin.h>
void fl_register_plugins(FlPluginRegistry* registry) {
g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin");
flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar);
g_autoptr(FlPluginRegistrar) flutter_udid_registrar =
fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterUdidPlugin");
flutter_udid_plugin_register_with_registrar(flutter_udid_registrar);

View File

@ -3,6 +3,7 @@
#
list(APPEND FLUTTER_PLUGIN_LIST
flutter_secure_storage_linux
flutter_udid
screen_retriever_linux
tray_manager

View File

@ -7,7 +7,9 @@ import Foundation
import connectivity_plus
import device_info_plus
import file_picker
import flutter_inappwebview_macos
import flutter_secure_storage_macos
import flutter_udid
import gal
import in_app_purchase_storekit
@ -17,12 +19,15 @@ import screen_retriever_macos
import share_plus
import tray_manager
import url_launcher_macos
import webview_flutter_wkwebview
import window_manager
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
ConnectivityPlugin.register(with: registry.registrar(forPlugin: "ConnectivityPlugin"))
DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin"))
FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin"))
InAppWebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "InAppWebViewFlutterPlugin"))
FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin"))
FlutterUdidPlugin.register(with: registry.registrar(forPlugin: "FlutterUdidPlugin"))
GalPlugin.register(with: registry.registrar(forPlugin: "GalPlugin"))
InAppPurchasePlugin.register(with: registry.registrar(forPlugin: "InAppPurchasePlugin"))
@ -32,5 +37,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
TrayManagerPlugin.register(with: registry.registrar(forPlugin: "TrayManagerPlugin"))
UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin"))
WebViewFlutterPlugin.register(with: registry.registrar(forPlugin: "WebViewFlutterPlugin"))
WindowManagerPlugin.register(with: registry.registrar(forPlugin: "WindowManagerPlugin"))
}

View File

@ -61,18 +61,18 @@ packages:
dependency: transitive
description:
name: async
sha256: "947bfcf187f74dbc5e146c9eb9c0f10c9f8b30743e341481c1e2ed3ecc18c20c"
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
url: "https://pub.dev"
source: hosted
version: "2.11.0"
version: "2.12.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "6cfb5af12253eaf2b368f07bacc5a80d1301a071c73360d746b7f2e32d762c66"
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.1"
version: "2.1.2"
build:
dependency: transitive
description:
@ -141,10 +141,10 @@ packages:
dependency: transitive
description:
name: characters
sha256: "04a925763edad70e8443c99234dc3328f442e811f1d8fd1a72f1c8ad0f69a605"
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.0"
charcode:
dependency: transitive
description:
@ -153,6 +153,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "1.4.0"
chatwoot_flutter_sdk:
dependency: "direct main"
description:
name: chatwoot_flutter_sdk
sha256: "8e8272b974e23654571bff96eaf9c5998cbf205b03189c4cbecb69bc5a3318a9"
url: "https://pub.dev"
source: hosted
version: "0.1.1"
checked_yaml:
dependency: transitive
description:
@ -173,10 +181,10 @@ packages:
dependency: transitive
description:
name: clock
sha256: cb6d7f03e1de671e34607e909a7213e31d7752be4fb66a86d29fe1eb14bfb5cf
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.1"
version: "1.1.2"
code_builder:
dependency: transitive
description:
@ -189,10 +197,10 @@ packages:
dependency: transitive
description:
name: collection
sha256: a1ace0a119f20aabc852d165077c036cd864315bd99b7eaa10a60100341941bf
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.0"
version: "1.19.1"
color:
dependency: transitive
description:
@ -361,6 +369,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "7.0.2"
diffutil_dart:
dependency: transitive
description:
name: diffutil_dart
sha256: "5e74883aedf87f3b703cb85e815bdc1ed9208b33501556e4a8a5572af9845c81"
url: "https://pub.dev"
source: hosted
version: "4.0.1"
dio:
dependency: "direct main"
description:
@ -409,6 +425,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.0.3"
equatable:
dependency: transitive
description:
name: equatable
sha256: "3e0141505477fd8ad55d6eb4e7776d3fe8430be8e497ccb1521370c3f21a3e2b"
url: "https://pub.dev"
source: hosted
version: "2.0.8"
extended_image:
dependency: "direct main"
description:
@ -429,10 +453,10 @@ packages:
dependency: transitive
description:
name: fake_async
sha256: "511392330127add0b769b75a987850d136345d9227c6b94c96a04cf4a391bf78"
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.1"
version: "1.3.3"
ffi:
dependency: transitive
description:
@ -457,6 +481,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.1.4"
file_picker:
dependency: "direct main"
description:
name: file_picker
sha256: d974b6ba2606371ac71dd94254beefb6fa81185bde0b59bdc1df09885da85fde
url: "https://pub.dev"
source: hosted
version: "10.3.8"
fixnum:
dependency: transitive
description:
@ -470,6 +502,22 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
flutter_chat_types:
dependency: transitive
description:
name: flutter_chat_types
sha256: e285b588f6d19d907feb1f6d912deaf22e223656769c34093b64e1c59b094fb9
url: "https://pub.dev"
source: hosted
version: "3.6.2"
flutter_chat_ui:
dependency: transitive
description:
name: flutter_chat_ui
sha256: "168a4231464ad00a17ea5f0813f1b58393bdd4035683ea4dc37bbe26be62891e"
url: "https://pub.dev"
source: hosted
version: "1.6.15"
flutter_gen_core:
dependency: transitive
description:
@ -566,14 +614,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.6.0"
flutter_keychain:
dependency: "direct main"
flutter_link_previewer:
dependency: transitive
description:
name: flutter_keychain
sha256: "0d000c0e9b3c16fdec016df406b4e89e7195bf719ed0882157400f1e16323cf8"
name: flutter_link_previewer
sha256: "007069e60f42419fb59872beb7a3cc3ea21e9f1bdff5d40239f376fa62ca9f20"
url: "https://pub.dev"
source: hosted
version: "2.5.0"
version: "3.2.2"
flutter_linkify:
dependency: transitive
description:
name: flutter_linkify
sha256: "74669e06a8f358fee4512b4320c0b80e51cffc496607931de68d28f099254073"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
flutter_loggy:
dependency: "direct main"
description:
@ -598,6 +654,22 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.7.7+1"
flutter_parsed_text:
dependency: transitive
description:
name: flutter_parsed_text
sha256: "529cf5793b7acdf16ee0f97b158d0d4ba0bf06e7121ef180abe1a5b59e32c1e2"
url: "https://pub.dev"
source: hosted
version: "2.2.1"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: ee8068e0e1cd16c4a82714119918efdeed33b3ba7772c54b5d094ab53f9b7fd1
url: "https://pub.dev"
source: hosted
version: "2.0.33"
flutter_riverpod:
dependency: transitive
description:
@ -614,6 +686,54 @@ packages:
url: "https://pub.dev"
source: hosted
version: "5.9.3"
flutter_secure_storage:
dependency: transitive
description:
name: flutter_secure_storage
sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea"
url: "https://pub.dev"
source: hosted
version: "9.2.4"
flutter_secure_storage_linux:
dependency: transitive
description:
name: flutter_secure_storage_linux
sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688
url: "https://pub.dev"
source: hosted
version: "1.2.3"
flutter_secure_storage_macos:
dependency: transitive
description:
name: flutter_secure_storage_macos
sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247"
url: "https://pub.dev"
source: hosted
version: "3.1.3"
flutter_secure_storage_platform_interface:
dependency: transitive
description:
name: flutter_secure_storage_platform_interface
sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8
url: "https://pub.dev"
source: hosted
version: "1.1.2"
flutter_secure_storage_web:
dependency: transitive
description:
name: flutter_secure_storage_web
sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9
url: "https://pub.dev"
source: hosted
version: "1.2.1"
flutter_secure_storage_windows:
dependency: transitive
description:
name: flutter_secure_storage_windows
sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709
url: "https://pub.dev"
source: hosted
version: "3.1.2"
flutter_svg:
dependency: "direct main"
description:
@ -932,26 +1052,34 @@ packages:
dependency: transitive
description:
name: leak_tracker
sha256: "7bb2830ebd849694d1ec25bf1f44582d6ac531a57a365a803a6034ff751d2d06"
sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de"
url: "https://pub.dev"
source: hosted
version: "10.0.7"
version: "11.0.2"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: "9491a714cca3667b60b5c420da8217e6de0d1ba7a5ec322fab01758f6998f379"
sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev"
source: hosted
version: "3.0.8"
version: "3.0.10"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
version: "3.0.2"
linkify:
dependency: transitive
description:
name: linkify
sha256: "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832"
url: "https://pub.dev"
source: hosted
version: "5.0.0"
lint:
dependency: "direct dev"
description:
@ -996,10 +1124,10 @@ packages:
dependency: transitive
description:
name: matcher
sha256: d2323aa2060500f906aa31a895b4030b6da3ebdcc5619d14ce1aada65cd161cb
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.16+1"
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
@ -1020,10 +1148,10 @@ packages:
dependency: transitive
description:
name: meta
sha256: bdb68674043280c3428e9ec998512fb681678676b3c54e773629ffe74419f8c7
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.15.0"
version: "1.16.0"
mime:
dependency: transitive
description:
@ -1076,10 +1204,10 @@ packages:
dependency: "direct main"
description:
name: path
sha256: "087ce49c3f0dc39180befefc60fdb4acd8f8620e5682fe2476afd0b3688bb4af"
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.0"
version: "1.9.1"
path_drawing:
dependency: transitive
description:
@ -1200,6 +1328,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "6.0.2"
photo_view:
dependency: transitive
description:
name: photo_view
sha256: "1fc3d970a91295fbd1364296575f854c9863f225505c28c46e0a03e48960c75e"
url: "https://pub.dev"
source: hosted
version: "0.15.0"
platform:
dependency: transitive
description:
@ -1392,6 +1528,14 @@ packages:
url: "https://pub.dev"
source: hosted
version: "0.2.0"
scroll_to_index:
dependency: transitive
description:
name: scroll_to_index
sha256: b707546e7500d9f070d63e5acf74fd437ec7eeeb68d3412ef7b0afada0b4f176
url: "https://pub.dev"
source: hosted
version: "3.0.1"
share_plus:
dependency: "direct main"
description:
@ -1481,10 +1625,10 @@ packages:
dependency: transitive
description:
name: source_span
sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c"
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.0"
version: "1.10.1"
sprintf:
dependency: transitive
description:
@ -1513,10 +1657,10 @@ packages:
dependency: transitive
description:
name: stack_trace
sha256: "9f47fd3630d76be3ab26f0ee06d213679aa425996925ff3feffdec504931c377"
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.0"
version: "1.12.1"
state_notifier:
dependency: transitive
description:
@ -1529,10 +1673,10 @@ packages:
dependency: transitive
description:
name: stream_channel
sha256: ba2aa5d8cc609d96bbb2899c28934f9e1af5cddbd60a827822ea467161eb54e7
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
version: "2.1.4"
stream_transform:
dependency: transitive
description:
@ -1545,26 +1689,34 @@ packages:
dependency: transitive
description:
name: string_scanner
sha256: "688af5ed3402a4bde5b3a6c15fd768dbf2621a614950b17f04626c431ab3c4c3"
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.3.0"
version: "1.4.1"
synchronized:
dependency: transitive
description:
name: synchronized
sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0
url: "https://pub.dev"
source: hosted
version: "3.4.0"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: a29248a84fbb7c79282b40b8c72a1209db169a2e0542bce341da992fe1bc7e84
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.1"
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: "664d3a9a64782fcdeb83ce9c6b39e78fd2971d4e37827b9b06c3aa1edc5e760c"
sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
url: "https://pub.dev"
source: hosted
version: "0.7.3"
version: "0.7.6"
time:
dependency: transitive
description:
@ -1713,18 +1865,26 @@ packages:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev"
source: hosted
version: "2.1.4"
version: "2.2.0"
visibility_detector:
dependency: transitive
description:
name: visibility_detector
sha256: dd5cc11e13494f432d15939c3aa8ae76844c42b723398643ce9addb88a5ed420
url: "https://pub.dev"
source: hosted
version: "0.4.0+2"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: f6be3ed8bd01289b34d679c2b62226f63c0e69f9fd2e50a6b3c1c729a961041b
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
url: "https://pub.dev"
source: hosted
version: "14.3.0"
version: "14.3.1"
watcher:
dependency: transitive
description:
@ -1757,6 +1917,38 @@ packages:
url: "https://pub.dev"
source: hosted
version: "3.0.3"
webview_flutter:
dependency: transitive
description:
name: webview_flutter
sha256: a3da219916aba44947d3a5478b1927876a09781174b5a2b67fa5be0555154bf9
url: "https://pub.dev"
source: hosted
version: "4.13.1"
webview_flutter_android:
dependency: transitive
description:
name: webview_flutter_android
sha256: eeeb3fcd5f0ff9f8446c9f4bbc18a99b809e40297528a3395597d03aafb9f510
url: "https://pub.dev"
source: hosted
version: "4.10.11"
webview_flutter_platform_interface:
dependency: transitive
description:
name: webview_flutter_platform_interface
sha256: "63d26ee3aca7256a83ccb576a50272edd7cfc80573a4305caa98985feb493ee0"
url: "https://pub.dev"
source: hosted
version: "2.14.0"
webview_flutter_wkwebview:
dependency: transitive
description:
name: webview_flutter_wkwebview
sha256: e49f378ed066efb13fc36186bbe0bd2425630d4ea0dbc71a18fdd0e4d8ed8ebc
url: "https://pub.dev"
source: hosted
version: "3.23.5"
win32:
dependency: transitive
description:
@ -1814,5 +2006,5 @@ packages:
source: hosted
version: "2.2.2"
sdks:
dart: ">=3.6.0 <4.0.0"
flutter: ">=3.27.0"
dart: ">=3.9.0 <4.0.0"
flutter: ">=3.35.0"

View File

@ -67,7 +67,6 @@ dependencies:
# 存储和安全
flutter_udid: ^4.0.0
flutter_keychain: 2.5.0
# 平台集成
window_manager: ^0.4.3
@ -113,6 +112,8 @@ dependencies:
intl: ^0.20.2
gal: ^2.3.2
openinstall_flutter_plugin: ^2.5.7
chatwoot_flutter_sdk: 0.1.1
file_picker: ^10.3.8
dev_dependencies:
flutter_test:
sdk: flutter

View File

@ -8,6 +8,7 @@
#include <connectivity_plus/connectivity_plus_windows_plugin.h>
#include <flutter_inappwebview_windows/flutter_inappwebview_windows_plugin_c_api.h>
#include <flutter_secure_storage_windows/flutter_secure_storage_windows_plugin.h>
#include <flutter_udid/flutter_udid_plugin_c_api.h>
#include <gal/gal_plugin_c_api.h>
#include <permission_handler_windows/permission_handler_windows_plugin.h>
@ -23,6 +24,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("ConnectivityPlusWindowsPlugin"));
FlutterInappwebviewWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterInappwebviewWindowsPluginCApi"));
FlutterSecureStorageWindowsPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin"));
FlutterUdidPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("FlutterUdidPluginCApi"));
GalPluginCApiRegisterWithRegistrar(

View File

@ -5,6 +5,7 @@
list(APPEND FLUTTER_PLUGIN_LIST
connectivity_plus
flutter_inappwebview_windows
flutter_secure_storage_windows
flutter_udid
gal
permission_handler_windows