### Main Application Setup Source: https://pub.dev/packages/flutter_blue_plus/versions/1.9.0/example Initializes the Flutter application and requests necessary Bluetooth and location permissions on Android. It then starts the main app widget. ```dart // Copyright 2017, Paul DeMarco. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'widgets.dart'; void main() { if (Platform.isAndroid) { WidgetsFlutterBinding.ensureInitialized(); [ Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan ].request().then((status) { runApp(const FlutterBlueApp()); }); } else { runApp(const FlutterBlueApp()); } } class FlutterBlueApp extends StatelessWidget { const FlutterBlueApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder( stream: FlutterBluePlus.instance.adapterState, initialData: BluetoothAdapterState.unknown, builder: (c, snapshot) { final adapterState = snapshot.data; if (adapterState == BluetoothAdapterState.on) { return const FindDevicesScreen(); } return BluetoothOffScreen(adapterState: adapterState); }), ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.adapterState}) : super(key: key); final BluetoothAdapterState? adapterState; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${adapterState != null ? adapterState.toString().substring(15) : 'not available'}.', style: Theme.of(context) .primaryTextTheme .titleSmall ?.copyWith(color: Colors.white), ), ElevatedButton( child: const Text('TURN ON'), onPressed: Platform.isAndroid ? () => FlutterBluePlus.instance.turnOn() : null, ), ], ), ), ); } } class FindDevicesScreen extends StatelessWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Find Devices'), actions: [ ElevatedButton( child: const Text('TURN OFF'), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, ), onPressed: Platform.isAndroid ? () => FlutterBluePlus.instance.turnOff() : null, ), ], ), body: RefreshIndicator( onRefresh: () => FlutterBluePlus.instance.startScan( timeout: const Duration(seconds: 4), androidUsesFineLocation: false), // if set to true add permission ACCESS_FINE_LOCATION to AndroidManifest.xml child: SingleChildScrollView( child: Column( children: [ StreamBuilder>( stream: Stream.periodic(const Duration(seconds: 2)) .asyncMap((_) => FlutterBluePlus.instance.connectedDevices), initialData: const [], builder: (c, snapshot) => Column( children: snapshot.data! .map((d) => ListTile( title: Text(d.localName), subtitle: Text(d.remoteId.toString()), trailing: StreamBuilder( stream: d.connectionState, initialData: BluetoothConnectionState.disconnected, builder: (c, snapshot) { if (snapshot.data == BluetoothConnectionState.connected) { return ElevatedButton( child: const Text('OPEN'), onPressed: () => Navigator.of(context).push( MaterialPageRoute( ``` -------------------------------- ### Main Application Setup Source: https://pub.dev/packages/flutter_blue_plus/versions/1.7.1/example Initializes the Flutter application, requests necessary Bluetooth and location permissions on Android, and starts the main app widget. Handles Bluetooth state changes to display the appropriate UI. ```dart // Copyright 2017, Paul DeMarco. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'widgets.dart'; void main() { if (Platform.isAndroid) { WidgetsFlutterBinding.ensureInitialized(); [ Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan ].request().then((status) { runApp(const FlutterBlueApp()); }); } else { runApp(const FlutterBlueApp()); } } class FlutterBlueApp extends StatelessWidget { const FlutterBlueApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder( stream: FlutterBluePlus.instance.state, initialData: BluetoothState.unknown, builder: (c, snapshot) { final state = snapshot.data; if (state == BluetoothState.on) { return const FindDevicesScreen(); } return BluetoothOffScreen(state: state); }), ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.state}) : super(key: key); final BluetoothState? state; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.', style: Theme.of(context) .primaryTextTheme .subtitle2 ?.copyWith(color: Colors.white), ), ElevatedButton( child: const Text('TURN ON'), onPressed: Platform.isAndroid ? () => FlutterBluePlus.instance.turnOn() : null, ), ], ), ), ); } } class FindDevicesScreen extends StatelessWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Find Devices'), actions: [ ElevatedButton( child: const Text('TURN OFF'), style: ElevatedButton.styleFrom( primary: Colors.black, onPrimary: Colors.white, ), onPressed: Platform.isAndroid ? () => FlutterBluePlus.instance.turnOff() : null, ), ], ), body: RefreshIndicator( onRefresh: () => FlutterBluePlus.instance .startScan(timeout: const Duration(seconds: 4)), child: SingleChildScrollView( child: Column( children: [ StreamBuilder>( stream: Stream.periodic(const Duration(seconds: 2)) .asyncMap((_) => FlutterBluePlus.instance.connectedDevices), initialData: const [], builder: (c, snapshot) => Column( children: snapshot.data! .map((d) => ListTile( title: Text(d.name), subtitle: Text(d.id.toString()), trailing: StreamBuilder( stream: d.state, initialData: BluetoothDeviceState.disconnected, builder: (c, snapshot) { if (snapshot.data == BluetoothDeviceState.connected) { return ElevatedButton( child: const Text('OPEN'), onPressed: () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => DeviceScreen(device: d))), ); } return Text(snapshot.data.toString()); } ), )) .toList(), ), ) ], ), ), ), ); } } class DeviceScreen extends StatelessWidget { const DeviceScreen({Key? key, required this.device}) : super(key: key); final BluetoothDevice device; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(device.name), actions: [ StreamBuilder( stream: device.state, initialData: BluetoothDeviceState.connecting, builder: (c, snapshot) => ( snapshot.data == BluetoothDeviceState.connected ? { TextButton( child: const Text('NORMAL'), onPressed: () => null, // TODO: implement ), TextButton( child: const Text('FULL'), onPressed: () => null, // TODO: implement ) } : const []) .firstOrNull ?? const Text(''), ) ], ), body: ListView( children: [ StreamBuilder( stream: device.state, initialData: BluetoothDeviceState.connecting, builder: (c, snapshot) => ListBody( children: [ ListTile(title: const Text('Device is'), subtitle: Text(snapshot.data.toString()), leading: const Icon(Icons.bluetooth_audio),), ListTile(title: const Text('Name'), subtitle: Text(device.name), leading: const Icon(Icons.bookmark_border),), ListTile(title: const Text('ID'), subtitle: Text(device.id.toString()), leading: const Icon(Icons.info_outline),), ListTile(title: const Text('System MTU'), subtitle: Text('${device.mtu.oops}'), leading: const Icon(Icons.branding_watermark),), // TODO: Add connection state // StreamBuilder(stream: device.isDiscoveringServices, initialData: false, builder: (c, snapshot) => ListTile(title: Text('Discovering Services...'), subtitle: Text(snapshot.data.toString()),),), // DeviceProvider(device: device, child: const ServicesList()), ], ), ) ] ..addAll( [ // TODO: Add connection state // StreamBuilder(stream: device.isDiscoveringServices, initialData: false, builder: (c, snapshot) => ListTile(title: Text('Discovering Services...'), subtitle: Text(snapshot.data.toString()),),), // DeviceProvider(device: device, child: const ServicesList()), ] ), ), ); } // TODO: Add connection state // Widget _buildConnectButton(BuildContext context, BluetoothDeviceState state) { // // ... // } } // TODO: Add connection state // class ServicesList extends StatelessWidget { // // ... // } // TODO: Add connection state // class DeviceProvider extends InheritedWidget { // // ... // } ``` -------------------------------- ### Main Application Setup Source: https://pub.dev/packages/flutter_blue_plus/versions/1.14.10/example Initializes the Flutter application, requests necessary Bluetooth and location permissions on Android, and starts the main app widget. Handles platform-specific initialization. ```dart // Copyright 2023, Charles Weinberger & Paul DeMarco. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'widgets.dart'; final snackBarKeyA = GlobalKey(); final snackBarKeyB = GlobalKey(); final snackBarKeyC = GlobalKey(); final Map> isConnectingOrDisconnecting = {}; void main() { if (Platform.isAndroid) { WidgetsFlutterBinding.ensureInitialized(); [ Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan ].request().then((status) { runApp(const FlutterBlueApp()); }); } else { runApp(const FlutterBlueApp()); } } class BluetoothAdapterStateObserver extends NavigatorObserver { StreamSubscription? _btStateSubscription; @override void didPush(Route route, Route? previousRoute) { super.didPush(route, previousRoute); if (route.settings.name == '/deviceScreen') { // Start listening to Bluetooth state changes when a new route is pushed _btStateSubscription ??= FlutterBluePlus.adapterState.listen((state) { if (state != BluetoothAdapterState.on) { // Pop the current route if Bluetooth is off navigator?.pop(); } }); } } @override void didPop(Route route, Route? previousRoute) { super.didPop(route, previousRoute); // Cancel the subscription when the route is popped _btStateSubscription?.cancel(); _btStateSubscription = null; } } class FlutterBlueApp extends StatelessWidget { const FlutterBlueApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder( stream: FlutterBluePlus.adapterState, initialData: BluetoothAdapterState.unknown, builder: (c, snapshot) { final adapterState = snapshot.data; if (adapterState == BluetoothAdapterState.on) { return const FindDevicesScreen(); } else { FlutterBluePlus.stopScan(); return BluetoothOffScreen(adapterState: adapterState); } }), navigatorObservers: [BluetoothAdapterStateObserver()], ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.adapterState}) : super(key: key); final BluetoothAdapterState? adapterState; @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyA, child: Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${adapterState != null ? adapterState.toString().split(".").last : 'not available'}.', style: Theme.of(context).primaryTextTheme.titleSmall?.copyWith(color: Colors.white), ), if (Platform.isAndroid) ElevatedButton( child: const Text('TURN ON'), onPressed: () async { try { if (Platform.isAndroid) { await FlutterBluePlus.turnOn(); } } catch (e) { final snackBar = snackBarFail(prettyException("Error Turning On:", e)); snackBarKeyA.currentState?.removeCurrentSnackBar(); snackBarKeyA.currentState?.showSnackBar(snackBar); } }, ), ], ), ), ), ); } } class FindDevicesScreen extends StatefulWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override State createState() => _FindDevicesScreenState(); } class _FindDevicesScreenState extends State { @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyB, child: Scaffold( appBar: AppBar( ``` -------------------------------- ### Main Application Setup and Permissions Source: https://pub.dev/packages/flutter_blue_plus/versions/1.7.4/example Initializes the Flutter application, requests necessary Bluetooth and location permissions on Android, and starts the main app widget. On other platforms, it directly runs the app. ```dart // Copyright 2017, Paul DeMarco. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'widgets.dart'; void main() { if (Platform.isAndroid) { WidgetsFlutterBinding.ensureInitialized(); [ Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan ].request().then((status) { runApp(const FlutterBlueApp()); }); } else { runApp(const FlutterBlueApp()); } } class FlutterBlueApp extends StatelessWidget { const FlutterBlueApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder( stream: FlutterBluePlus.instance.state, initialData: BluetoothState.unknown, builder: (c, snapshot) { final state = snapshot.data; if (state == BluetoothState.on) { return const FindDevicesScreen(); } return BluetoothOffScreen(state: state); }), ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.state}) : super(key: key); final BluetoothState? state; @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${state != null ? state.toString().substring(15) : 'not available'}.', style: Theme.of(context) .primaryTextTheme .subtitle2 ?.copyWith(color: Colors.white), ), ElevatedButton( child: const Text('TURN ON'), onPressed: Platform.isAndroid ? () => FlutterBluePlus.instance.turnOn() : null, ), ], ), ), ); } } class FindDevicesScreen extends StatelessWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Find Devices'), actions: [ ElevatedButton( child: const Text('TURN OFF'), style: ElevatedButton.styleFrom( primary: Colors.black, onPrimary: Colors.white, ), onPressed: Platform.isAndroid ? () => FlutterBluePlus.instance.turnOff() : null, ), ], ), body: RefreshIndicator( onRefresh: () => FlutterBluePlus.instance .startScan(timeout: const Duration(seconds: 4)), child: SingleChildScrollView( child: Column( children: [ StreamBuilder>( stream: Stream.periodic(const Duration(seconds: 2)) .asyncMap((_) => FlutterBluePlus.instance.connectedDevices), initialData: const [], builder: (c, snapshot) => Column( children: snapshot.data! .map((d) => ListTile( title: Text(d.name), subtitle: Text(d.id.toString()), trailing: StreamBuilder( stream: d.state, initialData: BluetoothDeviceState.disconnected, builder: (c, snapshot) { if (snapshot.data == BluetoothDeviceState.connected) { return ElevatedButton( child: const Text('OPEN'), onPressed: () => Navigator.of(context).push( MaterialPageRoute( builder: (context) => DeviceScreen(device: d))), ); } return Text(snapshot.data.toString()); } ), )) .toList(), ), ) ], ), ), ), ); } } class DeviceScreen extends StatelessWidget { const DeviceScreen({Key? key, required this.device}) : super(key: key); final BluetoothDevice device; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(device.name), actions: [ StreamBuilder( stream: device.state, initialData: BluetoothDeviceState.connecting, builder: (c, snapshot) => (snapshot.data == BluetoothDeviceState.connected) ? TextButton( child: const Text( 'DISCONNECT', style: TextStyle(color: Colors.white), ), onPressed: () async { await device.disconnect(); Navigator.of(context).pop(); }, ) : Text(''), ) ], ), body: ListView( children: [ StreamBuilder( stream: device.state, initialData: BluetoothDeviceState.connecting, builder: (c, snapshot) => ListTile( leading: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(snapshot.data == BluetoothDeviceState.connected ? Icons.bluetooth_connected : Icons.bluetooth_ \\_off), if (snapshot.data == BluetoothDeviceState.connected) StreamBuilder( stream: device.mtu, initialData: 0, builder: (c, snapshot) => Text(snapshot.data.toString() + ' mtu'), ) ], ), title: Text( 'Device is ${snapshot.data.toString().split('.')[1]} with RSSI: ${device.rssi}' ), ), ), StreamBuilder>( stream: device.discoverServices(), builder: (c, snapshot) { returnЕЛ Column( children: snapshot.data?.map((s) => ServiceTile(service: s)).toList() ?? [], ); }, ), ].where((w) => w != null).toList(), ), ); } } class ServiceTile extends StatelessWidget { const ServiceTile({Key? key, required this.service}) : super(key: key); final BluetoothService service; @override Widget build(BuildContext context) { return Column(children: [ ListTile( title: Text('SERVICE'), subtitle: Text(service.uuid.toString().shortFormat), ), if (service.characteristics.isNotEmpty) ...service.characteristics.map((c) => CharacteristicTile(characteristic: c)).toList() ?? [], ]); } } class CharacteristicTile extends StatelessWidget { const CharacteristicTile({Key? key, required this.characteristic}) : super(key: key); final BluetoothCharacteristic characteristic; @override Widget build(BuildContext context) { return ListTile( title: Text(characteristic.uuid.toString().shortFormat), subtitle: Text(characteristic.properties.toString()), trailing: StreamBuilder>( stream: characteristic.value, initialData: [], builder: (c, snapshot) => Row( mainAxisSize: MainAxisSize.min, children: [ Text(snapshot.data.toString()), if (characteristic.properties.read) TextButton( child: const Text('READ'), onPressed: () async { await characteristic.read(); }), if (characteristic.properties.write) TextButton( child: const Text('WRITE'), onPressed: () async { await characteristic.write([0x10, 0x11, 0x12], withoutResponse: false); }), if (characteristic.properties.notify) TextButton( child: const Text('NOTIFY'), onPressed: () async { await characteristic.setNotifyValue(true); }), ].where((w) => w != null).toList(), ), ), ); } } extension on String { String shortFormat() { return replaceRange(8, null, '…'); } } ``` -------------------------------- ### Start Bluetooth Scan Source: https://pub.dev/packages/flutter_blue_plus/versions/1.11.6/example This example demonstrates how to initiate a Bluetooth scan with a specified timeout and configuration for Android. It checks if a scan is already in progress. ```dart onRefresh: () { if (FlutterBluePlus.isScanningNow == false) { return FlutterBluePlus.startScan(timeout: const Duration(seconds: 15), androidUsesFineLocation: false); } return Future.value(); }, ``` -------------------------------- ### Main Application Setup Source: https://pub.dev/packages/flutter_blue_plus/versions/1.11.1/example Sets up the main Flutter application, handling Bluetooth permissions on Android and initializing the app based on the Bluetooth adapter state. ```dart // Copyright 2017, Paul DeMarco. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'widgets.dart'; final snackBarKeyA = GlobalKey(); final snackBarKeyB = GlobalKey(); final snackBarKeyC = GlobalKey(); void main() { if (Platform.isAndroid) { WidgetsFlutterBinding.ensureInitialized(); [ Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan ].request().then((status) { runApp(const FlutterBlueApp()); }); } else { runApp(const FlutterBlueApp()); } } class FlutterBlueApp extends StatelessWidget { const FlutterBlueApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder( stream: FlutterBluePlus.adapterState, initialData: BluetoothAdapterState.unknown, builder: (c, snapshot) { final adapterState = snapshot.data; if (adapterState == BluetoothAdapterState.on) { return const FindDevicesScreen(); } return BluetoothOffScreen(adapterState: adapterState); }), ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.adapterState}) : super(key: key); final BluetoothAdapterState? adapterState; @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyA, child: Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${adapterState != null ? adapterState.toString().split(".").last : 'not available'}.', style: Theme.of(context).primaryTextTheme.titleSmall?.copyWith(color: Colors.white), ), ElevatedButton( child: const Text('TURN ON'), onPressed: () async { try { if (Platform.isAndroid) { await FlutterBluePlus.turnOn(); } } catch (e) { final snackBar = SnackBar(content: Text(prettyException("Error Turning On:", e))); snackBarKeyA.currentState?.showSnackBar(snackBar); } }, ), ], ), ), ), ); } } class FindDevicesScreen extends StatelessWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyB, child: Scaffold( appBar: AppBar( title: const Text('Find Devices'), actions: [ if (Platform.isAndroid) ElevatedButton( child: const Text('TURN OFF'), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, ), onPressed: () async { try { if (Platform.isAndroid) { await FlutterBluePlus.turnOff(); } } catch (e) { final snackBar = SnackBar(content: Text(prettyException("Error Turning On:", e))); snackBarKeyB.currentState?.showSnackBar(snackBar); } }, ), ], ), body: RefreshIndicator( onRefresh: () => FlutterBluePlus.startScan( timeout: const Duration(seconds: 15), androidUsesFineLocation: false), child: SingleChildScrollView( child: Column( children: [ StreamBuilder>( stream: Stream.periodic(const Duration(seconds: 2)) .asyncMap((_) => FlutterBluePlus.connectedSystemDevices), initialData: const [], ``` -------------------------------- ### Main Application Setup Source: https://pub.dev/packages/flutter_blue_plus/versions/1.11.8/example Sets up the main Flutter application, handling platform-specific Bluetooth permissions on Android and initializing the app. It also includes logic to display the appropriate screen based on the Bluetooth adapter's state. ```dart // Copyright 2017, Paul DeMarco. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'widgets.dart'; final snackBarKeyA = GlobalKey(); final snackBarKeyB = GlobalKey(); final snackBarKeyC = GlobalKey(); void main() { if (Platform.isAndroid) { WidgetsFlutterBinding.ensureInitialized(); [ Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan ].request().then((status) { runApp(const FlutterBlueApp()); }); } else { runApp(const FlutterBlueApp()); } } class BluetoothAdapterStateObserver extends NavigatorObserver { StreamSubscription? _btStateSubscription; @override void didPush(Route route, Route? previousRoute) { super.didPush(route, previousRoute); if (route.settings.name == '/deviceScreen') { // Start listening to Bluetooth state changes when a new route is pushed _btStateSubscription ??= FlutterBluePlus.adapterState.listen((state) { if (state != BluetoothAdapterState.on) { // Pop the current route if Bluetooth is off navigator?.pop(); } }); } } @override void didPop(Route route, Route? previousRoute) { super.didPop(route, previousRoute); // Cancel the subscription when the route is popped _btStateSubscription?.cancel(); _btStateSubscription = null; } } class FlutterBlueApp extends StatelessWidget { const FlutterBlueApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder( stream: FlutterBluePlus.adapterState, initialData: BluetoothAdapterState.unknown, builder: (c, snapshot) { final adapterState = snapshot.data; if (adapterState == BluetoothAdapterState.on) { return const FindDevicesScreen(); } else { FlutterBluePlus.stopScan(); return BluetoothOffScreen(adapterState: adapterState); } }), navigatorObservers: [BluetoothAdapterStateObserver()], ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.adapterState}) : super(key: key); final BluetoothAdapterState? adapterState; @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyA, child: Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${adapterState != null ? adapterState.toString().split(".").last : 'not available'}.', style: Theme.of(context).primaryTextTheme.titleSmall?.copyWith(color: Colors.white), ), if (Platform.isAndroid) ElevatedButton( child: const Text('TURN ON'), onPressed: () async { try { if (Platform.isAndroid) { await FlutterBluePlus.turnOn(); } } catch (e) { final snackBar = SnackBar(content: Text(prettyException("Error Turning On:", e))); snackBarKeyA.currentState?.showSnackBar(snackBar); } }, ), ], ), ), ), ); } } class FindDevicesScreen extends StatelessWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyB, child: Scaffold( appBar: AppBar( title: const Text('Find Devices'), actions: [ if (Platform.isAndroid) ElevatedButton( child: const Text('TURN OFF'), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, ``` -------------------------------- ### Find Devices Screen State Source: https://pub.dev/packages/flutter_blue_plus/versions/1.16.1/example Represents the stateful widget for the screen that finds Bluetooth devices. This is the starting point for device discovery in the example app. ```dart class FindDevicesScreen extends StatefulWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override State createState() => _FindDevicesScreenState(); } class _FindDevicesScreenState extends State { ``` -------------------------------- ### Main Application Setup and Permission Handling Source: https://pub.dev/packages/flutter_blue_plus/versions/1.12.10/example Initializes the Flutter application, requests necessary Bluetooth and location permissions on Android, and sets up the main app widget. Handles Bluetooth adapter state to display appropriate UI. ```dart // Copyright 2017, Paul DeMarco. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'widgets.dart'; final snackBarKeyA = GlobalKey(); final snackBarKeyB = GlobalKey(); final snackBarKeyC = GlobalKey(); void main() { if (Platform.isAndroid) { WidgetsFlutterBinding.ensureInitialized(); [ Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan ].request().then((status) { runApp(const FlutterBlueApp()); }); } else { runApp(const FlutterBlueApp()); } } class BluetoothAdapterStateObserver extends NavigatorObserver { StreamSubscription? _btStateSubscription; @override void didPush(Route route, Route? previousRoute) { super.didPush(route, previousRoute); if (route.settings.name == '/deviceScreen') { // Start listening to Bluetooth state changes when a new route is pushed _btStateSubscription ??= FlutterBluePlus.adapterState.listen((state) { if (state != BluetoothAdapterState.on) { // Pop the current route if Bluetooth is off navigator?.pop(); } }); } } @override void didPop(Route route, Route? previousRoute) { super.didPop(route, previousRoute); // Cancel the subscription when the route is popped _btStateSubscription?.cancel(); _btStateSubscription = null; } } class FlutterBlueApp extends StatelessWidget { const FlutterBlueApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder( stream: FlutterBluePlus.adapterState, initialData: BluetoothAdapterState.unknown, builder: (c, snapshot) { final adapterState = snapshot.data; if (adapterState == BluetoothAdapterState.on) { return const FindDevicesScreen(); } else { FlutterBluePlus.stopScan(); return BluetoothOffScreen(adapterState: adapterState); } }), navigatorObservers: [BluetoothAdapterStateObserver()], ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.adapterState}) : super(key: key); final BluetoothAdapterState? adapterState; @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyA, child: Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${adapterState != null ? adapterState.toString().split(".").last : 'not available'}.', style: Theme.of(context).primaryTextTheme.titleSmall?.copyWith(color: Colors.white), ), if (Platform.isAndroid) ElevatedButton( child: const Text('TURN ON'), onPressed: () async { try { if (Platform.isAndroid) { await FlutterBluePlus.turnOn(); } } catch (e) { final snackBar = SnackBar(content: Text(prettyException("Error Turning On:", e))); snackBarKeyA.currentState?.showSnackBar(snackBar); } }, ), ], ), ), ), ); } } class FindDevicesScreen extends StatelessWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyB, child: Scaffold( appBar: AppBar( title: const Text('Find Devices'), ), body: RefreshIndicator( onRefresh: () { if (FlutterBluePlus.isScanningNow == false) { return FlutterBluePlus.startScan(timeout: const Duration(seconds: 15), androidUsesFineLocation: false); } return Future.value(); ``` -------------------------------- ### Main Application Setup and Permissions Source: https://pub.dev/packages/flutter_blue_plus/versions/1.12.6/example Initializes the Flutter application, requests necessary Bluetooth and location permissions on Android, and sets up the main app structure with adapter state observation. ```dart // Copyright 2017, Paul DeMarco. // All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. import 'dart:async'; import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'widgets.dart'; final snackBarKeyA = GlobalKey(); final snackBarKeyB = GlobalKey(); final snackBarKeyC = GlobalKey(); void main() { if (Platform.isAndroid) { WidgetsFlutterBinding.ensureInitialized(); [ Permission.location, Permission.storage, Permission.bluetooth, Permission.bluetoothConnect, Permission.bluetoothScan ].request().then((status) { runApp(const FlutterBlueApp()); }); } else { runApp(const FlutterBlueApp()); } } class BluetoothAdapterStateObserver extends NavigatorObserver { StreamSubscription? _btStateSubscription; @override void didPush(Route route, Route? previousRoute) { super.didPush(route, previousRoute); if (route.settings.name == '/deviceScreen') { // Start listening to Bluetooth state changes when a new route is pushed _btStateSubscription ??= FlutterBluePlus.adapterState.listen((state) { if (state != BluetoothAdapterState.on) { // Pop the current route if Bluetooth is off navigator?.pop(); } }); } } @override void didPop(Route route, Route? previousRoute) { super.didPop(route, previousRoute); // Cancel the subscription when the route is popped _btStateSubscription?.cancel(); _btStateSubscription = null; } } class FlutterBlueApp extends StatelessWidget { const FlutterBlueApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( color: Colors.lightBlue, home: StreamBuilder( stream: FlutterBluePlus.adapterState, initialData: BluetoothAdapterState.unknown, builder: (c, snapshot) { final adapterState = snapshot.data; if (adapterState == BluetoothAdapterState.on) { return const FindDevicesScreen(); } else { FlutterBluePlus.stopScan(); return BluetoothOffScreen(adapterState: adapterState); } }), navigatorObservers: [BluetoothAdapterStateObserver()], ); } } class BluetoothOffScreen extends StatelessWidget { const BluetoothOffScreen({Key? key, this.adapterState}) : super(key: key); final BluetoothAdapterState? adapterState; @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyA, child: Scaffold( backgroundColor: Colors.lightBlue, body: Center( child: Column( mainAxisSize: MainAxisSize.min, children: [ const Icon( Icons.bluetooth_disabled, size: 200.0, color: Colors.white54, ), Text( 'Bluetooth Adapter is ${adapterState != null ? adapterState.toString().split(".").last : 'not available'}.', style: Theme.of(context).primaryTextTheme.titleSmall?.copyWith(color: Colors.white), ), if (Platform.isAndroid) ElevatedButton( child: const Text('TURN ON'), onPressed: () async { try { if (Platform.isAndroid) { await FlutterBluePlus.turnOn(); } } catch (e) { final snackBar = SnackBar(content: Text(prettyException("Error Turning On:", e))); snackBarKeyA.currentState?.showSnackBar(snackBar); } }, ), ], ), ), ), ); } } class FindDevicesScreen extends StatelessWidget { const FindDevicesScreen({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return ScaffoldMessenger( key: snackBarKeyB, child: Scaffold( appBar: AppBar( title: const Text('Find Devices'), actions: [ if (Platform.isAndroid) ElevatedButton( child: const Text('TURN OFF'), style: ElevatedButton.styleFrom( backgroundColor: Colors.black, foregroundColor: Colors.white, ), onPressed: () async { try { if (Platform.isAndroid) { await FlutterBluePlus.turnOff(); } } catch (e) { final snackBar = SnackBar(content: Text(prettyException("Error Turning Off:", e))); snackBarKeyB.currentState?.showSnackBar(snackBar); } }, ) ], ), body: RefreshIndicator( onRefresh: () => FlutterBluePlus.startScan(timeout: const Duration(seconds: 4)), child: ListView( children: [ StreamBuilder( stream: FlutterBluePlus.adapterState, builder: (context, snapshot) { final adapterState = snapshot.data; return BluetoothStats( adapterState: adapterState ?? BluetoothAdapterState.unknown, ); } ), StreamBuilder>( stream: FlutterBluePlus.scanResults, initialData: const [], builder: (c, snapshot) => Column( children: snapshot.data ?.where((r) => r.device.name.isNotEmpty) .toList()! .sort( (a, b) => a.device.name.compareTo(b.device.name)) .map((r) => DeviceTile(device: r.device, onTap: () { FlutterBluePlus.stopScan(); Navigator.of(context).push( MaterialPageRoute(builder: (c) { return DeviceScreen(device: r.device); }), ); })) .toList() ?? [], ), ) ].toList(), ), ), ), ); } } ``` -------------------------------- ### Run Example App Source: https://pub.dev/packages/flutter_blue_plus Navigate to the example directory and run the example app to test the plugin's functionality. ```bash cd ./example flutter run ``` -------------------------------- ### Example: Fix deprecations Source: https://pub.dev/packages/flutter_blue_plus/versions/1.7.8/changelog Deprecations within the example project have been addressed. This ensures the example code is up-to-date with current Flutter and Dart practices. ```dart Example: fix deprecations ```