Browse Source

提交苹果版本

newdev_shunjiawei
liwei1dao 1 year ago
parent
commit
0b4e612b88
  1. 4
      ios/Podfile.lock
  2. 4
      ios/Runner.xcodeproj/project.pbxproj
  3. 25
      ios/Runner/Info.plist
  4. 10
      lib/data/services/ble_manager.dart
  5. 46
      lib/modules/pairing/controllers/pairing_controller.dart
  6. 586
      local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleScanManager.swift
  7. 26
      local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift
  8. 11
      local_plugins/ble_service/lib/ble_service.dart
  9. 1
      local_plugins/ota/ios/Classes/BleManager/JLBleManager.m

4
ios/Podfile.lock

@ -85,7 +85,7 @@ PODS:
- SDWebImage/Core (~> 5.17)
- spotify_sdk (0.0.1):
- Flutter
- tencentcloud_cos_sdk_plugin (1.2.3):
- tencentcloud_cos_sdk_plugin (1.2.4):
- Flutter
- QCloudCOSXML (= 6.4.7)
- WechatOpenSDK-XCFramework (2.0.4)
@ -203,7 +203,7 @@ SPEC CHECKSUMS:
SDWebImage: f84b0feeb08d2d11e6a9b843cb06d75ebf5b8868
SDWebImageWebPCoder: e38c0a70396191361d60c092933e22c20d5b1380
spotify_sdk: a48400bb29f70c4fe251ebfdc9135c37097ac5ca
tencentcloud_cos_sdk_plugin: c3d78b2c3bae42b5a20009dc047f3f1621e6272b
tencentcloud_cos_sdk_plugin: 7bed564dbe72df23e7b5cacb1e51b1a20cb1639c
WechatOpenSDK-XCFramework: 36fb2bea0754266c17184adf4963d7e6ff98b69f
wifi_iot: f645260a2be8608517b2a9bf4c39b98e97003acc

4
ios/Runner.xcodeproj/project.pbxproj

@ -252,7 +252,7 @@
);
mainGroup = 97C146E51CF9000F007C117D;
packageReferences = (
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */,
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */,
D013B7972DFA83E400B2B69B /* XCRemoteSwiftPackageReference "flutterfire" */,
);
productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
@ -793,7 +793,7 @@
/* End XCConfigurationList section */
/* Begin XCLocalSwiftPackageReference section */
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "FlutterGeneratedPluginSwiftPackage" */ = {
781AD8BC2B33823900A9FFBB /* XCLocalSwiftPackageReference "Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage" */ = {
isa = XCLocalSwiftPackageReference;
relativePath = Flutter/ephemeral/Packages/FlutterGeneratedPluginSwiftPackage;
};

25
ios/Runner/Info.plist

@ -85,10 +85,6 @@
<string>语音助理耳机</string>
</dict>
</array>
<key>NSAccessorySetupKitSupports</key>
<array>
<string>Bluetooth</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
@ -117,10 +113,25 @@
</dict>
</dict>
</dict>
<!-- 蓝牙权限描述 -->
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要蓝牙权限用于连接和管理音频设备</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>需要蓝牙权限用于连接和管理音频设备</string>
<!-- 后台模式支持 -->
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>audio</string>
<string>location</string>
</array>
<!-- AccessorySetup支持(用于配对) -->
<key>NSAccessorySetupKitSupports</key>
<array>
<string>Bluetooth</string>
</array>
<key>NSCalendarsUsageDescription</key>
<string>需要日历权限用于安排和管理您的音频会议和录音任务</string>
<key>NSCameraUsageDescription</key>
@ -137,12 +148,6 @@
<string>需要相册权限用于保存录音文件和导入音频文件</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>audio</string>
<string>location</string>
</array>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>

10
lib/data/services/ble_manager.dart

@ -859,4 +859,14 @@ class BleManager extends GetxService {
}
return Future.value(Get.find<BleManager>());
}
/// 请求蓝牙权限
Future<bool> requestBluetoothPermission() async {
try {
return await _bleService.requestBluetoothPermission();
} catch (e) {
Logger.error('请求蓝牙权限失败: ${e.toString()}');
return false;
}
}
}

46
lib/modules/pairing/controllers/pairing_controller.dart

@ -418,17 +418,45 @@ class PairingController extends GetxController {
/// 检查权限
Future<bool> _checkPermissions() async {
// Android权限检查
if (Platform.isAndroid) {
// 检查蓝牙相关权限
final bluetoothScan = await Permission.bluetoothScan.request();
final bluetoothConnect = await Permission.bluetoothConnect.request();
final location = await Permission.locationWhenInUse.request();
return bluetoothScan.isGranted &&
bluetoothConnect.isGranted &&
location.isGranted;
// Android 平台权限检查
Map<Permission, PermissionStatus> statuses = await [
Permission.bluetoothScan,
Permission.bluetoothConnect,
Permission.locationWhenInUse,
].request();
return statuses[Permission.bluetoothScan]!.isGranted &&
statuses[Permission.bluetoothConnect]!.isGranted &&
statuses[Permission.locationWhenInUse]!.isGranted;
} else if (Platform.isIOS) {
// iOS 平台权限检查
Map<Permission, PermissionStatus> statuses = await [
Permission.locationWhenInUse,
Permission.bluetooth, // 添加蓝牙权限检查
].request();
// 检查位置权限
bool locationGranted = statuses[Permission.locationWhenInUse]!.isGranted;
// 检查蓝牙权限
bool bluetoothGranted = statuses[Permission.bluetooth]!.isGranted;
// 如果蓝牙权限未确定,强制触发权限申请
if (!bluetoothGranted) {
try {
await _bleManager.requestBluetoothPermission();
// 重新检查蓝牙权限状态
final newBluetoothStatus = await Permission.bluetooth.status;
bluetoothGranted = newBluetoothStatus.isGranted;
} catch (e) {
Logger.e(_tag, '蓝牙权限申请失败: $e');
}
}
return locationGranted && bluetoothGranted;
}
return true;
}

586
local_plugins/ble_service/ios/ble_service/Sources/ble_service/BleScanManager.swift

@ -0,0 +1,586 @@
import Foundation
import CoreBluetooth
import UIKit // 添加UIKit导入
import os.log
/// 简化的 BLE 扫描管理器
/// 只提供扫描和获取设备列表功能
@available(iOS 13.0, *)
public class BleScanManager: NSObject {
// MARK: - 单例
public static let shared = BleScanManager()
// MARK: - 数据模型
public struct BleDeviceInfo {
public let identifier: UUID
public let name: String?
public let rssi: NSNumber
public let advertisementData: [String: Any]
public let discoveryMethod: DiscoveryMethod
public let lastSeen: Date
public enum DiscoveryMethod {
case traditional
case accessorySetupKit
}
}
// MARK: - 属性
private var centralManager: CBCentralManager!
private let logger = OSLog(subsystem: "com.yunqiinnovation.ble_service", category: "BleScanManager")
// 扫描状态
private var isScanning = false
private var scanTimeout: Timer?
// 设备列表
private var discoveredDevices: [UUID: BleDeviceInfo] = [:]
// MARK: - 初始化
private override init() {
super.init()
setupCentralManager()
}
// 在setupCentralManager后添加权限检查
private func setupCentralManager() {
let options: [String: Any] = [
CBCentralManagerOptionShowPowerAlertKey: true,
CBCentralManagerOptionRestoreIdentifierKey: "BleScanManager"
]
centralManager = CBCentralManager(delegate: self, queue: nil, options: options)
// 添加权限检查和触发逻辑
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
self?.checkAndTriggerPermission()
}
}
private func checkAndTriggerPermission() {
// 检查蓝牙权限状态,兼容不同iOS版本
let authorization: CBManagerAuthorization
if #available(iOS 13.1, *) {
authorization = CBManager.authorization
} else if #available(iOS 13.0, *) {
// iOS 13.0 使用实例方法,需要确保centralManager已初始化
authorization = centralManager?.authorization ?? .notDetermined
} else {
// iOS 13.0以下版本没有权限检查API,默认为未确定
authorization = .notDetermined
}
os_log("📊 蓝牙权限状态: %d", log: logger, type: .info, authorization.rawValue)
os_log("📊 CBCentralManager状态: %d", log: logger, type: .info, centralManager?.state.rawValue ?? -1)
// 只在权限未确定且蓝牙状态为关闭时触发扫描
if authorization == .notDetermined && centralManager?.state == .poweredOff {
os_log("📊 主动触发一次扫描来申请权限", log: logger, type: .info)
// 主动触发一次扫描来申请权限
centralManager?.scanForPeripherals(withServices: nil, options: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) { [weak self] in
self?.centralManager?.stopScan()
}
}
}
// MARK: - 公共接口
/// 开始扫描 BLE 设备
/// - Parameter timeout: 扫描超时时间,默认 10 秒
/// - Returns: 是否成功开始扫描
public func startScan(timeout: TimeInterval = 30.0) -> Bool {
os_log("🔍 开始 BLE 扫描,超时时间: %.1f 秒", log: logger, type: .info, timeout)
guard !isScanning else {
os_log("⚠️ 扫描已在进行中", log: logger, type: .info)
return false
}
// 清空之前的设备列表
discoveredDevices.removeAll()
// iOS 18 兼容性检查
if #available(iOS 18.0, *) {
// iOS 18 使用新的权限检查方式
return startScanForIOS18(timeout: timeout)
} else {
// iOS 17 及以下使用传统方式
return startScanLegacy(timeout: timeout)
}
}
@available(iOS 18.0, *)
private func startScanForIOS18(timeout: TimeInterval) -> Bool {
// 对于 iOS 18,直接检查 CBCentralManager 状态
guard let centralManager = centralManager else {
os_log("❌ CBCentralManager 未初始化", log: logger, type: .error)
return false
}
let currentState = centralManager.state
os_log("📊 iOS 18 蓝牙状态: %d (%{public}@)", log: logger, type: .info, currentState.rawValue, getBluetoothStateString(currentState))
switch currentState {
case .poweredOn:
return performScanWithPermission(timeout: timeout)
case .unauthorized:
os_log("❌ 蓝牙权限被拒绝", log: logger, type: .error)
showPermissionAlert()
return false
case .unknown:
os_log("⚠️ 蓝牙状态未知,等待状态更新", log: logger, type: .info)
// 设置监听器等待状态更新
waitForBluetoothState(timeout: timeout)
return true
default:
os_log("❌ 蓝牙不可用: %{public}@", log: logger, type: .error, getBluetoothStateString(currentState))
return false
}
}
private func startScanLegacy(timeout: TimeInterval) -> Bool {
// 检查并申请蓝牙权限
let authorization: CBManagerAuthorization = CBManager.authorization
os_log("📊 当前蓝牙权限状态: %d", log: logger, type: .info, authorization.rawValue)
switch authorization {
case .allowedAlways:
return performScanWithPermission(timeout: timeout)
case .denied, .restricted:
os_log("❌ 蓝牙权限被拒绝或受限", log: logger, type: .error)
showPermissionAlert()
return false
case .notDetermined:
// 权限未确定,需要主动触发蓝牙操作来显示权限弹窗
if centralManager == nil {
setupCentralManager()
}
// 等待CBCentralManager状态更新后,主动开始扫描来触发权限弹窗
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
guard let self = self else { return }
if self.centralManager.state == .poweredOn {
// 开始一个短暂的扫描来触发权限申请
self.centralManager.scanForPeripherals(withServices: nil, options: nil)
// 立即停止扫描
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.centralManager.stopScan()
}
} else if self.centralManager.state == .unauthorized {
// 权限被拒绝,显示设置提示
self.showPermissionAlert()
}
}
return true
@unknown default:
os_log("⚠️ 未知的蓝牙权限状态", log: logger, type: .info)
return false
}
}
private func waitForBluetoothState(timeout: TimeInterval) {
var checkCount = 0
let maxChecks = 20
let timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { [weak self] timer in
guard let self = self else {
timer.invalidate()
return
}
checkCount += 1
let currentState = self.centralManager?.state ?? .unknown
os_log("🔍 检查蓝牙状态 (%d/%d): %{public}@", log: self.logger, type: .info, checkCount, maxChecks, self.getBluetoothStateString(currentState))
switch currentState {
case .poweredOn:
timer.invalidate()
_ = self.performScanWithPermission(timeout: timeout)
case .unauthorized:
timer.invalidate()
self.showPermissionAlert()
case .poweredOff, .unsupported:
timer.invalidate()
os_log("❌ 蓝牙不可用", log: self.logger, type: .error)
default:
if checkCount >= maxChecks {
timer.invalidate()
os_log("⏰ 等待蓝牙状态超时", log: self.logger, type: .error)
}
}
}
}
private func forceTriggerPermissionRequest(timeout: TimeInterval) {
// 完全清理旧的 centralManager
centralManager?.delegate = nil
centralManager = nil
// 强制重新初始化,确保触发权限申请
let options: [String: Any] = [
CBCentralManagerOptionShowPowerAlertKey: true,
CBCentralManagerOptionRestoreIdentifierKey: "BleScanManager"
]
centralManager = CBCentralManager(delegate: self, queue: nil, options: options)
// 设置一个监听器来等待权限状态更新
waitForPermissionResponse(timeout: timeout)
}
private func waitForPermissionResponse(timeout: TimeInterval) {
// 设置一个定时器来检查权限状态变化
var checkCount = 0
let maxChecks = 20 // 最多检查20次,每次间隔0.5秒,总共10秒
let timer = Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { [weak self] timer in
guard let self = self else {
timer.invalidate()
return
}
checkCount += 1
let currentAuth = CBManager.authorization
os_log("🔍 检查权限状态 (%d/%d): %d", log: self.logger, type: .info, checkCount, maxChecks, currentAuth.rawValue)
switch currentAuth {
case .allowedAlways:
timer.invalidate()
os_log("✅ 蓝牙权限已获得,开始扫描", log: self.logger, type: .info)
_ = self.performScanWithPermission(timeout: timeout)
case .denied, .restricted:
timer.invalidate()
os_log("❌ 蓝牙权限被拒绝", log: self.logger, type: .error)
self.showPermissionAlert()
case .notDetermined:
if checkCount >= maxChecks {
timer.invalidate()
os_log("⏰ 等待权限响应超时", log: self.logger, type: .error)
self.showPermissionAlert()
}
// 继续等待
@unknown default:
timer.invalidate()
os_log("⚠️ 未知权限状态", log: self.logger, type: .error)
}
}
}
private func reinitializeCentralManager() {
// 清理旧的 centralManager
centralManager?.delegate = nil
centralManager = nil
// 重新初始化
setupCentralManager()
}
/// 检查蓝牙权限状态
private func checkBluetoothPermissionStatus() -> (hasPermission: Bool, needsRequest: Bool) {
// 检查权限状态
let authorization: CBManagerAuthorization
if #available(iOS 13.1, *) {
authorization = CBManager.authorization
} else if #available(iOS 13.0, *) {
if centralManager == nil {
setupCentralManager()
}
authorization = centralManager?.authorization ?? .notDetermined
} else {
// iOS 13以下没有权限概念
return (true, false)
}
os_log("📊 蓝牙权限状态: %d, CBCentralManager状态: %d", log: logger, type: .info, authorization.rawValue, centralManager?.state.rawValue ?? -1)
switch authorization {
case .allowedAlways:
return (true, false)
case .denied, .restricted:
return (false, false)
case .notDetermined:
return (false, true)
@unknown default:
return (false, true)
}
}
private func performScanWithPermission(timeout: TimeInterval) -> Bool {
// 首先检查权限状态
let permissionStatus = checkBluetoothPermissionStatus()
if !permissionStatus.hasPermission {
if permissionStatus.needsRequest {
os_log("🔐 需要申请蓝牙权限", log: logger, type: .info)
_ = requestBluetoothPermission()
return false
} else {
os_log("❌ 蓝牙权限被拒绝", log: logger, type: .error)
showPermissionAlert()
return false
}
}
// 权限已获得,检查蓝牙硬件状态
let currentState = centralManager.state
os_log("📊 蓝牙硬件状态: %d (%{public}@)", log: logger, type: .info, currentState.rawValue, getBluetoothStateString(currentState))
switch currentState {
case .poweredOn:
// 蓝牙已开启,可以扫描
break
case .unknown:
os_log("⚠️ 蓝牙状态未知,等待状态更新...", log: logger, type: .info)
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) { [weak self] in
_ = self?.performScanWithPermission(timeout: timeout)
}
return false
case .poweredOff:
// 区分是权限问题还是硬件关闭
if permissionStatus.hasPermission {
os_log("❌ 蓝牙硬件已关闭,请在设备设置中开启蓝牙", log: logger, type: .error)
} else {
os_log("❌ 可能是权限问题导致的蓝牙状态异常", log: logger, type: .error)
_ = requestBluetoothPermission()
}
return false
case .unauthorized:
os_log("❌ 应用未授权使用蓝牙", log: logger, type: .error)
showPermissionAlert()
return false
case .unsupported:
os_log("❌ 设备不支持蓝牙", log: logger, type: .error)
return false
default:
os_log("⚠️ 其他蓝牙状态: %d", log: logger, type: .error, currentState.rawValue)
return false
}
// 开始BLE扫描
centralManager.scanForPeripherals(withServices: nil, options: [
CBCentralManagerScanOptionAllowDuplicatesKey: true
])
isScanning = true
// 设置扫描超时
scanTimeout = Timer.scheduledTimer(withTimeInterval: timeout, repeats: false) { [weak self] _ in
self?.stopScan()
}
os_log("✅ 开始BLE扫描,超时时间: %.1f 秒", log: logger, type: .info, timeout)
return true
}
private func showPermissionAlert() {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
let window = windowScene.windows.first else {
os_log("❌ 无法获取当前窗口", log: logger, type: .error)
return
}
let alert = UIAlertController(
title: "需要蓝牙权限",
message: "请在设置中开启蓝牙权限以使用设备扫描功能",
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: "去设置", style: .default) { _ in
if let settingsUrl = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(settingsUrl)
}
})
alert.addAction(UIAlertAction(title: "取消", style: .cancel))
window.rootViewController?.present(alert, animated: true)
}
/// 停止扫描
public func stopScan() {
guard isScanning else { return }
os_log("🛑 停止 BLE 扫描", log: logger, type: .info)
centralManager.stopScan() // 直接使用,不需要可选绑定
isScanning = false
scanTimeout?.invalidate()
scanTimeout = nil
}
/// 获取已发现的设备列表
/// - Returns: 按最后发现时间排序的设备列表
public func getDiscoveredDevices() -> [BleDeviceInfo] {
return Array(discoveredDevices.values).sorted { $0.lastSeen > $1.lastSeen }
}
/// 清除设备列表
public func clearDeviceList() {
discoveredDevices.removeAll()
os_log("🗑️ 已清除设备列表", log: logger, type: .info)
}
/// 检查是否正在扫描
public func isScanningActive() -> Bool {
return isScanning
}
/// 获取蓝牙状态
public func getBluetoothState() -> CBManagerState {
return centralManager.state // 直接返回,不需要 ?? .unknown
}
// MARK: - 私有方法
private func addOrUpdateDevice(_ deviceInfo: BleDeviceInfo) {
let identifier = deviceInfo.identifier
discoveredDevices[identifier] = deviceInfo
os_log("📱 发现设备: %{public}@", log: logger, type: .debug, deviceInfo.name ?? "Unknown")
}
/// 强制触发蓝牙权限申请
public func requestBluetoothPermission() -> Bool {
os_log("🔐 强制触发蓝牙权限申请", log: logger, type: .info)
// 检查当前权限状态
let authorization: CBManagerAuthorization
if #available(iOS 13.1, *) {
authorization = CBManager.authorization
} else if #available(iOS 13.0, *) {
// 确保centralManager已初始化
if centralManager == nil {
setupCentralManager()
}
authorization = centralManager.authorization
} else {
// iOS 13以下没有权限概念,直接返回true
return true
}
os_log("📊 当前权限状态: %d", log: logger, type: .info, authorization.rawValue)
switch authorization {
case .notDetermined:
// 权限未确定,需要主动触发蓝牙操作来显示权限弹窗
if centralManager == nil {
os_log("📊 初始化蓝牙管理对象", log: logger, type: .info, "")
setupCentralManager()
}
// 等待CBCentralManager状态更新后,主动开始扫描来触发权限弹窗
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
guard let self = self else { return }
if self.centralManager.state == .poweredOn {
// 开始一个短暂的扫描来触发权限申请
self.centralManager.scanForPeripherals(withServices: nil, options: nil)
// 立即停止扫描
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.centralManager.stopScan()
}
} else if self.centralManager.state == .unauthorized {
// 权限被拒绝,显示设置提示
self.showPermissionAlert()
}
}
return true
case .allowedAlways:
os_log("✅ 权限已授予", log: logger, type: .info)
return true
case .denied, .restricted:
os_log("❌ 权限被拒绝,显示设置提示", log: logger, type: .error)
showPermissionAlert()
return false
@unknown default:
os_log("⚠️ 未知权限状态", log: logger, type: .info)
return false
}
}
}
// MARK: - CBCentralManagerDelegate
@available(iOS 13.0, *)
extension BleScanManager: CBCentralManagerDelegate {
public func centralManagerDidUpdateState(_ central: CBCentralManager) {
let stateString = getBluetoothStateString(central.state)
os_log("🔧 CBCentralManager 状态更新: %{public}@ (原始值: %d)", log: logger, type: .info, stateString, central.state.rawValue)
switch central.state {
case .poweredOn:
os_log("✅ 蓝牙已开启,可以开始扫描", log: logger, type: .info)
// 如果有待处理的扫描请求,现在可以执行
case .poweredOff:
os_log("❌ 蓝牙已关闭", log: logger, type: .error)
if isScanning {
stopScan()
}
case .unauthorized:
os_log("❌ 蓝牙权限被拒绝", log: logger, type: .error)
if isScanning {
stopScan()
}
case .unsupported:
os_log("❌ 设备不支持蓝牙", log: logger, type: .error)
if isScanning {
stopScan()
}
case .unknown:
os_log("⚠️ 蓝牙状态未知,等待进一步更新", log: logger, type: .error)
case .resetting:
os_log("⚠️ 蓝牙正在重置", log: logger, type: .error)
if isScanning {
stopScan()
}
@unknown default:
os_log("⚠️ 未知蓝牙状态: %d", log: logger, type: .error, central.state.rawValue)
}
}
public func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral,
advertisementData: [String : Any], rssi RSSI: NSNumber) {
let deviceInfo = BleDeviceInfo(
identifier: peripheral.identifier,
name: peripheral.name ?? advertisementData[CBAdvertisementDataLocalNameKey] as? String,
rssi: RSSI,
advertisementData: advertisementData,
discoveryMethod: .traditional,
lastSeen: Date()
)
addOrUpdateDevice(deviceInfo)
}
public func centralManager(_ central: CBCentralManager, willRestoreState dict: [String : Any]) {
os_log("🔄 恢复 CBCentralManager 状态", log: logger, type: .info)
// 恢复扫描状态
if dict[CBCentralManagerRestoredStateScanServicesKey] != nil {
isScanning = true
}
}
private func getBluetoothStateString(_ state: CBManagerState) -> String {
switch state {
case .unknown: return "未知状态"
case .resetting: return "重置中"
case .unsupported: return "设备不支持蓝牙"
case .unauthorized: return "应用未授权使用蓝牙"
case .poweredOff: return "蓝牙已关闭"
case .poweredOn: return "蓝牙已开启"
@unknown default: return "未知状态"
}
}
}

26
local_plugins/ble_service/ios/ble_service/Sources/ble_service/SwiftBleServicePlugin.swift

@ -230,7 +230,31 @@ public class SwiftBleServicePlugin: NSObject, FlutterPlugin {
os_log("当前环境不支持AccessorySetupKit", log: logger, type: .info)
result(false)
#endif
case "startScan":
let arguments = call.arguments as? [String: Any]
let devicename = (arguments?["devicename"] as? String) ?? ""
// 修复:支持所有iOS版本
if #available(iOS 18.0, *) {
// iOS 18+ 使用新的BleScanManager
os_log("iOS 18+ 使用 BleScanManager 进行扫描", log: logger, type: .info)
let succ = BleScanManager.shared.startScan(timeout: 15.0)
result(succ)
} else {
// iOS 17及以下使用传统BleService
os_log("iOS 17及以下使用传统 BleService 进行扫描", log: logger, type: .info)
BleService.shared.startScan()
result(true)
}
case "getDeviceInfo":
let arguments = call.arguments as? [String: Any]
let address = (arguments?["address"] as? String) ?? ""
let info = BleScanManager.shared.getDiscoveredDevices()
result(info)
case "requestBluetoothPermission":
BleScanManager.shared.requestBluetoothPermission();
result(true)
default:
result(FlutterMethodNotImplemented)
}
@ -394,4 +418,4 @@ class BleStatusStreamHandler: NSObject, FlutterStreamHandler {
plugin?.statusEventSink = nil
return nil
}
}
}

11
local_plugins/ble_service/lib/ble_service.dart

@ -435,4 +435,15 @@ class BleService {
return false;
}
}
/// 请求蓝牙权限(仅iOS)
Future<bool> requestBluetoothPermission() async {
try {
final result = await _methodChannel.invokeMethod<bool>('requestBluetoothPermission');
return result ?? false;
} catch (e) {
print('请求蓝牙权限失败: $e');
return false;
}
}
}

1
local_plugins/ota/ios/Classes/BleManager/JLBleManager.m

@ -218,6 +218,7 @@ NSString *FLT_BLE_RCSP_R = @"AE02"; //命令“读”通道
}
- (void)addPeripheral:(CBPeripheral*)peripheral Info:(NSString*)macStr {
kJLLog(JLLOG_DEBUG, @"BLE addPeripheral ---> Device %@", peripheral.name);
if (self.lastAddress && [macStr isEqualToString:self.lastAddress]) {
[self stopScanBLE];
[self connectBLE:peripheral];

Loading…
Cancel
Save