Introduce GATT functionality for Android#40
Introduce GATT functionality for Android#40wuwbobo2021 wants to merge 11 commits intoalexmoon:mainfrom
Conversation
|
In I just found the |
|
I have been also been working on this is an as yet unpublished crate (still working out the bugs). I also have a branch that uses that crate in bluest (See the basic commit MaticianInc@76e6457). We are using it in our (still in beta) Android app at Matic. I have been waiting to publish it until we have something stable. I can either help review this or publish my version when is its ready. |
|
@abezukor I'm glad to see yet another solution of Android support; however, where is the |
Will do. I wasnt planning on publishing it until I had fixed all the bugs, but I can if you want to collaborate. |
|
@abezukor Would you please describe about those most significant bugs? I think It's difficult to determine which implementation is more viable if you don't make it public. |
I think An adapter config parameter to enable requesting the MTU on connection would also be good. |
I hope to open up my code later this week. It has been an internal project until now, and I need to spend some time writing documentation etc. |
|
@abezukor I am willing to dismiss my current implementation if the On the other hand, something like blurdroid (with C code) might not be acceptable. I guess you are not making something similar to that crate. |
|
@abezukor I can't wait for knowing if your implementation has structural advantages over this attempt. Could you make it public earlier, even with minor bugs? Otherwise I may continue to improve my own implementation. |
I have released a version https://github.com/abezukor/android_rust. I had to re-organize a bunch of it to make it compatible with Quickly looking at your implementation, the main structural difference is I decided to put more logic on the java side, because I found it more ergonomic to write that way. I also have created a bunch of components that are reused in an NSD (mDNS) crate. |
|
@abezukor Some notes for |
|
I am still confused about the schedule of "planned support for Android". Maybe it's time to make the decision: to close #40 as unmerged and accept the implementation from @abezukor, or to check this PR seriously. A few changes could be made here if #40 should be kept:
|
|
I have just fixed some problems noted above, and solved the problems of no responding in case of scanning without permission and reading/writing data while the device is disconnected. Test case to be built by cargo-apk or cargo-apk2[workspace]
[package]
name = "bluest-test"
version = "0.1.0"
edition = "2024"
publish = false
[dependencies]
bluest = { path = "..", features = ["unstable", "l2cap"] }
tracing = "0.1.36"
tracing-subscriber = "0.3.15"
# android-activity uses `log`
log = "0.4"
tracing-log = "0.2.0"
ndk-context = "0.1.1"
android-activity = { version = "0.6", features = ["native-activity"] }
# jni-min-helper = { version = "0.3", features = ["futures"] }
futures-lite = "2.6"
async-channel = "2.2.0"
futures-timer = "3.0.3"
[lib]
crate-type = ["cdylib"]
[package.metadata.android]
package = "com.example.bluest_test"
build_targets = ["aarch64-linux-android"]
# "Arm64V8a" is for `cargo-apk2` which is required for putting `PermActivity` in the app
# build_targets = [ "Arm64V8a" ]
# put <https://docs.rs/crate/jni-min-helper/0.3.2/source/java/PermActivity.java> in this folder
# java_sources = "java"
# Android 12 or above may require runtime permission request.
# <https://developer.android.com/develop/connectivity/bluetooth/bt-permissions>
# <https://docs.rs/jni-min-helper/0.3.2/jni_min_helper/struct.PermissionRequest.html>
# Use `cargo-apk2` or check <https://github.com/rust-mobile/cargo-apk/pull/72>
[package.metadata.android.sdk]
min_sdk_version = 23
target_sdk_version = 33
[[package.metadata.android.uses_feature]]
name = "android.hardware.bluetooth_le"
required = true
[[package.metadata.android.uses_permission]]
name = "android.permission.BLUETOOTH_SCAN"
min_sdk_version = 31
[[package.metadata.android.uses_permission]]
name = "android.permission.BLUETOOTH_CONNECT"
min_sdk_version = 31
[[package.metadata.android.uses_permission]]
name = "android.permission.ACCESS_FINE_LOCATION"
# TODO: uncomment this line when `usesPermissionFlags` becomes supported in `cargo-apk2`.
# max_sdk_version = 30
[[package.metadata.android.uses_permission]]
name = "android.permission.BLUETOOTH"
max_sdk_version = 30
[[package.metadata.android.uses_permission]]
name = "android.permission.BLUETOOTH_ADMIN"
max_sdk_version = 30
# these are for `cargo-apk2`
# [[package.metadata.android.application.activity]]
# name = "android.app.NativeActivity"
# [[package.metadata.android.application.activity.intent_filter]]
# actions = ["android.intent.action.VIEW", "android.intent.action.MAIN"]
# categories = ["android.intent.category.LAUNCHER"]
# [[package.metadata.android.application.activity.meta_data]]
# name = "android.app.lib_name"
# value = "bluest_test"
# [[package.metadata.android.application.activity]]
# name = "rust.jniminhelper.PermActivity"#![allow(unused)]
use bluest::btuuid::bluetooth_uuid_from_u16;
use bluest::Uuid;
use futures_timer::Delay;
use std::time::Duration;
use android_activity::{AndroidApp, MainEvent, PollEvent};
use futures_lite::{FutureExt, StreamExt};
use tracing::{error, info};
#[unsafe(no_mangle)]
fn android_main(app: AndroidApp) {
// android_logger::init_once(
// android_logger::Config::default()
// .with_max_level(log::LevelFilter::Info)
// .with_tag("bluest_test".as_bytes()),
// );
// NOTE: View tracing log on the host with `adb logcat RustStdoutStderr:D '*:S'`.
let subscriber = tracing_subscriber::FmtSubscriber::builder().without_time().finish();
tracing::subscriber::set_global_default(subscriber).expect("setting tracing default failed");
tracing_log::LogTracer::init().expect("setting log tracer failed");
// calling `block_on` with bluetooth operations in `android_main` thread may block forever...
let (tx, rx) = async_channel::unbounded();
std::thread::spawn(move || {
let res = futures_lite::future::block_on(async_main().or(async {
let _ = rx.recv().await;
info!("async thread received stop signal.....");
Ok(())
}));
if let Err(e) = res {
info!("async thread's `block_on` received error: {e}");
} else {
info!("async thread terminates itself after it received stop signal.");
}
});
let mut on_destroy = false;
loop {
app.poll_events(None, |event| match event {
PollEvent::Main(MainEvent::Stop) => {
info!("Main Stop Event.");
let _ = tx.send(());
}
PollEvent::Main(MainEvent::Destroy) => {
on_destroy = true;
}
_ => (),
});
if on_destroy {
return;
}
}
}
async fn async_main() -> Result<(), Box<dyn std::error::Error>> {
// Currently this requires `cargo-apk2` instead of `cargo-apk` to work.
// But this is required if the user chooses to confirm permission on every startup.
/*
let req = jni_min_helper::PermissionRequest::request(
"BLE Test",
[
"android.permission.BLUETOOTH_SCAN",
"android.permission.BLUETOOTH_CONNECT",
"android.permission.ACCESS_FINE_LOCATION",
],
)?;
if let Some(req) = req {
info!("requesting permissions...");
let result = req.await;
for (perm_name, granted) in result.unwrap_or_default() {
if !granted {
eprintln!("{perm_name} is denied by the user.");
return Ok(());
}
}
};
*/
let adapter = bluest::Adapter::with_config(bluest::AdapterConfig::default()).await?;
adapter.wait_available().await?;
info!("adapter is now available.");
// Please put your test case here.
info!("async task terminates itself.");
Ok(())
} |
|
I did a test that adds log messages for ACTION_ACL_CONNECTED and I am afraid that the problem marked by I will not make further changes without your suggestions. Thank you. |
|
I realized a structural problem in my current implementation: while it seems possible to reconnect a device with private random resolvable address, Another problem found in my I think the implementation from @abezukor is (currently) less problematic at these points. |
This comment was marked as outdated.
This comment was marked as outdated.
|
Closing this because https://crates.io/crates/android-ble is released. I'll not consider opening another PR, at least before the PR of using |
Note: this is still experimental, and behaviors on services changed event is untested; pairing with user confirmation needs testing on newest Android versions.