diff --git a/README.md b/README.md
index c2bc74ef8..fc164950d 100644
--- a/README.md
+++ b/README.md
@@ -208,6 +208,7 @@ The object returned from a call to `cordova.InAppBrowser.open` when the target i
- __exit__: event fires when the `InAppBrowser` window is closed.
- __beforeload__: event fires when the `InAppBrowser` decides whether to load an URL or not (only with option `beforeload` set).
- __message__: event fires when the `InAppBrowser` receives a message posted from the page loaded inside the `InAppBrowser` Webview.
+ - __customscheme__: event fires when a link is followed that matches `AllowedSchemes`.
- __download__: _(Android Only)_ event fires when the `InAppBrowser` loads a URL that leads in downloading of a file.
- __callback__: the function that executes when the event fires. The function is passed an `InAppBrowserEvent` object as a parameter.
@@ -309,6 +310,36 @@ function messageCallBack(params){
}
```
+
+### Customscheme event Example
+
+Sometimes you may want to respond to an event happening on the page loaded in the browser,
+for example a button to open the barcode scanner, or closing the browser when a login flow
+was finished. This can done by navigating to a URL with a custom scheme listed in the
+`AllowedSchemes` preference in `config.xml`, triggering a `customscheme` event on the
+browser. Multiple values are separated by comma's.
+
+- **type** _it contains the String value "customscheme" always_
+- **url** _The url with custom scheme that triggered the event_
+
+In `config.xml`, include the following:
+```xml
+
+```
+
+```javascript
+function onCustomScheme(e) {
+ if (e.url === 'app://hide') {
+ inAppBrowserRef.hide();
+ }
+}
+
+inAppBrowserRef = cordova.InAppBrowser.open('https://example.com', '_blank');
+inAppBrowserRef.addEventListener('customscheme', onCustomScheme);
+```
+
+When the opened page navigates to the link `app://hide`, the browser is hidden.
+
#### Download event Example
Whenever the InAppBrowser receives or locates to a url which leads in downloading a file, the callback assigned to the "download" event is called. The parameter passed to this callback is an object with the the following properties
@@ -340,7 +371,7 @@ function downloadListener(params){
### InAppBrowserEvent Properties
-- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, `message` or `exit`. _(String)_
+- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, `message`, `customscheme` or `exit`. _(String)_
- __url__: the URL that was loaded. _(String)_
- __code__: the error code, only in the case of `loaderror`. _(Number)_
- __message__: the error message, only in the case of `loaderror`. _(String)_
@@ -354,7 +385,7 @@ function downloadListener(params){
### Browser Quirks
-`loadstart`, `loaderror`, `message` events are not fired.
+`loadstart`, `loaderror`, `message`, `customscheme` events are not fired.
### Quick Example
@@ -376,6 +407,7 @@ function downloadListener(params){
- __loaderror__: event fires when the `InAppBrowser` encounters an error loading a URL.
- __exit__: event fires when the `InAppBrowser` window is closed.
- __message__: event fires when the `InAppBrowser` receives a message posted from the page loaded inside the `InAppBrowser` Webview.
+ - __customscheme__: event fires when a link is followed that matches `AllowedSchemes`.
- __download__: _(Android only)_ event fires when the `InAppBrowser` loads a URL that leads in downloading of a file.
- __callback__: the function to execute when the event fires.
diff --git a/src/ios/CDVWKInAppBrowser.m b/src/ios/CDVWKInAppBrowser.m
index 993181cdc..6fa25a845 100644
--- a/src/ios/CDVWKInAppBrowser.m
+++ b/src/ios/CDVWKInAppBrowser.m
@@ -413,6 +413,21 @@ - (void)injectStyleFile:(CDVInvokedUrlCommand *)command
[self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
}
+- (BOOL)isAllowedScheme:(NSString *)scheme
+{
+ NSString *allowedSchemesPreference = [self.commandDelegate.settings cordovaSettingForKey:@"AllowedSchemes"];
+ if (allowedSchemesPreference == nil || [allowedSchemesPreference isEqualToString:@""]) {
+ // Preference missing.
+ return NO;
+ }
+ for (NSString *allowedScheme in [allowedSchemesPreference componentsSeparatedByString:@","]) {
+ if ([allowedScheme isEqualToString:scheme]) {
+ return YES;
+ }
+ }
+ return NO;
+}
+
/**
* The message handler bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging
* to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no
@@ -465,6 +480,15 @@ - (void)webView:(WKWebView *)theWebView decidePolicyForNavigationAction:(WKNavig
if ([allowedSchemes containsObject:[url scheme]]) {
[theWebView stopLoading];
[self openInSystem:url];
+ shouldStart = NO;
+ } else if ((self.callbackId != nil) && ![[url scheme] isEqualToString:@"http"] && ![[url scheme] isEqualToString:@"https"] && [self isAllowedScheme:[url scheme]]) {
+ // Send a customscheme event for allowed schemes that are not http/https.
+ CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsDictionary:@{@"type":@"customscheme", @"url":[url absoluteString]}];
+ [pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
+
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
+
shouldStart = NO;
} else if ((self.callbackId != nil) && isTopLevelNavigation) {
// Send a loadstart event for each top-level navigation (includes redirects).
diff --git a/tests/tests.js b/tests/tests.js
index f315f0675..4e492a47e 100644
--- a/tests/tests.js
+++ b/tests/tests.js
@@ -377,6 +377,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
'Make sure http://www.apple.com is not in the white list.' +
'In iOS, starred * tests will put the app in a state with no way to return. ' +
'
User-Agent: ' +
+ 'Make sure your config.xml contains: <preference name="AllowedSchemes" value="custom" >/
' +
'';
const local_tests =
@@ -525,6 +526,11 @@ exports.defineManualTests = function (contentEl, createActionButton) {
'
' +
'Expected result: consistently open browsers with with the appropriate option: hardwareback=defaults to yes then hardwareback=no then hardwareback=defaults to yes. By default hardwareback is yes so pressing back button should navigate backwards in history then close InAppBrowser';
+ const customscheme_tests =
+ 'Customscheme
' +
+ ' ' +
+ 'Expected result: open an alert dialog with the text "Results verified". Works only on Android and iOS.';
+
contentEl.innerHTML =
info_div +
platform_info +
@@ -539,7 +545,8 @@ exports.defineManualTests = function (contentEl, createActionButton) {
clearing_cache_tests +
video_tag_tests +
local_with_anchor_tag_tests +
- hardwareback_tests;
+ hardwareback_tests +
+ customscheme_tests;
document.getElementById('user-agent').textContent = navigator.userAgent;
@@ -979,4 +986,28 @@ exports.defineManualTests = function (contentEl, createActionButton) {
},
'openHardwareBackDefaultAfterNo'
);
+
+ // Customscheme
+ createActionButton(
+ 'customscheme',
+ function () {
+ const ref = cordova.InAppBrowser.open('about:blank', '_blank', 'hidden=yes' + (platformOpts ? ',' + platformOpts : ''));
+ ref.addEventListener('loadstop', function (_) {
+ ref.executeScript({ code: 'window.location.replace("custom://test");' });
+ });
+ ref.addEventListener('customscheme', function (e) {
+ if (e && e.url === 'custom://test') {
+ alert('Results verified');
+ } else {
+ alert('Got: ' + e.url);
+ }
+ ref.close();
+ });
+ ref.addEventListener('loaderror', function (e) {
+ alert('Load error: ' + e.message + '\nYou may need to set the AllowedSchemes preference');
+ ref.close();
+ });
+ },
+ 'openCustomscheme'
+ );
};