mirror of
https://github.com/rust-mobile/android-activity.git
synced 2026-07-04 05:47:26 +00:00
Support an optional 'android_on_create' entrypoint
This adds support for an optional `android_on_crate` entrypoint which is called from within the Activity.onCreate native method callback from the Java main / UI thread. This gives applications an opportunity initialize state while the `Activity`'s class loader is on the stack, so `FindClass` will be able to find application classes. This can be a more-convenient place to initialize JNI bindings, without needing to explicitly get the class loader from the Activity to be able to look up application classes from the android_main thread. This may also be convenient for initially using JNI to interact with your new Activity in case you need to use SDK APIs that are only safe to use from the Java main / UI thread. The moves the thread initialization functions out of util.rs into a new init.rs While adding documentation for this feature, this also does a more-general pass over the top-level crate documentation to try and ensure it's up-to-date. Fixes: #169 Addresses: #82
This commit is contained in:
@@ -37,22 +37,33 @@ Cargo.toml
|
||||
[dependencies]
|
||||
log = "0.4"
|
||||
android_logger = "0.13"
|
||||
android-activity = { version = "0.5", features = [ "native-activity" ] }
|
||||
android-activity = { version = "0.6", features = [ "native-activity" ] }
|
||||
|
||||
[lib]
|
||||
crate_type = ["cdylib"]
|
||||
crate-type = ["cdylib"]
|
||||
```
|
||||
|
||||
_Note: that you will need to either specify the **"native-activity"** feature or **"game-activity"** feature to identify which `Activity` base class your application is based on_
|
||||
_Note: that you will need to either specify the **"native-activity"** feature or
|
||||
**"game-activity"** feature to identify which `Activity` base class your
|
||||
application is based on_
|
||||
|
||||
lib.rs
|
||||
|
||||
```rust
|
||||
use android_activity::{AndroidApp, InputStatus, MainEvent, PollEvent};
|
||||
|
||||
#[no_mangle]
|
||||
#[unsafe(no_mangle)]
|
||||
fn android_main(app: AndroidApp) {
|
||||
android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info));
|
||||
|
||||
// `android_main` is tied to your `Activity` lifecycle, not your application lifecycle
|
||||
// and so it may be called multiple times if your activity is destroyed and recreated.
|
||||
//
|
||||
// Use a `OnceLock` or similar to ensure that you don't attempt to initialize global state
|
||||
// multiple times.
|
||||
static APP_ONCE: OnceLock<()> = OnceLock::new();
|
||||
APP_ONCE.get_or_init(|| {
|
||||
android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info));
|
||||
});
|
||||
|
||||
loop {
|
||||
app.poll_events(Some(std::time::Duration::from_millis(500)) /* timeout */, |event| {
|
||||
@@ -62,6 +73,11 @@ fn android_main(app: AndroidApp) {
|
||||
PollEvent::Main(main_event) => {
|
||||
log::info!("Main event: {:?}", main_event);
|
||||
match main_event {
|
||||
// Once you receive a `Destroy` event, your `AndroidApp` will no longer
|
||||
// be associated with any `Activity` and it's methods will effectively be no-ops.
|
||||
//
|
||||
// You should return from `android_main` and if your `Activity` gets recreated then
|
||||
// a new `AndroidApp` will be passsed to a new invocation of `android_main`.
|
||||
MainEvent::Destroy => { return; }
|
||||
_ => {}
|
||||
}
|
||||
@@ -85,6 +101,36 @@ cargo apk run
|
||||
adb logcat example:V *:S
|
||||
```
|
||||
|
||||
## Optional `android_on_create` entry point
|
||||
|
||||
`android-activity` also supports an optional `android_on_create` entry point that gets called from the
|
||||
`Activity.onCreate()` callback before `android_main()` is called, allowing for doing some setup work on the Java main
|
||||
thread before the main Rust code starts running.
|
||||
|
||||
For example:
|
||||
|
||||
```rust
|
||||
use std::sync::OnceLock;
|
||||
use jni::{JavaVM, objects::JObject};
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
fn android_on_create(state: &android_activity::OnCreateState) {
|
||||
|
||||
// `android_on_create` is tied to your `Activity` lifecycle, not your application lifecycle
|
||||
// and so it may be called multiple times if your activity is destroyed and recreated.
|
||||
//
|
||||
// Use a `OnceLock` or similar to ensure that you don't attempt to initialize global state
|
||||
// multiple times.
|
||||
static APP_ONCE: OnceLock<()> = OnceLock::new();
|
||||
APP_ONCE.get_or_init(|| {
|
||||
// Initialize logging...
|
||||
});
|
||||
let vm = unsafe { JavaVM::from_raw(state.vm_as_ptr().cast()) };
|
||||
let activity = state.activity_as_ptr() as jni::sys::jobject;
|
||||
// Do some other setup work on the Java main thread before `android_main` starts running
|
||||
}
|
||||
```
|
||||
|
||||
## Full Examples
|
||||
|
||||
See [this collection of examples](https://github.com/rust-mobile/rust-android-examples) (based on both `GameActivity` and `NativeActivity`).
|
||||
@@ -111,7 +157,7 @@ Even if you start out using `NativeActivity` for the convenience, it's likely th
|
||||
|
||||
Firstly; if you have a [Winit](https://crates.io/crates/winit) based application and also have an explicit dependency on `ndk-glue` your application will need to remove its dependency on `ndk-glue` for the 0.28 release of Winit which will be based on android-activity (Since glue crates, due to their nature, can't be compatible with alternative glue crates).
|
||||
|
||||
Winit-based applications can follow the [Android documentation](https://docs.rs/winit/latest/winit/platform/android/index.html) guidance for advice on how to switch over. Most Winit-based applications should aim to remove any explicit dependency on a specific glue crate (so not depend directly on `ndk-glue` or `android-activity` and instead rely on Winit to pull in the right glue crate). The main practical change will then be to add a `#[no_mangle]fn android_main(app: AndroidApp)` entry point.
|
||||
Winit-based applications can follow the [Android documentation](https://docs.rs/winit/latest/winit/platform/android/index.html) guidance for advice on how to switch over. Most Winit-based applications should aim to remove any explicit dependency on a specific glue crate (so not depend directly on `ndk-glue` or `android-activity` and instead rely on Winit to pull in the right glue crate). The main practical change will then be to add a `#[unsafe(no_mangle)]fn android_main(app: AndroidApp)` entry point.
|
||||
|
||||
See the [Android documentation](https://docs.rs/winit/latest/winit/platform/android/index.html) for more details and also see the [Winit-based examples here](https://github.com/rust-mobile/rust-android-examples).
|
||||
|
||||
@@ -126,7 +172,7 @@ Middleware libraries can instead look at using the [ndk-context](https://crates.
|
||||
The steps to switch a simple standalone application over from `ndk-glue` to `android-activity` (still based on `NativeActivity`) should be:
|
||||
|
||||
1. Remove `ndk-glue` from your Cargo.toml
|
||||
2. Add a dependency on `android-activity`, like `android-activity = { version="0.5", features = [ "native-activity" ] }`
|
||||
2. Add a dependency on `android-activity`, like `android-activity = { version="0.6", features = [ "native-activity" ] }`
|
||||
3. Optionally add a dependency on `android_logger = "0.13.0"`
|
||||
4. Update the `main` entry point to look like this:
|
||||
|
||||
|
||||
Reference in New Issue
Block a user