Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in
Toggle navigation
A
anchor_collect_flutter
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
hywang
anchor_collect_flutter
Commits
16cc47d9
Commit
16cc47d9
authored
Dec 20, 2023
by
hywang
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
1.蓝牙连接
parent
0611ffc4
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
205 additions
and
68 deletions
+205
-68
RfidPlugin.java
...main/java/com/phlx/anchor_collect_flutter/RfidPlugin.java
+5
-3
ble_service.dart
lib/controllers/ble_service.dart
+75
-37
main.dart
lib/main.dart
+2
-0
home_view.dart
lib/pages/home/home_view.dart
+5
-2
main_view.dart
lib/pages/main/main_view.dart
+2
-2
setting_logic.dart
lib/pages/setting/setting_logic.dart
+37
-2
setting_state.dart
lib/pages/setting/setting_state.dart
+3
-1
setting_view.dart
lib/pages/setting/setting_view.dart
+64
-19
rfid_plugin.dart
lib/rfid/rfid_plugin.dart
+12
-2
No files found.
android/app/src/main/java/com/phlx/anchor_collect_flutter/RfidPlugin.java
View file @
16cc47d9
...
...
@@ -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
);
}
}
lib/controllers/ble_service.dart
View file @
16cc47d9
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'
;
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
)
{
if
(
service
.
serviceId
.
toString
()
==
'000180'
)
{
_serviceId
=
service
.
serviceId
;
if
(
kDebugMode
)
{
print
(
'Discovered service
${service.serviceId}
'
);
}
for
(
final
characteristic
in
service
.
characteristics
)
{
print
(
'Discovered characteristic
${characteristic.characteristicId}
of service
${service.serviceId}
'
);
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:
serviceUui
d
,
characteristicId:
characteristicUui
d
,
serviceId:
_serviceI
d
,
characteristicId:
_writeCharacteristicI
d
,
);
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:
serviceUui
d
,
characteristicId:
characteristicUui
d
,
serviceId:
_serviceI
d
,
characteristicId:
_writeCharacteristicI
d
,
);
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
;
}
}
lib/main.dart
View file @
16cc47d9
...
...
@@ -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...'
);
}
...
...
lib/pages/home/home_view.dart
View file @
16cc47d9
...
...
@@ -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
),
},
),
],
),
...
...
lib/pages/main/main_view.dart
View file @
16cc47d9
...
...
@@ -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
(
...
...
lib/pages/setting/setting_logic.dart
View file @
16cc47d9
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
;
}
}
lib/pages/setting/setting_state.dart
View file @
16cc47d9
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
;
...
...
lib/pages/setting/setting_view.dart
View file @
16cc47d9
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,32 +21,74 @@ 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
(
'停止'
),
);
}),
),
// TextButton(
// onPressed: () => {},
// child: const Text(
// '停止',
// style: TextStyle(
// fontSize: 20,
// ),
// ),
// ),
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
,
);
},
),
],
),
],
),
...
...
lib/rfid/rfid_plugin.dart
View file @
16cc47d9
...
...
@@ -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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment