pauldemarco / flutter_blue Goto Github PK
View Code? Open in Web Editor NEWBluetooth plugin for Flutter
License: BSD 3-Clause "New" or "Revised" License
Bluetooth plugin for Flutter
License: BSD 3-Clause "New" or "Revised" License
operator == on Guid is just comparing Guid hash codes, and not subsequently comparing Guid values, so will give false positives if the hash codes for two different values collide.
operator ==(other) =>
other is Guid && this.hashCode == other.hashCode;
The example needs refactoring, lots of duplicate code.
iOS will terminate if user tries to manually write the CCC descriptor:
'NSInternalInconsistencyException', 'Client Characteristic Configuration descriptors must be configured using setNotifyValue:forCharacteristic:'
Handle this gracefully by blacklisting CCCD UUID before call is made.
From dart pub
Right now you must both listen on deviceDiscovered() and initiate the method call with startScanningForDevicesAsync.
Consider combining this into:
Stream<Device> startScanningForDevices()
Simplifies API.
I have added flutter_blue to my yaml file after that I'm getting pod error
dependencies:
flutter:
sdk: flutter
flutter_blue: "0.3.1"
cupertino_icons: ^0.1.0
If I remove flutter_blue then it starts to work normally
Why is this issue happening and how can I solve this?
I tried the example from https://pub.dartlang.org/packages/flutter_blue#-example-tab-
with the install instruction from https://pub.dartlang.org/packages/flutter_blue#-installing-tab-
Running it resulted in a working app, the moment I hit the search button, this message was displayed:
==========================
D/BluetoothAdapter(24334): STATE_ON
D/BluetoothLeScanner(24334): onClientRegistered() - status=0 clientIf=6 mClientIf=0
W/Binder (24334): Binder call failed.
W/Binder (24334): java.lang.SecurityException: Need ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission to get scan results
W/Binder (24334): at android.os.Parcel.readException(Parcel.java:1684)
W/Binder (24334): at android.os.Parcel.readException(Parcel.java:1637)
W/Binder (24334): at android.bluetooth.IBluetoothGatt$Stub$Proxy.startScan(IBluetoothGatt.java:678)
W/Binder (24334): at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper.onClientRegistered(BluetoothLeScanner.java:367)
W/Binder (24334): at android.bluetooth.IBluetoothGattCallback$Stub.onTransact(IBluetoothGattCallback.java:56)
W/Binder (24334): at android.os.Binder.execTransact(Binder.java:565)
D/BluetoothAdapter(24334): STATE_ON
==========================
I tried to add the permissions in AndroidManifest.xml in the android/app/src as they were in the example provided with the package code, but no dice
================
package="com.yourcompany.johanblue">
<!-- The INTERNET permission is required for development. Specifically,
flutter needs it to communicate with the running application
to allow setting breakpoints, to provide hot reload, etc.
-->
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
================
What are the appropriate steps to get this thing running?
(testing on Moto Z Play, Android 7.1.1 securitypatches december 2017)
Kind Regards,
Johan
As of right now, an NSMutableDictionary contains all discovered peripherals that occur during a scan.
Consider removing this duplicate data set and use retrievePeripheralsWithIdentifiers directly, via findPeripheral
method.
In android, I got the following error while trying to stop scanning from my application:
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): Failed to handle method call
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): java.lang.NullPointerException: Attempt to invoke virtual method 'void android.bluetooth.le.BluetoothLeScanner.stopScan(android.bluetooth.le.ScanCallback)' on a null object reference
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at com.pauldemarco.flutterblue.FlutterBluePlugin.stopScan21(FlutterBluePlugin.java:609)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at com.pauldemarco.flutterblue.FlutterBluePlugin.stopScan(FlutterBluePlugin.java:565)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at com.pauldemarco.flutterblue.FlutterBluePlugin.onMethodCall(FlutterBluePlugin.java:153)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at io.flutter.plugin.common.MethodChannel$IncomingMethodCallHandler.onMessage(MethodChannel.java:191)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at io.flutter.view.FlutterNativeView.handlePlatformMessage(FlutterNativeView.java:133)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at android.os.MessageQueue.nativePollOnce(Native Method)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at android.os.MessageQueue.next(MessageQueue.java:323)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at android.os.Looper.loop(Looper.java:136)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at android.app.ActivityThread.main(ActivityThread.java:6186)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at java.lang.reflect.Method.invoke(Native Method)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:889)
E/MethodChannel#plugins.pauldemarco.com/flutter_blue/methods(10734): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:779)
D/BluetoothAdapter(10734): onBluetoothServiceDown: Sending callbacks to 1 clients
D/BluetoothAdapter(10734): onBluetoothServiceDown: Finished sending callbacks to registered clients
The problem here seems to be in stopScan21
, that doesn't check whether mBluetoothAdapter.getBluetoothLeScanner()
returns null. There seems to be the same problem in startScan21
Is there any support for advertising?
When trying to retrieve a list of connected peripherals, we are required to supply a list of service UUID to search for.
There is no "Search All" method, so therefore the common information service is used (0x180A), see here: https://stackoverflow.com/questions/25865937/how-to-detect-if-a-iphone-is-connected-to-any-bluetooth-device-or-not
Consider keeping an internal array of connected devices.
Look at flutter widgets to see how to properly document classes. Right now they are an absolute mess.
With issue #21 implemented, consider making state
a Stream<BluetoothDeviceState>
and simply leverage the power of Dart streams, i.e. state.first
(if state is only needed once)
This code should allow concurrent reading of characteristics:
Future.wait([
device.readCharacteristic(char1),
device.readCharacteristic(char2),
// etc.
])
.then((returnsList) {
print('In Future.wait.then, ${returnsList.length}');
})
.catchError((e) {
print('error $e');
});
But in fact it never gets to .then
... nor does it throw an error.
Based on the debug messages coming out of flutter_blue it appears that both characteristics are indeed being read. So maybe there's a tweak needed to handle the case that multiple futures are active at the same time?
Covered here in Dart docs: Async
Now that scanning stops once the subscription to startScan is canceled, we can consider renaming startScan to simply scan.
Original suggestion by @brianegan in PR #17 .
I will be considering this breaking change for a bit, but I'm leaning towards implementing. If you have some thoughts please share.
Can anyone add the current version number to readme doc plz?
In android, the scan settings passed to FlutterBlue::scan
are simply ignored.
The api function void startScan (List<ScanFilter> filters, ScanSettings settings, ScanCallback callback)
should be used instad of void startScan (ScanCallback callback)
As of right now, characteristics and descriptor hold onto their parent service, but do not account for the fact that the service might be a nested service.
Need to think about how to handle this, it doesn't seem iOS supports it.
iOS also supports the ability to setup scan options:
https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/peripheral_scanning_options
Decide whether these should be exposed as options in ScanSettings.
Flutter blue has a map of connections by deviceId kept in a java hashmap that survives across hot reloads, and connect is not allowed to reuse an existing connection. Thus it is not possible to connect to the same device after a hot reload.
To reproduce:
Run app, connect to a device.
Hot reload app.
Try to connect to same device, run into this:
case "connect":
...
// If device is already connected, return error
if(mGattServers.containsKey(deviceId) && isConnected) {
result.error("already_connected", "connection with device already exists", null);
return;
}
Device disconnection is a private method ('_cancelConnection') so I can't kill the connection myself as a workaround.
So, for now, I am just doing a full app restart each time.
David
Hey hey :) Just noticed connect
and cancelConnection
... quick scan looks like it might have the same issue as the other PR we merged with startScan
/ stopScan
and thought I'd note it
When trying to add flutter_blue to the most basic app setup with no other dependencies in android studio 3.0 it gives this error message:
/home/maarten/flutter/bin/flutter --no-color packages get
Running "flutter packages get" in tanngrisnir...
Package protobuf has no versions that match >=0.5.5 <0.6.0 derived from:
this is my pubspec.yaml:
name: tanngrisnir
description: Remote control app for tanngrisnir
depend
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://wwname: tanngrisnir
description: Remote control app for tanngrisnir
depend
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: trueencies:
flutter_blue: "^0.2.4"
flutter:
sdk: flutter
# The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^0.1.0
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# The following line ensures that the Material Icons font is
# included with your application, so that you can use the icons in
# the material Icons class.
uses-material-design: true
Hi,
On iOS, I'm not seeing any data for the following properties on AdvertisementData
in my ScanResult
event stream handler:
localName
manufacturerData
serviceData
I observed this to be consistent over ScanResult
s for responses for 19 different devices.
localName
returns an empty String
, and manufacturerData
and serviceData
return an empty List<int>
.
Let me know if I can provide more details or if I can help in troubleshooting, debugging, or verifying a fix.
Thanks.
Either keep the breakdown of separate examples, or combine into one succinct usage snippet.
startScan and discoverServices should support the ability to filter by service UUIDs.
iOS supports options while using connectPeripheral:
https://developer.apple.com/documentation/corebluetooth/cbcentralmanager/peripheral_connection_options?language=objc
iOS allows a CBPeripheral to specify a list of service UUIDs to discover:
https://developer.apple.com/documentation/corebluetooth/cbperipheral/1518706-discoverservices?language=objc
Consider adding this to the Dart API.
(Android doesn't support such granularity, and simply discovers everything at once).
As of right now, whenever an object is created, it creates it's own PlatformChannel with it's specific path name. If however another object is created for that same GUID path, we will have duplicate PlatformChannels for the same path, and neither will work.
Consider creating a PlatformChannel Factory, which will keep a HashMap of path to channels list, and can be used by any objects requiring a channel.
I'm having trouble getting the list of services from a bt device, my snippet:
List<BluetoothService> services = await widget.device.discoverServices();
print("success discovered");
never gets to print "success", here's what i see in the log:
D/FlutterBluePlugin(24804): onServicesDiscovered: 4 sink:null
It seems the servicesDiscoveredHandler.onListen function (which registers the servicesDiscoveredSink) is called only after onServicesDiscovered; but i can't find out why.
Maybe some change in the flutter framework? I've tried using alpha channel (2017-12-12) and git from yesterday. This seems to happen with flutter_blue 0.2.3 and git HEAD.
If you can't find time to fix this, any hints would be appreciated to maybe enable me to produce a PR.
Hi,
I would like to ask is there any way that I can use this plugin for serial communication with another bluetooth device? Is there anywhere that I can look into to implement this function?
Thanks.
Platform code contains logging that should be user-configurable.
Allow the user to change verbosity level for the plugin.
If a device is advertising very frequently during a scan, the timeout will never get called on the startScan stream.
It would be nice to support advertising as well as it is available on ios and Android( >=5.0)
An Objective-C implementation is still needed on iOS side.
This is because the contained CCC descriptor's value has not updated yet in the characteristic sent back in result(...)
.
Solution:
Move the setNotifyValue
callback to a channel method and call from didUpdateNotificationStateForCharacteristic
This would require a new Protobuf type of ProtosSetNotificationResponse
Unless I am mistaken, the following code only allows one notification to be active at a time:
/// Notifies when the characteristic's value has changed.
/// setNotification() should be run first to enable them on the peripheral
Stream<List<int>> onValueChanged(BluetoothCharacteristic characteristic) {
return FlutterBlue.instance._characteristicNotifiedChannel
.receiveBroadcastStream()
.map((buffer) => new protos.OnNotificationResponse.fromBuffer(buffer))
.where((p) => p.remoteId == id.toString())
.map((p) => new BluetoothCharacteristic.fromProto(p.characteristic))
.where((c) => c.uuid == characteristic.uuid)
.map((c) {
characteristic.updateDescriptors(c.descriptors);
characteristic.value = c.value;
return c.value;
});
}
For many BLE devices it is necessary to listen to notifications from multiple characteristics at the same time. Not to mention from multiple devices!
Add the .dartignore file as well!
With the upcoming Dart 2 changes we will run into errors when returning anything other than Future<dynamic>
from invokeMethod
calls.
Calls like:
Future<bool> get isOn => _channel.invokeMethod('isOn');
Need to be updated to:
Future<bool> get isOn async {
final bool isOn = await _channel.invokeMethod('isOn');
return isOn;
}
More details in this issue: flutter/flutter#15654
Switch AnimatedRssi to use the RssiPainterCircle painter.
Scan for devices
Notice the elastic animation is not picking up where it left off, causing a stuttery look.
Attempting to run the example code on a Nexus 7 (running android 6.0.1)
I'm consistently getting this stacktrace and an application crash a few seconds after initiating a scan:
E/AndroidRuntime( 7688): FATAL EXCEPTION: main
E/AndroidRuntime( 7688): Process: com.pauldemarco.flutterblueexample, PID: 7688
E/AndroidRuntime( 7688): java.lang.NullPointerException
E/AndroidRuntime( 7688): at com.pauldemarco.flutterblue.Protos$BluetoothDevice.setName(Protos.java:2850)
E/AndroidRuntime( 7688): at com.pauldemarco.flutterblue.Protos$BluetoothDevice.access$4900(Protos.java:2689)
E/AndroidRuntime( 7688): at com.pauldemarco.flutterblue.Protos$BluetoothDevice$Builder.setName(Protos.java:3089)
E/AndroidRuntime( 7688): at com.pauldemarco.flutterblue.ProtoMaker.from(ProtoMaker.java:38)
E/AndroidRuntime( 7688): at com.pauldemarco.flutterblue.ProtoMaker.from(ProtoMaker.java:28)
E/AndroidRuntime( 7688): at com.pauldemarco.flutterblue.FlutterBluePlugin$2.onScanResult(FlutterBluePlugin.java:579)
E/AndroidRuntime( 7688): at android.bluetooth.le.BluetoothLeScanner$BleScanCallbackWrapper$1.run(BluetoothLeScanner.java:355)
E/AndroidRuntime( 7688): at android.os.Handler.handleCallback(Handler.java:739)
E/AndroidRuntime( 7688): at android.os.Handler.dispatchMessage(Handler.java:95)
E/AndroidRuntime( 7688): at android.os.Looper.loop(Looper.java:148)
E/AndroidRuntime( 7688): at android.app.ActivityThread.main(ActivityThread.java:5417)
E/AndroidRuntime( 7688): at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime( 7688): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
E/AndroidRuntime( 7688): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
Having to do a lot of this:
// Immediately get the state of FlutterBlue
_flutterBlue.state.then((s) {
setState(() {
state = s;
});
});
// Subscribe to state changes
_stateSubscription = _flutterBlue.onStateChanged().listen((s) {
setState(() {
state = s;
});
});
By having onStateChanged() always return current state when listened to, we can avoid the extra then call.
Look to other flutter plugins for how to maximize code coverage.
Unlike Android, iOS requires all characteristics and descriptors to be explicitly discovered using:
discoverCharacteristics:forService:
discoverDescriptorsForCharacteristic:
Current implementation of Flutter Blue will return the discoverServices call once the first descriptor is received, often being too early and missing other characteristic and services information.
Solution idea: Implement stacks to keep track of services/characteristics/descriptors that still need discovered, and return the discovered tree only when these arrays are empty.
A secondary service will also receive the channel path of "flutterblue.pauldemarco.com/device/${deviceId.toString()}/service/${serviceId.toString()}/methods"
This could cause conflicts if a primary service shares the same UUID, is this possible in the BLE spec?
There are separate event channels for reading characteristics, reading descriptors, discovering services, etc. Should these be consolidated onto the main method channel, and then dispatched dart side (see firebase_database plugin's Query class)?
Always nice to get a feel for it in action :)
Thanks!
Steps to reproduce:
Note: This doesn't happen if a difference device is connected to
The underlying framework doesn't set the permissions for the characteristic. Instead, it performs retry attempts with increasing security, see here: https://stackoverflow.com/questions/23674668/android-bluetooth-low-energy-characteristic-getpermissions-returns-0
This error is sometimes experienced when trying to flutter run
:
[!] ERROR: Parsing unable to continue due to parsing error:
contained in the file located at /Users/pauldemarco/flutter_blue/example/ios/Podfile.lock
PODS:
- !ProtoCompiler (3.4.0):
- Protobuf (~> 3.0)
- Flutter (1.0.0)
- flutter_blue (0.0.1):
- !ProtoCompiler
- Flutter
- flutter_blue/Protos (= 0.0.1)
- flutter_blue/Protos (0.0.1):
- !ProtoCompiler
- Flutter
- Protobuf
- Protobuf (3.5.0)
DEPENDENCIES:
- Flutter (from `/Users/pauldemarco/flutter/bin/cache/artifacts/engine/ios`)
- flutter_blue (from `/Users/pauldemarco/flutter_blue/ios`)
EXTERNAL SOURCES:
Flutter:
:path: /Users/pauldemarco/flutter/bin/cache/artifacts/engine/ios
flutter_blue:
:path: /Users/pauldemarco/flutter_blue/ios
SPEC CHECKSUMS:
!ProtoCompiler: 07d0c441bc00e7f01e84debf7c53794683fbca7c
Flutter: 58dd7d1b27887414a370fcccb9e645c08ffd7a6a
flutter_blue: 6a29a637fac55c8918a01e9d2c3d381612b1357a
Protobuf: 8a9838fba8dae3389230e1b7f8c104aa32389c03
PODFILE CHECKSUM: 351e02e34b831289961ec3558a535cbd2c4965d2
COCOAPODS: 1.3.1
/Library/Ruby/Gems/2.3.0/gems/cocoapods-core-1.2.1/lib/cocoapods-core/yaml_helper.rb:62:in `rescue in load_string'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-core-1.2.1/lib/cocoapods-core/yaml_helper.rb:57:in `load_string'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-core-1.2.1/lib/cocoapods-core/yaml_helper.rb:75:in `load_file'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-core-1.2.1/lib/cocoapods-core/lockfile.rb:40:in `from_file'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.2.1/lib/cocoapods/config.rb:199:in `lockfile'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.2.1/lib/cocoapods/command.rb:138:in `installer_for_config'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.2.1/lib/cocoapods/command/install.rb:38:in `run'
/Library/Ruby/Gems/2.3.0/gems/claide-1.0.2/lib/claide/command.rb:334:in `run'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.2.1/lib/cocoapods/command.rb:52:in `run'
/Library/Ruby/Gems/2.3.0/gems/cocoapods-1.2.1/bin/pod:55:in `<top (required)>'
/usr/local/bin/pod:22:in `load'
/usr/local/bin/pod:22:in `<main>'
Error running pod install
Flutter plugin imports must also be included in the example's pubspec.yaml. For instance:
convert: "^2.0.1"
I would prefer it to only be needed once, in the libraries pubspec.yaml
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.