Flutter蓝牙BLE开发完全指南
我将为您提供一个完整的Flutter蓝牙BLE实现方案,包含UI设计、权限处理、设备扫描、连接通信等完整功能。
完整实现方案
1. 添加依赖与权限配置
pubspec.yaml
dependencies:
flutter:
sdk: flutter
flutter_blue_plus: ^1.10.0
permission_handler: ^10.4.0
provider: ^6.0.5
animated_text_kit: ^4.2.2
percent_indicator: ^4.2.3
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"/>
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<uses-permission android:name="android.permission.BLUETOOTH_SCAN"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
Info.plist (iOS)
<key>NSBluetoothAlwaysUsageDescription</key>
<string>需要蓝牙权限来连接设备</string>
<key>NSBluetoothPeripheralUsageDescription</key>
<string>需要蓝牙权限来连接设备</string>
<key>UIBackgroundModes</key>
<array>
<string>bluetooth-central</string>
<string>bluetooth-peripheral</string>
</array>
2. 蓝牙状态管理类
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:provider/provider.dart';
class BluetoothProvider extends ChangeNotifier {
List<ScanResult> scannedDevices = [];
BluetoothDevice? connectedDevice;
List<BluetoothService> services = [];
BluetoothCharacteristic? targetCharacteristic;
bool isScanning = false;
bool isConnecting = false;
bool isDiscovering = false;
String connectionStatus = "未连接";
List<List<int>> receivedData = [];
Future<void> startScan() async {
if (isScanning) return;
scannedDevices.clear();
isScanning = true;
notifyListeners();
try {
await FlutterBluePlus.startScan(
timeout: const Duration(seconds: 15),
androidUsesFineLocation: true,
);
FlutterBluePlus.scanResults.listen((results) {
scannedDevices = results;
notifyListeners();
});
} catch (e) {
print("扫描错误: $e");
isScanning = false;
notifyListeners();
}
}
Future<void> stopScan() async {
if (!isScanning) return;
await FlutterBluePlus.stopScan();
isScanning = false;
notifyListeners();
}
Future<void> connectToDevice(BluetoothDevice device) async {
if (isConnecting) return;
isConnecting = true;
connectionStatus = "连接中...";
notifyListeners();
try {
await device.connect(autoConnect: false);
connectedDevice = device;
connectionStatus = "已连接";
// 监听连接状态
device.connectionState.listen((state) {
if (state == BluetoothConnectionState.disconnected) {
connectedDevice = null;
services.clear();
targetCharacteristic = null;
connectionStatus = "已断开";
notifyListeners();
}
});
// 发现服务
isDiscovering = true;
notifyListeners();
services = await device.discoverServices();
isDiscovering = false;
notifyListeners();
} catch (e) {
print("连接错误: $e");
connectionStatus = "连接失败";
isConnecting = false;
notifyListeners();
}
isConnecting = false;
notifyListeners();
}
Future<void> disconnectDevice() async {
if (connectedDevice == null) return;
try {
await connectedDevice!.disconnect();
} catch (e) {
print("断开连接错误: $e");
} finally {
connectedDevice = null;
services.clear();
targetCharacteristic = null;
connectionStatus = "已断开";
notifyListeners();
}
}
Future<void> setCharacteristic(BluetoothCharacteristic characteristic) async {
targetCharacteristic = characteristic;
// 设置通知监听
await characteristic.setNotifyValue(true);
characteristic.value.listen((value) {
receivedData.add(value);
notifyListeners();
});
notifyListeners();
}
Future<void> writeData(List<int> data) async {
if (targetCharacteristic == null) return;
try {
await targetCharacteristic!.write(data);
} catch (e) {
print("写入错误: $e");
}
}
}
3. 主界面实现
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:provider/provider.dart';
import 'bluetooth_provider.dart';
void main() {
runApp(
ChangeNotifierProvider(
create: (context) => BluetoothProvider(),
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({
super.key});
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter蓝牙BLE',
theme: ThemeData(
primarySwatch: Colors.blue,
scaffoldBackgroundColor: Colors.grey[100],
appBarTheme: const AppBarTheme(
backgroundColor: Colors.deepPurple,
foregroundColor: Colors.white,
),
),
home: const BluetoothHomePage(),
);
}
}
class BluetoothHomePage extends StatefulWidget {
const BluetoothHomePage({
super.key});
State<BluetoothHomePage> createState() => _BluetoothHomePageState();
}
class _BluetoothHomePageState extends State<BluetoothHomePage> {
void initState() {
super.initState();
_checkPermissions();
}
Future<void> _checkPermissions() async {
// 检查并请求权限
final locationStatus = await Permission.location.request();
final bluetoothStatus = await Permission.bluetooth.request();
if (locationStatus.isDenied || bluetoothStatus.isDenied) {
showDialog(
context: context,
builder: (context) => AlertDialog(
title: const Text('权限不足'),
content: const Text('需要位置和蓝牙权限才能扫描设备'),
actions: [
TextButton(
onPressed: () => Navigator.pop(context),
child: const Text('确定'),
),
],
),
);
}
}
Widget build(BuildContext context) {
final bluetoothProvider = Provider.of<BluetoothProvider>(context);
return Scaffold(
appBar: AppBar(
title: const Text('Flutter蓝牙BLE'),
actions: [
IconButton(
icon: const Icon(Icons.bluetooth),
onPressed: () {
if (bluetoothProvider.connectedDevice != null) {
bluetoothProvider.disconnectDevice();
} else {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DeviceScanPage(),
),
);
}
},
),
],
),
body: _buildBody(bluetoothProvider),
);
}
Widget _buildBody(BluetoothProvider provider) {
if (provider.connectedDevice == null) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.bluetooth_disabled, size: 100, color: Colors.grey),
const SizedBox(height: 20),
const Text(
'未连接设备',
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
),
const SizedBox(height: 10),
ElevatedButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const DeviceScanPage(),
),
);
},
child: const Text('扫描设备'),
),
],
),
);
}
return DefaultTabController(
length: 3,
child: Column(
children: [
_buildDeviceHeader(provider),
const TabBar(
tabs: [
Tab(icon: Icon(Icons.devices), text: '设备信息'),
Tab(icon: Icon(Icons.settings), text: '服务'),
Tab(icon: Icon(Icons.message), text: '通信'),
],
),
Expanded(
child: TabBarView(
children: [
_buildDeviceInfo(provider),
_buildServices(provider),
_buildCommunication(provider),
],
),
),
],
),
);
}
Widget _buildDeviceHeader(BluetoothProvider provider) {
return Container(
padding: const EdgeInsets.all(16),
color: Colors.deepPurple[50],
child: Row(
children: [
const Icon(Icons.bluetooth_connected, color: Colors.deepPurple, size: 36),
const SizedBox(width: 16),
Expanded(
child: Column(
crossA