Flutter蓝牙连接插件xunil_blue_connect的使用
Flutter蓝牙连接插件xunil_blue_connect的使用
此插件用于基本的蓝牙管理。目前该插件仅支持Android平台,并将在未来增加iOS支持。
当前版本支持经典蓝牙,但即将加入对低功耗蓝牙技术的支持。
功能列表
- ✅ 检查位置设置
- ✅ 申请位置权限
- ✅ 检查蓝牙可用性
- ✅ 设置蓝牙开启/关闭
- ✅ 建立/关闭连接
- ✅ 配对设备
- ✅ 写入数据
- ✅ 当断开连接时重新写入数据的状态
- ✅ 开始/停止搜索
- ✅ 发现设备
- ✅ 获取已配对设备的服务UUID
- ✅ 获取名称和UUID的简短描述
- ✅ 监听连接和配对状态
- ✅ 监听开始/停止搜索状态
- ✅ 支持Android 12
- ❌ iOS支持
- ❌ 蓝牙低功耗(BLE)支持
- ❌ 读取/重置
- ❌ 多连接
- ❌ 自动连接
- ❌ 重新连接
- ❌ 移除配对
导入库
import 'package:xunil_blue_connect/xunil_blue_connect.dart';
初始化
XunilBlueConnect blueConnect = XunilBlueConnect();
异步使用
检查蓝牙是否可用
await blueConnect.isBluetoothAvailable();
检查位置设置
await blueConnect.checkSettingLocation();
申请位置权限
await blueConnect.applyPermissionLocation();
设置蓝牙开启
await blueConnect.bluetoothSetEnable();
设置蓝牙关闭
await blueConnect.bluetoothSetDisable();
设备扫描
开始扫描设备
await blueConnect.startDiscovery();
监听扫描结果
blueConnect.listenDeviceResults.listen((device){
print(device);
});
或者使用 StreamBuilder
监听
StreamBuilder(
stream: blueConnect.listenDeviceResults,
builder: (context, snapshot) {
if (snapshot.hasData) {
var device = BluetoothDevice.fromJson(
jsonDecode(snapshot.data as String)
);
print(device);
}
},
),
扫描返回参数
name
-> 设备名称,由硬件提供(默认)aliasName
-> 用户指定的设备名称address
-> 设备的MAC地址(仅限Android)type
-> 设备类型isPaired
-> 设备的配对状态uuids
-> 设备的UUID(仅限已配对设备)
状态监听
监听发现、连接和配对状态
blueConnect.listenStatus.listen((status){
print(status);
});
或者使用 StreamBuilder
StreamBuilder(
stream: blueConnect.listenStatus,
builder: (context, snapshot) {
if (snapshot.hasData) {
var STATUS = jsonDecode(snapshot.data as String);
// 对于配对状态
switch (STATUS['STATUS_PAIRING']) {
case PairedStatus.PAIRED:
print(PairedStatus.PAIRED);
break;
case PairedStatus.PAIRING:
print(PairedStatus.PAIRING);
break;
case PairedStatus.PAIRED_NONE:
print(PairedStatus.PAIRED_NONE);
break;
case PairedStatus.UNKNOWN_PAIRED:
print(PairedStatus.UNKNOWN_PAIRED);
break;
}
// 对于连接状态
switch (STATUS['STATUS_CONNECTING']) {
case ConnectingStatus.STATE_CONNECTED:
print(STATUS['MAC_ADDRESS']);
print(ConnectingStatus.STATE_CONNECTED);
break;
case ConnectingStatus.STATE_DISCONNECTED:
print(STATUS['MAC_ADDRESS']);
print(ConnectingStatus.STATE_DISCONNECTED);
break;
}
// 对于发现状态
switch (STATUS['STATUS_DISCOVERY']) {
case DiscoveryStatus.STARTED:
print(DiscoveryStatus.STARTED);
break;
case DiscoveryStatus.FINISHED:
print(DiscoveryStatus.FINISHED);
break;
}
}
},
),
建立连接
连接设备
// 默认串口UUID
await blueConnect.connect(macAddress: device.macAddress);
// 或者指定任意UUID
await blueConnect.connect(macAddress: device.macAddress, uuidString: "00001200-0000-1000-8000-00805F9B34FB");
断开连接
// 如果不传参数,则断开最后一个连接
await blueConnect.disconnect();
// 或者指定要断开连接的设备MAC地址
await blueConnect.disconnect(macAddress: device.macAddress);
配对设备
配对设备
await blueConnect.pair(macAddress: device.macAddress);
获取所有已配对设备
await blueConnect.getPairedDevices();
写入数据
写入数据
await blueConnect.write(data: "Lorem ipsum dolor sit amet.", autoConnect: true);
对于蓝牙和位置权限
在 /android/app/src/main/AndroidManifest.xml
中添加以下权限:
蓝牙权限
<uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="30" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="30" />
// 对于Android 12
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
位置权限
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
示例代码
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:xunil_blue_connect/xunil_blue_connect.dart';
import 'package:xunil_blue_connect_example/device.dart';
import 'package:xunil_blue_connect/utils/status.dart';
import 'package:xunil_blue_connect_example/uuid.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
[@override](/user/override)
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: SafeArea(
child: Scaffold(
appBar: AppBar(
title: const Text('基本蓝牙管理'),
),
body: const Center(
child: MainBody(),
),
),
),
);
}
}
class MainBody extends StatefulWidget {
const MainBody({Key? key}) : super(key: key);
[@override](/user/override)
State<MainBody> createState() => _BodyState();
}
class _BodyState extends State<MainBody> {
bool _isBluetoothAvailable = false;
bool _isLocationAvailable = false;
bool _isLocationOn = false;
List<BluetoothDevice>? devices = [];
bool isLoading = false;
// 调用类
XunilBlueConnect blueConnect = XunilBlueConnect();
void bottomsheetForUUIDS(List<UUIDS>? uuids) {
showModalBottomSheet(
context: context,
isDismissible: true,
backgroundColor: Colors.white,
builder: (data) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.6,
child: ListView.builder(
itemCount: uuids?.length,
shrinkWrap: true,
itemBuilder: (context, index) {
return ListTile(
visualDensity: VisualDensity.adaptivePlatformDensity,
style: ListTileStyle.list,
title: Text(
uuids![index].name!.toString(),
style: const TextStyle(
fontSize: 12.0,
fontWeight: FontWeight.bold,
),
),
subtitle: Text(
uuids[index].shortDescription!.toString(),
style: const TextStyle(
fontSize: 12.0,
),
),
trailing: Text(
uuids[index].uuid!.toString(),
style: const TextStyle(
fontSize: 12.0,
),
),
);
},
),
);
},
);
}
[@override](/user/override)
Widget build(BuildContext context) {
return SizedBox(
height: MediaQuery.of(context).size.height * 0.85,
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text('蓝牙是 ${_isBluetoothAvailable ? '开启' : '关闭'}'),
Text(
'位置权限是 ${_isLocationAvailable ? '开启' : '关闭'}'),
Text('位置设置是 ${_isLocationOn ? '开启' : '关闭'}'),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
_isBluetoothAvailable ? Colors.lightGreen : Colors.blue),
),
onPressed: () async {
// 调用函数并异步执行
// 如果函数返回null,表示设备不支持蓝牙
var isBlue = await blueConnect.isBluetoothAvailable();
setState(() {
_isBluetoothAvailable = isBlue;
});
},
child: const Text('检查蓝牙'),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
await blueConnect.startDiscovery();
setState(() {
isLoading = true;
});
Timer(const Duration(seconds: 13), () async {
await blueConnect.stopDiscovery();
setState(() {
isLoading = false;
});
});
},
child: const Text('开始搜索'),
),
ElevatedButton(
onPressed: () async {
await blueConnect.stopDiscovery();
setState(() {
isLoading = false;
});
},
child: const Text('停止搜索'),
),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
// 调用函数并异步执行
// 打开蓝牙
await blueConnect.bluetoothSetEnable();
},
child: const Text('打开蓝牙'),
),
ElevatedButton(
onPressed: () async {
// 调用函数并异步执行
// 关闭蓝牙
await blueConnect.bluetoothSetDisable();
},
child: const Text('关闭蓝牙'),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
// 调用函数并异步执行
// 如果函数返回null,表示设备的位置权限关闭
var apply = await blueConnect.applyPermissionLocation();
setState(() {
_isLocationAvailable = apply;
});
},
child: const Text('申请位置权限'),
),
ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
_isLocationOn ? Colors.lightGreen : Colors.blue)),
onPressed: () async {
// 调用函数并异步执行
// 如果函数返回null,表示设备的位置关闭
var isLocation = await blueConnect.checkSettingLocation();
setState(() {
_isLocationOn = isLocation;
});
},
child: const Text('检查位置'),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
// 调用函数并异步执行
// 跳转到位置设置页面以启用位置服务
await blueConnect.goLocationForEnable();
},
child: const Text('跳转到位置设置以启用'),
)
],
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () async {
var devices = await blueConnect.getPairedDevices();
print(devices);
},
child: const Text('获取已配对设备'),
)
],
),
if (isLoading)
const LinearProgressIndicator(color: Colors.orangeAccent),
StreamBuilder(
stream: blueConnect.listenStatus,
builder: (context, snapshot) {
if (snapshot.hasData) {
var STATUS = jsonDecode(snapshot.data as String);
// 对于配对状态
switch (STATUS['STATUS_PAIRING']) {
case PairedStatus.PAIRED:
print(PairedStatus.PAIRED);
break;
case PairedStatus.PAIRING:
print(PairedStatus.PAIRING);
break;
case PairedStatus.PAIRED_NONE:
print(PairedStatus.PAIRED_NONE);
break;
case PairedStatus.UNKNOWN_PAIRED:
print(PairedStatus.UNKNOWN_PAIRED);
break;
}
// 对于连接状态
switch (STATUS['STATUS_CONNECTING']) {
case ConnectingStatus.STATE_CONNECTED:
print(STATUS['MAC_ADDRESS']);
print(ConnectingStatus.STATE_CONNECTED);
break;
case ConnectingStatus.STATE_DISCONNECTED:
print(STATUS['MAC_ADDRESS']);
print(ConnectingStatus.STATE_DISCONNECTED);
break;
}
// 对于发现状态
switch (STATUS['STATUS_DISCOVERY']) {
case DiscoveryStatus.STARTED:
print(DiscoveryStatus.STARTED);
break;
case DiscoveryStatus.FINISHED:
print(DiscoveryStatus.FINISHED);
break;
}
}
return const SizedBox();
},
),
StreamBuilder(
stream: blueConnect.listenDeviceResults,
builder: (context, snapshot) {
if (snapshot.hasData) {
var device = BluetoothDevice.fromJson(
jsonDecode(snapshot.data as String));
bool isEmpty = devices!
.where(
(localAddress) => localAddress.address == device.address,
)
.isEmpty;
if (isEmpty) {
devices?.add(device);
}
return devices!.isNotEmpty
? Expanded(
child: ListView.builder(
shrinkWrap: true,
itemCount: devices?.length,
padding: const EdgeInsets.all(10.0),
itemBuilder: (context, index) {
return ListTile(
onLongPress: () {
bottomsheetForUUIDS(devices![index].uuids);
},
onTap: () async {
await blueConnect.connect(
macAddress: devices![index].address!,
);
},
title: Text(devices![index].name! +
" (${devices![index].aliasName!})"),
subtitle: Text(devices![index].address!),
trailing: Row(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.end,
children: [
SizedBox(
width: 30.0,
child: ElevatedButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(
EdgeInsets.zero),
backgroundColor:
MaterialStateProperty.all(
devices![index].isPaired! == "PAIRED"
? Colors.lightGreen
: Colors.blue,
),
),
onPressed: () async {
await blueConnect.pair(
macAddress: devices![index].address!,
);
},
child: Text(
devices![index].isPaired! == "PAIRED"
? "C"
: "P",
),
),
),
const SizedBox(
width: 5.0,
),
if (devices![index].isPaired! == "PAIRED")
SizedBox(
width: 30.0,
child: ElevatedButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(
EdgeInsets.zero),
backgroundColor:
MaterialStateProperty.all(
Colors.redAccent[400]),
),
onPressed: () async {
await blueConnect.disconnect();
},
child: const Text("D"),
),
),
if (devices![index].isPaired! == "PAIRED")
const SizedBox(
width: 5.0,
),
if (devices![index].isPaired! == "PAIRED")
SizedBox(
width: 30.0,
child: ElevatedButton(
style: ButtonStyle(
padding: MaterialStateProperty.all(
EdgeInsets.zero),
backgroundColor:
MaterialStateProperty.all(
Colors.blueGrey),
),
onPressed: () async {
await blueConnect.write(
data:
"世界是这样的,你知道的",
autoConnect: true,
);
},
child: const Text("W"),
),
),
],
),
);
},
),
)
: const SizedBox();
}
return const SizedBox();
},
),
],
),
);
}
}
更多关于Flutter蓝牙连接插件xunil_blue_connect的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter蓝牙连接插件xunil_blue_connect的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
xunil_blue_connect
是一个用于在 Flutter 应用中实现蓝牙连接的插件。虽然它可能不是一个广泛使用的官方插件,但它的功能通常包括扫描设备、连接设备、读写数据等。以下是一个基本的使用指南,帮助你开始使用 xunil_blue_connect
插件。
1. 添加依赖
首先,你需要在 pubspec.yaml
文件中添加 xunil_blue_connect
插件的依赖。
dependencies:
flutter:
sdk: flutter
xunil_blue_connect: ^版本号
请将 ^版本号
替换为插件的实际版本号。
2. 获取插件实例
在你的 Dart 文件中,首先需要导入插件并获取插件实例。
import 'package:xunil_blue_connect/xunil_blue_connect.dart';
final xunilBlueConnect = XunilBlueConnect();
3. 检查蓝牙状态
在开始扫描设备之前,建议检查蓝牙是否已启用。
Future<void> checkBluetoothStatus() async {
bool isEnabled = await xunilBlueConnect.isBluetoothEnabled();
if (!isEnabled) {
// 请求用户启用蓝牙
await xunilBlueConnect.requestEnableBluetooth();
}
}
4. 扫描设备
你可以使用 startScan
方法来扫描附近的蓝牙设备。通常在扫描到设备后,你会得到一个设备列表。
void startScanning() {
xunilBlueConnect.startScan().listen((device) {
// 处理扫描到的设备
print('Found device: ${device.name}, ID: ${device.id}');
}, onError: (error) {
// 处理错误
print('Error occurred while scanning: $error');
});
}
5. 连接设备
找到设备后,你可以使用 connect
方法来连接设备。
Future<void> connectToDevice(String deviceId) async {
try {
await xunilBlueConnect.connect(deviceId);
print('Connected to device: $deviceId');
} catch (e) {
print('Failed to connect to device: $e');
}
}
6. 读写数据
一旦设备连接成功,你可以使用 write
和 read
方法来与设备进行数据交互。
Future<void> writeData(String deviceId, List<int> data) async {
try {
await xunilBlueConnect.write(deviceId, data);
print('Data written successfully');
} catch (e) {
print('Failed to write data: $e');
}
}
Future<void> readData(String deviceId) async {
try {
List<int> data = await xunilBlueConnect.read(deviceId);
print('Data read: $data');
} catch (e) {
print('Failed to read data: $e');
}
}
7. 断开连接
在不需要连接时,记得断开连接。
Future<void> disconnectDevice(String deviceId) async {
try {
await xunilBlueConnect.disconnect(deviceId);
print('Disconnected from device: $deviceId');
} catch (e) {
print('Failed to disconnect: $e');
}
}
8. 处理权限
在某些平台上,使用蓝牙可能需要特定的权限。确保你已经在 Android 和 iOS 上处理了所需的权限。
-
Android: 需要在
AndroidManifest.xml
中添加以下权限:<uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
-
iOS: 需要在
Info.plist
中添加以下权限描述:<key>NSBluetoothAlwaysUsageDescription</key> <string>We need Bluetooth access to connect to devices</string> <key>NSBluetoothPeripheralUsageDescription</key> <string>We need Bluetooth access to connect to devices</string>
9. 处理生命周期
在 Flutter 应用中,确保在页面销毁时停止扫描和断开连接。
[@override](/user/override)
void dispose() {
xunilBlueConnect.stopScan();
super.dispose();
}