Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
<preference name="AllowedSchemes" value="app" />
```

```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
Expand Down Expand Up @@ -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)_
Expand All @@ -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

Expand All @@ -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.
Expand Down
24 changes: 24 additions & 0 deletions src/ios/CDVWKInAppBrowser.m
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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]}];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • absoluteString is a property of url, write url.absoluteString instead of [url absoluteString]

[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • Write here pluginResult.keepCallback = [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).
Expand Down
33 changes: 32 additions & 1 deletion tests/tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
'Make sure http://www.apple.com is not in the white list.</br>' +
'In iOS, starred <span style="vertical-align:super">*</span> tests will put the app in a state with no way to return. </br>' +
'<h4>User-Agent: <span id="user-agent"> </span></hr>' +
'Make sure your config.xml contains: &lt;preference name="AllowedSchemes" value="custom" &gt;/<br/>' +
'</div>';

const local_tests =
Expand Down Expand Up @@ -525,6 +526,11 @@ exports.defineManualTests = function (contentEl, createActionButton) {
'<p/> <div id="openHardwareBackDefaultAfterNo"></div>' +
'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 =
'<h1>Customscheme</h1>' +
'<p/> <div id="openCustomscheme"></div>' +
'Expected result: open an alert dialog with the text "Results verified". Works only on Android and iOS.';

contentEl.innerHTML =
info_div +
platform_info +
Expand All @@ -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;

Expand Down Expand Up @@ -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'
);
};