// // flutter bluetooth with provider plugin // original article -> https://blog.kuzzle.io/communicate-through-ble-using-flutter // // pubspec.yaml // flutter_blue: 0.6.3+1 // progress_dialog: // provider: // // make sure bluetooth and location is on // make sure app is granted location in settings // // android/app/gradle.build -> line 42 minSdkVersion 19 // // import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter_blue/flutter_blue.dart'; import 'package:provider/provider.dart'; import './notify_value.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) => MaterialApp( title: 'BLE Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => NotifyValue()) ], child: MyHomePage(title: 'Flutter BLE Demo'), ), ); } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; final FlutterBlue flutterBlue = FlutterBlue.instance; final List devicesList = new List(); final Map> readValues = new Map>(); @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { final _writeController = TextEditingController(); BluetoothDevice _connectedDevice; List _services; _addDeviceTolist(final BluetoothDevice device) { if (!widget.devicesList.contains(device)) { setState(() { widget.devicesList.add(device); }); } } @override void initState() { super.initState(); widget.flutterBlue.connectedDevices .asStream() .listen((List devices) { for (BluetoothDevice device in devices) { _addDeviceTolist(device); } }); widget.flutterBlue.scanResults.listen((List results) { for (ScanResult result in results) { _addDeviceTolist(result.device); } }); widget.flutterBlue.startScan(); } ListView _buildListViewOfDevices() { List containers = new List(); for (BluetoothDevice device in widget.devicesList) { containers.add( Container( height: 50, child: Row( children: [ Expanded( child: Column( children: [ Text(device.name == '' ? '(unknown device)' : device.name), Text(device.id.toString()), ], ), ), FlatButton( color: Colors.blue, child: Text( 'Connect', style: TextStyle(color: Colors.white), ), onPressed: () async { widget.flutterBlue.stopScan(); try { await device.connect(); } catch (e) { if (e.code != 'already_connected') { throw e; } } finally { _services = await device.discoverServices(); } setState(() { _connectedDevice = device; }); }, ), ], ), ), ); } return ListView( padding: const EdgeInsets.all(8), children: [ ...containers, ], ); } List _buildReadWriteNotifyButton( BluetoothCharacteristic characteristic) { List buttons = new List(); if (characteristic.properties.read) { buttons.add( ButtonTheme( minWidth: 10, height: 20, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: RaisedButton( color: Colors.blue, child: Text('READ', style: TextStyle(color: Colors.white)), onPressed: () async { var sub = characteristic.value.listen((value) { setState(() { widget.readValues[characteristic.uuid] = value; }); }); await characteristic.read(); sub.cancel(); }, ), ), ), ); } if (characteristic.properties.write) { buttons.add( ButtonTheme( minWidth: 10, height: 20, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: RaisedButton( child: Text('WRITE', style: TextStyle(color: Colors.white)), onPressed: () async { await showDialog( context: context, builder: (BuildContext context) { return AlertDialog( title: Text("Write"), content: Row( children: [ Expanded( child: TextField( controller: _writeController, ), ), ], ), actions: [ FlatButton( child: Text("Send"), onPressed: () { characteristic.write( utf8.encode(_writeController.value.text)); Navigator.pop(context); }, ), FlatButton( child: Text("Cancel"), onPressed: () { Navigator.pop(context); }, ), ], ); }); }, ), ), ), ); } if (characteristic.properties.notify) { buttons.add( ButtonTheme( minWidth: 10, height: 20, child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: RaisedButton( child: Text('NOTIFY', style: TextStyle(color: Colors.white)), onPressed: () async { characteristic.value.listen((value) { Provider.of(context, listen: false).setData(String.fromCharCodes(value)); print("*************${String.fromCharCodes(value)}"); //setState((){widget.readValues[characteristic.uuid] = value;}); }); await characteristic.setNotifyValue(true); }, ), ), ), ); } return buttons; } ListView _buildConnectDeviceView() { List containers = new List(); for (BluetoothService service in _services) { List characteristicsWidget = new List(); for (BluetoothCharacteristic characteristic in service.characteristics) { String notifyValue = Provider.of(context).value; characteristicsWidget.add( Align( alignment: Alignment.centerLeft, child: Column( children: [ Row( children: [ Text(characteristic.uuid.toString(), style: TextStyle(fontWeight: FontWeight.bold)), ], ), Row( children: [ ..._buildReadWriteNotifyButton(characteristic), ], ), Row( children: [ Text('Value: ' + notifyValue), // widget.readValues[characteristic.uuid].toString()), ], ), Divider(), ], ), ), ); } containers.add( Container( child: ExpansionTile( title: Text(service.uuid.toString()), children: characteristicsWidget), ), ); } return ListView( padding: const EdgeInsets.all(8), children: [ ...containers, ], ); } ListView _buildView() { if (_connectedDevice != null) { return _buildConnectDeviceView(); } return _buildListViewOfDevices(); } @override Widget build(BuildContext context) => Scaffold( appBar: AppBar( title: Text(widget.title), ), body: _buildView(), ); } /////////////////////////////////////////////////////// ///////////////// notify_value.dart ///////////////////// import 'package:flutter/material.dart'; class NotifyValue with ChangeNotifier { String _value = ""; String get value => _value; NotifyValue() { _value = "initial data"; } void setData(String newValue) { _value = newValue; notifyListeners(); } }