Skip to content

Commit 03831d7

Browse files
authored
feat(ios): Support custom scheme event for iOS (#1112)
- Add support for the `AllowedSchemes` preference and `customscheme` event for iOS like on Android. - Token from PR #274 which was implementing it in `UIWebView` - JIRA-Ticket: https://issues.apache.org/jira/browse/CB-14187
1 parent b7ab3d0 commit 03831d7

3 files changed

Lines changed: 90 additions & 3 deletions

File tree

README.md

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ The object returned from a call to `cordova.InAppBrowser.open` when the target i
208208
- __exit__: event fires when the `InAppBrowser` window is closed.
209209
- __beforeload__: event fires when the `InAppBrowser` decides whether to load an URL or not (only with option `beforeload` set).
210210
- __message__: event fires when the `InAppBrowser` receives a message posted from the page loaded inside the `InAppBrowser` Webview.
211+
- __customscheme__: event fires when a link is followed that matches `AllowedSchemes`.
211212
- __download__: _(Android Only)_ event fires when the `InAppBrowser` loads a URL that leads in downloading of a file.
212213

213214
- __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){
309310
}
310311

311312
```
313+
314+
### Customscheme event Example
315+
316+
Sometimes you may want to respond to an event happening on the page loaded in the browser,
317+
for example a button to open the barcode scanner, or closing the browser when a login flow
318+
was finished. This can done by navigating to a URL with a custom scheme listed in the
319+
`AllowedSchemes` preference in `config.xml`, triggering a `customscheme` event on the
320+
browser. Multiple values are separated by comma's.
321+
322+
- **type** _it contains the String value "customscheme" always_
323+
- **url** _The url with custom scheme that triggered the event_
324+
325+
In `config.xml`, include the following:
326+
```xml
327+
<preference name="AllowedSchemes" value="app" />
328+
```
329+
330+
```javascript
331+
function onCustomScheme(e) {
332+
if (e.url === 'app://hide') {
333+
inAppBrowserRef.hide();
334+
}
335+
}
336+
337+
inAppBrowserRef = cordova.InAppBrowser.open('https://example.com', '_blank');
338+
inAppBrowserRef.addEventListener('customscheme', onCustomScheme);
339+
```
340+
341+
When the opened page navigates to the link `app://hide`, the browser is hidden.
342+
312343
#### Download event Example
313344

314345
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){
340371

341372
### InAppBrowserEvent Properties
342373

343-
- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, `message` or `exit`. _(String)_
374+
- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, `message`, `customscheme` or `exit`. _(String)_
344375
- __url__: the URL that was loaded. _(String)_
345376
- __code__: the error code, only in the case of `loaderror`. _(Number)_
346377
- __message__: the error message, only in the case of `loaderror`. _(String)_
@@ -354,7 +385,7 @@ function downloadListener(params){
354385

355386
### Browser Quirks
356387

357-
`loadstart`, `loaderror`, `message` events are not fired.
388+
`loadstart`, `loaderror`, `message`, `customscheme` events are not fired.
358389

359390
### Quick Example
360391

@@ -376,6 +407,7 @@ function downloadListener(params){
376407
- __loaderror__: event fires when the `InAppBrowser` encounters an error loading a URL.
377408
- __exit__: event fires when the `InAppBrowser` window is closed.
378409
- __message__: event fires when the `InAppBrowser` receives a message posted from the page loaded inside the `InAppBrowser` Webview.
410+
- __customscheme__: event fires when a link is followed that matches `AllowedSchemes`.
379411
- __download__: _(Android only)_ event fires when the `InAppBrowser` loads a URL that leads in downloading of a file.
380412

381413
- __callback__: the function to execute when the event fires.

src/ios/CDVWKInAppBrowser.m

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -413,6 +413,21 @@ - (void)injectStyleFile:(CDVInvokedUrlCommand *)command
413413
[self injectDeferredObject:[command argumentAtIndex:0] withWrapper:jsWrapper];
414414
}
415415

416+
- (BOOL)isAllowedScheme:(NSString *)scheme
417+
{
418+
NSString *allowedSchemesPreference = [self.commandDelegate.settings cordovaSettingForKey:@"AllowedSchemes"];
419+
if (allowedSchemesPreference == nil || [allowedSchemesPreference isEqualToString:@""]) {
420+
// Preference missing.
421+
return NO;
422+
}
423+
for (NSString *allowedScheme in [allowedSchemesPreference componentsSeparatedByString:@","]) {
424+
if ([allowedScheme isEqualToString:scheme]) {
425+
return YES;
426+
}
427+
}
428+
return NO;
429+
}
430+
416431
/**
417432
* The message handler bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging
418433
* 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
465480
if ([allowedSchemes containsObject:[url scheme]]) {
466481
[theWebView stopLoading];
467482
[self openInSystem:url];
483+
shouldStart = NO;
484+
} else if ((self.callbackId != nil) && ![[url scheme] isEqualToString:@"http"] && ![[url scheme] isEqualToString:@"https"] && [self isAllowedScheme:[url scheme]]) {
485+
// Send a customscheme event for allowed schemes that are not http/https.
486+
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
487+
messageAsDictionary:@{@"type":@"customscheme", @"url":[url absoluteString]}];
488+
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
489+
490+
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
491+
468492
shouldStart = NO;
469493
} else if ((self.callbackId != nil) && isTopLevelNavigation) {
470494
// Send a loadstart event for each top-level navigation (includes redirects).

tests/tests.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
377377
'Make sure http://www.apple.com is not in the white list.</br>' +
378378
'In iOS, starred <span style="vertical-align:super">*</span> tests will put the app in a state with no way to return. </br>' +
379379
'<h4>User-Agent: <span id="user-agent"> </span></hr>' +
380+
'Make sure your config.xml contains: &lt;preference name="AllowedSchemes" value="custom" &gt;/<br/>' +
380381
'</div>';
381382

382383
const local_tests =
@@ -525,6 +526,11 @@ exports.defineManualTests = function (contentEl, createActionButton) {
525526
'<p/> <div id="openHardwareBackDefaultAfterNo"></div>' +
526527
'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';
527528

529+
const customscheme_tests =
530+
'<h1>Customscheme</h1>' +
531+
'<p/> <div id="openCustomscheme"></div>' +
532+
'Expected result: open an alert dialog with the text "Results verified". Works only on Android and iOS.';
533+
528534
contentEl.innerHTML =
529535
info_div +
530536
platform_info +
@@ -539,7 +545,8 @@ exports.defineManualTests = function (contentEl, createActionButton) {
539545
clearing_cache_tests +
540546
video_tag_tests +
541547
local_with_anchor_tag_tests +
542-
hardwareback_tests;
548+
hardwareback_tests +
549+
customscheme_tests;
543550

544551
document.getElementById('user-agent').textContent = navigator.userAgent;
545552

@@ -979,4 +986,28 @@ exports.defineManualTests = function (contentEl, createActionButton) {
979986
},
980987
'openHardwareBackDefaultAfterNo'
981988
);
989+
990+
// Customscheme
991+
createActionButton(
992+
'customscheme',
993+
function () {
994+
const ref = cordova.InAppBrowser.open('about:blank', '_blank', 'hidden=yes' + (platformOpts ? ',' + platformOpts : ''));
995+
ref.addEventListener('loadstop', function (_) {
996+
ref.executeScript({ code: 'window.location.replace("custom://test");' });
997+
});
998+
ref.addEventListener('customscheme', function (e) {
999+
if (e && e.url === 'custom://test') {
1000+
alert('Results verified');
1001+
} else {
1002+
alert('Got: ' + e.url);
1003+
}
1004+
ref.close();
1005+
});
1006+
ref.addEventListener('loaderror', function (e) {
1007+
alert('Load error: ' + e.message + '\nYou may need to set the AllowedSchemes preference');
1008+
ref.close();
1009+
});
1010+
},
1011+
'openCustomscheme'
1012+
);
9821013
};

0 commit comments

Comments
 (0)