Update READMEs

This commit is contained in:
Robert Bragg
2022-07-03 23:34:25 +01:00
parent 2264826535
commit b63b5e15fa
8 changed files with 78 additions and 136 deletions
+44 -44
View File
@@ -1,13 +1,23 @@
This project includes a number of Android "glue" crates for native Rust development
(comparable to [`android_native_app_glue.c`][ndk_concepts] which supports C/C++
applications).
# Overview
These glue crates provide a way to load a `cdylib` via the `onCreate` method of
`android-activity` provides a "glue" layer for building native Rust
applications on Android, supporting multiple [`Activity`] base classes.
It's comparable to [`android_native_app_glue.c`][ndk_concepts]
for C/C++ applications.
`android-activity` supports [`NativeActivity`] or [`GameActivity`] from the
Android Game Development Kit and can be extended to support additional base
classes.
`android-activity` provides a way to load a `cdylib` via the `onCreate` method of
your `Activity` class; run an `android_main()` function in a separate thread from the Java
main thread and marshal events (such as lifecycle events and input events) between
Java and your native thread.
[`Activity`]: https://developer.android.com/reference/android/app/Activity
[`NativeActivity`]: https://developer.android.com/reference/android/app/NativeActivity
[ndk_concepts]: https://developer.android.com/ndk/guides/concepts#naa
[`GameActivity`]: https://developer.android.com/games/agdk/integrate-game-activity
### Example
@@ -20,7 +30,7 @@ Cargo.toml
[dependencies]
log = "0.4"
android_logger = "0.11"
native-activity = { git = "https://github.com/rib/agdk-rust/" }
android-activity = { git = "https://github.com/rib/android-activity/", features = [ "native-activity" ] }
[lib]
crate_type = ["cdylib"]
@@ -29,15 +39,14 @@ crate_type = ["cdylib"]
lib.rs
```rust
use log::info;
use native_activity::{PollEvent, MainEvent};
use android_activity::{PollEvent, MainEvent};
#[no_mangle]
extern "C" fn android_main() {
fn android_main(app: AndroidApp) {
android_logger::init_once(
android_logger::Config::default().with_min_level(log::Level::Info)
);
let app = native_activity::android_app();
loop {
app.poll_events(Some(std::time::Duration::from_millis(500)) /* timeout */, |event| {
match event {
@@ -71,8 +80,8 @@ adb logcat example:V *:S
# Game Activity
Originally the aim was to enable support for building Rust applications based on the
[GameActivity] based class provided by [Google's Android Game Development Kit][agdk]
which should also facilitate integration with additional AGDK libraries including:
[GameActivity] class provided by [Google's Android Game Development Kit][agdk]
which can also facilitate integration with additional AGDK libraries including:
1. [Game Text Input](https://developer.android.com/games/agdk/add-support-for-text-input): a library
to help fullscreen native applications utilize the Android soft keyboard.
2. [Game Controller Library, aka 'Paddleboat'](https://developer.android.com/games/sdk/game-controller):
@@ -98,7 +107,7 @@ This project also supports [`NativeActivity`][NativeActivity] based applications
NativeActivity is more limited than `GameActivity` and does not derive from `AppCompatActivity` it
can sometimes still be convenient to build on `NativeActivity` in situations where you are using a
limited/minimal build system that is not able to compile Java or Kotlin code or fetch from Maven
repositories. This is because `NativeActivity` is included as part of the Android platform.
repositories - this is because `NativeActivity` is included as part of the Android platform.
[NativeActivity]: https://developer.android.com/reference/android/app/NativeActivity
@@ -106,18 +115,12 @@ repositories. This is because `NativeActivity` is included as part of the Androi
## Compatibility
Both the [game-activity] glue crate and the [native-activity] glue crate support a common API that allows
them to be used interchangably, depending on which base class your application decides to use.
All `Activity` classes are supported via a common API that enables you to write
`Activity` subclass agnostic code wherever you don't depend on features that are
specific to a particular subclass.
Although it's expected that the `game-activity` crate will gain features that aren't possible with `native-activity`
those should be covered by optional features that allow downstream crates, such as Winit to practically be
able to support alternative glue layers.
The hope is that the core, common API can be supported via any Activity subclass that your
application needs to use.
[game-activity]: https://github.com/rib/agdk-rust/tree/main/game-activity
[native-activity]: https://github.com/rib/agdk-rust/tree/main/native-activity
For example, it makes it possible to have a [Winit backend](https://github.com/rib/winit/tree/agdk-game-activity)
that supports Android applications running with different `Activity` classes.
## API Summary
@@ -126,48 +129,45 @@ application needs to use.
The glue crates define a standard entrypoint ABI for your `cdylib` that looks like:
```rust
use android_activity::AndroidApp;
#[no_mangle]
extern "C" fn android_main() {
fn android_main(app: AndroidApp) {
...
}
```
There's currently no high-level macro provided for things like initializing logging or allowing the
main function to return a `Result<>` since it's expected that different downstream frameworks may
each have differing oppinions on the details and may want to provide their own macros.
There's currently no high-level macro provided for things like initializing
logging or allowing the main function to return a `Result<>` since it's expected
that different downstream frameworks may each have differing opinions on the
details and may want to provide their own macros.
### Global `AndroidApp`
The glue layer provides a `'static` `AndroidApp` API to access state about your running application
and handle synchronized interaction between your native Rust application and the `Activity` running
on the Java main thread.
### `AndroidApp`
Your `android_main()` function is passed an `AndroidApp` struct to access state
about your running application and handle synchronized interaction between your
native Rust application and the `Activity` running on the Java main thread.
For example, the `AndroidApp` API enables:
1. Access to Android lifecycle events
2. Notifications of SurfaceView lifecycle events
3. Access to input events
4. Ability to save and restore state each time your process stops and starts
5. Access application [`Configuration`] state
6. internal/external/obb filesystem paths
For example:
```rust
#[no_mangle]
extern "C" fn android_main() {
let app = game_activity::android_app();
...
}
```
_Note: that some of the `AndroidApp` APIs (such as for polling events) are only deemed safe to use
from the application's main thread_
_Note: that some of the `AndroidApp` APIs (such as for polling events) are only
deemed safe to use from the application's main thread_
[`Configuration`]: https://developer.android.com/reference/android/content/res/Configuration
### Synchronized event callbacks
The `AndroidApp::poll_events()` API is similar to the Winit `EventLoop::run` API in that it
takes a `FnMut` closure that is called for each outstanding event (such as for lifecycle events).
This is modeled on the original `android_native_app_glue` design for C/C++ that reserves the
ability for the glue layer to insert "pre-" and "-post" hooks around the application's event
callback that can handle any required synchronization with the Java main thread.
This design ensures the glue layer can transparently handle any required synchronization with
Java before and after each callback.
For example, when the Java main thread notifies the glue layer that its `SurfaceView` is being
destroyed the Java thread will then block until it gets an explicit acknowledgement that the
-40
View File
@@ -1,40 +0,0 @@
This crate provides a "glue" layer for building native Rust applications on Android, supporting multiple `Activity` base classes that the application can choose.
Currently the crate supports `NativeActivity` or [`GameActivity`](https://developer.android.com/games/agdk/integrate-game-activity) from the Android Game Development Kit.
This serves a similar purpose to [`android_native_app_glue.c`](https://android.googlesource.com/platform/development/+/4948c163663ecc343c97e4c2a2139234f1d3273f/ndk/sources/android/native_app_glue) for `C/C++` applications.
Here's a minimal illustration of an Android main function and main loop based on this crate:
```rust
use log::info;
use android_activity::{AndroidApp, PollEvent, MainEvent};
#[no_mangle]
fn android_main(app: AndroidApp) {
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| {
match event {
PollEvent::Wake => { info!("Early wake up"); },
PollEvent::Timeout => { info!("Timed out"); },
PollEvent::Main(main_event) => {
info!("Main event: {:?}", main_event);
match main_event {
MainEvent::Destroy => { return; }
_ => {}
}
},
_ => {}
}
app.input_events(|event| {
info!("Input Event: {event:?}");
});
});
}
}
```
+6 -10
View File
@@ -1,21 +1,17 @@
This tests using the game_activity crate with egui, winit and wgpu.
This tests using `GameActivity` with egui, winit and wgpu.
This is based on a re-worked winit backend here:
https://github.com/rib/winit/tree/agdk-game-activity
and based on updated egui-winit and egui-wgpu crates here:
https://github.com/rib/egui/tree/android-deferred-winit-wgpu
https://github.com/rib/winit/tree/android-activity
```
rustup target add aarch64-linux-android
export ANDROID_NDK_HOME="path/to/ndk"
export ANDROID_HOME="path/to/sdk"
rustup target add aarch64-linux-android
cargo install cargo-ndk
export ANDROID_NDK_HOME="path/to/ndk"
cargo ndk -t arm64-v8a -o app/src/main/jniLibs/ build
export ANDROID_HOME="path/to/sdk"
./gradlew build
./gradlew installDebug
adb shell am start -n co.realfit.agdkegui/.MainActivity
```
```
+8 -10
View File
@@ -1,19 +1,17 @@
This is a minimal test application that just runs a mainloop based
on game_activity::poll_events() and traces the events received
without doing any rendering. It also saves and restores some
minimal application state.
This is a minimal test application based on `GameActivity` that just
runs a mainloop based on android_activity::poll_events() and traces
the events received without doing any rendering. It also saves and
restores some minimal application state.
```
rustup target add aarch64-linux-android
export ANDROID_NDK_HOME="path/to/ndk"
export ANDROID_HOME="path/to/sdk"
rustup target add aarch64-linux-android
cargo install cargo-ndk
export ANDROID_NDK_HOME="path/to/ndk"
cargo ndk -t arm64-v8a -o app/src/main/jniLibs/ build
export ANDROID_HOME="path/to/sdk"
./gradlew build
./gradlew installDebug
adb shell am start -n co.realfit.agdkmainloop/.MainActivity
```
```
+5 -6
View File
@@ -1,7 +1,7 @@
This tests using the game_activity crate with winit and wgpu.
This tests using `GameActivity` with winit and wgpu.
This is based on a re-worked winit backend here:
https://github.com/rib/winit/tree/agdk-game-activity
https://github.com/rib/winit/tree/android-activity
Although it would have been possible to handle the suspend/resume
lifecycle events with a simpler approach of destroying and
@@ -16,14 +16,13 @@ applications (that need to be portable) can work. (enable
"desktop" feature to build binary)
```
rustup target add aarch64-linux-android
export ANDROID_NDK_HOME="path/to/ndk"
export ANDROID_HOME="path/to/sdk"
rustup target add aarch64-linux-android
cargo install cargo-ndk
export ANDROID_NDK_HOME="path/to/ndk"
cargo ndk -t arm64-v8a -o app/src/main/jniLibs/ build
export ANDROID_HOME="path/to/sdk"
./gradlew build
./gradlew installDebug
adb shell am start -n co.realfit.agdkwinitwgpu/.MainActivity
+9 -16
View File
@@ -1,31 +1,22 @@
This is a minimal test application similar to `agdk-mainloop` that
is based on `NativeActivity` instead of `GameActivity`.
It shows how to run a mainloop based on `native_activity::poll_events()` and
traces the events received without doing any rendering. It also saves and
This is a minimal test application based on `NativeActivity` that just
runs a mainloop based on android_activity::poll_events() and traces
the events received without doing any rendering. It also saves and
restores some minimal application state.
Since this test doesn't require a custom `Activity` subclass it's
optionally possible to build this example with `cargo apk`.
The idea here is to test whether we can have a `NativeActivity` based
glue layer which is API compatible with `game-activity`, which can
optionally be used for _very_ basic tests/demos that want the convenience
of not needing to compile any Java code.
# Gradle Build
```
rustup target add aarch64-linux-android
export ANDROID_NDK_HOME="path/to/ndk"
export ANDROID_HOME="path/to/sdk"
rustup target add aarch64-linux-android
cargo install cargo-ndk
export ANDROID_NDK_HOME="path/to/ndk"
cargo ndk -t arm64-v8a -o app/src/main/jniLibs/ build
export ANDROID_HOME="path/to/sdk"
./gradlew build
./gradlew installDebug
adb shell am start -n co.realfit.namainloop/.MainActivity
```
# Cargo APK Build
@@ -33,7 +24,9 @@ adb shell am start -n co.realfit.namainloop/.MainActivity
export ANDROID_NDK_HOME="path/to/ndk"
export ANDROID_SDK_HOME="path/to/sdk"
rustup target add aarch64-linux-android
cargo install cargo-apk
cargo apk build
cargo apk run
```
```
+3 -4
View File
@@ -7,14 +7,13 @@ Note: unlike the `na-mainloop` example, this one can't be built via
# Gradle Build
```
rustup target add aarch64-linux-android
export ANDROID_NDK_HOME="path/to/ndk"
export ANDROID_HOME="path/to/sdk"
rustup target add aarch64-linux-android
cargo install cargo-ndk
export ANDROID_NDK_HOME="path/to/ndk"
cargo ndk -t arm64-v8a -o app/src/main/jniLibs/ build
export ANDROID_HOME="path/to/sdk"
./gradlew build
./gradlew installDebug
adb shell am start -n co.realfit.nasubclassjni/.MainActivity
+3 -6
View File
@@ -1,8 +1,5 @@
This is the same as agdk-winit-wgpu except it enables the "native-activity"
feature for winit, for running with `NativeActivity` instead of `GameActivity`
This is to see if it's practical to support multiple glue implementations with
a common API.
This is the same as agdk-winit-wgpu except it runs with `NativeActivity`
instead of `GameActivity`
# Gradle Build
```
@@ -23,7 +20,7 @@ export ANDROID_NDK_HOME="path/to/ndk"
export ANDROID_SDK_HOME="path/to/sdk"
rustup target add aarch64-linux-android
cargo install cargo-apk
cargo apk run
```