Open blopker opened 1 year ago
Hi, the current state of BLE in Flutter is a disaster, that's why I had a look into btleplug and I agree that it could be "the one". However, it doesn't align with my current work anymore and at the moment I don't have the time to maintain a flutter plugin but I'd be happy to help.
So, to make this a proper plugin it needs:
Ah, fair enough! It seems like you've already done a lot of the hard work integrating with the JVM though.
For the name, I'd guess flutter_btleplug
would be the obvious one to me. I suppose it could be useful in just Dart as well, but I'd imagine the user base would be much smaller.
Looking forward to the iOS integration. It seems like iOS and MacOS are so similar getting one done means the other usually works too.
I did notice that the plugin mostly just prints strings from Rust, without giving the Flutter side Dart objects to work with. That's something I might be able to help with.
Anyway, I'll watch this in case you do want to pick it up again.
The main part of integrating the JVM was done by @qdot, all I did was throwing it into a flutter plugin.
I thought about it and it would be really nice to have a working Flutter BLE plugin. So, I'll try to add the iOS code soon and maybe I can spare a day per month to work on the code. Are you familiar with Rust?
Nice! I have some light hobby experience with Rust. I can probably write some workable glue code if needed. Although I wouldn't claim it would be the most efficient. What do you have in mind? I'm happy to take on specific tickets.
native/src/api.rs
. This should be realtively straight forward.Nice. I'm playing with it right now. Are you able to get the just build-android
command working? After a bunch of issues, I'm now stuck on error occurred: Failed to find tool. Is `aarch64-linux-android31-clang` installed?
.
Nevermind! Got it working :)
Hi, would you still like to contribute? I've managed to build a basic version that is able to scan and connect to devices :)
Oh hell yeah. I make https://github.com/blopker/superduper, and it mostly works with flutter_reactive_ble. There were a lot of issues though. I've managed to work around the showstoppers, but it doesn't do a good job of cleaning up after itself and eventually the app has to be killed and restarted. I'd love to port the app over to this if we can make it more reliable.
I can test out what you've got so far. Before I blindly dig in, what would you like me to look at?
Ok, great! I think the best way to start is the example and see if it works, I've only tested on Android so far. It doesn't do much, just lists discovered devices and connects by tapping the button.
I have build the plugin such that it remembers discovered devices for 3 seconds and the removes them from the list unless there is an Update event, which is equal for receiving an rssi value. I'm not sure if that is the best solution for all cases and we can make this optional of course.
Then, I've created a few issues that I would address next. But what features do you need for superduper? We could start by implementing them first.
One of the fun portions of this that I may have to work with y'all on is iOS foregrounding.
I just got android backgrounding w/ everything but scanning in the foreground task (which is going to require annoying permissions requests) into my btleplug-using app that's on the play store already. iOS is currently blocked because we need some sort of bluetooth-function-based keepalive for the foreground process in iOS (otherwise it dies in ~30s), but that may need to happen at the btleplug level. I'm looking at putting in some sort of callable, api exposed function that'll trip the keepalive timer, which may be useful for this library. I'll try to remember to update here once I get that figured out.
Nice! I'll check it out this week.
What SD currently uses:
It would also be useful to have subscriptions, but I couldn't get that working reliably with the other packages so for that data I just poll read every few seconds.
Nice! I'll check it out this week.
What SD currently uses:
* Scan for a specific device name. Example: Find all devices called "Super". All bikes have the same name, with different addresses. Maybe the filter is part of this API, or something that happens in app code?
I'm planning to implement a filter but I haven't thought much about the how yet. So at the moment it is
* Connect to a specific bike.
check
* Read the device ID. SD stores this in a database to key config data with. I noticed with flutter_reactive_ble is that the device IDs are different for the same device between iOS and Android. I haven't looked into why though. I could see that being an issue for some applications.
They are different on iOS and Android. Maybe we can use the address instead.
Read from known characteristics. SD doesn't use any discovery functions since all services are known beforehand.
Write to known characteristics.
Disconnect from device. This is where other solutions start to get wonky since the disconnect isn't always clean. Some people have multiple bikes and need to switch between them as quickly as possible, so this issue pops up often. Although now that I think about it, perhaps it's possible to have multiple bike connections happening at the same time?
I think it's possible to connect to four or five devices at a time.
* The app also needs access to some kind of connection state stream to alert the user when the bike is disconnected/connecting/connected or if bluetooth is disabled.
That sounds useful.
It would also be useful to have subscriptions, but I couldn't get that working reliably with the other packages so for that data I just poll read every few seconds. I'm sure we'll manage that :)
I'm planning to implement a filter but I haven't thought much about the how yet. So at the moment it is
It's usually easiest to hand the user all the advertisements and let them filter.
They are different on iOS and Android. Maybe we can use the address instead.
Address is gonna be different across platforms too. CoreBluetooth and WebBluetooth platforms obscure addresses, but they should remain similar when accessing the same device.
I think it's possible to connect to four or five devices at a time.
This is limited by the radio processing. I start getting data loss at 6.
It would also be useful to have subscriptions, but I couldn't get that working reliably with the other packages so for that data I just poll read every few seconds. I'm sure we'll manage that :)
I'm working on this concurrently in btleplug (subs/notificiations already implemented, just not used much) and my own app, so it'll be tested from multiple directions.
I'm planning to implement a filter but I haven't thought much about the how yet. So at the moment it is
It's usually easiest to hand the user all the advertisements and let them filter.
Yes, that is something we should implement once we have some experiance with the lib and know that it's a pain point. But I can imagine that it could be a nice feature to filter for the name.
They are different on iOS and Android. Maybe we can use the address instead.
Address is gonna be different across platforms too. CoreBluetooth and WebBluetooth platforms obscure addresses, but they should remain similar when accessing the same device.
So, that means the only way to identify a device with iOS and Android is with it's name?
I just got android backgrounding w/ everything but scanning in the foreground task (which is going to require annoying permissions requests) into my btleplug-using app that's on the play store already. iOS is currently blocked because we need some sort of bluetooth-function-based keepalive for the foreground process in iOS (otherwise it dies in ~30s), but that may need to happen at the btleplug level. I'm looking at putting in some sort of callable, api exposed function that'll trip the keepalive timer, which may be useful for this library. I'll try to remember to update here once I get that figured out.
I'm not sure I understand everything of what you wrote here or maybe I don't understand the terminology of back- and foregrounding. On Android you managed to run btleplug in the background but scanning is still done in the foreground?
So, that means the only way to identify a device with iOS and Android is with it's name?
Name, Manufacturer Data, Advertised Service Data...
On Android you managed to run btleplug in the background but scanning is still done in the foreground?
Whoops, that should've all said "foregrounding".
On mobile apps:
You'll be interested in foregrounding for Bluetooth, because you want your device connection to stay alive when someone sleeps their phone or uses another app. Depending on the situation, it may also be useful to have the ability to scan for devices in the foreground task, though that should be up to the library user as that requires permissions that require extra steps with the relevant store to get (i.e. sending in videos of usage, etc).
Foregrounding works far differently between Android and iOS, you'll have to take into account power/sleep/foreground task considerations per platform, etc...
Cool, I got the example working on Android! I did have to make 2 changes. 1) Add mkdir -p "packages/flutter_btleplug/android/src/main/jniLibs"
to build-android-dev.sh
since jniLibs didn't exist after first clone. And 2) I needed to add permission_handler: ^10.2.0
to the example pub file and then add await Permission.bluetoothScan.request();
when pressing the scan
button. Otherwise, a pretty hairy error was thrown. I guess error handling could be improved in that sense. The average Flutter dev may not be able to understand it.
According to the feature matrix in the readme, I'll need at least writing to characteristics before I can try to integrate it into SD though.
Permissions are more complicated than that, depending on your Android version support. There was a permissions split at Android 12 (API version 30) that means you need to ask for a different set of permissions if you want to support older Android builds.
Here's my code for perms checking, which I shipped last weekend and seems to work back to Android 9. (Breaks on Android 6/7, no one has tested 8/8.1 yet).
https://github.com/intiface/intiface-central/blob/main/lib/intiface_central_app.dart#L99
You'll also need a matching set w/ version conditionals in your manifest:
https://github.com/intiface/intiface-central/blob/main/android/app/src/main/AndroidManifest.xml#L5
@blopker great that you could make it work! Could you make a PR with your changes? And do you want to try to implement r/w of characteristics?
@qdot Thanks a lot! This will save some time and headaches for sure^^
Any chance you could let me push branches to this repo? That would simplify my workflow to add changes :)
I spent a few hours exploring how to make a BLE server I could test against. The only device I have is my bike and, sadly (I asked!), I'm unable to bring the bike into my house. I tried to run a server on my Mac, but no luck, tried on Android, also no luck. I didn't try iOS. Otherwise, I don't have easy access to a Linux box with a Bluetooth module.
How are y'all making test Bluetooth servers to debug with?
Not sure what you mean by "BLE server".
Sorry, I'm new to the Bluetooth world. I may try to shoe horn web language in... I mean a peripheral? Something that btleplug can connect to. I now see https://pypi.org/project/bless/ might do what I want, but need to try it still.
It should also be possible to use another phone to simulate or act as a bluetooth sensor.
As for push rights, I would prefer to use PR because otherwise I will lose track of what's happening. I hope that's okay.
That's fair. Although, I didn't mean to say I wanted to push directly to main, only the ability to make branches in this repo and make PRs. Making PRs from my fork and keeping everything in sync is clunky. Is that OK?
Also, have you gotten a phone to work as a peripheral? I haven't had any success yet.
I haven't tried them but https://play.google.com/store/apps/details?id=com.techbitar.android.sensoduino or https://play.google.com/store/apps/details?id=com.amalanjula.sensorApp&gl=US could work.
I think the only way to give you branch push permission would be to make you a collaborator which gives access to like everything or to create an organisation which we could do...or do you know another way to allow you to push branches?
With github-cli syncing looks pretty easy:
gh repo sync owner/cli-fork -b main
Hey! I'm writing an app to control a popular ebike for additional functionality. The problem is all the Flutter BLE libraries are pretty broken in various ways (maybe you've seen this too?). They often have weird bugs and function differently on different platforms.
This project is sorely needed! Is there anything I can do to help get it into pub.dev? From what I've seen this could definitely be the "one true" Bluetooth plugin for Flutter/Dart.