Skip to content

Commit 0ca4dd7

Browse files
committed
CB-14187: (ios) Change the InAppBrowser to allow custom schemes
1 parent 27fe8ec commit 0ca4dd7

4 files changed

Lines changed: 94 additions & 2 deletions

File tree

CONTRIBUTING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ cordova plugin add ../cordova-plugin-inappbrowser/tests
5858
cordova plugin add ../cordova-plugin-test-framework
5959
```
6060
* edit ```config.xml``` and replace ```<content src="index.html" />``` with ```<content src="cdvtests/index.html" />```
61+
* edit ```config.xml``` and add ```<preference name="AllowedSchemes" value="custom" />```
6162
* run application
6263
```
6364
cordova run

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ The object returned from a call to `cordova.InAppBrowser.open` when the target i
218218
- __loaderror__: event fires when the `InAppBrowser` encounters an error when loading a URL.
219219
- __exit__: event fires when the `InAppBrowser` window is closed.
220220
- __beforeload__: event fires when the `InAppBrowser` decides whether to load an URL or not (only with option `beforeload=yes`).
221+
- __customscheme__: event fires when a link is followed that matches `AllowedSchemes` (Android, iOS).
221222

222223
- __callback__: the function that executes when the event fires. The function is passed an `InAppBrowserEvent` object as a parameter.
223224

@@ -326,6 +327,10 @@ function beforeloadCallback(params, callback) {
326327
- Windows
327328
- OSX
328329

330+
### iOS Quirks
331+
332+
`loadstop` is being fired after a `customscheme` event. The event URL is that of the currently loaded page, not the URL with the custom scheme.
333+
329334
### Browser Quirks
330335

331336
`loadstart` and `loaderror` events are not being fired.
@@ -349,6 +354,7 @@ function beforeloadCallback(params, callback) {
349354
- __loadstop__: event fires when the `InAppBrowser` finishes loading a URL.
350355
- __loaderror__: event fires when the `InAppBrowser` encounters an error loading a URL.
351356
- __exit__: event fires when the `InAppBrowser` window is closed.
357+
- __customscheme__: event fires when a link is followed that matches `AllowedSchemes` (Android, iOS).
352358

353359
- __callback__: the function to execute when the event fires.
354360
The function is passed an `InAppBrowserEvent` object.
@@ -651,6 +657,35 @@ function executeScriptCallBack(params) {
651657

652658
```
653659

660+
### <a id="events_from_browser"></a>Events from the browser
661+
662+
Sometimes you may want to respond to an event happening on the page loaded in the browser,
663+
for example a button to open the barcode scanner, or closing the browser when a login flow
664+
was finished. This can done by navigating to a URL with a custom scheme listed in the
665+
`AllowedSchemes` preference in `config.xml`, triggering a `customscheme` event on the
666+
browser. Multiple values are separated by comma's.
667+
668+
In `config.xml`, include the following:
669+
```xml
670+
<preference name="AllowedSchemes" value="app" />
671+
```
672+
673+
```javascript
674+
function onCustomScheme(e) {
675+
if (e.url === 'app://hide') {
676+
inAppBrowserRef.hide();
677+
}
678+
}
679+
680+
inAppBrowserRef = cordova.InAppBrowser.open('https://example.com', '_blank');
681+
inAppBrowserRef.addEventListener('customscheme', onCustomScheme);
682+
```
683+
684+
When the opened page navigates to the link `app://hide`, the browser is hidden.
685+
686+
Please note that this feature is only available on Android and iOS (pull requests
687+
for other platforms are welcome).
688+
654689
## More Usage Info
655690

656691
### Local Urls ( source is in the app package )

src/ios/CDVUIInAppBrowser.m

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,21 @@ - (BOOL)isValidCallbackId:(NSString *)callbackId
427427
return NO;
428428
}
429429

430+
- (BOOL)isAllowedScheme:(NSString*)scheme
431+
{
432+
NSString* allowedSchemesPreference = [self settingForKey:@"AllowedSchemes"];
433+
if (allowedSchemesPreference == nil || [allowedSchemesPreference isEqualToString:@""]) {
434+
// Preference missing.
435+
return NO;
436+
}
437+
for (NSString* allowedScheme in [allowedSchemesPreference componentsSeparatedByString:@","]) {
438+
if ([allowedScheme isEqualToString:scheme]) {
439+
return YES;
440+
}
441+
}
442+
return NO;
443+
}
444+
430445
/**
431446
* The iframe bridge provided for the InAppBrowser is capable of executing any oustanding callback belonging
432447
* to the InAppBrowser plugin. Care has been taken that other callbacks cannot be triggered, and that no
@@ -485,6 +500,16 @@ - (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*
485500
return NO;
486501
}
487502

503+
//test for whitelisted custom scheme names like mycoolapp:// or twitteroauthresponse:// (Twitter Oauth Response)
504+
else if (![[ url scheme] isEqualToString:@"http"] && ![[ url scheme] isEqualToString:@"https"] && [self isAllowedScheme:[url scheme]]) {
505+
// Send a customscheme event.
506+
CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
507+
messageAsDictionary:@{@"type":@"customscheme", @"url":[url absoluteString]}];
508+
[pluginResult setKeepCallback:[NSNumber numberWithBool:YES]];
509+
[self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId];
510+
return NO;
511+
}
512+
488513
//if is an app store link, let the system handle it, otherwise it fails to load it
489514
if ([[ url scheme] isEqualToString:@"itms-appss"] || [[ url scheme] isEqualToString:@"itms-apps"]) {
490515
[theWebView stopLoading];

tests/tests.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ exports.defineManualTests = function (contentEl, createActionButton) {
354354
'<div id="info">' +
355355
'Make sure http://cordova.apache.org and http://google.co.uk and https://www.google.co.uk are white listed. </br>' +
356356
'Make sure http://www.apple.com is not in the white list.</br>' +
357+
'Make sure your config.xml contains: &lt;preference name="AllowedSchemes" value="custom" &gt;/<br/>' +
357358
'In iOS, starred <span style="vertical-align:super">*</span> tests will put the app in a state with no way to return. </br>' +
358359
'<h4>User-Agent: <span id="user-agent"> </span></hr>' +
359360
'</div>';
@@ -492,16 +493,20 @@ exports.defineManualTests = function (contentEl, createActionButton) {
492493
'<p/> <div id="openHardwareBackDefaultAfterNo"></div>' +
493494
'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';
494495

496+
var customscheme_tests = '<h1>customscheme</h1>' +
497+
'<p/> <div id="openCustomscheme"></div>' +
498+
'Expected result: open an alert dialog with the text "Results verified". Works only on Android and iOS.';
499+
495500
// CB-7490 We need to wrap this code due to Windows security restrictions
496501
// see http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences for details
497502
if (window.MSApp && window.MSApp.execUnsafeLocalFunction) {
498503
MSApp.execUnsafeLocalFunction(function () {
499504
contentEl.innerHTML = info_div + platform_info + local_tests + white_listed_tests + non_white_listed_tests + page_with_redirects_tests + pdf_url_tests + invalid_url_tests +
500-
css_js_injection_tests + open_hidden_tests + clearing_cache_tests + video_tag_tests + local_with_anchor_tag_tests + hardwareback_tests;
505+
css_js_injection_tests + open_hidden_tests + clearing_cache_tests + video_tag_tests + local_with_anchor_tag_tests + hardwareback_tests + customscheme_tests;
501506
});
502507
} else {
503508
contentEl.innerHTML = info_div + platform_info + local_tests + white_listed_tests + non_white_listed_tests + page_with_redirects_tests + pdf_url_tests + invalid_url_tests +
504-
css_js_injection_tests + open_hidden_tests + clearing_cache_tests + video_tag_tests + local_with_anchor_tag_tests + hardwareback_tests;
509+
css_js_injection_tests + open_hidden_tests + clearing_cache_tests + video_tag_tests + local_with_anchor_tag_tests + hardwareback_tests + customscheme_tests;
505510
}
506511

507512
document.getElementById('user-agent').textContent = navigator.userAgent;
@@ -732,4 +737,30 @@ exports.defineManualTests = function (contentEl, createActionButton) {
732737
});
733738
});
734739
}, 'openHardwareBackDefaultAfterNo');
740+
741+
// Customscheme
742+
createActionButton('customscheme', function () {
743+
744+
var ref = cordova.InAppBrowser.open('about:blank', '_blank', 'hidden=yes' + (platformOpts ? ',' + platformOpts : ''));
745+
var openedCustomscheme = false;
746+
ref.addEventListener('loadstop', function (e) {
747+
// Avoid showing the alert twice on iOS, since loadstop is also being called after the customscheme event.
748+
if (!openedCustomscheme) {
749+
openedCustomscheme = true;
750+
ref.executeScript({ code: 'window.location.replace("custom://test");' });
751+
}
752+
});
753+
ref.addEventListener('customscheme', function (e) {
754+
if (e && e.url === 'custom://test') {
755+
alert('Results verified'); // eslint-disable-line no-undef
756+
} else {
757+
alert('Got: ' + e.url); // eslint-disable-line no-undef
758+
}
759+
ref.close();
760+
});
761+
ref.addEventListener('loaderror', function (e) {
762+
alert('Load error: ' + e.message + '\nYou may need to set the AllowedSchemes preference'); // eslint-disable-line no-undef
763+
ref.close();
764+
});
765+
}, 'openCustomscheme');
735766
};

0 commit comments

Comments
 (0)