-
-
Notifications
You must be signed in to change notification settings - Fork 185
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"