Skip to content

Release 0.6.1#244

Merged
rib merged 2 commits intomainfrom
release-0.6.1
Mar 24, 2026
Merged

Release 0.6.1#244
rib merged 2 commits intomainfrom
release-0.6.1

Conversation

@rib
Copy link
Member

@rib rib commented Mar 23, 2026

Added

  • input: TextInputAction enum representing action button types on soft keyboards. (#216)
  • input: InputEvent::TextAction event for handling action button presses from soft keyboards. (#216)
  • The ndk and ndk-sys crates are now re-exported under android_activity::ndk and android_activity::ndk_sys (#194)
  • AndroidApp::java_main_looper() gives access to the ALooper for 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_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 / UI thread before the android_main Rust 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 MotionEvent history, providing higher fidelity input data for things like stylus input (native-activity + game-activity backends). (#218)

Changed

  • rust-version bumped to 1.85.0 (#193, #219)
  • GameActivity updated to 4.4.0 (#191, #240)
  • ndk-context is initialized with an Application context instead of an Activity context (#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:

  1. ndk-context only provides a single, global context reference for the entire application that can't be updated
  2. An Android application can have multiple Activity instances over its lifetime (and at times could have no Activity instances at all, e.g. if the app is running a background Service)
  3. Whatever is put into ndk-context needs to leak a corresponding global reference to ensure it remains valid to access safely. This is inappropriate for an Activity reference 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 an AssetManager that has a safe 'static lifetime that's not invalidated when android_main() returns (#233)
  • Safety The native-activity backend clears its ANativeActivity ptr after onDestroy and AndroidApp remains safe to access after android_main() returns (#234)
  • Safety AndroidApp::activity_as_ptr() returns a pointer to a global reference that remains valid until AndroidApp is dropped, instead of the ANativeActivity's clazz pointer which is only guaranteed to be valid until onDestroy returns (native-activity backend) (#234)
  • Safety The game-activity backend clears its android_app ptr after onDestroy and AndroidApp remains safe to access after android_main() returns (#236)
  • Support for AndroidApp::show/hide_soft_input() APIs in the native-activity backend (#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).

@rib rib force-pushed the release-0.6.1 branch 2 times, most recently from 6ae7ee0 to 9789d35 Compare March 23, 2026 18:59
@rib rib merged commit 11a5a54 into main Mar 24, 2026
10 checks passed
@rib rib deleted the release-0.6.1 branch March 24, 2026 00:47
@rib rib mentioned this pull request Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant