Skip to content

Commit 3397fd9

Browse files
authored
feat(core): back button event on Android, closes #8142 (#14133)
* feat(core): back button event and exit on Android, closes #8142 I've used https://github.com/ionic-team/capacitor-plugins/blob/main/app/android/src/main/java/com/capacitorjs/plugins/app/AppPlugin.java as a reference here, checking if there's a back button event handler with a default of webview's goBack implementation * missing change file * remove exit impl * fmt * update wry * fix default back press * add remove_listener
1 parent 3b4fac2 commit 3397fd9

File tree

13 files changed

+167
-12
lines changed

13 files changed

+167
-12
lines changed

.changes/android-app-plugin.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"tauri": minor:feat
3+
---
4+
5+
Added mobile app plugin to support exit and back button press event.

.changes/back-button-press-api.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tauri-apps/api": minor:feat
3+
---
4+
5+
Added `app > onBackButtonPress` for Android back button handling.

Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/tauri-runtime-wry/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ rustc-args = ["--cfg", "docsrs"]
1717
rustdoc-args = ["--cfg", "docsrs"]
1818

1919
[dependencies]
20-
wry = { version = "0.53.2", default-features = false, features = [
20+
wry = { version = "0.53.4", default-features = false, features = [
2121
"drag-drop",
2222
"protocol",
2323
"os-webview",

crates/tauri/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[
164164
("set_app_theme", false),
165165
("set_dock_visibility", false),
166166
("bundle_type", true),
167+
("register_listener", true),
168+
("remove_listener", true),
167169
],
168170
),
169171
(

crates/tauri/mobile/android-codegen/TauriActivity.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import app.tauri.plugin.PluginManager
1212

1313
abstract class TauriActivity : WryActivity() {
1414
var pluginManager: PluginManager = PluginManager(this)
15+
override val handleBackNavigation: Boolean = false
1516

1617
override fun onNewIntent(intent: Intent) {
1718
super.onNewIntent(intent)
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright 2019-2024 Tauri Programme within The Commons Conservancy
2+
// SPDX-License-Identifier: Apache-2.0
3+
// SPDX-License-Identifier: MIT
4+
5+
package app.tauri
6+
7+
import android.app.Activity
8+
import android.webkit.WebView
9+
import androidx.activity.OnBackPressedCallback
10+
import androidx.appcompat.app.AppCompatActivity
11+
import app.tauri.annotation.Command
12+
import app.tauri.annotation.TauriPlugin
13+
import app.tauri.plugin.Plugin
14+
import app.tauri.plugin.Invoke
15+
import app.tauri.plugin.JSObject
16+
17+
@TauriPlugin
18+
class AppPlugin(private val activity: Activity): Plugin(activity) {
19+
private val BACK_BUTTON_EVENT = "back-button"
20+
21+
private var webView: WebView? = null
22+
23+
override fun load(webView: WebView) {
24+
this.webView = webView
25+
}
26+
27+
init {
28+
val callback = object : OnBackPressedCallback(true) {
29+
override fun handleOnBackPressed() {
30+
if (!hasListener(BACK_BUTTON_EVENT)) {
31+
if (this@AppPlugin.webView?.canGoBack() == true) {
32+
this@AppPlugin.webView!!.goBack()
33+
} else {
34+
this.isEnabled = false
35+
this@AppPlugin.activity.onBackPressed()
36+
this.isEnabled = true
37+
}
38+
} else {
39+
val data = JSObject().apply {
40+
put("canGoBack", this@AppPlugin.webView?.canGoBack() ?: false)
41+
}
42+
trigger(BACK_BUTTON_EVENT, data)
43+
}
44+
}
45+
}
46+
(activity as AppCompatActivity).onBackPressedDispatcher.addCallback(activity, callback)
47+
}
48+
49+
@Command
50+
fun exit(invoke: Invoke) {
51+
invoke.resolve()
52+
activity.finish()
53+
}
54+
}

crates/tauri/mobile/android/src/main/java/app/tauri/plugin/Plugin.kt

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import android.app.Activity
88
import android.content.Intent
99
import android.content.pm.PackageManager
1010
import android.net.Uri
11-
import android.os.Bundle
1211
import android.webkit.WebView
1312
import androidx.activity.result.IntentSenderRequest
1413
import androidx.core.app.ActivityCompat
@@ -22,7 +21,6 @@ import app.tauri.annotation.InvokeArg
2221
import app.tauri.annotation.PermissionCallback
2322
import app.tauri.annotation.TauriPlugin
2423
import com.fasterxml.jackson.databind.ObjectMapper
25-
import org.json.JSONException
2624
import java.util.*
2725
import java.util.concurrent.CopyOnWriteArrayList
2826

@@ -148,6 +146,10 @@ abstract class Plugin(private val activity: Activity) {
148146
}
149147
}
150148

149+
fun hasListener(event: String): Boolean {
150+
return !listeners[event].isNullOrEmpty()
151+
}
152+
151153
@Command
152154
open fun registerListener(invoke: Invoke) {
153155
val args = invoke.parseArgs(RegisterListenerArgs::class.java)

crates/tauri/permissions/app/autogenerated/reference.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ Default permissions for the plugin.
99
- `allow-tauri-version`
1010
- `allow-identifier`
1111
- `allow-bundle-type`
12+
- `allow-register-listener`
13+
- `allow-remove-listener`
1214

1315
## Permission Table
1416

@@ -204,6 +206,32 @@ Denies the name command without any pre-configured scope.
204206
<tr>
205207
<td>
206208

209+
`core:app:allow-register-listener`
210+
211+
</td>
212+
<td>
213+
214+
Enables the register_listener command without any pre-configured scope.
215+
216+
</td>
217+
</tr>
218+
219+
<tr>
220+
<td>
221+
222+
`core:app:deny-register-listener`
223+
224+
</td>
225+
<td>
226+
227+
Denies the register_listener command without any pre-configured scope.
228+
229+
</td>
230+
</tr>
231+
232+
<tr>
233+
<td>
234+
207235
`core:app:allow-remove-data-store`
208236

209237
</td>
@@ -230,6 +258,32 @@ Denies the remove_data_store command without any pre-configured scope.
230258
<tr>
231259
<td>
232260

261+
`core:app:allow-remove-listener`
262+
263+
</td>
264+
<td>
265+
266+
Enables the remove_listener command without any pre-configured scope.
267+
268+
</td>
269+
</tr>
270+
271+
<tr>
272+
<td>
273+
274+
`core:app:deny-remove-listener`
275+
276+
</td>
277+
<td>
278+
279+
Denies the remove_listener command without any pre-configured scope.
280+
281+
</td>
282+
</tr>
283+
284+
<tr>
285+
<td>
286+
233287
`core:app:allow-set-app-theme`
234288

235289
</td>

crates/tauri/scripts/bundle.global.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)