Flutter蓝牙BLE开发完全指南
我将为您提供一个完整的Flutter蓝牙BLE实现方案,包含UI设计、权限处理、设备扫描、连接通信等完整功能。
完整实现方案
1. 添加依赖与权限配置
pubspec.yaml
dependencies:flutter:sdk: flutterflutter_blue_plus: ^1.10.0permission_handler: ^10.4.0provider: ^6.0.5animated_text_kit: ^4.2.2percent_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