Flutter – BLE Scanning Page

2024/08/18 使用當前最新版 flutter_blue_plus (1.32.12) 寫的無IDE建議或警告的藍牙掃描頁面。

import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';

class BLEHomePage extends StatefulWidget {
  const BLEHomePage({super.key});

  @override
  BLEHomePageState createState() => BLEHomePageState();
}

class BLEHomePageState extends State<BLEHomePage> {
  BluetoothDevice? connectedDevice;
  List<ScanResult> devicesList = <ScanResult>[];
  BluetoothCharacteristic? characteristic;
  bool isScanning = false;
  StreamSubscription<List<ScanResult>>? scanSubscription;

  @override
  void initState() {
    super.initState();
    startScan();
  }

  void startScan() async {
    if (isScanning) return;

    setState(() {
      isScanning = true;
      devicesList = [];
    });

    // 啟動掃描,並訂閱掃描結果 (使用 scanResults)
    scanSubscription?.cancel();
    scanSubscription = FlutterBluePlus.scanResults.listen((results) {
      setState(() {
        devicesList = results;
      });

      for (ScanResult r in results) {
        if (r.device.platformName == "AI Glove" && connectedDevice == null) {
          connectToDevice(r.device);
          stopScan();
          break;
        }
      }
    }, onError: (error) {
      // 處理掃描錯誤
      if (kDebugMode) {
        print('Error during scan: $error');
      }
      // 在使用 context 之前檢查 mounted
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Scanning error: $error')),
        );
      }
    });

    // 啟動掃描 (使用 startScan, without timeout)
    await FlutterBluePlus.startScan();

    // 設定掃描超時 (使用 Timer)
    Timer(const Duration(seconds: 4), () {
      stopScan();
    });
  }

  void connectToDevice(BluetoothDevice device) async {
    try {
      await FlutterBluePlus.stopScan();
      await device.connect();
      setState(() {
        connectedDevice = device;
        isScanning = false;
      });

      List<BluetoothService> services = await device.discoverServices();
      for (BluetoothService service in services) {
        List<BluetoothCharacteristic> characteristics = service.characteristics;
        for (BluetoothCharacteristic c in characteristics) {
          if (c.properties.notify) {
            characteristic = c;
            await c.setNotifyValue(true);

            // Use lastValueStream instead of value
            c.lastValueStream.listen((value) {
             // Do somethings
            });
          }
        }
      }
    } catch (e) {
      // 處理連接錯誤
      if (kDebugMode) {
        print('Error connecting to device: $e');
      }
      // 在使用 context 之前檢查 mounted
      if (mounted) {
        ScaffoldMessenger.of(context).showSnackBar(
          SnackBar(content: Text('Connection error: $e')),
        );
      }
    }
  }

  void stopScan() {
    if (!isScanning) return;

    FlutterBluePlus.stopScan();
    scanSubscription?.cancel();
    setState(() {
      isScanning = false;
    });
  }

  @override
  void dispose() {
    FlutterBluePlus.stopScan();
    scanSubscription?.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BLE'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: isScanning ? null : startScan,
          ),
        ],
      ),
      body: Center(
        child: connectedDevice == null
            ? isScanning
                ? const CircularProgressIndicator() // 在掃描時顯示進度指示器
                : const Text('No devices found. Please try scanning again.')
            : Text('Connected to ${connectedDevice!.platformName}'),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: isScanning ? null : startScan,
        child: const Icon(Icons.refresh),
      ),
    );
  }
}

留言

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.