-
Notifications
You must be signed in to change notification settings - Fork 0
feat(core): back button event on Android, closes #8142 #19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: coderabbit_combined_20260121_augment_sentry_coderabbit_1_base_featcore_back_button_event_on_android_closes_8142_pr162
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "tauri": minor:feat | ||
| --- | ||
|
|
||
| Added mobile app plugin to support exit and back button press event. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@tauri-apps/api": minor:feat | ||
| --- | ||
|
|
||
| Added `app > onBackButtonPress` for Android back button handling. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,54 @@ | ||||||||||
| // Copyright 2019-2024 Tauri Programme within The Commons Conservancy | ||||||||||
| // SPDX-License-Identifier: Apache-2.0 | ||||||||||
| // SPDX-License-Identifier: MIT | ||||||||||
|
|
||||||||||
| package app.tauri | ||||||||||
|
|
||||||||||
| import android.app.Activity | ||||||||||
| import android.webkit.WebView | ||||||||||
| import androidx.activity.OnBackPressedCallback | ||||||||||
| import androidx.appcompat.app.AppCompatActivity | ||||||||||
| import app.tauri.annotation.Command | ||||||||||
| import app.tauri.annotation.TauriPlugin | ||||||||||
| import app.tauri.plugin.Plugin | ||||||||||
| import app.tauri.plugin.Invoke | ||||||||||
| import app.tauri.plugin.JSObject | ||||||||||
|
|
||||||||||
| @TauriPlugin | ||||||||||
| class AppPlugin(private val activity: Activity): Plugin(activity) { | ||||||||||
| private val BACK_BUTTON_EVENT = "back-button" | ||||||||||
|
|
||||||||||
| private var webView: WebView? = null | ||||||||||
|
|
||||||||||
| override fun load(webView: WebView) { | ||||||||||
| this.webView = webView | ||||||||||
| } | ||||||||||
|
|
||||||||||
| init { | ||||||||||
| val callback = object : OnBackPressedCallback(true) { | ||||||||||
| override fun handleOnBackPressed() { | ||||||||||
| if (!hasListener(BACK_BUTTON_EVENT)) { | ||||||||||
| if (this@AppPlugin.webView?.canGoBack() == true) { | ||||||||||
| this@AppPlugin.webView!!.goBack() | ||||||||||
| } else { | ||||||||||
| this.isEnabled = false | ||||||||||
| this@AppPlugin.activity.onBackPressed() | ||||||||||
| this.isEnabled = true | ||||||||||
| } | ||||||||||
| } else { | ||||||||||
| val data = JSObject().apply { | ||||||||||
| put("canGoBack", this@AppPlugin.webView?.canGoBack() ?: false) | ||||||||||
| } | ||||||||||
| trigger(BACK_BUTTON_EVENT, data) | ||||||||||
| } | ||||||||||
| } | ||||||||||
| } | ||||||||||
| (activity as AppCompatActivity).onBackPressedDispatcher.addCallback(activity, callback) | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unsafe cast to The cast 🔧 Suggested defensive check- (activity as AppCompatActivity).onBackPressedDispatcher.addCallback(activity, callback)
+ if (activity is AppCompatActivity) {
+ activity.onBackPressedDispatcher.addCallback(activity, callback)
+ }Note: If the callback isn't registered when activity is not 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| } | ||||||||||
|
|
||||||||||
| @Command | ||||||||||
| fun exit(invoke: Invoke) { | ||||||||||
| activity.finish() | ||||||||||
| invoke.resolve() | ||||||||||
| } | ||||||||||
| } | ||||||||||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -132,5 +132,17 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> { | |
| set_dock_visibility, | ||
| bundle_type, | ||
| ]) | ||
| .setup(|_app, _api| { | ||
| #[cfg(target_os = "android")] | ||
| { | ||
| let handle = _api.register_android_plugin("app.tauri", "AppPlugin")?; | ||
| let handle_ref = &handle; | ||
| _app.manage(AppPlugin(*handle_ref)); | ||
| } | ||
| Ok(()) | ||
| }) | ||
|
Comment on lines
+135
to
+143
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Search for PluginHandle definition
fd "\.rs$" -x rg -l "PluginHandle" {} \; | head -10Repository: qodo-benchmark/tauri-combined-coderabbit Length of output: 224 🏁 Script executed: #!/bin/bash
# Get the structure and trait impls for PluginHandle
rg -n "struct PluginHandle|enum PluginHandle" --type rust -A 10 | head -50Repository: qodo-benchmark/tauri-combined-coderabbit Length of output: 843 🏁 Script executed: #!/bin/bash
# Search for Copy/Clone implementations for PluginHandle
rg -n "impl.*Copy.*PluginHandle|impl.*Clone.*PluginHandle|#\[derive\(.*Copy.*\)|#\[derive\(.*Clone.*\)" --type rust -B 3 -A 5 | grep -A 5 -B 5 "PluginHandle"Repository: qodo-benchmark/tauri-combined-coderabbit Length of output: 816 🏁 Script executed: #!/bin/bash
# Read the specific lines mentioned in the review
sed -n '135,143p' crates/tauri/src/app/plugin.rsRepository: qodo-benchmark/tauri-combined-coderabbit Length of output: 338 🏁 Script executed: #!/bin/bash
# Get more context around those lines
sed -n '130,150p' crates/tauri/src/app/plugin.rsRepository: qodo-benchmark/tauri-combined-coderabbit Length of output: 562 🏁 Script executed: #!/bin/bash
# Search for AppPlugin struct definition
rg -n "struct AppPlugin|impl.*AppPlugin" --type rust -A 5 | head -30Repository: qodo-benchmark/tauri-combined-coderabbit Length of output: 379 This code does not compile as written.
Remove the intermediate reference and pass the owned ♻️ Corrected code .setup(|_app, _api| {
#[cfg(target_os = "android")]
{
let handle = _api.register_android_plugin("app.tauri", "AppPlugin")?;
- let handle_ref = &handle;
- _app.manage(AppPlugin(*handle_ref));
+ _app.manage(AppPlugin(handle));
}
Ok(())
})🤖 Prompt for AI Agents |
||
| .build() | ||
| } | ||
|
|
||
| #[cfg(target_os = "android")] | ||
| pub(crate) struct AppPlugin<R: Runtime>(pub crate::plugin::PluginHandle<R>); | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🌐 Web query:
Android onBackPressed deprecated API level Android 13 OnBackPressedDispatcher💡 Result:
Short answer
Details
Example (Kotlin)
Sources
[1] ComponentActivity (AndroidX) — deprecation note.
[2] OnBackPressedDispatcher (AndroidX) — usage and addCallback.
[3] Android Developers guide: Provide custom back navigation (recommendation to replace onBackPressed with OnBackPressedCallback).
🌐 Web query:
Android Activity onBackPressed() deprecated replacement best practices💡 Result:
Short answer
Why and when
Best practices (concise)
Minimal examples
Activity (Kotlin, Jetpack):
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { /* custom */ }
}
onBackPressedDispatcher.addCallback(this, callback) // lifecycle-aware. [1]
Fragment (Kotlin):
val cb = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { /* handle or call requireActivity().onBackPressedDispatcher.onBackPressed() */ }
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, cb) // use viewLifecycleOwner. [1]
Docs / references
If you want, I can paste a copy‑pasteable Kotlin sample showing AndroidX + API‑33 bridging (setOnBackInvokedDispatcher) and explain version checks.
🏁 Script executed:
Repository: qodo-benchmark/tauri-combined-coderabbit
Length of output: 156
🏁 Script executed:
Repository: qodo-benchmark/tauri-combined-coderabbit
Length of output: 2002
🏁 Script executed:
Repository: qodo-benchmark/tauri-combined-coderabbit
Length of output: 2002
Replace deprecated
onBackPressed()withOnBackPressedDispatcher.onBackPressed().The
Activity.onBackPressed()method is deprecated in AndroidX. The modern approach is to callonBackPressedDispatcher.onBackPressed(), which properly delegates to the next callback in the dispatcher queue or the system's default back handling. The disable/re-enable pattern is still needed here to prevent callback recursion.🔧 Suggested fix
} else { this.isEnabled = false - this@AppPlugin.activity.onBackPressed() + (this@AppPlugin.activity as AppCompatActivity).onBackPressedDispatcher.onBackPressed() this.isEnabled = true }📝 Committable suggestion
🤖 Prompt for AI Agents