feat(core): back button event on Android, closes #8142#19
Conversation
Code Review by Qodo
1. Unsafe activity cast
|
| } | ||
| } | ||
| } | ||
| (activity as AppCompatActivity).onBackPressedDispatcher.addCallback(activity, callback) |
There was a problem hiding this comment.
1. Unsafe activity cast 📘 Rule violation ⛯ Reliability
• AppPlugin force-casts activity to AppCompatActivity when registering the back-press callback, which can crash with ClassCastException if a non-AppCompatActivity is ever passed. • This is an unhandled edge case at a critical input boundary (Android host activity type) and provides no graceful fallback or actionable error context.
Agent prompt
## Issue description
`AppPlugin` force-casts `activity` to `AppCompatActivity`, which can throw at runtime and is not handled.
## Issue Context
This is a platform integration boundary; any mismatch in the host activity type should not cause an unhandled crash.
## Fix Focus Areas
- crates/tauri/mobile/android/src/main/java/app/tauri/AppPlugin.kt[17-47]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| .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)); | ||
| } |
There was a problem hiding this comment.
2. Misleading _app/_api names 📘 Rule violation ✓ Correctness
• The .setup(|_app, _api| { ... }) closure uses underscore-prefixed parameter names even though
they are used, which is misleading and reduces readability.
• The extra handle_ref indirection further obscures intent and makes the code less
self-documenting.
Agent prompt
## Issue description
The new setup closure uses underscore-prefixed names for variables that are actually used, and adds unnecessary `handle_ref` indirection.
## Issue Context
Clear naming improves maintainability and reduces confusion during review and future changes.
## Fix Focus Areas
- crates/tauri/src/app/plugin.rs[135-141]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| let handle = _api.register_android_plugin("app.tauri", "AppPlugin")?; | ||
| let handle_ref = &handle; | ||
| _app.manage(AppPlugin(*handle_ref)); |
There was a problem hiding this comment.
3. Android build compile error 🐞 Bug ✓ Correctness
• On Android builds, AppPlugin(*handle_ref) attempts to move a non-Copy PluginHandle out of a shared reference, which should not compile. • This is gated by #[cfg(target_os = "android")], so it can slip through non-Android CI while still breaking Android builds. • Fix by moving handle directly into state or cloning it explicitly (no ref+deref).
Agent prompt
### Issue description
Android-only setup code attempts to construct `AppPlugin(*handle_ref)` from a `&PluginHandle`, but `PluginHandle` is not `Copy`, so this should fail to compile for Android targets.
### Issue Context
`PluginHandle` implements `Clone` but not `Copy`. Dereferencing a shared reference (`*handle_ref`) requires `Copy`; otherwise it’s a move out of a shared reference.
### Fix Focus Areas
- crates/tauri/src/app/plugin.rs[135-141]
- crates/tauri/src/plugin.rs[123-138]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| async function onBackButtonPress( | ||
| handler: (payload: OnBackButtonPressPayload) => void | ||
| ): Promise<PluginListener> { | ||
| return addPluginListener<OnBackButtonPressPayload>( | ||
| 'app', | ||
| 'back-button', | ||
| handler | ||
| ) |
There was a problem hiding this comment.
4. Listener fallback never triggers 🐞 Bug ✓ Correctness
• The new onBackButtonPress API relies on addPluginListener, which tries register_listener and intends to fall back to registerListener. • That fallback uses synchronous try/catch around a Promise (invoke(...).then(...)), so command-not-found rejections won’t be caught and the fallback will never execute. • On Android, plugin commands are keyed strictly by method name (camelCase), so register_listener/remove_listener won’t match registerListener/removeListener; this likely breaks back-button subscription and unsubscription.
Agent prompt
### Issue description
`addPluginListener` uses `try/catch` around a Promise, so it does not catch asynchronous rejections. This breaks the intended fallback to camelCase commands. `PluginListener.unregister()` also lacks any fallback and always calls `remove_listener`.
### Issue Context
Android plugin dispatch keys commands strictly by method name (`registerListener`/`removeListener`), so snake_case calls can fail.
### Fix Focus Areas
- packages/api/src/core.ts[156-200]
- packages/api/src/app.ts[267-275]
- crates/tauri/mobile/android/src/main/java/app/tauri/plugin/PluginHandle.kt[138-167]
- crates/tauri/mobile/android/src/main/java/app/tauri/plugin/Plugin.kt[153-180]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
Benchmark PR from qodo-benchmark#162