Skip to content

Commit 6c56293

Browse files
authored
feat(app): Add support for toggling Android back button handling (#2390)
1 parent 24539e4 commit 6c56293

File tree

6 files changed

+153
-15
lines changed

6 files changed

+153
-15
lines changed

app/README.md

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,49 @@ const checkAppLaunchUrl = async () => {
6767
};
6868
```
6969

70+
## Configuration
71+
72+
<docgen-config>
73+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
74+
75+
| Prop | Type | Description | Default | Since |
76+
| ------------------------------ | -------------------- | ------------------------------------------------------------------------------ | ------------------ | ----- |
77+
| **`disableBackButtonHandler`** | <code>boolean</code> | Disable the plugin's default back button handling. Only available for Android. | <code>false</code> | 7.1.0 |
78+
79+
### Examples
80+
81+
In `capacitor.config.json`:
82+
83+
```json
84+
{
85+
"plugins": {
86+
"App": {
87+
"disableBackButtonHandler": true
88+
}
89+
}
90+
}
91+
```
92+
93+
In `capacitor.config.ts`:
94+
95+
```ts
96+
/// <reference types="@capacitor/app" />
97+
98+
import { CapacitorConfig } from '@capacitor/cli';
99+
100+
const config: CapacitorConfig = {
101+
plugins: {
102+
App: {
103+
disableBackButtonHandler: true,
104+
},
105+
},
106+
};
107+
108+
export default config;
109+
```
110+
111+
</docgen-config>
112+
70113
## API
71114

72115
<docgen-index>
@@ -76,6 +119,7 @@ const checkAppLaunchUrl = async () => {
76119
* [`getState()`](#getstate)
77120
* [`getLaunchUrl()`](#getlaunchurl)
78121
* [`minimizeApp()`](#minimizeapp)
122+
* [`toggleBackButtonHandler(...)`](#togglebackbuttonhandler)
79123
* [`addListener('appStateChange', ...)`](#addlistenerappstatechange-)
80124
* [`addListener('pause', ...)`](#addlistenerpause-)
81125
* [`addListener('resume', ...)`](#addlistenerresume-)
@@ -167,6 +211,25 @@ Only available for Android.
167211
--------------------
168212

169213

214+
### toggleBackButtonHandler(...)
215+
216+
```typescript
217+
toggleBackButtonHandler(options: ToggleBackButtonHandlerOptions) => Promise<void>
218+
```
219+
220+
Enables or disables the plugin's back button handling during runtime.
221+
222+
Only available for Android.
223+
224+
| Param | Type |
225+
| ------------- | ----------------------------------------------------------------------------------------- |
226+
| **`options`** | <code><a href="#togglebackbuttonhandleroptions">ToggleBackButtonHandlerOptions</a></code> |
227+
228+
**Since:** 7.1.0
229+
230+
--------------------
231+
232+
170233
### addListener('appStateChange', ...)
171234

172235
```typescript
@@ -364,6 +427,13 @@ Remove all native listeners for this plugin
364427
| **`url`** | <code>string</code> | The url used to open the app. | 1.0.0 |
365428

366429

430+
#### ToggleBackButtonHandlerOptions
431+
432+
| Prop | Type | Description | Since |
433+
| ------------- | -------------------- | -------------------------------------------------------------------- | ----- |
434+
| **`enabled`** | <code>boolean</code> | Indicates whether to enable or disable default back button handling. | 7.1.0 |
435+
436+
367437
#### PluginListenerHandle
368438

369439
| Prop | Type |

app/android/src/main/java/com/capacitorjs/plugins/app/AppPlugin.java

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ public class AppPlugin extends Plugin {
2525
private static final String EVENT_RESUME = "resume";
2626
private boolean hasPausedEver = false;
2727

28+
private OnBackPressedCallback onBackPressedCallback;
29+
2830
public void load() {
31+
boolean disableBackButtonHandler = getConfig().getBoolean("disableBackButtonHandler", false);
32+
2933
bridge
3034
.getApp()
3135
.setStatusChangeListener(
@@ -44,22 +48,24 @@ public void load() {
4448
notifyListeners(EVENT_RESTORED_RESULT, result.getWrappedResult(), true);
4549
}
4650
);
47-
OnBackPressedCallback callback = new OnBackPressedCallback(true) {
48-
@Override
49-
public void handleOnBackPressed() {
50-
if (!hasListeners(EVENT_BACK_BUTTON)) {
51-
if (bridge.getWebView().canGoBack()) {
52-
bridge.getWebView().goBack();
51+
this.onBackPressedCallback =
52+
new OnBackPressedCallback(!disableBackButtonHandler) {
53+
@Override
54+
public void handleOnBackPressed() {
55+
if (!hasListeners(EVENT_BACK_BUTTON)) {
56+
if (bridge.getWebView().canGoBack()) {
57+
bridge.getWebView().goBack();
58+
}
59+
} else {
60+
JSObject data = new JSObject();
61+
data.put("canGoBack", bridge.getWebView().canGoBack());
62+
notifyListeners(EVENT_BACK_BUTTON, data, true);
63+
bridge.triggerJSEvent("backbutton", "document");
5364
}
54-
} else {
55-
JSObject data = new JSObject();
56-
data.put("canGoBack", bridge.getWebView().canGoBack());
57-
notifyListeners(EVENT_BACK_BUTTON, data, true);
58-
bridge.triggerJSEvent("backbutton", "document");
5965
}
60-
}
61-
};
62-
getActivity().getOnBackPressedDispatcher().addCallback(getActivity(), callback);
66+
};
67+
68+
getActivity().getOnBackPressedDispatcher().addCallback(getActivity(), this.onBackPressedCallback);
6369
}
6470

6571
@PluginMethod
@@ -112,6 +118,19 @@ public void minimizeApp(PluginCall call) {
112118
call.resolve();
113119
}
114120

121+
@PluginMethod
122+
public void toggleBackButtonHandler(PluginCall call) {
123+
if (this.onBackPressedCallback == null) {
124+
call.reject("onBackPressedCallback is not set");
125+
return;
126+
}
127+
128+
Boolean enabled = call.getBoolean("enabled");
129+
130+
this.onBackPressedCallback.setEnabled(enabled);
131+
call.resolve();
132+
}
133+
115134
/**
116135
* Handle ACTION_VIEW intents to store a URL that was used to open the app
117136
* @param intent

app/ios/Sources/AppPlugin/AppPlugin.swift

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ public class AppPlugin: CAPPlugin, CAPBridgedPlugin {
1010
CAPPluginMethod(name: "getInfo", returnType: CAPPluginReturnPromise),
1111
CAPPluginMethod(name: "getLaunchUrl", returnType: CAPPluginReturnPromise),
1212
CAPPluginMethod(name: "getState", returnType: CAPPluginReturnPromise),
13-
CAPPluginMethod(name: "minimizeApp", returnType: CAPPluginReturnPromise)
13+
CAPPluginMethod(name: "minimizeApp", returnType: CAPPluginReturnPromise),
14+
CAPPluginMethod(name: "toggleBackButtonHandler", returnType: CAPPluginReturnPromise)
1415
]
1516
private var observers: [NSObjectProtocol] = []
1617

@@ -113,4 +114,8 @@ public class AppPlugin: CAPPlugin, CAPBridgedPlugin {
113114
@objc func minimizeApp(_ call: CAPPluginCall) {
114115
call.unimplemented()
115116
}
117+
118+
@objc func toggleBackButtonHandler(_ call: CAPPluginCall) {
119+
call.unimplemented()
120+
}
116121
}

app/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
},
4949
"devDependencies": {
5050
"@capacitor/android": "^7.0.0",
51+
"@capacitor/cli": "^7.0.0",
5152
"@capacitor/core": "^7.0.0",
5253
"@capacitor/docgen": "0.2.2",
5354
"@capacitor/ios": "^7.0.0",

app/src/definitions.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,24 @@
1+
/// <reference types="@capacitor/cli" />
2+
13
import type { PluginListenerHandle } from '@capacitor/core';
24

5+
declare module '@capacitor/cli' {
6+
export interface PluginsConfig {
7+
App?: {
8+
/**
9+
* Disable the plugin's default back button handling.
10+
*
11+
* Only available for Android.
12+
*
13+
* @since 7.1.0
14+
* @default false
15+
* @example true
16+
*/
17+
disableBackButtonHandler?: boolean;
18+
};
19+
}
20+
}
21+
322
export interface AppInfo {
423
/**
524
* The name of the app.
@@ -125,6 +144,15 @@ export interface BackButtonListenerEvent {
125144
canGoBack: boolean;
126145
}
127146

147+
export interface ToggleBackButtonHandlerOptions {
148+
/**
149+
* Indicates whether to enable or disable default back button handling.
150+
*
151+
* @since 7.1.0
152+
*/
153+
enabled: boolean;
154+
}
155+
128156
export type StateChangeListener = (state: AppState) => void;
129157
export type URLOpenListener = (event: URLOpenListenerEvent) => void;
130158
export type RestoredListener = (event: RestoredListenerEvent) => void;
@@ -171,6 +199,17 @@ export interface AppPlugin {
171199
*/
172200
minimizeApp(): Promise<void>;
173201

202+
/**
203+
* Enables or disables the plugin's back button handling during runtime.
204+
*
205+
* Only available for Android.
206+
*
207+
* @since 7.1.0
208+
*/
209+
toggleBackButtonHandler(
210+
options: ToggleBackButtonHandlerOptions,
211+
): Promise<void>;
212+
174213
/**
175214
* Listen for changes in the app or the activity states.
176215
*

app/src/web.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ export class AppWeb extends WebPlugin implements AppPlugin {
3232
throw this.unimplemented('Not implemented on web.');
3333
}
3434

35+
async toggleBackButtonHandler(): Promise<void> {
36+
throw this.unimplemented('Not implemented on web.');
37+
}
38+
3539
private handleVisibilityChange = () => {
3640
const data = {
3741
isActive: document.hidden !== true,

0 commit comments

Comments
 (0)