Commit 16cc47d9 authored by hywang's avatar hywang

1.蓝牙连接

parent 0611ffc4
......@@ -108,8 +108,9 @@ public class RfidPlugin implements FlutterPlugin, MethodChannel.MethodCallHandle
@Override
public void getBluetoothData(byte[] bytes) {
Map<String, byte[]> result = new HashMap<>();
result.put("BluetoothData", bytes);
Map result = new HashMap();
result.put("key", "BluetoothData");
result.put("value", bytes);
_eventSink.success(result);
}
......@@ -119,7 +120,8 @@ public class RfidPlugin implements FlutterPlugin, MethodChannel.MethodCallHandle
String epc = TextUtil.byteToHexString(inventoryData.getEPC_Data(), inventoryData.getEpcLength()).substring(1);
String tid = TextUtil.byteToHexString(inventoryData.getData(), inventoryData.getDataLength());
result.put("InventoryData", epc + "," + tid);
result.put("key", "InventoryData");
result.put("value", epc + "," + tid);
_eventSink.success(result);
}
}
import 'dart:async';
import 'package:anchor_collect_flutter/utils/dialog_utils.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:get/get.dart';
......@@ -11,20 +12,29 @@ import '../models/cattle_resume_entity.dart';
import '../models/dict_entity.dart';
import '../models/user_model.dart';
class BleService extends GetxService {
typedef void DiscoveredCallback(args);
typedef void ConnectCallback(args);
class BleService extends GetxService {
static BleService get to => Get.find();
late DiscoveredCallback? discoveredCallback;
late ConnectCallback? connectCallback;
// 添加一个 StreamController
final _readController = StreamController<List<int>>();
Stream<List<int>> get readStream => _readController.stream;
late Uuid _serviceId;
late Uuid _writeCharacteristicId;
late Uuid _notifiCharacteristicId;
// 添加一个标志,用于控制读取循环是否应该继续
bool _shouldContinueReading = false;
static BleService get to => Get.find();
var isScanning = false.obs;
final ble = FlutterReactiveBle();
final deviceList = <DiscoveredDevice>[].obs;
//判断是否正在扫描
StreamSubscription<DiscoveredDevice>? scanSubscription;
......@@ -33,14 +43,18 @@ class BleService extends GetxService {
final selectedDevice = Rx<DiscoveredDevice?>(null);
//判断设备连接状态
final deviceStatus = ''.obs;
String deviceStatus = '';
// ignore: cancel_subscriptions
late StreamSubscription<ConnectionStateUpdate> streamSubscriptionConnection;
Future<BleService> init() async {
return this;
}
// 切换扫描状态
Future<void> toggleScan() async {
Future<void> toggleScan(DiscoveredCallback callback) async {
discoveredCallback = callback;
if (isScanning.value) {
await scanSubscription?.cancel();
isScanning.value = false;
......@@ -59,7 +73,6 @@ class BleService extends GetxService {
}
// 扫描开始时,设置 isScanning 为 true
isScanning.value = true;
deviceList.clear();
// 扫描设备
final scanStream = ble.scanForDevices(
......@@ -73,23 +86,29 @@ class BleService extends GetxService {
scanSubscription = scanStream.listen((device) {
// 如果设备名称不为空,且列表中没有该设备,则添加到列表中
if (device.name != null && device.name!.isNotEmpty) {
// 如果列表中没有该设备,则添加到列表中
if (!deviceList.any((element) => element.id == device.id)) {
deviceList.add(device);
deviceList.refresh(); // 手动触发 Obx 的更新
if (discoveredCallback != null) {
discoveredCallback!(device);
}
}
});
///扫描10秒
Future.delayed(const Duration(seconds: 15), () async {
await scanSubscription?.cancel();
isScanning.value = false;
DialogUtils.showToast('自动停止扫描');
});
}
// 连接设备
Future<void> connectToDevice(DiscoveredDevice device, BuildContext context) async {
Future<void> connectToDevice(DiscoveredDevice device, BuildContext context, ConnectCallback callback) async {
connectCallback = callback;
selectedDevice.value = device; // 设置当前选中的设备
await scanSubscription?.cancel(); // 在连接设备之前,停止扫描
isScanning.value = false; // 设置 isScanning 为 false
DialogUtils.showLoadingDialog('Connecting to ${device.name}');
DialogUtils.showLoadingDialog('正在连接到 ${device.name}');
// 显示正在连接的对话框
// showDialog(
// context: context,
......@@ -103,49 +122,71 @@ class BleService extends GetxService {
// );
// 连接设备
final connection = ble.connectToDevice(
var connection = ble.connectToDevice(
id: device.id,
connectionTimeout: const Duration(milliseconds: 10000),
servicesWithCharacteristicsToDiscover: {},
);
// 监听连接状态
connection.listen((update) async {
streamSubscriptionConnection = connection.listen((update) async {
// 如果连接状态为 connected,则显示连接成功的提示
if (update.connectionState == DeviceConnectionState.connected) {
// 发现服务和特性
final services = await ble.discoverServices(device.id);
for (final service in services) {
print('Discovered service ${service.serviceId}');
for (final characteristic in service.characteristics) {
print('Discovered characteristic ${characteristic.characteristicId} of service ${service.serviceId}');
if (service.serviceId.toString() == '000180') {
_serviceId = service.serviceId;
if (kDebugMode) {
print('Discovered service ${service.serviceId}');
}
for (final characteristic in service.characteristics) {
if(characteristic.isWritableWithoutResponse) {
_writeCharacteristicId = characteristic.characteristicId;
if (kDebugMode) {
print('WritableWithoutResponse characteristic ${characteristic.characteristicId} of service ${service.serviceId}');
}
}
if(characteristic.isNotifiable) {
_notifiCharacteristicId = characteristic.characteristicId;
if (kDebugMode) {
print('Notifiable characteristic ${characteristic.characteristicId} of service ${service.serviceId}');
}
}
}
}
}
// 设置最大传输单元
await ble.requestMtu(deviceId: device.id, mtu: 512);
await Future.delayed(Duration(seconds: 1)); // 添加延迟
deviceStatus.value = 'Connected'; // 更新设备的连接状态
Get.snackbar('Connected', 'Connected to ${device.name}');
await Future.delayed(const Duration(seconds: 1)); // 添加延迟
deviceStatus = 'Connected'; // 更新设备的连接状态
// Get.snackbar('Connected', 'Connected to ${device.name}');
// Navigator.of(context).pop();
if (connectCallback != null) {
connectCallback!(device);
}
// 关闭对话框
DialogUtils.dismissDialog();
} else if (update.connectionState == DeviceConnectionState.connecting) {
DialogUtils.showToast('设备连接中');
} else {
deviceStatus.value = 'Disconnected'; // 更新设备的连接状态
DialogUtils.dismissDialog();
DialogUtils.showToast('连接设备失败');
deviceStatus = 'Disconnected'; // 更新设备的连接状态
}
});
}
// 读取数据
Future<List<int>> readData(Uuid serviceUuid, Uuid characteristicUuid) async {
Future<List<int>> readData() async {
if (selectedDevice.value == null) {
throw Exception('No device connected');
}
final characteristic = QualifiedCharacteristic(
deviceId: selectedDevice.value!.id,
serviceId: serviceUuid,
characteristicId: characteristicUuid,
serviceId: _serviceId,
characteristicId: _writeCharacteristicId,
);
final result = await ble.readCharacteristic(characteristic);
......@@ -154,31 +195,31 @@ class BleService extends GetxService {
}
// 写入数据
Future<void> writeData(Uuid serviceUuid, Uuid characteristicUuid, List<int> data) async {
Future<void> writeData(List<int> data) async {
if (selectedDevice.value == null) {
throw Exception('No device connected');
}
final characteristic = QualifiedCharacteristic(
deviceId: selectedDevice.value!.id,
serviceId: serviceUuid,
characteristicId: characteristicUuid,
serviceId: _serviceId,
characteristicId: _writeCharacteristicId,
);
await ble.writeCharacteristicWithResponse(characteristic, value: data);
}
// 启动循环读取数据
Future<void> startReading(Uuid serviceUuid,Uuid characteristicUuid) async {
Future<void> startReading() async {
_shouldContinueReading = true;
while (_shouldContinueReading) {
// 读取数据
final data = await readData(serviceUuid,characteristicUuid);
final data = await readData();
// 将数据添加到 Stream 中
_readController.add(data);
// 等待一段时间,然后再次读取数据
await Future.delayed(Duration(seconds: 1));
await Future.delayed(const Duration(seconds: 1));
}
}
......@@ -186,13 +227,13 @@ class BleService extends GetxService {
void stopReading() {
_shouldContinueReading = false;
}
@override
void onClose() {
_readController.close();
super.onClose();
}
// 检查权限
Future<bool> requestBlePermissions() async {
var isLocationGranted = await Permission.locationWhenInUse.request();
......@@ -212,7 +253,4 @@ class BleService extends GetxService {
isBleConnectGranted == PermissionStatus.granted &&
isBleAdvertiseGranted == PermissionStatus.granted;
}
}
......@@ -10,6 +10,7 @@ import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'controllers/ble_service.dart';
import 'controllers/global_service.dart';
final mDialog = FlutterSmartDialog.init();
......@@ -41,6 +42,7 @@ Future<void> initServices() async {
///这里是你放get_storage、hive、shared_pref初始化的地方。
///或者moor连接,或者其他什么异步的东西。
await Get.putAsync(() => GlobalService().init());
await Get.putAsync(() => BleService().init());
print('All services started...');
}
......
......@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../congifs.dart';
import '../../routes/routes.dart';
import 'home_logic.dart';
class HomePage extends StatelessWidget {
......@@ -18,8 +19,10 @@ class HomePage extends StatelessWidget {
elevation: 10,
actions: [
InkWell(
child: Icon(Icons.settings),
onTap: () => {},
child: const Icon(Icons.settings),
onTap: () => {
Get.toNamed(AppRoute.SETTING),
},
),
],
),
......
......@@ -15,11 +15,11 @@ class MainPage extends StatelessWidget {
final state = Get.find<MainLogic>().state;
final syncLogic = Get.find<SyncLogic>();
final messageLogic = Get.find<MessageLogic>();
static List<Widget> _pageList = [
static final List<Widget> _pageList = [
HomePage(),
MessagePage(),
SyncPage(),
MinePage(),
const MinePage(),
];
final PageController _pageController = PageController(
......
import 'package:anchor_collect_flutter/controllers/ble_service.dart';
import 'package:anchor_collect_flutter/routes/routes.dart';
import 'package:anchor_collect_flutter/utils/dialog_utils.dart';
import 'package:flutter/cupertino.dart';
import 'package:get/get.dart';
import 'package:permission_handler/permission_handler.dart';
import 'setting_state.dart';
class SettingLogic extends GetxController {
final SettingState state = SettingState();
@override
......@@ -13,6 +16,39 @@ class SettingLogic extends GetxController {
requestBlePermissions();
}
refreshBle() {
if (BleService.to.isScanning.value) {
DialogUtils.showToast('停止扫描');
} else {
state.deviceList.clear();
DialogUtils.showToast('开始扫描');
}
BleService.to.toggleScan((device) => {
// 如果列表中没有该设备,则添加到列表中
if (!state.deviceList.any((element) => element.id == device.id))
{
state.deviceList.add(device),
state.deviceList.refresh(), // 手动触发 Obx 的更新
}
});
}
connectBle(BuildContext context, int index) {
if (BleService.to.deviceStatus == 'Connected') {
if (state.deviceList[index].id != BleService.to.selectedDevice.value!.id) {
BleService.to.streamSubscriptionConnection.cancel();
} else {
DialogUtils.showToast('请勿重复链接蓝牙设备');
return;
}
}
BleService.to.connectToDevice(state.deviceList[index], context, (args) {
DialogUtils.showToast('蓝牙设备连接成功');
// DialogUtils.dismissDialog();
Get.back();
});
}
// 检查权限
Future<bool> requestBlePermissions() async {
var isLocationGranted = await Permission.locationWhenInUse.request();
......@@ -32,5 +68,4 @@ class SettingLogic extends GetxController {
isBleConnectGranted == PermissionStatus.granted &&
isBleAdvertiseGranted == PermissionStatus.granted;
}
}
import 'package:flutter/material.dart';
import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
import 'package:get/get.dart';
class SettingState {
List<Widget> items = [];
final deviceList = <DiscoveredDevice>[].obs;
bool isBleOn = false;
......
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../controllers/ble_service.dart';
import 'setting_logic.dart';
class SettingPage extends StatelessWidget {
......@@ -9,7 +10,9 @@ class SettingPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
final logic = Get.find<SettingLogic>();
final state = Get.find<SettingLogic>().state;
final state = Get
.find<SettingLogic>()
.state;
return Scaffold(
appBar: AppBar(
......@@ -18,33 +21,75 @@ class SettingPage extends StatelessWidget {
),
body: Center(
child: Column(
mainAxisSize: MainAxisSize.max,
children: [
Obx(() {
return Expanded(
child: ListView.separated(
itemCount: state.deviceList.length,
itemBuilder: (BuildContext context, int index) {
return ListTile(
title: Text(state.deviceList[index].name),
subtitle: Text(state.deviceList[index].id),
onTap: ()=>{
logic.connectBle(context,index),
},
);
},
separatorBuilder: (BuildContext context, int index) {
return Container(
height: 1,
color: Colors.black12,
);
},
),
);
}),
SizedBox(
height: 1,
child: Container(
height: 1,
color: Colors.black54,
),
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
TextButton(
onPressed: () => {},
child: const Text('刷新'),
onPressed: () => {
logic.refreshBle(),
},
child: Obx(() {
return Text(
BleService.to.isScanning.value ? '停止' : '刷新',
style: TextStyle(
fontSize: 20,
),
);
}),
),
// TextButton(
// onPressed: () => {},
// child: const Text(
// '停止',
// style: TextStyle(
// fontSize: 20,
// ),
// ),
// ),
TextButton(
onPressed: () => {},
child: const Text('停止'),
),
TextButton(
onPressed: () => {},
child: const Text('清空'),
onPressed: () => {
state.deviceList.clear(),
},
child: const Text(
'清空',
style: TextStyle(
fontSize: 20,
),
),
),
],
),
ListView.separated(
itemCount: 3,
itemBuilder: (BuildContext context, int index) {},
separatorBuilder: (BuildContext context, int index) {
return Container(
height: 3,
color: Colors.black12,
);
},
),
],
),
),
......
......@@ -4,6 +4,8 @@ import 'package:anchor_collect_flutter/utils/empty_utils.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import '../controllers/ble_service.dart';
typedef void EventCallback(args, args2);
class RfidPlugin {
......@@ -18,11 +20,11 @@ class RfidPlugin {
String rfidTagTemp = '';
RfidPlugin() {
_streamSubscription = _eventChannel.receiveBroadcastStream().listen((event) {
_streamSubscription = _eventChannel.receiveBroadcastStream().listen((event) async {
final Map<dynamic, dynamic> map = event;
switch (map['key']) {
case 'BluetoothData':
//TODO 发送给蓝牙
await BleService.to.writeData(map['BluetoothData']);
break;
case 'InventoryData':
checkInventory(map['value'].toString());
......@@ -50,6 +52,14 @@ class RfidPlugin {
await _methodChannel.invokeMethod('stop_inventory');
}
Future<void> pushRemoteRFIDData() async {
List<int> readData = await BleService.to.readData();
Map params = {
"value":readData,
};
await _methodChannel.invokeMethod('push_data', params);
}
errorEventListen(Object obj) {
final Object e = obj;
if (kDebugMode) {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment