flutter_ble_central 0.2.1 copy "flutter_ble_central: ^0.2.1" to clipboard
flutter_ble_central: ^0.2.1 copied to clipboard

A Flutter package for scanning BLE data in central mode.

example/lib/main.dart

import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_ble_central/flutter_ble_central.dart';

void main() {
  runApp(const MyApp());
}

/// Example app demonstrating Flutter BLE Central functionality
class MyApp extends StatefulWidget {
  /// Creates the example app
  const MyApp({super.key});

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final _messengerKey = GlobalKey<ScaffoldMessengerState>();
  final _ble = FlutterBleCentral();

  final Map<String, ScanResult> _devices = {};
  StreamSubscription<ScanResult>? _scanResultSub;
  StreamSubscription<int>? _scanErrorSub;

  bool _isScanning = false;
  int _packetsFound = 0;

  @override
  void initState() {
    super.initState();
    _ble.enableTimingStats = true; // Only for dev purposes
    _listenToScanStreams();
  }

  @override
  Future<void> dispose() async {
    await _scanResultSub?.cancel();
    await _scanErrorSub?.cancel();
    super.dispose();
  }

  void _listenToScanStreams() {
    _scanErrorSub = _ble.onScanError?.listen((event) {
      final error = AndroidError.values[event];
      _showSnackBar('Scan error: $error (code $event)', isError: true);
    });

    _scanResultSub = _ble.onScanResult.listen((result) {
      _packetsFound++;

      final address = result.device?.address;
      if (address != null) {
        _devices[address] = result;
      }

      // Only rebuild when scanning to keep UI smooth
      if (_isScanning) setState(() {});
    });
  }

  void _showSnackBar(String message, {bool isError = false}) {
    _messengerKey.currentState
      ?..clearSnackBars()
      ..showSnackBar(
        SnackBar(
          content: Text(message),
          backgroundColor: isError ? Colors.red : Colors.green,
        ),
      );
  }

  Future<void> _checkPermission() async {
    final status = await _ble.hasPermission();
    _showSnackBar(
      'Permission status: ${status.name}',
      isError: status != BluetoothCentralState.granted,
    );
  }

  Future<void> _requestPermission() async {
    final status = await _ble.requestPermission();
    _showSnackBar(
      'Permission status: ${status.name}',
      isError: status != BluetoothCentralState.granted,
    );
  }

  Future<void> _startScan() async {
    final state = await _ble.start();

    switch (state) {
      case BluetoothCentralState.ready:
      case BluetoothCentralState.granted:
        setState(() {
          _isScanning = true;
          _devices.clear();
          _packetsFound = 0;
        });
      case BluetoothCentralState.denied:
        _showSnackBar('Bluetooth denied. You can ask again.', isError: true);
      case BluetoothCentralState.permanentlyDenied:
        _showSnackBar('Bluetooth permanently denied.', isError: true);
      case BluetoothCentralState.turnedOff:
        _showSnackBar('Bluetooth turned off.', isError: true);
      case BluetoothCentralState.unsupported:
        _showSnackBar('Bluetooth unsupported.', isError: true);
      case BluetoothCentralState.restricted:
        _showSnackBar('Bluetooth restricted.', isError: true);
      case BluetoothCentralState.limited:
        _showSnackBar('Bluetooth limited.', isError: true);
      case BluetoothCentralState.unknown:
        _showSnackBar('Bluetooth unavailable.', isError: true);
    }
  }

  Future<void> _stopScan() async {
    await _ble.stop();
    setState(() {
      _isScanning = false;
    });
  }

  Future<void> _startScanFor30s() async {
    await _startScan();
    await Future<void>.delayed(const Duration(seconds: 30));
    await _stopScan();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      scaffoldMessengerKey: _messengerKey,
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        appBar: AppBar(
          title: const Text('Flutter BLE Central Example'),
          actions: [
            IconButton(
              icon: const Icon(Icons.security),
              tooltip: 'Request permission',
              onPressed: _requestPermission,
            ),
            IconButton(
              icon: const Icon(Icons.help_outline),
              tooltip: 'Check permission',
              onPressed: _checkPermission,
            ),
            if (_isScanning)
              IconButton(
                icon: const Icon(Icons.pause_circle_filled),
                tooltip: 'Stop scanning',
                onPressed: _stopScan,
              )
            else
              IconButton(
                icon: const Icon(Icons.play_arrow),
                tooltip: 'Start scanning',
                onPressed: _startScan,
              ),
          ],
        ),
        body: Column(
          children: [
            const SizedBox(height: 8),
            Text(
              'Packets found: $_packetsFound\nDevices: ${_devices.length}',
              textAlign: TextAlign.center,
              style: const TextStyle(fontSize: 16),
            ),
            const SizedBox(height: 8),
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                ElevatedButton(
                  onPressed: _startScanFor30s,
                  child: const Text('30s Test'),
                ),
                ElevatedButton(
                  onPressed: _ble.openBluetoothSettings,
                  child: const Text('Bluetooth Settings'),
                ),
                ElevatedButton(
                  onPressed: _ble.openAppSettings,
                  child: const Text('App Settings'),
                ),
              ],
            ),
            const SizedBox(height: 8),
            Expanded(
              child: _devices.isEmpty
                  ? const Center(child: Text('No devices found yet'))
                  : ListView.separated(
                      padding: const EdgeInsets.all(8),
                      itemCount: _devices.length,
                      separatorBuilder: (_, __) => const Divider(height: 1),
                      itemBuilder: (context, index) {
                        final scanResult = _devices.values.elementAt(index);
                        final name =
                            scanResult.scanRecord?.deviceName ?? 'Unknown';
                        final address = scanResult.device?.address ?? 'N/A';
                        final rssi = scanResult.rssi ?? 0;

                        return Card(
                          child: ListTile(
                            leading: const Icon(Icons.bluetooth),
                            title: Text(name),
                            subtitle: Text('$address\nRSSI: $rssi'),
                            isThreeLine: true,
                          ),
                        );
                      },
                    ),
            ),
          ],
        ),
      ),
    );
  }
}
1
likes
140
points
203
downloads

Publisher

verified publishersteenbakker.dev

Weekly Downloads

A Flutter package for scanning BLE data in central mode.

Documentation

API reference

License

BSD-3-Clause (license)

Dependencies

flutter, json_annotation

More

Packages that depend on flutter_ble_central

Packages that implement flutter_ble_central