refactor(android): 重构Android端实现使用官方SDK替代反射调用

- 移除反射机制,直接集成CH934XLib.jar官方SDK
- 添加CH934XManager初始化逻辑并处理Application上下文兼容性
- 实现设备枚举、串口打开关闭等核心功能的直接调用
- 集成IDataCallback和IModemStatus回调处理
- 更新异常回调机制,支持原生层主动推送异常事件
- 优化设备连接状态管理和USB权限处理
- 为Dart模型类添加相等性比较和哈希码实现
- 更新示例应用UI以适配新的串口索引选择逻辑
This commit is contained in:
Developer
2026-07-06 16:48:14 +08:00
parent e0d1a1775d
commit 90de9121ff
4 changed files with 468 additions and 267 deletions
+57 -17
View File
@@ -43,7 +43,9 @@ class _Ch934xSerialExamplePageState extends State<Ch934xSerialExamplePage> {
List<Ch934xDeviceInfo> _devices = const <Ch934xDeviceInfo>[];
Ch934xDeviceInfo? _selectedDevice;
Ch934xSerialPortInfo? _selectedPort;
/// 当前选中设备的可用串口索引集合(由 SDK getSerialCount 决定)。
List<int> _availablePortIndices = const <int>[];
int? _selectedPortIndex;
StreamSubscription<Ch934xException>? _exceptionSubscription;
StreamSubscription<Uint8List>? _dataSubscription;
@@ -87,26 +89,58 @@ class _Ch934xSerialExamplePageState extends State<Ch934xSerialExamplePage> {
Future<void> _refreshDeviceList() async {
try {
final devices = await _plugin.getDeviceList();
if (!mounted) return;
setState(() {
_devices = devices;
// 清理已不再列表中的旧选项,避免 DropdownButton value 不在 items 中报错。
final selected = _selectedDevice;
if (selected != null && !devices.contains(selected)) {
_selectedDevice = null;
_availablePortIndices = const <int>[];
_selectedPortIndex = null;
} else if (selected != null) {
_availablePortIndices = _resolvePortIndices(selected);
final current = _selectedPortIndex;
if (current == null || !_availablePortIndices.contains(current)) {
_selectedPortIndex = _availablePortIndices.isNotEmpty
? _availablePortIndices.first
: null;
}
}
_status = '已扫描到 ${devices.length} 台 CH934X 设备';
});
} on Exception catch (e) {
if (!mounted) return;
setState(() => _status = '设备扫描失败: $e');
}
}
/// 把设备的串口描述转换为可用索引列表。
///
/// 优先使用 SDK 返回的 [Ch934xSerialPortInfo.portIndex],缺
/// 失时回退到 0..N-1,确保 UI 始终有可选项。
List<int> _resolvePortIndices(Ch934xDeviceInfo device) {
if (device.serialPorts.isNotEmpty) {
return device.serialPorts.map((p) => p.portIndex).toList()..sort();
}
if (device.interfaceCount > 0) {
return List<int>.generate(device.interfaceCount, (i) => i);
}
// 最坏情况下,允许打开串口 0;用户可通过业务调用切换。
return const <int>[0];
}
Future<void> _openPort() async {
final device = _selectedDevice;
final port = _selectedPort;
if (device == null || port == null) {
final portIndex = _selectedPortIndex;
if (device == null || portIndex == null) {
setState(() => _status = '请先选择设备与串口');
return;
}
final target = Ch934xPortTarget(
deviceId: device.deviceId,
interfaceNumber: device.interfaceCount > 0 ? 0 : 0,
serialPortIndex: port.portIndex,
interfaceNumber: 0,
serialPortIndex: portIndex,
);
final ok = await _plugin.openPort(target);
if (!ok) {
@@ -115,7 +149,7 @@ class _Ch934xSerialExamplePageState extends State<Ch934xSerialExamplePage> {
}
setState(() {
_portOpened = true;
_status = '串口 ${port.portIndex} 已打开';
_status = '串口 $portIndex 已打开';
});
_startReceiving();
}
@@ -215,27 +249,33 @@ class _Ch934xSerialExamplePageState extends State<Ch934xSerialExamplePage> {
onChanged: (device) {
setState(() {
_selectedDevice = device;
_selectedPort = device?.serialPorts.isNotEmpty == true
? device!.serialPorts.first
: null;
if (device == null) {
_availablePortIndices = const <int>[];
_selectedPortIndex = null;
} else {
_availablePortIndices = _resolvePortIndices(device);
_selectedPortIndex = _availablePortIndices.isNotEmpty
? _availablePortIndices.first
: null;
}
});
},
),
if (_selectedDevice?.serialPorts.isNotEmpty == true) ...[
if (_selectedDevice != null) ...[
const SizedBox(height: 8),
DropdownButton<Ch934xSerialPortInfo>(
DropdownButton<int>(
isExpanded: true,
value: _selectedPort,
value: _selectedPortIndex,
hint: const Text('选择串口'),
items: _selectedDevice!.serialPorts
items: _availablePortIndices
.map(
(p) => DropdownMenuItem<Ch934xSerialPortInfo>(
value: p,
child: Text('port #${p.portIndex}'),
(idx) => DropdownMenuItem<int>(
value: idx,
child: Text('port #$idx'),
),
)
.toList(),
onChanged: (p) => setState(() => _selectedPort = p),
onChanged: (idx) => setState(() => _selectedPortIndex = idx),
),
],
const SizedBox(height: 16),