Skip to content

Commit 383d67f

Browse files
fix(android,ios): properly return errors (#54)
* fix: send errors with both error code and message on Android * fix: return both error code and description in iOS bridge * feat: show error from invalidScheme in alert * chore: update Gradle and Podfile dependencies on example-app * chore: replace GeneralError with OpenFailed error * chore: update error code for bridgeNotInitialised error
1 parent 898a962 commit 383d67f

File tree

7 files changed

+114
-41
lines changed

7 files changed

+114
-41
lines changed

android/src/main/java/com/capacitorjs/osinappbrowser/InAppBrowserPlugin.kt

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ class InAppBrowserPlugin : Plugin() {
3434
fun openInExternalBrowser(call: PluginCall) {
3535
val url = call.getString("url")
3636
if (url.isNullOrEmpty()) {
37-
call.reject("The value of the 'url' input parameter of the 'openInExternalBrowser' action is missing or is empty.")
37+
sendErrorResult(call, OSInAppBrowserError.InputArgumentsIssue(OSInAppBrowserTarget.EXTERNAL_BROWSER))
3838
return
3939
}
4040

4141
if (!isSchemeValid(url)) {
42-
call.reject("The URL provided must begin with either http:// or https://.")
42+
sendErrorResult(call, OSInAppBrowserError.InvalidURL)
4343
return
4444
}
4545

@@ -50,11 +50,11 @@ class InAppBrowserPlugin : Plugin() {
5050
if (success) {
5151
call.resolve()
5252
} else {
53-
call.reject("External browser couldn't open the following URL: '$url'")
53+
sendErrorResult(call, OSInAppBrowserError.OpenFailed(url, OSInAppBrowserTarget.EXTERNAL_BROWSER))
5454
}
5555
}
5656
} catch (e: Exception) {
57-
call.reject("An error occurred while trying to open the external browser: ${e.message}")
57+
sendErrorResult(call, OSInAppBrowserError.OpenFailed(url, OSInAppBrowserTarget.EXTERNAL_BROWSER))
5858
}
5959
}
6060

@@ -63,18 +63,13 @@ class InAppBrowserPlugin : Plugin() {
6363
val url = call.getString("url")
6464
val options = call.getObject("options")
6565

66-
if (url.isNullOrEmpty()) {
67-
call.reject("The value of the 'url' input parameter of the 'openInSystemBrowser' action is missing or is empty.")
66+
if (url.isNullOrEmpty() || options == null) {
67+
sendErrorResult(call, OSInAppBrowserError.InputArgumentsIssue(OSInAppBrowserTarget.SYSTEM_BROWSER))
6868
return
6969
}
7070

7171
if (!isSchemeValid(url)) {
72-
call.reject("The URL provided must begin with either http:// or https://.")
73-
return
74-
}
75-
76-
if (options == null) {
77-
call.reject("The value of the 'options' input parameter of the 'openInSystemBrowser' action is missing or isn't valid.")
72+
sendErrorResult(call, OSInAppBrowserError.InvalidURL)
7873
return
7974
}
8075

@@ -101,12 +96,12 @@ class InAppBrowserPlugin : Plugin() {
10196
activeRouter = customTabsRouter
10297
call.resolve()
10398
} else {
104-
call.reject("Custom Tabs couldn't open the following URL:'$url'")
99+
sendErrorResult(call, OSInAppBrowserError.OpenFailed(url, OSInAppBrowserTarget.SYSTEM_BROWSER))
105100
}
106101
}
107102
}
108103
} catch (e: Exception) {
109-
call.reject("An error occurred while trying to open Custom Tabs: ${e.message}")
104+
sendErrorResult(call, OSInAppBrowserError.OpenFailed(url, OSInAppBrowserTarget.SYSTEM_BROWSER))
110105
}
111106
}
112107

@@ -115,30 +110,25 @@ class InAppBrowserPlugin : Plugin() {
115110
val url = call.getString("url")
116111
val options = call.getObject("options")
117112

118-
if (url.isNullOrEmpty()) {
119-
call.reject("The value of the 'url' input parameter of the 'openInWebView' action is missing or is empty.")
113+
if (url.isNullOrEmpty() || options == null) {
114+
sendErrorResult(call, OSInAppBrowserError.InputArgumentsIssue(OSInAppBrowserTarget.WEB_VIEW))
120115
return
121116
}
122117

123118
if (!isSchemeValid(url)) {
124-
call.reject("The URL provided must begin with either http:// or https://.")
125-
return
126-
}
127-
128-
if (options == null) {
129-
call.reject("The value of the 'options' input parameter of the 'openInWebView' action is missing or isn't valid.")
119+
sendErrorResult(call, OSInAppBrowserError.InvalidURL)
130120
return
131121
}
132122

133123
try {
134124
// Try closing active router before continuing to open
135125
close {
136-
val options = buildWebViewOptions(call.getObject("options"))
126+
val webViewOptions = buildWebViewOptions(options)
137127

138128
val webViewRouter = OSIABWebViewRouterAdapter(
139129
context = context,
140130
lifecycleScope = activity.lifecycleScope,
141-
options = options,
131+
options = webViewOptions,
142132
flowHelper = OSIABFlowHelper(),
143133
onBrowserPageLoaded = {
144134
notifyListeners(OSIABEventType.BROWSER_PAGE_LOADED.value, null)
@@ -153,12 +143,12 @@ class InAppBrowserPlugin : Plugin() {
153143
activeRouter = webViewRouter
154144
call.resolve()
155145
} else {
156-
call.reject("The WebView couldn't open the following URL: '$url'")
146+
sendErrorResult(call, OSInAppBrowserError.OpenFailed(url, OSInAppBrowserTarget.WEB_VIEW))
157147
}
158148
}
159149
}
160150
} catch (e: Exception) {
161-
call.reject("An error occurred while trying to open the WebView: ${e.message}")
151+
sendErrorResult(call, OSInAppBrowserError.OpenFailed(url, OSInAppBrowserTarget.WEB_VIEW))
162152
}
163153

164154
}
@@ -169,7 +159,7 @@ class InAppBrowserPlugin : Plugin() {
169159
if (success) {
170160
call.resolve()
171161
} else {
172-
call.reject("There's no browser view to close.")
162+
sendErrorResult(call, OSInAppBrowserError.CloseFailed)
173163
}
174164
}
175165
}
@@ -274,6 +264,16 @@ class InAppBrowserPlugin : Plugin() {
274264
return listOf("http://", "https://").any { url.startsWith(it, true) }
275265
}
276266

267+
/**
268+
* Helper method to send an error result using call.reject
269+
* @param call The PluginCall object to send the error result
270+
* @param error The OSInAppBrowserError object to send as the error result
271+
*/
272+
private fun sendErrorResult(call: PluginCall, error: OSInAppBrowserError) {
273+
call.reject(error.message, error.code)
274+
}
275+
276+
277277
}
278278

279279
enum class OSIABEventType(val value: String) {
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.capacitorjs.osinappbrowser
2+
3+
sealed class OSInAppBrowserError(val code: String, val message: String) {
4+
data class InputArgumentsIssue(val target: OSInAppBrowserTarget) : OSInAppBrowserError(
5+
code = target.inputIssueCode.formatErrorCode(),
6+
message = "The '${target.inputIssueText}' input parameters aren't valid."
7+
)
8+
9+
data class OpenFailed(val url: String, val target: OSInAppBrowserTarget) : OSInAppBrowserError(
10+
code = target.openFailedCode.formatErrorCode(),
11+
message = "${target.openFailedText} couldn't open the following URL: $url"
12+
)
13+
14+
data object CloseFailed : OSInAppBrowserError(
15+
code = 12.formatErrorCode(),
16+
message = "There's no browser view to close."
17+
)
18+
19+
data object InvalidURL : OSInAppBrowserError(
20+
code = 3.formatErrorCode(),
21+
message = "The URL provided must begin with either http:// or https://."
22+
)
23+
}
24+
25+
enum class OSInAppBrowserTarget(
26+
val inputIssueCode: Int,
27+
val inputIssueText: String,
28+
val openFailedCode: Int,
29+
val openFailedText: String,
30+
) {
31+
EXTERNAL_BROWSER(5, "openInExternalBrowser", 8, "External browser"),
32+
SYSTEM_BROWSER(6, "openInSystemBrowser", 10, "Custom Tabs"),
33+
WEB_VIEW(7, "openInWebView", 11, "The WebView")
34+
}
35+
36+
private fun Int.formatErrorCode(): String {
37+
return "OS-PLUG-IABP-" + this.toString().padStart(4, '0')
38+
}

example-app/android/capacitor.settings.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@ include ':capacitor-android'
33
project(':capacitor-android').projectDir = new File('../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/android/capacitor')
44

55
include ':capacitor-app'
6-
project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@[email protected]alpha.2_@[email protected]/node_modules/@capacitor/app/android')
6+
project(':capacitor-app').projectDir = new File('../node_modules/.pnpm/@[email protected]rc.0_@[email protected]/node_modules/@capacitor/app/android')
77

88
include ':capacitor-haptics'
9-
project(':capacitor-haptics').projectDir = new File('../node_modules/.pnpm/@[email protected]alpha.2_@[email protected]/node_modules/@capacitor/haptics/android')
9+
project(':capacitor-haptics').projectDir = new File('../node_modules/.pnpm/@[email protected]rc.0_@[email protected]/node_modules/@capacitor/haptics/android')
1010

1111
include ':capacitor-inappbrowser'
1212
project(':capacitor-inappbrowser').projectDir = new File('../node_modules/@capacitor/inappbrowser/android')
1313

1414
include ':capacitor-keyboard'
15-
project(':capacitor-keyboard').projectDir = new File('../node_modules/.pnpm/@[email protected]alpha.2_@[email protected]/node_modules/@capacitor/keyboard/android')
15+
project(':capacitor-keyboard').projectDir = new File('../node_modules/.pnpm/@[email protected]rc.0_@[email protected]/node_modules/@capacitor/keyboard/android')
1616

1717
include ':capacitor-status-bar'
18-
project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@[email protected]alpha.2_@[email protected]/node_modules/@capacitor/status-bar/android')
18+
project(':capacitor-status-bar').projectDir = new File('../node_modules/.pnpm/@[email protected]rc.0_@[email protected]/node_modules/@capacitor/status-bar/android')

example-app/ios/App/Podfile

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ install! 'cocoapods', :disable_input_output_paths => true
1111
def capacitor_pods
1212
pod 'Capacitor', :path => '../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/ios'
1313
pod 'CapacitorCordova', :path => '../../node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@capacitor/ios'
14-
pod 'CapacitorApp', :path => '../../node_modules/.pnpm/@[email protected]alpha.2_@[email protected]/node_modules/@capacitor/app'
15-
pod 'CapacitorHaptics', :path => '../../node_modules/.pnpm/@[email protected]alpha.2_@[email protected]/node_modules/@capacitor/haptics'
16-
pod 'CapacitorInappbrowser', :path => '../../node_modules/.pnpm/file+.._@[email protected]/node_modules/@capacitor/inappbrowser'
17-
pod 'CapacitorKeyboard', :path => '../../node_modules/.pnpm/@[email protected]alpha.2_@[email protected]/node_modules/@capacitor/keyboard'
18-
pod 'CapacitorStatusBar', :path => '../../node_modules/.pnpm/@[email protected]alpha.2_@[email protected]/node_modules/@capacitor/status-bar'
14+
pod 'CapacitorApp', :path => '../../node_modules/.pnpm/@[email protected]rc.0_@[email protected]/node_modules/@capacitor/app'
15+
pod 'CapacitorHaptics', :path => '../../node_modules/.pnpm/@[email protected]rc.0_@[email protected]/node_modules/@capacitor/haptics'
16+
pod 'CapacitorInappbrowser', :path => '../../node_modules/.pnpm/@capacitor+inappbrowser@file+.._@[email protected]/node_modules/@capacitor/inappbrowser'
17+
pod 'CapacitorKeyboard', :path => '../../node_modules/.pnpm/@[email protected]rc.0_@[email protected]/node_modules/@capacitor/keyboard'
18+
pod 'CapacitorStatusBar', :path => '../../node_modules/.pnpm/@[email protected]rc.0_@[email protected]/node_modules/@capacitor/status-bar'
1919
end
2020

2121
target 'App' do

example-app/src/pages/Home.tsx

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,19 @@ const Home: React.FC = () => {
1010
});
1111
}
1212

13-
const invalidScheme = () => {
14-
InAppBrowser.openInExternalBrowser({
15-
url: "mailto://[email protected]"
16-
});
13+
const invalidScheme = async () => {
14+
try {
15+
const result = await InAppBrowser.openInExternalBrowser({
16+
url: "mailto://[email protected]"
17+
});
18+
} catch (error) {
19+
if (error instanceof Error) {
20+
alert("Error: " + (error as any).code + ": " + error.message);
21+
} else {
22+
alert("Error: Unknown error");
23+
}
24+
}
25+
1726
}
1827

1928
const openInSystemBrowserWithDefaults = () => {

ios/Sources/InAppBrowserPlugin/InAppBrowserPlugin.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ private extension InAppBrowserPlugin {
201201
}
202202

203203
func error(_ call: CAPPluginCall, type errorType: OSInAppBrowserError) {
204-
call.reject(errorType.description)
204+
call.reject(errorType.description, errorType.code)
205205
}
206206
}
207207

ios/Sources/InAppBrowserPlugin/OSInAppBrowserError.swift

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,30 @@ enum OSInAppBrowserError: Error {
4141

4242
return result
4343
}
44+
45+
var code: String {
46+
let baseCode: Int
47+
switch self {
48+
case .invalidURLScheme:
49+
baseCode = 3
50+
case .inputArgumentsIssue(let target):
51+
baseCode = switch target {
52+
case .externalBrowser: 5
53+
case .systemBrowser: 6
54+
case .webView: 7
55+
}
56+
case .failedToOpen(_, let target):
57+
baseCode = switch target {
58+
case .externalBrowser: 8
59+
case .systemBrowser: 9
60+
case .webView: 11
61+
}
62+
case .noBrowserToClose:
63+
baseCode = 12
64+
case .bridgeNotInitialised:
65+
baseCode = 13
66+
}
67+
return "OS-PLUG-IABP-\(String(format: "%04d", baseCode))"
68+
}
69+
4470
}

0 commit comments

Comments
 (0)