From 0592236adaa55e663a9446d1fc5d9f31c19951e6 Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 28 Jul 2026 15:47:44 +0800 Subject: [PATCH 01/11] refactor: changes for tao 0.36 lifecycle renames --- src/android/kotlin/Rust.kt | 16 ++++++++-------- src/android/kotlin/WryActivity.kt | 16 ++++++++-------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/android/kotlin/Rust.kt b/src/android/kotlin/Rust.kt index f10f47d58..75ccd7180 100644 --- a/src/android/kotlin/Rust.kt +++ b/src/android/kotlin/Rust.kt @@ -16,18 +16,18 @@ object Rust { System.loadLibrary("{{library}}") } - @JvmStatic external fun onActivityCreate(activity: WryActivity) - @JvmStatic external fun onActivityDestroy(activity: WryActivity) - @JvmStatic external fun onActivitySaveInstanceState() - @JvmStatic external fun onActivityLowMemory() + @JvmStatic external fun onCreate(activity: WryActivity) + @JvmStatic external fun onStart(activity: WryActivity) + @JvmStatic external fun onResume(activity: WryActivity) + @JvmStatic external fun onPause(activity: WryActivity) + @JvmStatic external fun onStop(activity: WryActivity) + @JvmStatic external fun onSaveInstanceState(activity: WryActivity) + @JvmStatic external fun onDestroy(activity: WryActivity) + @JvmStatic external fun onLowMemory(activity: WryActivity) @JvmStatic external fun onWindowFocusChanged(activity: WryActivity, focus: Boolean) @JvmStatic external fun onNewIntent(intent: Intent) @JvmStatic external fun create() - @JvmStatic external fun start(activity: WryActivity) - @JvmStatic external fun resume(activity: WryActivity) - @JvmStatic external fun pause(activity: WryActivity) - @JvmStatic external fun stop(activity: WryActivity) @JvmStatic external fun wryCreate() @JvmStatic external fun onWebviewDestroy(activity: WryActivity, webviewId: String) diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index db38174db..2ae0b2783 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -126,12 +126,12 @@ abstract class WryActivity : AppCompatActivity() { } ProcessLifecycleOwner.get().lifecycle.addObserver(WryLifecycleObserver) - Rust.onActivityCreate(this) + Rust.onCreate(this) } override fun onStart() { super.onStart() - Rust.start(this) + Rust.onStart(this) } override fun onWindowFocusChanged(hasFocus: Boolean) { @@ -142,12 +142,12 @@ abstract class WryActivity : AppCompatActivity() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putInt(ACTIVITY_ID_KEY, id) - Rust.onActivitySaveInstanceState() + Rust.onSaveInstanceState(this) } override fun onPause() { super.onPause() - Rust.pause(this) + Rust.onPause(this) if (::mWebView.isInitialized) { mWebView.onPause() } @@ -155,7 +155,7 @@ abstract class WryActivity : AppCompatActivity() { override fun onResume() { super.onResume() - Rust.resume(this) + Rust.onResume(this) if (::mWebView.isInitialized) { mWebView.onResume() } @@ -163,18 +163,18 @@ abstract class WryActivity : AppCompatActivity() { override fun onStop() { super.onStop() - Rust.stop(this) + Rust.onStop(this) } override fun onDestroy() { super.onDestroy() - Rust.onActivityDestroy(this) + Rust.onDestroy(this) Rust.onWebviewDestroy(this, if (::mWebView.isInitialized) { mWebView.id } else { "" }) } override fun onLowMemory() { super.onLowMemory() - Rust.onActivityLowMemory() + Rust.onLowMemory(this) } override fun onNewIntent(intent: Intent) { From a7f2b4dbfa987aa9c25649f487eaa5a093d25649 Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 28 Jul 2026 19:06:33 +0800 Subject: [PATCH 02/11] Update --- src/android/kotlin/Rust.kt | 7 +++---- src/android/kotlin/WryActivity.kt | 5 ++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/android/kotlin/Rust.kt b/src/android/kotlin/Rust.kt index 75ccd7180..af151886c 100644 --- a/src/android/kotlin/Rust.kt +++ b/src/android/kotlin/Rust.kt @@ -16,19 +16,18 @@ object Rust { System.loadLibrary("{{library}}") } + // Tao bindings + @JvmStatic external fun onFirstActivityCreate() @JvmStatic external fun onCreate(activity: WryActivity) @JvmStatic external fun onStart(activity: WryActivity) @JvmStatic external fun onResume(activity: WryActivity) @JvmStatic external fun onPause(activity: WryActivity) @JvmStatic external fun onStop(activity: WryActivity) - @JvmStatic external fun onSaveInstanceState(activity: WryActivity) @JvmStatic external fun onDestroy(activity: WryActivity) - @JvmStatic external fun onLowMemory(activity: WryActivity) @JvmStatic external fun onWindowFocusChanged(activity: WryActivity, focus: Boolean) + @JvmStatic external fun onLowMemory() @JvmStatic external fun onNewIntent(intent: Intent) - @JvmStatic external fun create() - @JvmStatic external fun wryCreate() @JvmStatic external fun onWebviewDestroy(activity: WryActivity, webviewId: String) diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index 2ae0b2783..a372a0320 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -25,7 +25,7 @@ private val ACTIVITY_ID_KEY = "__wryActivityId" object WryLifecycleObserver : DefaultLifecycleObserver { override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) - Rust.create() + Rust.onFirstActivityCreate() Rust.wryCreate() } } @@ -142,7 +142,6 @@ abstract class WryActivity : AppCompatActivity() { override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putInt(ACTIVITY_ID_KEY, id) - Rust.onSaveInstanceState(this) } override fun onPause() { @@ -174,7 +173,7 @@ abstract class WryActivity : AppCompatActivity() { override fun onLowMemory() { super.onLowMemory() - Rust.onLowMemory(this) + Rust.onLowMemory() } override fun onNewIntent(intent: Intent) { From 70c855c26ac5f57140ffe90908ba6e903e2664ff Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 28 Jul 2026 19:17:19 +0800 Subject: [PATCH 03/11] Make it easier to see that `onCreate` runs first --- src/android/kotlin/WryActivity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index a372a0320..e913eff78 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -125,8 +125,8 @@ abstract class WryActivity : AppCompatActivity() { activityListener?.invoke(result) } - ProcessLifecycleOwner.get().lifecycle.addObserver(WryLifecycleObserver) Rust.onCreate(this) + ProcessLifecycleOwner.get().lifecycle.addObserver(WryLifecycleObserver) } override fun onStart() { From f96ea1b81a2ceab9c3298381bd490f7bfc61c209 Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 28 Jul 2026 19:17:32 +0800 Subject: [PATCH 04/11] more docs --- src/android/binding.rs | 1 + src/android/kotlin/WryActivity.kt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/android/binding.rs b/src/android/binding.rs index fc2041a4f..9d42c3d70 100644 --- a/src/android/binding.rs +++ b/src/android/binding.rs @@ -273,6 +273,7 @@ fn handle_request( Ok(*web_resource_response) } +/// This is called on the first activity created #[allow(non_snake_case)] pub unsafe fn wryCreate(env: JNIEnv, _: JClass) { let mut main_pipe = MainPipe { env }; diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index e913eff78..2b9d34758 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -23,6 +23,7 @@ import androidx.lifecycle.ProcessLifecycleOwner private val ACTIVITY_ID_KEY = "__wryActivityId" object WryLifecycleObserver : DefaultLifecycleObserver { + // This only runs once: https://developer.android.com/reference/androidx/lifecycle/ProcessLifecycleOwner override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) Rust.onFirstActivityCreate() @@ -185,6 +186,7 @@ abstract class WryActivity : AppCompatActivity() { return Class.forName(name) } + // Called by tao through JNI fun startActivity(cls: Class<*>): Int { val intent = Intent(this, cls) val id = kotlin.random.Random.nextInt() From 11dab6bcc0a472f2bd6555d7f545bdd08fda4232 Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 28 Jul 2026 20:53:23 +0800 Subject: [PATCH 05/11] Try to use an atomic bool instead of ProcessLifecycleOwner --- src/android/kotlin/WryActivity.kt | 26 +++++++++----------------- 1 file changed, 9 insertions(+), 17 deletions(-) diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index 2b9d34758..1307db971 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -9,27 +9,16 @@ import android.content.Intent import android.os.Build import android.os.Bundle import android.webkit.WebView -import android.view.KeyEvent import androidx.activity.OnBackPressedCallback import androidx.activity.result.ActivityResult -import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.ProcessLifecycleOwner - -private val ACTIVITY_ID_KEY = "__wryActivityId" - -object WryLifecycleObserver : DefaultLifecycleObserver { - // This only runs once: https://developer.android.com/reference/androidx/lifecycle/ProcessLifecycleOwner - override fun onCreate(owner: LifecycleOwner) { - super.onCreate(owner) - Rust.onFirstActivityCreate() - Rust.wryCreate() - } -} +import java.util.concurrent.atomic.AtomicBoolean + +private const val ACTIVITY_ID_KEY = "__wryActivityId" + +val firstActivity = AtomicBoolean(true) abstract class WryActivity : AppCompatActivity() { private lateinit var mWebView: RustWebView @@ -126,8 +115,11 @@ abstract class WryActivity : AppCompatActivity() { activityListener?.invoke(result) } + if (firstActivity.getAndSet(false)) { + Rust.onFirstActivityCreate() + Rust.wryCreate() + } Rust.onCreate(this) - ProcessLifecycleOwner.get().lifecycle.addObserver(WryLifecycleObserver) } override fun onStart() { From 93ed73368e62e2b12b201a1156458c3d28c0d5ce Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 28 Jul 2026 21:04:35 +0800 Subject: [PATCH 06/11] Revert "Try to use an atomic bool instead of ProcessLifecycleOwner" This reverts commit 11dab6bcc0a472f2bd6555d7f545bdd08fda4232. --- src/android/kotlin/WryActivity.kt | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index 1307db971..2b9d34758 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -9,16 +9,27 @@ import android.content.Intent import android.os.Build import android.os.Bundle import android.webkit.WebView +import android.view.KeyEvent import androidx.activity.OnBackPressedCallback import androidx.activity.result.ActivityResult +import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity -import java.util.concurrent.atomic.AtomicBoolean - -private const val ACTIVITY_ID_KEY = "__wryActivityId" - -val firstActivity = AtomicBoolean(true) +import androidx.lifecycle.DefaultLifecycleObserver +import androidx.lifecycle.LifecycleOwner +import androidx.lifecycle.ProcessLifecycleOwner + +private val ACTIVITY_ID_KEY = "__wryActivityId" + +object WryLifecycleObserver : DefaultLifecycleObserver { + // This only runs once: https://developer.android.com/reference/androidx/lifecycle/ProcessLifecycleOwner + override fun onCreate(owner: LifecycleOwner) { + super.onCreate(owner) + Rust.onFirstActivityCreate() + Rust.wryCreate() + } +} abstract class WryActivity : AppCompatActivity() { private lateinit var mWebView: RustWebView @@ -115,11 +126,8 @@ abstract class WryActivity : AppCompatActivity() { activityListener?.invoke(result) } - if (firstActivity.getAndSet(false)) { - Rust.onFirstActivityCreate() - Rust.wryCreate() - } Rust.onCreate(this) + ProcessLifecycleOwner.get().lifecycle.addObserver(WryLifecycleObserver) } override fun onStart() { From 62a587804ded77a9c1be4b63e888e708133280a8 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 29 Jul 2026 10:20:22 +0800 Subject: [PATCH 07/11] update tao --- Cargo.lock | 9 +++++---- Cargo.toml | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3bbdd19fd..d7e9383bb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2809,9 +2809,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cf65722394c2ac443e80120064987f8914ee1d4e4e36e63cdf10f2990f01159" +checksum = "e9fa4618f999c4249db1681cba0a19b890718f274de7fa93c445d46bd3a8a999" dependencies = [ "bitflags 2.8.0", "block2 0.6.2", @@ -2829,6 +2829,7 @@ dependencies = [ "libc", "log", "ndk", + "ndk-context", "ndk-sys 0.6.0+11769913", "objc2 0.6.4", "objc2-app-kit 0.3.2", @@ -2849,9 +2850,9 @@ dependencies = [ [[package]] name = "tao-macros" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4e16beb8b2ac17db28eab8bca40e62dbfbb34c0fcdc6d9826b11b7b5d047dfd" +checksum = "5f7eeb6d99155545da6150a1795945f16ac9c178deb2a5f2e74d776107bd5849" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 1d7b8be95..29a682218 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -196,13 +196,13 @@ sha2 = "0.10" base64 = "0.22" jni = "0.21" ndk = "0.9" -tao-macros = "0.1" +tao-macros = "0.1.4" libc = "0.2" dom_query = { version = "0.28.0", default-features = false } [dev-dependencies] pollster = "1.0.0" -tao = "0.35" +tao = "0.36" wgpu = "23" winit = "0.30" getrandom = "0.3" From 854b0411037f3a59e3eb394fcb3cdd27daf3234c Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 29 Jul 2026 10:25:52 +0800 Subject: [PATCH 08/11] update change file --- .changes/android-activity-lifecycle.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/.changes/android-activity-lifecycle.md b/.changes/android-activity-lifecycle.md index a825f3300..490614318 100644 --- a/.changes/android-activity-lifecycle.md +++ b/.changes/android-activity-lifecycle.md @@ -2,4 +2,19 @@ "wry": minor --- -Updated Android lifecycle JNI calls to pass the `WryActivity` instance for `start`, `resume`, `pause`, and `stop`, allowing Tao to emit window-specific lifecycle events. +Updated Android lifecycle JNI calls in `WryActivity` for Tao 0.36's renames: + +> - `create` to `onFirstActivityCreate` +> - `onActivityCreate` to `onCreate` +> - `start` to `onStart` +> - `resume` to `onResume` +> - `pause` to `onPause` +> - `stop` to `onStop` +> - Removed `onActivitySaveInstanceState` +> - `onActivityDestroy` to `onDestroy` +> - `onActivityLowMemory` to `onLowMemory` +> +> `onLowMemory` no longer takes any parameters. +> `onFirstActivityCreate` no longer takes any parameters. + +and also emitting them as window-specific events. From 189ed8e81d632d283b6dffa4b0cb3d33d3e12bac Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 29 Jul 2026 10:32:38 +0800 Subject: [PATCH 09/11] clean up --- src/android/kotlin/WryActivity.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index 2b9d34758..92a8d9fd4 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -9,10 +9,8 @@ import android.content.Intent import android.os.Build import android.os.Bundle import android.webkit.WebView -import android.view.KeyEvent import androidx.activity.OnBackPressedCallback import androidx.activity.result.ActivityResult -import androidx.activity.result.ActivityResultCallback import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity @@ -20,7 +18,7 @@ import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import androidx.lifecycle.ProcessLifecycleOwner -private val ACTIVITY_ID_KEY = "__wryActivityId" +private const val ACTIVITY_ID_KEY = "__wryActivityId" object WryLifecycleObserver : DefaultLifecycleObserver { // This only runs once: https://developer.android.com/reference/androidx/lifecycle/ProcessLifecycleOwner From a94fd60f027d48976ac0365d0d929dfccb62ac44 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 29 Jul 2026 17:00:25 +0800 Subject: [PATCH 10/11] Rename binding `wryCreate` to `onFirstActivityCreateWry` --- src/android/binding.rs | 5 ++--- src/android/kotlin/Rust.kt | 2 +- src/android/kotlin/WryActivity.kt | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/android/binding.rs b/src/android/binding.rs index 9d42c3d70..552b1b6d1 100644 --- a/src/android/binding.rs +++ b/src/android/binding.rs @@ -35,7 +35,7 @@ macro_rules! android_binding { ($domain:ident, $package:ident, $wry:path) => {{ use $wry::{android_setup as _, prelude::*}; - android_fn!($domain, $package, Rust, wryCreate, []); + android_fn!($domain, $package, Rust, onFirstActivityCreateWry, []); android_fn!( $domain, $package, @@ -273,9 +273,8 @@ fn handle_request( Ok(*web_resource_response) } -/// This is called on the first activity created #[allow(non_snake_case)] -pub unsafe fn wryCreate(env: JNIEnv, _: JClass) { +pub unsafe fn onFirstActivityCreateWry(env: JNIEnv, _: JClass) { let mut main_pipe = MainPipe { env }; let looper = ThreadLooper::for_thread().unwrap(); diff --git a/src/android/kotlin/Rust.kt b/src/android/kotlin/Rust.kt index af151886c..f05ec7dbe 100644 --- a/src/android/kotlin/Rust.kt +++ b/src/android/kotlin/Rust.kt @@ -28,7 +28,7 @@ object Rust { @JvmStatic external fun onLowMemory() @JvmStatic external fun onNewIntent(intent: Intent) - @JvmStatic external fun wryCreate() + @JvmStatic external fun onFirstActivityCreateWry() @JvmStatic external fun onWebviewDestroy(activity: WryActivity, webviewId: String) @JvmStatic external fun ipc(webviewId: String, url: String, message: String) diff --git a/src/android/kotlin/WryActivity.kt b/src/android/kotlin/WryActivity.kt index 92a8d9fd4..06e872d28 100644 --- a/src/android/kotlin/WryActivity.kt +++ b/src/android/kotlin/WryActivity.kt @@ -25,7 +25,7 @@ object WryLifecycleObserver : DefaultLifecycleObserver { override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) Rust.onFirstActivityCreate() - Rust.wryCreate() + Rust.onFirstActivityCreateWry() } } From e83abba89c3b009b5f1517eca1db06e6019aee7f Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 29 Jul 2026 17:05:19 +0800 Subject: [PATCH 11/11] more docs --- src/android/mod.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/android/mod.rs b/src/android/mod.rs index 967fa114a..00cd1e6ab 100644 --- a/src/android/mod.rs +++ b/src/android/mod.rs @@ -105,6 +105,10 @@ pub fn destroy_webview(activity_id: ActivityId, webview_id: &WebviewId) { /// /// This function must be run on the thread where the [`JNIEnv`] is registered and the looper is local, /// hence the requirement for a [`ThreadLooper`]. +/// +/// When used with tao, this is usually passed in like +/// `tao::android_binding!($domain, $app_name, $activity, android_setup, $main)` +/// to fill in `on_activity_create` which is run at the end of `onCreate` of an activiy pub unsafe fn android_setup( package: &str, mut env: JNIEnv,