Added
- input:
TextInputActionenum representing action button types on soft keyboards. (#216) - input:
InputEvent::TextActionevent for handling action button presses from soft keyboards. (#216) - The
ndkandndk-syscrates are now re-exported underandroid_activity::ndkandandroid_activity::ndk_sys(#194) AndroidApp::java_main_looper()gives access to theALooperfor the Java main / UI thread (#198)AndroidApp::run_on_java_main_thread()can be used to run boxed closures on the Java main / UI thread (#232)- Support for an optional
android_on_createentry point that gets called from theActivity.onCreate()callback beforeandroid_main()is called, allowing for doing some setup work on the Java main / UI thread before theandroid_mainRust code starts running.
For example:
use std::sync::OnceLock;
use android_activity::OnCreateState;
use jni::{JavaVM, refs::Global, objects::JObject};
#[unsafe(no_mangle)]
fn android_on_create(state: &OnCreateState) {
static APP_ONCE: OnceLock<()> = OnceLock::new();
APP_ONCE.get_or_init(|| {
// Initialize logging...
//
// Remember, `android_on_create` may be called multiple times but some
// logger crates will panic if initialized multiple times.
});
let vm = unsafe { JavaVM::from_raw(state.vm_as_ptr().cast()) };
let activity = state.activity_as_ptr() as jni::sys::jobject;
// Although the thread is implicitly already attached (we are inside an onCreate native method)
// using `vm.attach_current_thread` here will use the existing attachment, give us an `&Env`
// reference and also catch Java exceptions.
if let Err(err) = vm.attach_current_thread(|env| -> jni::errors::Result<()> {
// SAFETY:
// - The `Activity` reference / pointer is at least valid until we return
// - By creating a `Cast` we ensure we can't accidentally delete the reference
let activity = unsafe { env.as_cast_raw::<JObject>(&activity)? };
// Do something with the activity on the Java main thread...
Ok(())
}) {
eprintln!("Failed to interact with Android SDK on Java main thread: {err:?}");
}
}- Support for
MotionEventhistory, providing higher fidelity input data for things like stylus input (native-activity+game-activitybackends). (#218)
Changed
- rust-version bumped to 1.85.0 (#193, #219)
- GameActivity updated to 4.4.0 (#191, #240)
ndk-contextis initialized with anApplicationcontext instead of anActivitycontext (#229)
GameActivity 4.4.0 Update
Important: This release is no longer compatible with GameActivity 2.0.2
Android Packaging: Your Android application must be packaged with the corresponding androidX, GameActivity 4.x.x library from Google.
This release has been tested with the androidx.games:games-activity:4.4.0 stable
release, and is backwards
compatible with the 4.0.0 stable release.
If you use Gradle to build your Android application, you can depend on the 4.4.0 release of the GameActivity library via:
dependencies {
implementation 'androidx.appcompat:appcompat:1.7.1'
// To use the Games Activity library
implementation "androidx.games:games-activity:4.4.0"
// Note: don't include game-text-input separately, since it's integrated into game-activity
}Note: there is no guarantee that later 4.x.x releases of GameActivity will be compatible with this release of
android-activity, so please refer to the android-activity release notes for any future updates regarding
GameActivity compatibility.
Initializing ndk-context with an Application Context
ndk-context is a separate, framework-independent crate that provides a way for library crates to access a Java VM pointer and an android.content.Context JNI reference without needing to depend on android-activity directly.
ndk-context may be initialized by various framework crates, including android-activity, on behalf of library crates.
Historically android-activity has initialized ndk-context with an Activity context since that was the simplest choice considering that the entrypoint for android-activity comes from an Activity onCreate callback.
However, in retrospect it was realized that this was a short-sighted mistake when considering that:
ndk-contextonly provides a single, global context reference for the entire application that can't be updated- An Android application can have multiple
Activityinstances over its lifetime (and at times could have noActivityinstances at all, e.g. if the app is running a backgroundService) - Whatever is put into
ndk-contextneeds to leak a corresponding global reference to ensure it remains valid to access safely. This is inappropriate for anActivityreference since it can be destroyed and recreated multiple times over the lifetime of the application.
A far better choice, that aligns with the global nature of the ndk-context API is to initialize it with an Application context which is valid for the entire lifetime of the application.
Note: Although the ndk-context API only promises to provide an android.content.Context and specifically warns that user's should not assume the context is an Activity, there is still some risk that some users of ndk-context could be affected by the change made in #229.
For example, until recently the webbrowser crate (for opening URLs) was assuming it could access an Activity context via ndk-context. In preparation for making this change, webbrowser was updated to ensure it is agnostic to the type of context provided by ndk-context, see: amodm/webbrowser-rs#111
Other notable library crates that support Android (such as app_dirs2) are expected to be unaffected by this, since they already operate in terms of the android.content.Context API, not the Activity API.
_Note:: if some crate really needs an Activity reference then they should ideally be able to get one via the
AndroidApp::activity_as_ptr() API. They may need to add some Android-specific initialization API, similar to how Winit has a dedicated .with_android_app() API. An Android-specific init API that could accept a JNI reference to an Activity could avoid needing to specifically depend on android-activity.
Fixed
- Safety
AndroidApp::asset_manager()returns anAssetManagerthat has a safe'staticlifetime that's not invalidated whenandroid_main()returns (#233) - Safety The
native-activitybackend clears itsANativeActivityptr afteronDestroyandAndroidAppremains safe to access afterandroid_main()returns (#234) - Safety
AndroidApp::activity_as_ptr()returns a pointer to a global reference that remains valid untilAndroidAppis dropped, instead of theANativeActivity'sclazzpointer which is only guaranteed to be valid untilonDestroyreturns (native-activitybackend) (#234) - Safety The
game-activitybackend clears itsandroid_appptr afteronDestroyandAndroidAppremains safe to access afterandroid_main()returns (#236) - Support for
AndroidApp::show/hide_soft_input()APIs in thenative-activitybackend (#178)
Overall, some effort was made to ensure that android-activity can gracefully and safely handle cases where the Activity gets repeatedly created, destroyed and recreated (e.g due to configuration changes). Theoretically it should even be possible to run multiple Activity instances (although that's not really something that NativeActivity or GameActivity are designed for).
New Contributors
- @jb55 made their first contribution in #191
- @madsmtm made their first contribution in #199
- @atouchet made their first contribution in #220
- @markkimsal made their first contribution in #198
- @jancespivo made their first contribution in #178
Full Changelog: v0.6.0...v0.6.1