fix: 移除 BLE 蓝牙依赖,消除 CoreLocation API 引用

- 注释 flutter_blue_plus 和 permission_handler 依赖
- 删除蓝牙设备页、BLE service、omron provider 等 6 个源文件
- 移除路由和设备设置入口
- 清理 2 个 BLE 相关测试文件
- 解决 Transporter 报 NSLocationWhenInUseUsageDescription 缺失

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
sccsbc
2026-07-22 17:19:39 +08:00
parent 39c32f842b
commit ad93e38b7e
13 changed files with 29 additions and 2647 deletions

View File

@@ -1,187 +0,0 @@
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'bp_reading.dart';
enum BleDeviceType { bloodPressure, glucose, weightScale, pulseOximeter }
enum SupportedMetric { bloodPressure, heartRate, glucose, weight, spo2 }
extension BleDeviceTypeX on BleDeviceType {
String get code => switch (this) {
BleDeviceType.bloodPressure => 'bloodPressure',
BleDeviceType.glucose => 'glucose',
BleDeviceType.weightScale => 'weightScale',
BleDeviceType.pulseOximeter => 'pulseOximeter',
};
String get label => switch (this) {
BleDeviceType.bloodPressure => '血压计',
BleDeviceType.glucose => '血糖仪',
BleDeviceType.weightScale => '体重秤',
BleDeviceType.pulseOximeter => '血氧仪',
};
String get serviceUuid => switch (this) {
BleDeviceType.bloodPressure => BleDeviceIdentifier.bloodPressureServiceUuid,
BleDeviceType.glucose => BleDeviceIdentifier.glucoseServiceUuid,
BleDeviceType.weightScale => BleDeviceIdentifier.weightScaleServiceUuid,
BleDeviceType.pulseOximeter => BleDeviceIdentifier.pulseOximeterServiceUuid,
};
List<SupportedMetric> get metrics => switch (this) {
BleDeviceType.bloodPressure => [
SupportedMetric.bloodPressure,
SupportedMetric.heartRate,
],
BleDeviceType.glucose => [SupportedMetric.glucose],
BleDeviceType.weightScale => [SupportedMetric.weight],
BleDeviceType.pulseOximeter => [
SupportedMetric.spo2,
SupportedMetric.heartRate,
],
};
IconData get icon => switch (this) {
BleDeviceType.bloodPressure => Icons.speed_rounded,
BleDeviceType.glucose => Icons.water_drop_rounded,
BleDeviceType.weightScale => Icons.monitor_weight_outlined,
BleDeviceType.pulseOximeter => Icons.air_rounded,
};
static BleDeviceType? fromCode(String? code) {
for (final type in BleDeviceType.values) {
if (type.code == code) return type;
}
return null;
}
}
extension SupportedMetricX on SupportedMetric {
String get code => switch (this) {
SupportedMetric.bloodPressure => 'BloodPressure',
SupportedMetric.heartRate => 'HeartRate',
SupportedMetric.glucose => 'Glucose',
SupportedMetric.weight => 'Weight',
SupportedMetric.spo2 => 'SpO2',
};
String get label => switch (this) {
SupportedMetric.bloodPressure => '血压',
SupportedMetric.heartRate => '心率',
SupportedMetric.glucose => '血糖',
SupportedMetric.weight => '体重',
SupportedMetric.spo2 => '血氧',
};
}
class BoundBleDevice {
final String id;
final String name;
final BleDeviceType type;
final String serviceUuid;
final DateTime? lastSyncAt;
const BoundBleDevice({
required this.id,
required this.name,
required this.type,
required this.serviceUuid,
this.lastSyncAt,
});
List<SupportedMetric> get metrics => type.metrics;
BoundBleDevice copyWith({
String? id,
String? name,
BleDeviceType? type,
String? serviceUuid,
DateTime? lastSyncAt,
}) {
return BoundBleDevice(
id: id ?? this.id,
name: name ?? this.name,
type: type ?? this.type,
serviceUuid: serviceUuid ?? this.serviceUuid,
lastSyncAt: lastSyncAt ?? this.lastSyncAt,
);
}
Map<String, dynamic> toJson() => {
'id': id,
'name': name,
'type': type.code,
'serviceUuid': serviceUuid,
'lastSyncAt': lastSyncAt?.toUtc().toIso8601String(),
};
static BoundBleDevice? fromJson(Map<String, dynamic> json) {
final type = BleDeviceTypeX.fromCode(json['type']?.toString());
final id = json['id']?.toString();
if (type == null || id == null || id.isEmpty) return null;
final lastSyncRaw = json['lastSyncAt']?.toString();
return BoundBleDevice(
id: id,
name: json['name']?.toString() ?? type.label,
type: type,
serviceUuid: json['serviceUuid']?.toString() ?? type.serviceUuid,
lastSyncAt: lastSyncRaw == null || lastSyncRaw.isEmpty
? null
: DateTime.tryParse(lastSyncRaw)?.toLocal(),
);
}
}
class BleDeviceIdentifier {
static const glucoseServiceUuid = '00001808-0000-1000-8000-00805F9B34FB';
static const bloodPressureServiceUuid =
'00001810-0000-1000-8000-00805F9B34FB';
static const weightScaleServiceUuid = '0000181D-0000-1000-8000-00805F9B34FB';
static const pulseOximeterServiceUuid =
'00001822-0000-1000-8000-00805F9B34FB';
static BleDeviceType? typeFromScan(ScanResult result) {
return typeFromUuidStrings(
result.advertisementData.serviceUuids.map((uuid) => uuid.str128),
);
}
static BleDeviceType? typeFromServices(List<BluetoothService> services) {
return typeFromUuidStrings(services.map((service) => service.uuid.str128));
}
static BleDeviceType? typeFromUuidStrings(Iterable<String> uuids) {
final normalized = uuids.map((uuid) => uuid.toUpperCase()).toSet();
if (normalized.contains(bloodPressureServiceUuid)) {
return BleDeviceType.bloodPressure;
}
if (normalized.contains(glucoseServiceUuid)) {
return BleDeviceType.glucose;
}
if (normalized.contains(weightScaleServiceUuid)) {
return BleDeviceType.weightScale;
}
if (normalized.contains(pulseOximeterServiceUuid)) {
return BleDeviceType.pulseOximeter;
}
return null;
}
static bool isSupportedScanResult(ScanResult result) {
return typeFromScan(result) != null;
}
}
sealed class HealthBleSyncResult {
const HealthBleSyncResult({required this.device});
final BoundBleDevice device;
}
class BloodPressureSyncResult extends HealthBleSyncResult {
const BloodPressureSyncResult({required super.device, required this.reading});
final BpReading reading;
}