A Rust library for handling Android permissions in Android apps written in Rust with the Android NDK. This library provides a simple and idiomatic Rust interface for checking and requesting Android permissions.
- Check if a permission is granted
- Request one or multiple permissions synchronously
- Request one or multiple permissions asynchronously (with
asyncfeature) - Predefined constants for common Android permissions
- Automatic handling of permission request callbacks
- Seamless integration with Android NDK projects
Add this to your Cargo.toml:
[dependencies]
android-permissions = "0.1.2"To enable async support, enable the async feature:
[dependencies]
android-permissions = { version = "0.1.2", features = ["async"] }Add the required permissions to your AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />In your Cargo.toml, add the permissions metadata:
[[package.metadata.android.uses_permission]]
name = "android.permission.WRITE_EXTERNAL_STORAGE"
[[package.metadata.android.uses_permission]]
name = "android.permission.CAMERA"Here's a complete example of how to use the library synchronously:
use android_permissions::{self as permissions, Permission, PermissionManager, Result};
use jni::objects::{JObject, JValue};
use log::{error, info};
use std::collections::HashMap;
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
pub fn main() {
android_logger::init_once(
android_logger::Config::default().with_max_level(log::LevelFilter::Trace),
);
log::info!("Rust main function started.");
let native_activity = ndk_glue::native_activity();
let vm = unsafe { jni::JavaVM::from_raw(native_activity.vm()) }.expect("Failed to get JavaVM");
let activity_obj = native_activity.activity();
info!("App main function entered.");
let manager =
match permissions::PermissionManager::create(vm, unsafe { JObject::from_raw(native_activity.activity()) }) {
Ok(m) => m,
Err(e) => {
error!("Failed to create PermissionManager: {}", e);
return;
}
};
info!("PermissionManager created successfully.");
if let Err(e) = run_permission_demo(&manager) {
error!("An error occurred during permission demo: {}", e);
}
info!("Permission demo finished. The app will now idle.");
}
fn run_permission_demo(manager: &PermissionManager) -> Result<()> {
info!("Checking for CAMERA permission...");
match manager.check(&permissions::CAMERA) {
Ok(has_permission) => info!("Do we have CAMERA permission? -> {}", has_permission),
Err(e) => error!("Error checking for CAMERA permission: {}", e),
}
let permissions_to_request = &[
&permissions::CAMERA,
&permissions::WRITE_EXTERNAL_STORAGE,
&permissions::READ_EXTERNAL_STORAGE,
];
info!(
"Requesting permissions: {:?}",
permissions_to_request
.iter()
.map(|p| p.as_str())
.collect::<Vec<_>>()
);
match manager.request(permissions_to_request) {
Ok(grants) => {
info!("Permission request finished. Results:");
for (permission, granted) in &grants {
info!(
" - {}: {}",
permission,
if *granted { "GRANTED" } else { "DENIED" }
);
}
if grants.values().all(|&g| g) {
info!("All requested permissions were granted!");
} else {
info!("Some permissions were denied.");
}
}
Err(e) => error!("Error requesting permissions: {}", e),
}
Ok(())
}Here's an example using async/await (requires async feature):
use android_permissions::{self as permissions, Permission, PermissionManager, Result};
use jni::objects::{JObject, JValue};
use log::{error, info};
use std::collections::HashMap;
use std::future::Future;
#[cfg_attr(target_os = "android", ndk_glue::main(backtrace = "on"))]
pub fn main() {
android_logger::init_once(
android_logger::Config::default().with_max_level(log::LevelFilter::Trace),
);
log::info!("Rust main function started.");
let native_activity = ndk_glue::native_activity();
let vm = unsafe { jni::JavaVM::from_raw(native_activity.vm()) }.expect("Failed to get JavaVM");
let activity_obj = native_activity.activity();
let runtime = tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.unwrap();
runtime.block_on(async move {
info!("Async app main function entered.");
let manager =
match permissions::PermissionManager::create(vm, unsafe { JObject::from_raw(native_activity.activity()) }) {
Ok(m) => m,
Err(e) => {
error!("Failed to create PermissionManager: {}", e);
return;
}
};
info!("PermissionManager created successfully.");
if let Err(e) = run_permission_demo(&manager).await {
error!("An error occurred during permission demo: {}", e);
}
info!("Permission demo finished. The app will now idle.");
});
}
async fn run_permission_demo(manager: &PermissionManager) -> Result<()> {
info!("Checking for CAMERA permission...");
match manager.check(&permissions::CAMERA) {
Ok(has_permission) => info!("Do we have CAMERA permission? -> {}", has_permission),
Err(e) => error!("Error checking for CAMERA permission: {}", e),
}
let permissions_to_request = &[
&permissions::CAMERA,
&permissions::WRITE_EXTERNAL_STORAGE,
&permissions::READ_EXTERNAL_STORAGE,
];
info!(
"Requesting permissions: {:?}",
permissions_to_request
.iter()
.map(|p| p.as_str())
.collect::<Vec<_>>()
);
match manager.request_async(permissions_to_request).await {
Ok(grants) => {
info!("Permission request finished. Results:");
for (permission, granted) in &grants {
info!(
" - {}: {}",
permission,
if *granted { "GRANTED" } else { "DENIED" }
);
}
if grants.values().all(|&g| g) {
info!("All requested permissions were granted!");
} else {
info!("Some permissions were denied.");
}
}
Err(e) => error!("Error requesting permissions: {}", e),
}
Ok(())
}Initialize the permission manager with the JavaVM and Activity references.
Initialize the permission manager with an android-activity::AndroidApp reference. Requires the android-activity feature.
Check if a specific permission is granted.
Request one or more permissions from the user synchronously. Returns a map of permission names to their granted status.
PermissionManager.request_async(permissions: &[&Permission]) -> Future<Result<HashMap<String, bool>>>
Request one or more permissions from the user asynchronously. Returns a future that resolves with a map of permission names to their granted status. Requires the async feature.
The library provides constants for common Android permissions:
CAMERAREAD_EXTERNAL_STORAGEWRITE_EXTERNAL_STORAGEACCESS_FINE_LOCATIONACCESS_COARSE_LOCATIONRECORD_AUDIOPOST_NOTIFICATIONSREAD_MEDIA_IMAGESREAD_MEDIA_VIDEOREAD_MEDIA_AUDIOREAD_CONTACTSWRITE_CONTACTSGET_ACCOUNTSREAD_CALENDARWRITE_CALENDARSEND_SMSRECEIVE_SMSREAD_SMSCALL_PHONEREAD_PHONE_STATE
MIT