diff --git a/GoogleService-Info.plist b/GoogleService-Info.plist
index c90ada3a3..590c85a5f 100644
--- a/GoogleService-Info.plist
+++ b/GoogleService-Info.plist
@@ -3,9 +3,9 @@
CLIENT_ID
- 907754492821-oc9e77svgmmlgouo0op7vv00e1hb8278.apps.googleusercontent.com
+ 907754492821-tl2blr39g82re40sttkve36ovt6qcu6c.apps.googleusercontent.com
REVERSED_CLIENT_ID
- com.googleusercontent.apps.907754492821-oc9e77svgmmlgouo0op7vv00e1hb8278
+ com.googleusercontent.apps.907754492821-tl2blr39g82re40sttkve36ovt6qcu6c
ANDROID_CLIENT_ID
907754492821-9jakqvathu61e6b8g95i41ssi7o4dnka.apps.googleusercontent.com
API_KEY
@@ -15,7 +15,7 @@
PLIST_VERSION
1
BUNDLE_ID
- com.yunqiinnovation.deepsound
+ com.chuangxiangyunqi.deapsound
PROJECT_ID
deepsound-e0e3d
STORAGE_BUCKET
@@ -31,6 +31,6 @@
IS_SIGNIN_ENABLED
GOOGLE_APP_ID
- 1:907754492821:ios:246794fc44b23174145c9c
+ 1:907754492821:ios:e4b4f3b37e58a7d1145c9c
\ No newline at end of file
diff --git a/ios/Podfile b/ios/Podfile
index 4c7418ab9..a2084703d 100644
--- a/ios/Podfile
+++ b/ios/Podfile
@@ -1,5 +1,5 @@
# Define a global platform for your project
-platform :ios, '13.0'
+platform :ios, '18.0'
# CocoaPods analytics sends network stats synchronously affecting flutter build latency.
ENV['COCOAPODS_DISABLE_STATS'] = 'true'
diff --git a/ios/Podfile.lock b/ios/Podfile.lock
index c5e3caec9..336d0ad28 100644
--- a/ios/Podfile.lock
+++ b/ios/Podfile.lock
@@ -11,6 +11,8 @@ PODS:
- Flutter
- audio_waveforms (0.0.1):
- Flutter
+ - ble_service (0.0.1):
+ - Flutter
- chat_storage (0.0.1):
- Flutter
- classic_bluetooth (0.0.1):
@@ -231,6 +233,7 @@ DEPENDENCIES:
- app_settings (from `.symlinks/plugins/app_settings/ios`)
- audio_session (from `.symlinks/plugins/audio_session/ios`)
- audio_waveforms (from `.symlinks/plugins/audio_waveforms/ios`)
+ - ble_service (from `.symlinks/plugins/ble_service/ios`)
- chat_storage (from `.symlinks/plugins/chat_storage/ios`)
- classic_bluetooth (from `.symlinks/plugins/classic_bluetooth/ios`)
- device_info_plus (from `.symlinks/plugins/device_info_plus/ios`)
@@ -302,6 +305,8 @@ EXTERNAL SOURCES:
:path: ".symlinks/plugins/audio_session/ios"
audio_waveforms:
:path: ".symlinks/plugins/audio_waveforms/ios"
+ ble_service:
+ :path: ".symlinks/plugins/ble_service/ios"
chat_storage:
:path: ".symlinks/plugins/chat_storage/ios"
classic_bluetooth:
@@ -370,6 +375,7 @@ SPEC CHECKSUMS:
AppAuth: d4f13a8fe0baf391b2108511793e4b479691fb73
audio_session: 9bb7f6c970f21241b19f5a3658097ae459681ba0
audio_waveforms: a6dde7fe7c0ea05f06ffbdb0f7c1b2b2ba6cedcf
+ ble_service: 068ebe51800424f980282b16cbf757574eec4e08
chat_storage: 933a96144157a07a2fef7f6acb28c78ff18465d8
classic_bluetooth: c5e5c0c86acab8dcd6b8e9cef7fca654c3518034
device_info_plus: 71ffc6ab7634ade6267c7a93088ed7e4f74e5896
@@ -430,6 +436,6 @@ SPEC CHECKSUMS:
webview_flutter_wkwebview: 1821ceac936eba6f7984d89a9f3bcb4dea99ebb2
WechatOpenSDK-XCFramework: 36fb2bea0754266c17184adf4963d7e6ff98b69f
-PODFILE CHECKSUM: 017ca79b199d8f37c4acb8d83ec912447003b920
+PODFILE CHECKSUM: f62382080fcf32f2d4640dc419aa07d69eff0328
COCOAPODS: 1.16.2
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index 82ce9f671..70369f46d 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -44,6 +44,7 @@
/* Begin PBXFileReference section */
0AD944112DD9DB5C00557D21 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; };
+ 0AD944132DDA0C0D00557D21 /* AccessorySetupKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AccessorySetupKit.framework; path = System/Library/Frameworks/AccessorySetupKit.framework; sourceTree = SDKROOT; };
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; };
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; };
331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; };
@@ -106,6 +107,7 @@
1E5DDD8701F6FB27AA502080 /* Frameworks */ = {
isa = PBXGroup;
children = (
+ 0AD944132DDA0C0D00557D21 /* AccessorySetupKit.framework */,
E27AD0DBE6531F2655DB9986 /* Pods_Runner.framework */,
F79ADB762804BBED65875C03 /* Pods_RunnerTests.framework */,
);
@@ -499,6 +501,7 @@
DEVELOPMENT_TEAM = 42C82SZUVX;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -519,6 +522,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.yunqiinnovation.deepsound.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -537,6 +541,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.yunqiinnovation.deepsound.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -553,6 +558,7 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
GENERATE_INFOPLIST_FILE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.0;
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = com.yunqiinnovation.deepsound.RunnerTests;
PRODUCT_NAME = "$(TARGET_NAME)";
@@ -685,6 +691,7 @@
DEVELOPMENT_TEAM = 42C82SZUVX;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@@ -709,6 +716,7 @@
DEVELOPMENT_TEAM = 42C82SZUVX;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Runner/Info.plist;
+ IPHONEOS_DEPLOYMENT_TARGET = 18.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist
index 7425aacd2..eb35dbbf9 100644
--- a/ios/Runner/Info.plist
+++ b/ios/Runner/Info.plist
@@ -41,6 +41,12 @@
CFBundleVersion
$(FLUTTER_BUILD_NUMBER)
+ UIBackgroundModes
+
+ bluetooth-central
+ bluetooth-peripheral
+ external-accessory
+
LSApplicationQueriesSchemes
weixin
@@ -108,5 +114,9 @@
FacebookAutoLogAppEventsEnabled
+ NSAccessorySetupKitSupports
+
+ Bluetooth
+
diff --git a/lib/core/bindings/initial_binding.dart b/lib/core/bindings/initial_binding.dart
index 8921a6fca..7f5b428bd 100644
--- a/lib/core/bindings/initial_binding.dart
+++ b/lib/core/bindings/initial_binding.dart
@@ -4,9 +4,7 @@ import '../../data/services/speech_factory.dart';
import '../../data/services/chat_history_service.dart';
import '../../data/services/volcano_translation_service.dart';
import '../../data/services/language_manager.dart';
-import '../../data/services/volcano_ai_service.dart';
import '../../core/utils/logger.dart';
-import '../../data/services/open_ai_service_adapter.dart';
import '../../data/services/bluetooth_manager.dart';
import '../../data/services/ble_manager.dart';
@@ -17,10 +15,11 @@ class InitialBinding extends Bindings {
Logger.warning('InitialBinding dependencies');
// 语言管理器(需要最先初始化)
- Get.put(LanguageManager(), permanent: true);
+ // 语言管理器(需要最先初始化)
+ Get.lazyPut(() => LanguageManager(), fenix: true);
//初始化语音工厂
- Get.put(SpeechFactory(), permanent: true);
+ Get.lazyPut(() => SpeechFactory(), fenix: true);
Get.find().initialize(initialType: SpeechServiceType.azure);
// 历史记录服务
@@ -30,30 +29,14 @@ class InitialBinding extends Bindings {
Get.lazyPut(() => VolcanoTranslationService(),
fenix: true);
- // OpenAI服务适配器
- Get.lazyPut(() {
- final adapter = OpenAIServiceAdapter();
- adapter.initialize();
- return adapter;
- }, fenix: true);
-
// 蓝牙服务
- Get.put(BluetoothManager(), permanent: true);
+ Get.lazyPut(() => BluetoothManager(), fenix: true);
// BleManager
- Get.put(BleManager(), permanent: true);
+ Get.lazyPut(() => BleManager(), fenix: true);
// MusicManager
- Get.put(MusicManager(), permanent: true);
+ Get.lazyPut(() => MusicManager(), fenix: true);
// 火山AI服务
- Get.lazyPut(() => VolcanoAIService(), fenix: true);
-
- // 蓝牙媒体按钮服务
- // Get.lazyPut(
- // () => BluetoothMediaButtonService(),
- // fenix: true);
-
- // // 语音交互服务
- // Get.lazyPut(() => VoiceInteractionService(),
- // fenix: true);
+ // Get.lazyPut(() => VolcanoAIService(), fenix: true);
// 杰理蓝牙服务
diff --git a/lib/modules/pairing/controllers/pairing_controller.dart b/lib/modules/pairing/controllers/pairing_controller.dart
index 653c849a2..7f11158bf 100644
--- a/lib/modules/pairing/controllers/pairing_controller.dart
+++ b/lib/modules/pairing/controllers/pairing_controller.dart
@@ -15,8 +15,6 @@ import 'package:flutter/material.dart';
class PairingController extends GetxController {
static PairingController get to => Get.find();
- // 需要设备
- final bool needdeivice = false;
// 状态标志
final isLoading = false.obs;
@@ -65,6 +63,9 @@ class PairingController extends GetxController {
// BLE服务
final _bleService = BleService();
+ // 日志tag
+ static const _tag = 'PairingController';
+
@override
void onInit() {
super.onInit();
@@ -102,7 +103,7 @@ class PairingController extends GetxController {
// 检查蓝牙状态并刷新设备
await _checkBluetoothAndRefresh();
} catch (e) {
- Logger.error('初始化配对控制器失败: ${e.toString()}');
+ Logger.e(_tag, '初始化配对控制器失败: ${e.toString()}');
statusDescription.value = 'initializationFailure'.tr;
} finally {
isLoading.value = false;
@@ -134,13 +135,12 @@ class PairingController extends GetxController {
/// 检查设备配对状态
Future _checkDevicePairingStatus() async {
- // 只在Android平台且设备已连接时执行
- if (!Platform.isAndroid || !isDeviceConnected) return;
+ if (!isDeviceConnected) return;
try {
final isSupported = await _bleService.isCompanionSupported();
if (!isSupported) {
- Logger.info('设备不支持Companion功能');
+ Logger.i(_tag, '设备不支持Companion功能');
_companionAssociated.value = true; // 不支持则视为已配对
_userRejectedAssociation.value = false; // 重置拒绝状态
return;
@@ -149,16 +149,16 @@ class PairingController extends GetxController {
final pairedMac = await _bleService.getPairedMacAddress();
if (pairedMac == null) {
// 没有配对记录,需要开始配对
- Logger.info('无配对记录,需要开始设备配对');
+ Logger.i(_tag, '无配对记录,需要开始设备配对');
return;
}
- Logger.info('发现已关联的Companion设备: $pairedMac');
+ Logger.i(_tag, '发现已关联的Companion设备: $pairedMac');
// 检查当前连接设备与已保存的设备是否一致
if (currentDevice!.address != pairedMac) {
// MAC地址不匹配
- Logger.warning('当前连接的设备与已配对的DeepSound设备不符');
+ Logger.w(_tag, '当前连接的设备与已配对的DeepSound设备不符');
statusDescription.value = 'pleaseConnectPairedDevice'.tr;
return;
}
@@ -170,13 +170,13 @@ class PairingController extends GetxController {
}
// 设备匹配且合规,标记为已配对
- Logger.info('当前设备与已配对设备匹配');
+ Logger.i(_tag, '当前设备与已配对设备匹配');
_companionAssociated.value = true;
_userRejectedAssociation.value = false; // 重置拒绝状态
await _bleService.registerBackgroundScan();
_autoNavigateToHome();
} catch (e) {
- Logger.error('检查设备配对状态失败: ${e.toString()}');
+ Logger.e(_tag, '检查设备配对状态失败: ${e.toString()}');
}
}
@@ -198,45 +198,70 @@ class PairingController extends GetxController {
permissionsToRequest.add(Permission.bluetoothConnect);
}
} else if (Platform.isIOS) {
- // iOS上单独处理蓝牙权限请求,避免冲突
- PermissionStatus status = await Permission.bluetooth.status;
+ // iOS需要请求的权限
+ permissionsToRequest.add(Permission.bluetooth);
+ permissionsToRequest.add(Permission.location);
+
+ // 如果需要麦克风权限(例如语音功能)
+ // permissionsToRequest.add(Permission.microphone);
- if (status.isPermanentlyDenied) {
- Logger.warning('iOS蓝牙权限状态为permanentlyDenied,这可能是iOS系统误报');
+ try {
+ // 先尝试请求权限
+ if (permissionsToRequest.isNotEmpty) {
+ statuses = await permissionsToRequest.request();
+ bool allGranted = true;
+ statuses.forEach((permission, status) {
+ if (!status.isGranted) {
+ allGranted = false;
+ Logger.w(_tag, 'iOS权限 ${permission.toString()} 未被授予: $status');
+
+ // 特殊处理蓝牙权限
+ if (permission == Permission.bluetooth) {
+ Logger.w(_tag, 'iOS蓝牙权限未授予,状态: $status');
+ }
+ }
+ });
+
+ // 如果有权限未授予,但不是永久拒绝,继续尝试
+ if (!allGranted) {
+ bool hasPermanentlyDenied = statuses.values.any((status) => status.isPermanentlyDenied);
+ if (hasPermanentlyDenied) {
+ // 有权限被永久拒绝,需要引导用户去设置
+ _showPermissionSettingsDialog('部分权限被永久拒绝,请在设置中启用');
+ return false;
+ }
+ }
+ }
- // 在iOS上打开蓝牙设置对话框
- Get.dialog(
- AlertDialog(
- title: Text('需要蓝牙权限'),
- content: Text('请在系统设置中手动开启蓝牙权限,以便连接设备'),
- actions: [
- TextButton(
- onPressed: () => Get.back(),
- child: Text('稍后'),
- ),
- TextButton(
- onPressed: () {
- Get.back();
- openAppSettings();
- },
- child: Text('前往设置'),
- ),
- ],
- ),
- barrierDismissible: false,
- );
- return false;
- } else if (!status.isGranted) {
- // 单独请求蓝牙权限
- PermissionStatus result = await Permission.bluetooth.request();
- if (!result.isGranted) {
- Logger.warning('iOS蓝牙权限申请失败: $result');
- return false;
+ // 直接尝试使用蓝牙功能,这会触发iOS原生权限请求
+ bool isEnabled = await _bluetoothService.isBluetoothEnabled();
+ Logger.i(_tag, 'iOS蓝牙状态检查: ${isEnabled ? "已开启" : "未开启"}');
+
+ // 检测AccessorySetupKit支持情况(iOS 18+特性)
+ bool companionSupported = await _bleService.isCompanionSupported();
+ Logger.i(_tag, 'iOS Companion支持检查: ${companionSupported ? "支持" : "不支持"}');
+
+ if (companionSupported) {
+ // 针对iOS 18+,尝试预热AccessorySetupKit框架
+ try {
+ // 此调用会触发AccessorySetupKit相关权限请求
+ final pairedMac = await _bleService.getPairedMacAddress();
+ Logger.i(_tag, '获取已配对设备MAC: ${pairedMac ?? "无"}');
+ } catch (e) {
+ Logger.w(_tag, 'iOS 18+ AccessorySetupKit初始化失败: ${e.toString()}');
+ }
}
+
+ // 在iOS上视为权限已授予
+ _hasPermissions.value = true;
+ return true;
+ } catch (e) {
+ Logger.e(_tag, "iOS蓝牙初始化失败: ${e.toString()}");
+
+ // 显示自定义对话框引导用户
+ _showPermissionSettingsDialog('需要开启蓝牙权限才能配对设备');
+ return false;
}
-
- // iOS不再添加到批量请求列表
- // permissionsToRequest.add(Permission.bluetooth);
}
// 如果还有其他权限需要请求
@@ -247,7 +272,7 @@ class PairingController extends GetxController {
statuses.forEach((permission, status) {
if (!status.isGranted) {
allGranted = false;
- Logger.warning('权限 ${permission.toString()} 未被授予: $status');
+ Logger.w(_tag, '权限 ${permission.toString()} 未被授予: $status');
}
});
@@ -259,6 +284,30 @@ class PairingController extends GetxController {
_hasPermissions.value = true;
return true;
}
+
+ /// 显示权限设置对话框
+ void _showPermissionSettingsDialog(String message) {
+ Get.dialog(
+ AlertDialog(
+ title: Text('需要权限'),
+ content: Text(message),
+ actions: [
+ TextButton(
+ onPressed: () => Get.back(),
+ child: Text('稍后'),
+ ),
+ TextButton(
+ onPressed: () {
+ Get.back();
+ openBluetoothSettings();
+ },
+ child: Text('去设置'),
+ ),
+ ],
+ ),
+ barrierDismissible: false,
+ );
+ }
// 辅助方法获取Android SDK版本
Future _getAndroidSdkVersion() async {
@@ -281,14 +330,11 @@ class PairingController extends GetxController {
_deviceWorker =
ever(_bluetoothService.currentDeviceRx, (BluetoothDevice? device) {
if (device != null && !_isNavigatingToHome) {
- Logger.info('配对页面发现设备已连接: ${device.name}');
+ Logger.i(_tag, '配对页面发现设备已连接: ${device.name}');
_handleDeviceConnected();
}
_updateStatusDescription();
});
- if (needdeivice) {
- _handleDeviceConnected();
- }
}
/// 处理设备连接成功事件
@@ -347,9 +393,8 @@ class PairingController extends GetxController {
/// 启动Companion设备关联流程
Future _startCompanionAssociation() async {
- // 如果不是Android平台,已跳转,已完成关联或正在进行关联,直接返回
- if (!Platform.isAndroid ||
- _isNavigatingToHome ||
+ // 如果已跳转,已完成关联或正在进行关联,直接返回
+ if (_isNavigatingToHome ||
_companionAssociated.value ||
_isAssociating ||
!isDeviceConnected) {
@@ -367,7 +412,7 @@ class PairingController extends GetxController {
// 检查是否支持Companion功能
final isSupported = await _bleService.isCompanionSupported();
if (!isSupported) {
- Logger.info('设备不支持Companion功能,跳过关联');
+ Logger.i(_tag, '设备不支持Companion功能,跳过关联');
_companionAssociated.value = true;
_autoNavigateToHome();
return;
@@ -380,7 +425,7 @@ class PairingController extends GetxController {
return;
}
- Logger.info('开始Companion设备关联流程, 设备MAC: ${currentDevice!.address}');
+ Logger.i(_tag, '开始Companion设备关联流程, 设备MAC: ${currentDevice!.address}');
var success = await _bleService.startDeviceAssociation(
deviceNamePattern: currentDevice!.name,
@@ -389,7 +434,7 @@ class PairingController extends GetxController {
_isAssociating = false;
if (success) {
- Logger.info('Companion设备关联成功');
+ Logger.i(_tag, 'Companion设备关联成功');
_companionAssociated.value = true;
_userRejectedAssociation.value = false;
@@ -400,14 +445,14 @@ class PairingController extends GetxController {
// 关联成功后跳转
_autoNavigateToHome();
} else {
- Logger.error('Companion设备关联失败或被用户拒绝');
+ Logger.e(_tag, 'Companion设备关联失败或被用户拒绝');
// 关联失败 - 用户拒绝关联
_userRejectedAssociation.value = true;
// 确保UI状态更新
_updateStatusDescription();
}
} catch (e) {
- Logger.error('Companion设备关联过程发生错误: ${e.toString()}');
+ Logger.e(_tag, 'Companion设备关联过程发生错误: ${e.toString()}');
_isAssociating = false;
_userRejectedAssociation.value = true;
_updateStatusDescription();
@@ -416,13 +461,13 @@ class PairingController extends GetxController {
/// 自动跳转到主页
Future _autoNavigateToHome() async {
- if (needdeivice && (_isNavigatingToHome || !isDeviceConnected)) return;
+ if (_isNavigatingToHome || !isDeviceConnected) return;
// 启动BLE后台服务
await _startAgentService();
_isNavigatingToHome = true;
- Logger.info('已找到连接的设备 ${currentDevice!.name},自动跳转到主页');
+ Logger.i(_tag, '已找到连接的设备 ${currentDevice!.name},自动跳转到主页');
Future.delayed(const Duration(milliseconds: 500), () {
Get.offAllNamed(Routes.home);
@@ -432,12 +477,13 @@ class PairingController extends GetxController {
/// 启动BLE后台服务
Future _startAgentService() async {
try {
- if (needdeivice && !isDeviceConnected) return;
+ // 注释掉设备连接检查,确保无论是否连接设备都能启动服务
+ // if (!isDeviceConnected) return;
final result = await BleManager.to.startAgentService();
- Logger.info(result ? 'BLE后台服务启动成功' : 'BLE后台服务启动失败');
+ Logger.i(_tag, result ? 'BLE后台服务启动成功' : 'BLE后台服务启动失败');
} catch (e) {
- Logger.error('启动BLE后台服务发生错误: ${e.toString()}');
+ Logger.e(_tag, '启动BLE后台服务发生错误: ${e.toString()}');
}
}
@@ -445,9 +491,9 @@ class PairingController extends GetxController {
Future _stopAgentService() async {
try {
final result = await BleManager.to.stopAgentService();
- Logger.info(result ? 'BLE后台服务停止成功' : 'BLE后台服务停止失败');
+ Logger.i(_tag, result ? 'BLE后台服务停止成功' : 'BLE后台服务停止失败');
} catch (e) {
- Logger.error('停止BLE后台服务发生错误: ${e.toString()}');
+ Logger.e(_tag, '停止BLE后台服务发生错误: ${e.toString()}');
}
}
@@ -470,15 +516,82 @@ class PairingController extends GetxController {
} else if (Platform.isAndroid && !isBluetoothOn) {
AppSettings.openAppSettings(type: AppSettingsType.bluetooth);
} else if (Platform.isIOS) {
- openAppSettings();
+ // iOS上优先尝试打开蓝牙设置
+ if (!isBluetoothOn) {
+ // iOS上无法直接打开蓝牙设置,只能打开应用设置
+ AppSettings.openAppSettings();
+ } else {
+ // 如果蓝牙开启但有其他权限问题,打开应用设置
+ openAppSettings();
+ }
} else {
AppSettings.openAppSettings(type: AppSettingsType.bluetooth);
}
} catch (e) {
- Logger.error('打开设置失败: ${e.toString()}');
+ Logger.e(_tag, '打开设置失败: ${e.toString()}');
}
}
+ /// 重新初始化蓝牙
+ Future reinitializeBluetooth() async {
+ try {
+ isLoading.value = true;
+ statusDescription.value = '正在重新初始化蓝牙...';
+
+ // iOS上尝试重置权限状态
+ if (Platform.isIOS) {
+ await Future.delayed(Duration(milliseconds: 500));
+
+ // 检查蓝牙权限
+ PermissionStatus bluetoothStatus = await Permission.bluetooth.status;
+ Logger.i(_tag, "iOS蓝牙权限当前状态: $bluetoothStatus");
+
+ if (bluetoothStatus.isPermanentlyDenied) {
+ Logger.i(_tag, "iOS蓝牙权限处于永久拒绝状态,提示用户手动开启");
+ _showPermissionSettingsDialog('蓝牙权限被拒绝,请在设置中手动开启');
+ return;
+ }
+
+ // 尝试重新请求权限
+ if (!bluetoothStatus.isGranted) {
+ bluetoothStatus = await Permission.bluetooth.request();
+ Logger.i(_tag, "iOS蓝牙权限请求结果: $bluetoothStatus");
+ }
+
+ // 尝试检查蓝牙状态,这会重新触发系统权限弹窗
+ try {
+ bool isEnabled = await _bluetoothService.isBluetoothEnabled();
+ Logger.i(_tag, "iOS蓝牙状态: ${isEnabled ? '开启' : '关闭'}");
+ } catch (e) {
+ Logger.e(_tag, "iOS蓝牙状态检查失败: ${e.toString()}");
+ }
+
+ // 检查Companion功能(iOS 18+)
+ try {
+ bool isSupported = await _bleService.isCompanionSupported();
+ if (isSupported) {
+ Logger.i(_tag, "iOS 18+ Companion功能可用,尝试初始化");
+ // 尝试预热AccessorySetupKit
+ await _bleService.getPairedMacAddress();
+ }
+ } catch (e) {
+ Logger.w(_tag, "iOS Companion功能检查失败: ${e.toString()}");
+ }
+ }
+
+ // 重新检查权限
+ if (await _checkAndRequestPermissions()) {
+ // 重新检查蓝牙状态
+ await _checkBluetoothAndRefresh();
+ }
+ } catch (e) {
+ Logger.e(_tag, '重新初始化蓝牙失败: ${e.toString()}');
+ } finally {
+ isLoading.value = false;
+ _updateStatusDescription();
+ }
+ }
+
/// 打开应用设置
Future openAppSettings() async {
try {
@@ -488,7 +601,7 @@ class PairingController extends GetxController {
reinitializeBluetooth();
});
} catch (e) {
- Logger.error('打开应用设置失败: ${e.toString()}');
+ Logger.e(_tag, '打开应用设置失败: ${e.toString()}');
}
}
@@ -501,38 +614,13 @@ class PairingController extends GetxController {
/// 跳过连接
void skipConnecting() async {
- // 启动BLE后台服务
+ // 即使没有设备连接,也启动BLE后台服务
await _startAgentService();
_isNavigatingToHome = true;
+
+ // 记录跳过配对的日志
+ Logger.i(_tag, '用户跳过设备配对,直接跳转到主页');
+
Get.offAllNamed(Routes.home);
}
-
- /// 重新初始化蓝牙
- Future reinitializeBluetooth() async {
- try {
- isLoading.value = true;
- statusDescription.value = '正在重新初始化蓝牙...';
-
- // iOS上尝试重置权限状态
- if (Platform.isIOS) {
- await Future.delayed(Duration(milliseconds: 500));
- if (await Permission.bluetooth.isPermanentlyDenied) {
- Logger.info("iOS蓝牙权限仍处于永久拒绝状态,尝试直接使用蓝牙功能");
- // 在永久拒绝状态下,尝试使用蓝牙功能,iOS可能会再次弹出系统权限请求
- _bluetoothService.isBluetoothEnabled();
- }
- }
-
- // 重新检查权限
- if (await _checkAndRequestPermissions()) {
- // 重新检查蓝牙状态
- await _checkBluetoothAndRefresh();
- }
- } catch (e) {
- Logger.error('重新初始化蓝牙失败: ${e.toString()}');
- } finally {
- isLoading.value = false;
- _updateStatusDescription();
- }
- }
}
\ No newline at end of file
diff --git a/lib/modules/settings/controllers/settings_controller.dart b/lib/modules/settings/controllers/settings_controller.dart
index 05bca4804..984376632 100644
--- a/lib/modules/settings/controllers/settings_controller.dart
+++ b/lib/modules/settings/controllers/settings_controller.dart
@@ -12,6 +12,9 @@ import '../../../data/models/user_Info.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'package:package_info_plus/package_info_plus.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'dart:async';
+import 'package:app_settings/app_settings.dart';
class SettingsController extends GetxController {
// 语言设置
@@ -101,6 +104,81 @@ class SettingsController extends GetxController {
final appVersion = ''.obs;
final buildNumber = ''.obs;
+ // 权限相关
+ // 权限组,用于在UI中显示
+ final List