Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 186
Description
Hi there, I am new to android apps compiled in rust, so perphaps it's a really silly question, but I didn't get any idea why the app freezes when calling manager.adapters().await?.
I believe it has to do something with missing android permissions, but I am not really sure.
I've granted all permissions in the android app settings:
"Location" "Nearby devices" "Notifications" "Sensors" Describe the bug
Compiling and starting android app -> the app hangs when calling following function:
manager.adapters().await? So my last log entry is "call....0" here's my code:
debug!("call..."); getAllPermissions(); debug!("call...0"); let manager = Manager::new().await?; debug!("call...1"); let adapters = manager.adapters().await?; // <<<<< app hangs here debug!("call...2"); let central = adapters.into_iter().nth(0).unwrap(); debug!("call...3"); Expected behavior
Progess this function and view available BLE devices.
Actual behavior
App freezes on :let adapters = manager.adapters().await?
My android manifest.xml:
<?xml version="1.0" encoding="UTF-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.nonpolynomial.btleplug.android"> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/> <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS"/> <uses-permission android:name="android.permission.BLUETOOTH"/> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/> <uses-permission android:name="android.permission.BLUETOOTH_SCAN"/> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/> </manifest> I request permissions at runtime - I use this code here (not the best but I think it is working)
use jni::objects::{JObject, JValue}; use jni::{JNIEnv, JavaVM}; use ndk_context; use once_cell::sync::OnceCell; pub static JAVAVM: OnceCell<JavaVM> = OnceCell::new(); pub fn get_vm() -> JavaVM{unsafe{JavaVM::from_raw(ndk_context::android_context().vm().cast()).unwrap() } } fn get_activity_ptr() -> jni::sys::jobject{ndk_context::android_context().context().cast() } fn has_permissions(env: &JNIEnv, permissions: &[&str]) -> bool{for &permission in permissions{let perm_jstring = env.new_string(permission).unwrap(); let perm_obj: JObject = perm_jstring.into(); // Nutze das Activity-Objekt direkt im Methodenaufruf! let permission_status = env .call_method( unsafe{JObject::from(get_activity_ptr()) }, "checkSelfPermission", "(Ljava/lang/String;)I", &[JValue::Object(perm_obj)], ) .unwrap() .i() .unwrap(); if permission_status != 0{// debug!("{} not granted", permissions.join(", ")); return false} } // debug!("{} granted", permissions.join(", ")); true } fn request_permissions(env: &JNIEnv, permissions: &[&str]){debug!("request_permission{}", permissions.join(", ")); let string_class = env.find_class("java/lang/String").unwrap(); let default_string = env.new_string("").unwrap(); let permissions_array = env.new_object_array(permissions.len() as i32, string_class, default_string).unwrap(); for (i, &permission) in permissions.iter().enumerate(){let java_permission = env.new_string(permission).unwrap(); env.set_object_array_element(permissions_array, i as i32, java_permission).unwrap()} env.call_method( unsafe{JObject::from(get_activity_ptr()) }, "requestPermissions", "([Ljava/lang/String;I)V", &[ JValue::Object(JObject::from(permissions_array)), JValue::Int(0), ], ).unwrap(); debug!("request_permissions done")} pub fn ensure_permissions(env: &JNIEnv, permissions: &[&str]){debug!("ensure_permissions{}", permissions.join(", ")); request_permissions(env, permissions); // if !has_permissions(env, permissions){// request_permissions(env, permissions); // } else{// debug!("{} already granted", permissions.join(", ")); // } } pub fn getAllPermissions(){let vm = get_vm(); let env = vm.attach_current_thread().unwrap(); let permissions = [ "android.permission.ACCESS_COARSE_LOCATION", "android.permission.ACCESS_FINE_LOCATION", "android.permission.BLUETOOTH", "android.permission.BLUETOOTH_ADMIN", "android.permission.BLUETOOTH_SCAN", "android.permission.BLUETOOTH_CONNECT", ]; for perm in &permissions{ensure_permissions(&env, &[perm])} } #[no_mangle] pub extern "C" fn JNI_OnLoad(vm: jni::JavaVM, _res: *const std::os::raw::c_void) -> jni::sys::jint{let env = vm.get_env().unwrap(); // jni_utils::init(&env).unwrap(); // ggf. entfernen, wenn nicht kompatibel // btleplug::platform::init(&env).unwrap(); // Nur falls du btleplug verwendest und es kompatibel ist! let _ = JAVAVM.set(vm); jni::JNIVersion::V6.into() } Additional context
my TOML:
[package] name = "slint-rust-template" version = "0.1.0" edition = "2021" # android --> [lib] crate-type = ["cdylib"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] slint ={version = "1.8.2", features = ["backend-android-activity-06"] } anyhow = "1.0.98" btleplug = "0.11.8" futures = "0.3.31" futures-util = "0.3.31" tokio ={version = "1.12", features = ["full"] } tokio-stream = "0.1.17" uuid = "1.17.0" once_cell = "1" chrono = "0.4.41" strum = "0.27.1" strum_macros = "0.27.1" #jni = "0.21.1" jni = "0.19.0" android-activity = "0.6.0" ndk-context = "0.1.1" #ndk-glue = "0.7.0" #ndk = "0.9.0" #ndk = "0.8" ndk-glue = "0.7" android_logger = "0.13" log = "0.4" android-manifest = "0.2.0" #simplersble = "0.10.3" #android-manifest = "0.2.0" #jni-utils = "0.1.1" [build-dependencies] slint-build = "1.8.2" [package.metadata.android] # Specifies the package property of the manifest. package = "com.foo.bar" # Specifies the array of targets to build for. build_targets = [ "armv7-linux-androideabi", "aarch64-linux-android", "i686-linux-android", "x86_64-linux-android" ] # Path to your application's resources folder. # If not specified, resources will not be included in the APK. #resources = "path/to/resources_folder" # Path to the folder containing your application's assets. # If not specified, assets will not be included in the APK. #assets = "path/to/assets_folder" # Name for final APK file. # Defaults to package name. apk_name = "myapp" # See https://developer.android.com/guide/topics/manifest/uses-sdk-element # # Defaults to a `min_sdk_version` of 23 and `target_sdk_version` of 30 (or lower if the detected NDK doesn't support this). [package.metadata.android.sdk] min_sdk_version = 23 target_sdk_version = 30 max_sdk_version = 29 # See https://developer.android.com/guide/topics/manifest/uses-feature-element # # Note: there can be multiple .uses_feature entries. [[package.metadata.android.uses_feature]] name = "android.hardware.vulkan.level" required = true version = 1 # See https://developer.android.com/guide/topics/manifest/uses-permission-element # # Note: there can be multiple .uses_permission entries. [[package.metadata.android.uses_permission]] name = "android.permission.ACCESS_COARSE_LOCATION" [[package.metadata.android.uses_permission]] name = "android.permission.ACCESS_FINE_LOCATION" max_sdk_version = 30 [[package.metadata.android.uses_permission]] name = "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" [[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 [[package.metadata.android.uses_permission]] name = "android.permission.BLUETOOTH_CONNECT" [[package.metadata.android.uses_permission]] name = "android.permission.BLUETOOTH_SCAN" # See https://developer.android.com/guide/topics/manifest/application-element [package.metadata.android.application] # See https://developer.android.com/guide/topics/manifest/application-element#debug # # Defaults to false. debuggable = false # Defaults to the compiled artifact's name. label = "myApp" # See https://developer.android.com/guide/topics/manifest/application-element#extractNativeLibs extract_native_libs = true # See https://developer.android.com/guide/topics/manifest/application-element#usesCleartextTraffic uses_cleartext_traffic = true # See https://developer.android.com/guide/topics/manifest/meta-data-element # # Note: there can be several .meta_data entries. # Note: the `resource` attribute is currently not supported. [[package.metadata.android.application.meta_data]] name = "com.samsung.android.vr.application.mode" value = "vr_only" # See https://developer.android.com/guide/topics/manifest/activity-element [package.metadata.android.application.activity] # See https://developer.android.com/guide/topics/manifest/activity-element#config # # Defaults to "orientation|keyboardHidden|screenSize". config_changes = "orientation" # See https://developer.android.com/guide/topics/manifest/activity-element#label # # Defaults to the application's label. label = "Activity Name" # See https://developer.android.com/guide/topics/manifest/activity-element#lmode # # Defaults to "standard". launch_mode = "singleTop" # See https://developer.android.com/guide/topics/manifest/activity-element#screen # # Defaults to "unspecified". #orientation = "landscape" # See https://developer.android.com/guide/topics/manifest/activity-element#exported # # Unset by default, or true when targeting Android >= 31 (S and up). exported = true # See https://developer.android.com/guide/topics/manifest/activity-element#resizeableActivity # # Defaults to true on Android >= 24, no effect on earlier API levels resizeable_activity = false # See https://developer.android.com/guide/topics/manifest/activity-element#always always_retain_task_state = true # See https://developer.android.com/guide/topics/manifest/meta-data-element # # Note: there can be several .meta_data entries. # Note: the `resource` attribute is currently not supported. [[package.metadata.android.application.activity.meta_data]] name = "com.oculus.vr.focusaware" value = "true" # See https://developer.android.com/guide/topics/manifest/intent-filter-element # # Note: there can be several .intent_filter entries. [[package.metadata.android.application.activity.intent_filter]] # See https://developer.android.com/guide/topics/manifest/action-element actions = ["android.intent.action.VIEW", "android.intent.action.WEB_SEARCH"] # See https://developer.android.com/guide/topics/manifest/category-element categories = ["android.intent.category.DEFAULT", "android.intent.category.BROWSABLE"] # Set up reverse port forwarding through `adb reverse`, meaning that if the # Android device connects to `localhost` on port `1338` it will be routed to # the host on port `1338` instead. Source and destination ports can differ, # see the `adb` help page for possible configurations. [package.metadata.android.reverse_port_forward] "tcp:1338" = "tcp:1338"