Overview
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
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.
Example
cargo init --lib --name=example
Cargo.toml
[dependencies]
log = "0.4"
android_logger = "0.11"
android-activity = { git = "https://github.com/rib/android-activity/", features = [ "native-activity" ] }
[lib]
crate_type = ["cdylib"]
lib.rs
use info;
use ;
rustup target add aarch64-linux-android
cargo install cargo-apk
cargo apk run
adb logcat example:V *:S
Game Activity
Originally the aim was to enable support for building Rust applications based on the GameActivity class provided by Google's Android Game Development Kit which can also facilitate integration with additional AGDK libraries including:
- Game Text Input: a library to help fullscreen native applications utilize the Android soft keyboard.
- Game Controller Library, aka 'Paddleboat': a native library designed to help support access to game controller inputs. 3.Frame Pacing Library, aka ' Swappy': a library that helps OpenGL and Vulkan games achieve smooth rendering and correct frame pacing on Android.
- Memory Advice API: an API to help applications monitor their own memory usage to stay within safe limits for the system.
- Oboe audio library: a low-latency audio API for native applications.
Since GameActivity is based on the widely used AppCompatActivity base class, it also
provides a variety of back ported Activity APIs which can make it more practical to
support a wider range of devices and Android versions.
Native Activity
This project also supports NativeActivity based applications. Although
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.
Design
Compatibility
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.
For example, it makes it possible to have a Winit backend
that supports Android applications running with different Activity classes.
API Summary
android_main entrypoint
The glue crates define a standard entrypoint ABI for your cdylib that looks like:
use 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 opinions on the
details and may want to provide their own macros.
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:
- Access to Android lifecycle events
- Notifications of SurfaceView lifecycle events
- Access to input events
- Ability to save and restore state each time your process stops and starts
- Access application
Configurationstate - internal/external/obb filesystem paths
Note: that some of the AndroidApp APIs (such as for polling events) are only
deemed safe to use from the application's main thread
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 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
native application has had an opportunity to react to this notification. The glue layer will
automatically release the blocked Java thread once it has delivered the corresponding event.
For example:
use ;
use info;
extern "C"