Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Steinar Ágúst 2019-02-28 11:43:34 +00:00
commit 74ccef1226
29 changed files with 3785 additions and 1447 deletions

View File

@ -21,8 +21,10 @@ install:
- node --version
- npm install -g cordova-paramedic@https://github.com/apache/cordova-paramedic.git
- npm install -g cordova
- npm install
build: off
test_script:
- npm run eslint
- cordova-paramedic --config pr\%PLATFORM% --plugin . %JUST_BUILD%

42
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@ -0,0 +1,42 @@
<!--
Please have a look at the issue templates you get when you click "New issue" in the GitHub UI.
We very much prefer issues created by using one of these templates.
-->
### Issue Type
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->
- [ ] Bug Report
- [ ] Feature Request
- [ ] Support Question
## Description
## Information
<!-- Include all relevant information that might help understand and reproduce the problem -->
### Command or Code
<!-- What command or code is needed to reproduce the problem? -->
### Environment, Platform, Device
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->
### Version information
<!--
What are relevant versions you are using?
For example:
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins
Other Frameworks: Ionic Framework and CLI version
Operating System, Android Studio, Xcode etc.
-->
## Checklist
<!-- Please check the boxes by putting an `x` in the `[ ]` like so: `[x]` -->
- [ ] I searched for already existing GitHub issues about this
- [ ] I updated all Cordova tooling to their most recent version
- [ ] I included all the necessary information above

50
.github/ISSUE_TEMPLATE/BUG_REPORT.md vendored Normal file
View File

@ -0,0 +1,50 @@
---
name: 🐛 Bug Report
about: If something isn't working as expected.
---
# Bug Report
## Problem
### What is expected to happen?
### What does actually happen?
## Information
<!-- Include all relevant information that might help understand and reproduce the problem -->
### Command or Code
<!-- What command or code is needed to reproduce the problem? -->
### Environment, Platform, Device
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->
### Version information
<!--
What are relevant versions you are using?
For example:
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins
Other Frameworks: Ionic Framework and CLI version
Operating System, Android Studio, Xcode etc.
-->
## Checklist
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->
- [ ] I searched for existing GitHub issues
- [ ] I updated all Cordova tooling to most recent version
- [ ] I included all the necessary information above

View File

@ -0,0 +1,29 @@
---
name: 🚀 Feature Request
about: A suggestion for a new functionality
---
# Feature Request
## Motivation Behind Feature
<!-- Why should this feature be implemented? What problem does it solve? -->
## Feature Description
<!--
Describe your feature request in detail
Please provide any code examples or screenshots of what this feature would look like
Are there any drawbacks? Will this break anything for existing users?
-->
## Alternatives or Workarounds
<!--
Describe alternatives or workarounds you are currently using
Are there ways to do this with existing functionality?
-->

View File

@ -0,0 +1,27 @@
---
name: 💬 Support Question
about: If you have a question, please check out our Slack or StackOverflow!
---
<!------------^ Click "Preview" for a nicer view! -->
Apache Cordova uses GitHub Issues as a feature request and bug tracker _only_.
For usage and support questions, please check out the resources below. Thanks!
---
You can get answers to your usage and support questions about **Apache Cordova** on:
* Slack Community Chat: https://cordova.slack.com (you can sign-up at http://slack.cordova.io/)
* StackOverflow: https://stackoverflow.com/questions/tagged/cordova using the tag `cordova`
---
If you are using a tool that uses Cordova internally, like e.g. Ionic, check their support channels:
* **Ionic Framework**
* [Ionic Community Forum](https://forum.ionicframework.com/)
* [Ionic Worldwide Slack](https://ionicworldwide.herokuapp.com/)
* **PhoneGap**
* [PhoneGap Developer Community](https://forums.adobe.com/community/phonegap)

View File

@ -1,6 +1,5 @@
<!--
Please make sure the checklist boxes are all checked before submitting the PR. The checklist
is intended as a quick reference, for complete details please see our Contributor Guidelines:
Please make sure the checklist boxes are all checked before submitting the PR. The checklist is intended as a quick reference, for complete details please see our Contributor Guidelines:
http://cordova.apache.org/contribute/contribute_guidelines.html
@ -10,13 +9,27 @@ Thanks!
### Platforms affected
### What does this PR do?
### Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
<!-- If it fixes an open issue, please link to the issue here. -->
### What testing has been done on this change?
### Description
<!-- Describe your changes in detail -->
### Testing
<!-- Please describe in detail how you tested your changes. -->
### Checklist
- [ ] [Reported an issue](http://cordova.apache.org/contribute/issues.html) in the JIRA database
- [ ] Commit message follows the format: "CB-3232: (android) Fix bug with resolving file paths", where CB-xxxx is the JIRA ID & "android" is the platform affected.
- [ ] Added automated test coverage as appropriate for this change.
- [ ] I've run the tests to see all new and existing tests pass
- [ ] I added automated test coverage as appropriate for this change
- [ ] Commit is prefixed with `(platform)` if this change only applies to one platform (e.g. `(android)`)
- [ ] If this Pull Request resolves an issue, I linked to the issue in the text above (and used the correct [keyword to close issues using keywords](https://help.github.com/articles/closing-issues-using-keywords/))
- [ ] I've updated the documentation if necessary

1
.gitignore vendored
View File

@ -11,6 +11,7 @@ Thumbs.db
*.log
*.swp
*.user
*.idea
node_modules

View File

@ -1,11 +1,14 @@
sudo: false
addons:
jwt:
secure: TZ88IEvAw1bsWPWxvDzXdpi2NK0i3PN4hG15+vDpIt6wXGVPknjxuXWJeLj7TqBpAIvP7XDfS8ZvHVPLe7fe8oOchZPLuiDw9VVIk6cnHjE6wpoavdGc/1mDJ3Bi4PDcHwRUr5ng5spYQqqlTwcECkH/q7iPgudiFM6rlOlGRyA=
env:
global:
- SAUCE_USERNAME=snay
- TRAVIS_NODE_VERSION="4.2"
matrix:
include:
- env: PLATFORM=browser-chrome
@ -24,14 +27,15 @@ matrix:
os: linux
language: node_js
node_js: '4.2'
- env: PLATFORM=ios-9.3
os: osx
osx_image: xcode7.3
language: node_js
node_js: '4.2'
# iOS 9 not supported by iOS WKWebView implementation
# - env: PLATFORM=ios-9.3
# os: osx
# osx_image: xcode8.3
# language: node_js
# node_js: '4.2'
- env: PLATFORM=ios-10.0
os: osx
osx_image: xcode7.3
osx_image: xcode8.3
language: node_js
node_js: '4.2'
- env: PLATFORM=android-4.4
@ -74,6 +78,7 @@ matrix:
- platform-tools
- tools
- build-tools-26.0.2
before_install:
- rm -rf ~/.nvm && git clone https://github.com/creationix/nvm.git ~/.nvm && (cd ~/.nvm
&& git checkout `git describe --abbrev=0 --tags`) && source ~/.nvm/nvm.sh && nvm
@ -81,13 +86,15 @@ before_install:
- node --version
- if [[ "$PLATFORM" =~ android ]]; then gradle --version; fi
- if [[ "$PLATFORM" =~ ios ]]; then npm install -g ios-deploy; fi
- if [[ "$PLATFORM" =~ android ]]; then echo y | android update sdk -u --filter android-22,android-23,android-24,android-25,android-26;
- if [[ "$PLATFORM" =~ android ]]; then echo y | android update sdk -u --filter android-22,android-23,android-24,android-25,android-26,android-27;
fi
- git clone https://github.com/apache/cordova-paramedic /tmp/paramedic && pushd /tmp/paramedic
&& npm install && popd
- npm install -g cordova
install:
- npm install
script:
- npm test
- node /tmp/paramedic/main.js --config pr/$PLATFORM --plugin $(pwd) --shouldUseSauce

View File

@ -35,6 +35,8 @@ This plugin provides a web browser view that displays when calling `cordova.InAp
var ref = cordova.InAppBrowser.open('http://apache.org', '_blank', 'location=yes');
### `window.open`
The `cordova.InAppBrowser.open()` function is defined to be a drop-in replacement
for the `window.open()` function. Existing `window.open()` calls can use the
InAppBrowser window, by replacing window.open:
@ -66,10 +68,6 @@ Although `window.open` is in the global scope, InAppBrowser is not available unt
console.log("window.open works well");
}
Report issues with this plugin on the [Apache Cordova issue tracker](https://issues.apache.org/jira/issues/?jql=project%20%3D%20CB%20AND%20status%20in%20%28Open%2C%20%22In%20Progress%22%2C%20Reopened%29%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20%22cordova-plugin-inappbrowser%22%20ORDER%20BY%20priority%20DESC%2C%20summary%20ASC%2C%20updatedDate%20DESC)
## <a id="reference">Reference</a>
## Installation
cordova plugin add cordova-plugin-inappbrowser
@ -111,6 +109,7 @@ instance, or the system browser.
Android supports these additional options:
- __hidden__: set to `yes` to create the browser and load the page, but not show it. The loadstop event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally.
- __beforeload__: set to enable the `beforeload` event to modify which pages are actually loaded in the browser. Accepted values are `get` to intercept only GET requests, `post` to intercept on POST requests or `yes` to intercept both GET & POST requests. Note that POST requests are not currently supported and will be ignored (if you set `beforeload=post` it will raise an error).
- __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened
- __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened
- __closebuttoncaption__: set to a string to use as the close button's caption instead of a X. Note that you need to localize this value yourself.
@ -132,24 +131,29 @@ instance, or the system browser.
iOS supports these additional options:
- __usewkwebview__: set to `yes` to use WKWebView engine for the InappBrowser. Omit or set to `no` (default) to use UIWebView. Note: Using `usewkwebview=yes` requires that a WKWebView engine plugin be installed in the Cordova project (e.g. [cordova-plugin-wkwebview-engine](https://github.com/apache/cordova-plugin-wkwebview-engine) or [cordova-plugin-ionic-webview](https://github.com/ionic-team/cordova-plugin-ionic-webview)).
- __hidden__: set to `yes` to create the browser and load the page, but not show it. The loadstop event fires when loading is complete. Omit or set to `no` (default) to have the browser open and load normally.
- __beforeload__: set to enable the `beforeload` event to modify which pages are actually loaded in the browser. Accepted values are `get` to intercept only GET requests, `post` to intercept on POST requests or `yes` to intercept both GET & POST requests. Note that POST requests are not currently supported and will be ignored (if you set `beforeload=post` it will raise an error).
- __clearcache__: set to `yes` to have the browser's cookie cache cleared before the new window is opened
- __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened
- __clearsessioncache__: set to `yes` to have the session cookie cache cleared before the new window is opened. For WKWebView, requires iOS 11+ on target device.
- __cleardata__: set to `yes` to have the browser's entire local storage cleared (cookies, HTML5 local storage, IndexedDB, etc.) before the new window is opened
- __closebuttoncolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default __Done__ button's color. Only applicable if toolbar is not disabled.
- __closebuttoncaption__: set to a string to use as the __Done__ button's caption. Note that you need to localize this value yourself.
- __disallowoverscroll__: Set to `yes` or `no` (default is `no`). Turns on/off the UIWebViewBounce property.
- __hidenavigationbuttons__: set to `yes` or `no` to turn the toolbar navigation buttons on or off (defaults to `no`). Only applicable if toolbar is not disabled.
- __navigationbuttoncolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default color. Only applicable if navigation buttons are visible.
- __toolbar__: set to `yes` or `no` to turn the toolbar on or off for the InAppBrowser (defaults to `yes`)
- __toolbarcolor__: set as a valid hex color string, for example: `#00ff00`, to change from the default color of the toolbar. Only applicable if toolbar is not disabled.
- __toolbartranslucent__: set to `yes` or `no` to make the toolbar translucent(semi-transparent) (defaults to `yes`). Only applicable if toolbar is not disabled.
- __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`).
- __mediaPlaybackRequiresUserAction__: Set to `yes` to prevent HTML5 audio or video from autoplaying (defaults to `no`).
- __allowInlineMediaPlayback__: Set to `yes` or `no` to allow in-line HTML5 media playback, displaying within the browser window rather than a device-specific playback interface. The HTML's `video` element must also include the `webkit-playsinline` attribute (defaults to `no`)
- __keyboardDisplayRequiresUserAction__: Set to `yes` or `no` to open the keyboard when form elements receive focus via JavaScript's `focus()` call (defaults to `yes`).
- __suppressesIncrementalRendering__: Set to `yes` or `no` to wait until all new view content is received before being rendered (defaults to `no`).
- __enableViewportScale__: Set to `yes` or `no` to prevent viewport scaling through a meta tag (defaults to `no`). Only applicable to UIWebView (`usewkwebview=no`) and WKWebView (`usewkwebview=yes`) on iOS 10+.
- __mediaPlaybackRequiresUserAction__: Set to `yes` to prevent HTML5 audio or video from autoplaying (defaults to `no`). Applicable to UIWebView (`usewkwebview=no`) and WKWebView (`usewkwebview=yes`).
- __allowInlineMediaPlayback__: Set to `yes` or `no` to allow in-line HTML5 media playback, displaying within the browser window rather than a device-specific playback interface. The HTML's `video` element must also include the `webkit-playsinline` attribute (defaults to `no`). Applicable to UIWebView (`usewkwebview=no`) and WKWebView (`usewkwebview=yes`).
- __keyboardDisplayRequiresUserAction__: Set to `yes` or `no` to open the keyboard when form elements receive focus via JavaScript's `focus()` call (defaults to `yes`). Only applicable to UIWebView (`usewkwebview=no`).
- __suppressesIncrementalRendering__: Set to `yes` or `no` to wait until all new view content is received before being rendered (defaults to `no`). Only applicable to UIWebView (`usewkwebview=no`).
- __presentationstyle__: Set to `pagesheet`, `formsheet` or `fullscreen` to set the [presentation style](http://developer.apple.com/library/ios/documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalPresentationStyle) (defaults to `fullscreen`).
- __transitionstyle__: Set to `fliphorizontal`, `crossdissolve` or `coververtical` to set the [transition style](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIViewController_Class/Reference/Reference.html#//apple_ref/occ/instp/UIViewController/modalTransitionStyle) (defaults to `coververtical`).
- __toolbarposition__: Set to `top` or `bottom` (default is `bottom`). Causes the toolbar to be at the top or bottom of the window.
- __hidespinner__: Set to `yes` or `no` to change the visibility of the loading indicator (defaults to `no`).
Windows supports these additional options:
@ -211,6 +215,8 @@ The object returned from a call to `cordova.InAppBrowser.open` when the target i
- __loadstop__: event fires when the `InAppBrowser` finishes loading a URL.
- __loaderror__: event fires when the `InAppBrowser` encounters an error when loading a URL.
- __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.
- __callback__: the function that executes when the event fires. The function is passed an `InAppBrowserEvent` object as a parameter.
@ -224,7 +230,7 @@ function showHelp(url) {
var target = "_blank";
var options = "location=yes,hidden=yes";
var options = "location=yes,hidden=yes,beforeload=yes";
inAppBrowserRef = cordova.InAppBrowser.open(url, target, options);
@ -234,6 +240,9 @@ function showHelp(url) {
inAppBrowserRef.addEventListener('loaderror', loadErrorCallBack);
inAppBrowserRef.addEventListener('beforeload', beforeloadCallBack);
inAppBrowserRef.addEventListener('message', messageCallBack);
}
function loadStartCallBack() {
@ -248,6 +257,13 @@ function loadStopCallBack() {
inAppBrowserRef.insertCSS({ code: "body{font-size: 25px;" });
inAppBrowserRef.executeScript({ code: "\
var message = 'this is the message';\
var messageObj = {my_message: message};\
var stringifiedMessageObj = JSON.stringify(messageObj);\
webkit.messageHandlers.cordova_iab.postMessage(stringifiedMessageObj);"
});
$('#status-message').text("");
inAppBrowserRef.show();
@ -282,11 +298,29 @@ function executeScriptCallBack(params) {
}
function beforeloadCallback(params, callback) {
if (params.url.startsWith("http://www.example.com/")) {
// Load this URL in the inAppBrowser.
callback(params.url);
} else {
// The callback is not invoked, so the page will not be loaded.
$('#status-message').text("This browser only opens pages on http://www.example.com/");
}
}
function messageCallback(params){
$('#status-message').text("message received: "+params.data.my_message);
}
```
### InAppBrowserEvent Properties
- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, or `exit`. _(String)_
- __type__: the eventname, either `loadstart`, `loadstop`, `loaderror`, `message` or `exit`. _(String)_
- __url__: the URL that was loaded. _(String)_
@ -294,6 +328,8 @@ function executeScriptCallBack(params) {
- __message__: the error message, only in the case of `loaderror`. _(String)_
- __data__: the message contents , only in the case of `message`. A stringified JSON object. _(String)_
### Supported Platforms
@ -305,7 +341,11 @@ function executeScriptCallBack(params) {
### Browser Quirks
`loadstart` and `loaderror` events are not being fired.
`loadstart`, `loaderror`, `message` events are not fired.
### Windows Quirks
`message` event is not fired.
### Quick Example
@ -326,6 +366,7 @@ function executeScriptCallBack(params) {
- __loadstop__: event fires when the `InAppBrowser` finishes loading a URL.
- __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.
- __callback__: the function to execute when the event fires.
The function is passed an `InAppBrowserEvent` object.

View File

@ -20,6 +20,16 @@
-->
# Release Notes
### 3.1.0-dev (Unreleased)
* CB-7179 (iOS): Add support to optionally use WKWebView for iOS
### 3.0.0 (Apr 12, 2018)
* [CB-13659](https://issues.apache.org/jira/browse/CB-13659) **iOS** Add hidespinner option
* In file `AppBrowser.java`: New code within `shouldOverrideUrlLoading()` to check for whitelisting custom schemes via a new `AllowedSchemes` preference configuration item. Allows custom schemes like `mycoolapp://` or `wevotetwitterscheme://`
* `InAppBrowser.java`: New method `isURLWhileListed` to check for whitelisting of `AllowedSchemes` in a new preference configuration item. There is a new check in `shouldOverrideUrlLoading`, to allow whitelisted custom schemes like "mycoolapp://"
* Add customisation of the navigation buttons for **iOS**
* Fix navigation buttons on **iOS**
### 2.0.2 (Jan 24, 2018)
* [CB-13791](https://issues.apache.org/jira/browse/CB-13791) Add **Android** support for a footer close button
* [CB-13409](https://issues.apache.org/jira/browse/CB-13409) restore gitignore to default

View File

@ -1,6 +1,6 @@
{
"name": "cordova-plugin-inappbrowser",
"version": "2.0.3-dev",
"version": "3.1.0-dev",
"description": "Cordova InAppBrowser Plugin",
"types": "./types/index.d.ts",
"cordova": {
@ -42,7 +42,7 @@
"0.2.3": {
"cordova": ">=3.1.0"
},
"3.0.0": {
"4.0.0": {
"cordova": ">100"
}
}

View File

@ -20,7 +20,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="cordova-plugin-inappbrowser"
version="2.0.3-dev">
version="3.1.0-dev">
<name>InAppBrowser</name>
<description>Cordova InAppBrowser Plugin</description>
@ -76,11 +76,31 @@
<config-file target="config.xml" parent="/*">
<feature name="InAppBrowser">
<param name="ios-package" value="CDVInAppBrowser" />
<param name="onload" value="true" />
</feature>
<feature name="UIInAppBrowser">
<param name="ios-package" value="CDVUIInAppBrowser" />
<param name="onload" value="true" />
</feature>
<feature name="WKInAppBrowser">
<param name="ios-package" value="CDVWKInAppBrowser" />
<param name="onload" value="true" />
</feature>
</config-file>
<header-file src="src/ios/CDVInAppBrowser.h" />
<source-file src="src/ios/CDVInAppBrowser.m" />
<header-file src="src/ios/CDVInAppBrowserOptions.h" />
<source-file src="src/ios/CDVInAppBrowserOptions.m" />
<header-file src="src/ios/CDVInAppBrowserNavigationController.h" />
<source-file src="src/ios/CDVInAppBrowserNavigationController.m" />
<header-file src="src/ios/CDVUIInAppBrowser.h" />
<source-file src="src/ios/CDVUIInAppBrowser.m" />
<header-file src="src/ios/CDVWKInAppBrowser.h" />
<source-file src="src/ios/CDVWKInAppBrowser.m" />
<header-file src="src/ios/CDVWKInAppBrowserUIDelegate.h" />
<source-file src="src/ios/CDVWKInAppBrowserUIDelegate.m" />
<framework src="CoreGraphics.framework" />
</platform>

View File

@ -19,8 +19,13 @@
package org.apache.cordova.inappbrowser;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Parcelable;
import android.provider.Browser;
import android.content.res.Resources;
import android.graphics.Bitmap;
@ -44,8 +49,11 @@ import android.view.inputmethod.InputMethodManager;
import android.webkit.CookieManager;
import android.webkit.CookieSyncManager;
import android.webkit.HttpAuthHandler;
import android.webkit.JavascriptInterface;
import android.webkit.ValueCallback;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
@ -71,6 +79,7 @@ import org.json.JSONObject;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.HashMap;
@ -90,6 +99,7 @@ public class InAppBrowser extends CordovaPlugin {
private static final String LOAD_START_EVENT = "loadstart";
private static final String LOAD_STOP_EVENT = "loadstop";
private static final String LOAD_ERROR_EVENT = "loaderror";
private static final String MESSAGE_EVENT = "message";
private static final String CLEAR_ALL_CACHE = "clearcache";
private static final String CLEAR_SESSION_CACHE = "clearsessioncache";
private static final String HARDWARE_BACK_BUTTON = "hardwareback";
@ -106,6 +116,7 @@ public class InAppBrowser extends CordovaPlugin {
private static final String HIDE_URL = "hideurlbar";
private static final String FOOTER = "footer";
private static final String FOOTER_COLOR = "footercolor";
private static final String BEFORELOAD = "beforeload";
private static final List customizableOptions = Arrays.asList(CLOSE_BUTTON_CAPTION, TOOLBAR_COLOR, NAVIGATION_COLOR, CLOSE_BUTTON_COLOR, FOOTER_COLOR);
@ -135,6 +146,8 @@ public class InAppBrowser extends CordovaPlugin {
private boolean hideUrlBar = false;
private boolean showFooter = false;
private String footerColor = "";
private String beforeload = "";
private String[] allowedSchemes;
/**
* Executes the request and returns PluginResult.
@ -242,6 +255,20 @@ public class InAppBrowser extends CordovaPlugin {
else if (action.equals("close")) {
closeDialog();
}
else if (action.equals("loadAfterBeforeload")) {
if (beforeload == null) {
LOG.e(LOG_TAG, "unexpected loadAfterBeforeload called without feature beforeload=yes");
}
final String url = args.getString(0);
this.cordova.getActivity().runOnUiThread(new Runnable() {
@SuppressLint("NewApi")
@Override
public void run() {
((InAppBrowserClient)inAppWebView.getWebViewClient()).waitForBeforeload = false;
inAppWebView.loadUrl(url);
}
});
}
else if (action.equals("injectScriptCode")) {
String jsWrapper = null;
if (args.getBoolean(1)) {
@ -433,7 +460,8 @@ public class InAppBrowser extends CordovaPlugin {
intent.setData(uri);
}
intent.putExtra(Browser.EXTRA_APPLICATION_ID, cordova.getActivity().getPackageName());
this.cordova.getActivity().startActivity(intent);
// CB-10795: Avoid circular loops by preventing it from opening in the current app
this.openExternalExcludeCurrentApp(intent);
return "";
// not catching FileUriExposedException explicitly because buildtools<24 doesn't know about it
} catch (java.lang.RuntimeException e) {
@ -442,6 +470,46 @@ public class InAppBrowser extends CordovaPlugin {
}
}
/**
* Opens the intent, providing a chooser that excludes the current app to avoid
* circular loops.
*/
private void openExternalExcludeCurrentApp(Intent intent) {
String currentPackage = cordova.getActivity().getPackageName();
boolean hasCurrentPackage = false;
PackageManager pm = cordova.getActivity().getPackageManager();
List<ResolveInfo> activities = pm.queryIntentActivities(intent, 0);
ArrayList<Intent> targetIntents = new ArrayList<Intent>();
for (ResolveInfo ri : activities) {
if (!currentPackage.equals(ri.activityInfo.packageName)) {
Intent targetIntent = (Intent)intent.clone();
targetIntent.setPackage(ri.activityInfo.packageName);
targetIntents.add(targetIntent);
}
else {
hasCurrentPackage = true;
}
}
// If the current app package isn't a target for this URL, then use
// the normal launch behavior
if (hasCurrentPackage == false || targetIntents.size() == 0) {
this.cordova.getActivity().startActivity(intent);
}
// If there's only one possible intent, launch it directly
else if (targetIntents.size() == 1) {
this.cordova.getActivity().startActivity(targetIntents.get(0));
}
// Otherwise, show a custom chooser without the current app listed
else if (targetIntents.size() > 0) {
Intent chooser = Intent.createChooser(targetIntents.remove(targetIntents.size()-1), null);
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, targetIntents.toArray(new Parcelable[] {}));
this.cordova.getActivity().startActivity(chooser);
}
}
/**
* Closes the dialog
*/
@ -633,6 +701,9 @@ public class InAppBrowser extends CordovaPlugin {
if (footerColorSet != null) {
footerColor = footerColorSet;
}
if (features.get(BEFORELOAD) != null) {
beforeload = features.get(BEFORELOAD);
}
}
final CordovaWebView thatWebView = this.webView;
@ -893,7 +964,7 @@ public class InAppBrowser extends CordovaPlugin {
}
});
WebViewClient client = new InAppBrowserClient(thatWebView, edittext);
WebViewClient client = new InAppBrowserClient(thatWebView, edittext, beforeload);
inAppWebView.setWebViewClient(client);
WebSettings settings = inAppWebView.getSettings();
settings.setJavaScriptEnabled(true);
@ -901,8 +972,24 @@ public class InAppBrowser extends CordovaPlugin {
settings.setBuiltInZoomControls(showZoomControls);
settings.setPluginState(android.webkit.WebSettings.PluginState.ON);
// Add postMessage interface
class JsObject {
@JavascriptInterface
public void postMessage(String data) {
try {
JSONObject obj = new JSONObject();
obj.put("type", MESSAGE_EVENT);
obj.put("data", new JSONObject(data));
sendUpdate(obj, true);
} catch (JSONException ex) {
LOG.e(LOG_TAG, "data object passed to postMessage has caused a JSON error.");
}
}
}
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
settings.setMediaPlaybackRequiresUserGesture(mediaPlaybackRequiresUserGesture);
inAppWebView.addJavascriptInterface(new JsObject(), "cordova_iab");
}
String overrideUserAgent = preferences.getString("OverrideUserAgent", null);
@ -1054,6 +1141,8 @@ public class InAppBrowser extends CordovaPlugin {
public class InAppBrowserClient extends WebViewClient {
EditText edittext;
CordovaWebView webView;
String beforeload;
boolean waitForBeforeload;
/**
* Constructor.
@ -1061,9 +1150,41 @@ public class InAppBrowser extends CordovaPlugin {
* @param webView
* @param mEditText
*/
public InAppBrowserClient(CordovaWebView webView, EditText mEditText) {
public InAppBrowserClient(CordovaWebView webView, EditText mEditText, String beforeload) {
this.webView = webView;
this.edittext = mEditText;
this.beforeload = beforeload;
this.waitForBeforeload = beforeload != null;
}
/**
* Override the URL that should be loaded
*
* Legacy (deprecated in API 24)
* For Android 6 and below.
*
* @param webView
* @param url
*/
@SuppressWarnings("deprecation")
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
return shouldOverrideUrlLoading(url, null);
}
/**
* Override the URL that should be loaded
*
* New (added in API 24)
* For Android 7 and above.
*
* @param webView
* @param request
*/
@TargetApi(Build.VERSION_CODES.N)
@Override
public boolean shouldOverrideUrlLoading(WebView webView, WebResourceRequest request) {
return shouldOverrideUrlLoading(request.getUrl().toString(), request.getMethod());
}
/**
@ -1071,17 +1192,53 @@ public class InAppBrowser extends CordovaPlugin {
*
* This handles a small subset of all the URIs that would be encountered.
*
* @param webView
* @param url
* @param method
*/
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String url) {
public boolean shouldOverrideUrlLoading(String url, String method) {
boolean override = false;
boolean useBeforeload = false;
String errorMessage = null;
if(beforeload.equals("yes")
//TODO handle POST requests then this condition can be removed:
&& !method.equals("POST"))
{
useBeforeload = true;
}else if(beforeload.equals("get") && (method == null || method.equals("GET"))){
useBeforeload = true;
}else if(beforeload.equals("post") && (method == null || method.equals("POST"))){
//TODO handle POST requests
errorMessage = "beforeload doesn't yet support POST requests";
}
// On first URL change, initiate JS callback. Only after the beforeload event, continue.
if (useBeforeload && this.waitForBeforeload) {
if(sendBeforeLoad(url, method)){
return true;
}
}
if(errorMessage != null){
try {
LOG.e(LOG_TAG, errorMessage);
JSONObject obj = new JSONObject();
obj.put("type", LOAD_ERROR_EVENT);
obj.put("url", url);
obj.put("code", -1);
obj.put("message", errorMessage);
sendUpdate(obj, true, PluginResult.Status.ERROR);
}catch(Exception e){
LOG.e(LOG_TAG, "Error sending loaderror for " + url + ": " + e.toString());
}
}
if (url.startsWith(WebView.SCHEME_TEL)) {
try {
Intent intent = new Intent(Intent.ACTION_DIAL);
intent.setData(Uri.parse(url));
cordova.getActivity().startActivity(intent);
return true;
override = true;
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error dialing " + url + ": " + e.toString());
}
@ -1090,7 +1247,7 @@ public class InAppBrowser extends CordovaPlugin {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse(url));
cordova.getActivity().startActivity(intent);
return true;
override = true;
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error with " + url + ": " + e.toString());
}
@ -1121,15 +1278,89 @@ public class InAppBrowser extends CordovaPlugin {
intent.putExtra("address", address);
intent.setType("vnd.android-dir/mms-sms");
cordova.getActivity().startActivity(intent);
return true;
override = true;
} catch (android.content.ActivityNotFoundException e) {
LOG.e(LOG_TAG, "Error sending sms " + url + ":" + e.toString());
}
}
// Test for whitelisted custom scheme names like mycoolapp:// or twitteroauthresponse:// (Twitter Oauth Response)
else if (!url.startsWith("http:") && !url.startsWith("https:") && url.matches("^[A-Za-z0-9+.-]*://.*?$")) {
if (allowedSchemes == null) {
String allowed = preferences.getString("AllowedSchemes", null);
if(allowed != null) {
allowedSchemes = allowed.split(",");
}
}
if (allowedSchemes != null) {
for (String scheme : allowedSchemes) {
if (url.startsWith(scheme)) {
try {
JSONObject obj = new JSONObject();
obj.put("type", "customscheme");
obj.put("url", url);
sendUpdate(obj, true);
override = true;
} catch (JSONException ex) {
LOG.e(LOG_TAG, "Custom Scheme URI passed in has caused a JSON error.");
}
}
}
}
}
if (useBeforeload) {
this.waitForBeforeload = true;
}
return override;
}
private boolean sendBeforeLoad(String url, String method){
try {
JSONObject obj = new JSONObject();
obj.put("type", "beforeload");
obj.put("url", url);
if(method != null){
obj.put("method", method);
}
sendUpdate(obj, true);
return true;
} catch (JSONException ex) {
LOG.e(LOG_TAG, "URI passed in has caused a JSON error.");
}
return false;
}
/**
* Legacy (deprecated in API 21)
* For Android 4.4 and below.
* @param view
* @param url
* @return
*/
@SuppressWarnings("deprecation")
@Override
public WebResourceResponse shouldInterceptRequest (final WebView view, String url) {
return shouldInterceptRequest(url, super.shouldInterceptRequest(view, url), null);
}
/**
* New (added in API 21)
* For Android 5.0 and above.
*
* @param webView
* @param request
*/
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {
return shouldInterceptRequest(request.getUrl().toString(), super.shouldInterceptRequest(view, request), request.getMethod());
}
public WebResourceResponse shouldInterceptRequest(String url, WebResourceResponse response, String method){
return response;
}
/*
* onPageStarted fires the LOAD_START_EVENT
*
@ -1172,6 +1403,11 @@ public class InAppBrowser extends CordovaPlugin {
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
// Set the namespace for postMessage()
if (Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1){
injectDeferredObject("window.webkit={messageHandlers:{cordova_iab:cordova_iab}}", null);
}
// CB-10395 InAppBrowser's WebView not storing cookies reliable to local device storage
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP) {
CookieManager.getInstance().flush();

View File

@ -19,99 +19,18 @@
#import <Cordova/CDVPlugin.h>
#import <Cordova/CDVInvokedUrlCommand.h>
#import <Cordova/CDVScreenOrientationDelegate.h>
#ifdef __CORDOVA_4_0_0
#import <Cordova/CDVUIWebViewDelegate.h>
#else
#import <Cordova/CDVWebViewDelegate.h>
#endif
@interface CDVInAppBrowser : CDVPlugin {}
@class CDVInAppBrowserViewController;
@interface CDVInAppBrowser : CDVPlugin {
}
@property (nonatomic, retain) CDVInAppBrowserViewController* inAppBrowserViewController;
@property (nonatomic, copy) NSString* callbackId;
@property (nonatomic, copy) NSRegularExpression *callbackIdPattern;
@property (nonatomic, assign) BOOL wkwebviewavailable;
@property (nonatomic, assign) BOOL usewkwebview;
- (void)open:(CDVInvokedUrlCommand*)command;
- (void)close:(CDVInvokedUrlCommand*)command;
- (void)injectScriptCode:(CDVInvokedUrlCommand*)command;
- (void)show:(CDVInvokedUrlCommand*)command;
- (void)hide:(CDVInvokedUrlCommand*)command;
- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command;
@end
@interface CDVInAppBrowserOptions : NSObject {}
@property (nonatomic, assign) BOOL location;
@property (nonatomic, assign) BOOL toolbar;
@property (nonatomic, copy) NSString* closebuttoncaption;
@property (nonatomic, copy) NSString* closebuttoncolor;
@property (nonatomic, assign) BOOL lefttoright;
@property (nonatomic, copy) NSString* toolbarposition;
@property (nonatomic, copy) NSString* toolbarcolor;
@property (nonatomic, assign) BOOL toolbartranslucent;
@property (nonatomic, assign) BOOL hidenavigationbuttons;
@property (nonatomic, assign) BOOL clearcache;
@property (nonatomic, assign) BOOL clearsessioncache;
@property (nonatomic, copy) NSString* presentationstyle;
@property (nonatomic, copy) NSString* transitionstyle;
@property (nonatomic, assign) BOOL enableviewportscale;
@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction;
@property (nonatomic, assign) BOOL allowinlinemediaplayback;
@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction;
@property (nonatomic, assign) BOOL suppressesincrementalrendering;
@property (nonatomic, assign) BOOL hidden;
@property (nonatomic, assign) BOOL disallowoverscroll;
+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options;
@end
@interface CDVInAppBrowserViewController : UIViewController <UIWebViewDelegate, CDVScreenOrientationDelegate>{
@private
NSString* _userAgent;
NSString* _prevUserAgent;
NSInteger _userAgentLockToken;
CDVInAppBrowserOptions *_browserOptions;
#ifdef __CORDOVA_4_0_0
CDVUIWebViewDelegate* _webViewDelegate;
#else
CDVWebViewDelegate* _webViewDelegate;
#endif
}
@property (nonatomic, strong) IBOutlet UIWebView* webView;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton;
@property (nonatomic, strong) IBOutlet UILabel* addressLabel;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* backButton;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* forwardButton;
@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner;
@property (nonatomic, strong) IBOutlet UIToolbar* toolbar;
@property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
@property (nonatomic, weak) CDVInAppBrowser* navigationDelegate;
@property (nonatomic) NSURL* currentURL;
- (void)close;
- (void)navigateTo:(NSURL*)url;
- (void)showLocationBar:(BOOL)show;
- (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition;
- (void)setCloseButtonTitle:(NSString*)title : (NSString*) colorString : (int) buttonIndex;
- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions;
@end
@interface CDVInAppBrowserNavigationController : UINavigationController
@property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
@end

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,27 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <Cordova/CDVScreenOrientationDelegate.h>
@interface CDVInAppBrowserNavigationController : UINavigationController
@property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
@end

View File

@ -0,0 +1,85 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVInAppBrowserNavigationController.h"
#define STATUSBAR_HEIGHT 20.0
@implementation CDVInAppBrowserNavigationController : UINavigationController
- (void) dismissViewControllerAnimated:(BOOL)flag completion:(void (^)(void))completion {
if ( self.presentedViewController) {
[super dismissViewControllerAnimated:flag completion:completion];
}
}
- (void) viewDidLoad {
CGRect statusBarFrame = [self invertFrameIfNeeded:[UIApplication sharedApplication].statusBarFrame];
statusBarFrame.size.height = STATUSBAR_HEIGHT;
// simplified from: http://stackoverflow.com/a/25669695/219684
UIToolbar* bgToolbar = [[UIToolbar alloc] initWithFrame:statusBarFrame];
bgToolbar.barStyle = UIBarStyleDefault;
[bgToolbar setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
[self.view addSubview:bgToolbar];
[super viewDidLoad];
}
- (CGRect) invertFrameIfNeeded:(CGRect)rect {
if (UIInterfaceOrientationIsLandscape([[UIApplication sharedApplication] statusBarOrientation])) {
CGFloat temp = rect.size.width;
rect.size.width = rect.size.height;
rect.size.height = temp;
}
rect.origin = CGPointZero;
return rect;
}
#pragma mark CDVScreenOrientationDelegate
- (BOOL)shouldAutorotate
{
if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotate)]) {
return [self.orientationDelegate shouldAutorotate];
}
return YES;
}
- (NSUInteger)supportedInterfaceOrientations
{
if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(supportedInterfaceOrientations)]) {
return [self.orientationDelegate supportedInterfaceOrientations];
}
return 1 << UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
if ((self.orientationDelegate != nil) && [self.orientationDelegate respondsToSelector:@selector(shouldAutorotateToInterfaceOrientation:)]) {
return [self.orientationDelegate shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
return YES;
}
@end

View File

@ -0,0 +1,53 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
@interface CDVInAppBrowserOptions : NSObject {}
@property (nonatomic, assign) BOOL usewkwebview;
@property (nonatomic, assign) BOOL location;
@property (nonatomic, assign) BOOL toolbar;
@property (nonatomic, copy) NSString* closebuttoncaption;
@property (nonatomic, copy) NSString* closebuttoncolor;
@property (nonatomic, assign) BOOL lefttoright;
@property (nonatomic, copy) NSString* toolbarposition;
@property (nonatomic, copy) NSString* toolbarcolor;
@property (nonatomic, assign) BOOL toolbartranslucent;
@property (nonatomic, assign) BOOL hidenavigationbuttons;
@property (nonatomic, copy) NSString* navigationbuttoncolor;
@property (nonatomic, assign) BOOL cleardata;
@property (nonatomic, assign) BOOL clearcache;
@property (nonatomic, assign) BOOL clearsessioncache;
@property (nonatomic, assign) BOOL hidespinner;
@property (nonatomic, copy) NSString* presentationstyle;
@property (nonatomic, copy) NSString* transitionstyle;
@property (nonatomic, assign) BOOL enableviewportscale;
@property (nonatomic, assign) BOOL mediaplaybackrequiresuseraction;
@property (nonatomic, assign) BOOL allowinlinemediaplayback;
@property (nonatomic, assign) BOOL keyboarddisplayrequiresuseraction;
@property (nonatomic, assign) BOOL suppressesincrementalrendering;
@property (nonatomic, assign) BOOL hidden;
@property (nonatomic, assign) BOOL disallowoverscroll;
@property (nonatomic, copy) NSString* beforeload;
+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options;
@end

View File

@ -0,0 +1,93 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVInAppBrowserOptions.h"
@implementation CDVInAppBrowserOptions
- (id)init
{
if (self = [super init]) {
// default values
self.usewkwebview = NO;
self.location = YES;
self.toolbar = YES;
self.closebuttoncaption = nil;
self.toolbarposition = @"bottom";
self.cleardata = NO;
self.clearcache = NO;
self.clearsessioncache = NO;
self.hidespinner = NO;
self.enableviewportscale = NO;
self.mediaplaybackrequiresuseraction = NO;
self.allowinlinemediaplayback = NO;
self.keyboarddisplayrequiresuseraction = YES;
self.suppressesincrementalrendering = NO;
self.hidden = NO;
self.disallowoverscroll = NO;
self.hidenavigationbuttons = NO;
self.closebuttoncolor = nil;
self.lefttoright = false;
self.toolbarcolor = nil;
self.toolbartranslucent = YES;
self.beforeload = @"";
}
return self;
}
+ (CDVInAppBrowserOptions*)parseOptions:(NSString*)options
{
CDVInAppBrowserOptions* obj = [[CDVInAppBrowserOptions alloc] init];
// NOTE: this parsing does not handle quotes within values
NSArray* pairs = [options componentsSeparatedByString:@","];
// parse keys and values, set the properties
for (NSString* pair in pairs) {
NSArray* keyvalue = [pair componentsSeparatedByString:@"="];
if ([keyvalue count] == 2) {
NSString* key = [[keyvalue objectAtIndex:0] lowercaseString];
NSString* value = [keyvalue objectAtIndex:1];
NSString* value_lc = [value lowercaseString];
BOOL isBoolean = [value_lc isEqualToString:@"yes"] || [value_lc isEqualToString:@"no"];
NSNumberFormatter* numberFormatter = [[NSNumberFormatter alloc] init];
[numberFormatter setAllowsFloats:YES];
BOOL isNumber = [numberFormatter numberFromString:value_lc] != nil;
// set the property according to the key name
if ([obj respondsToSelector:NSSelectorFromString(key)]) {
if (isNumber) {
[obj setValue:[numberFormatter numberFromString:value_lc] forKey:key];
} else if (isBoolean) {
[obj setValue:[NSNumber numberWithBool:[value_lc isEqualToString:@"yes"]] forKey:key];
} else {
[obj setValue:value forKey:key];
}
}
}
}
return obj;
}
@end

View File

@ -0,0 +1,91 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <Cordova/CDVPlugin.h>
#import <Cordova/CDVInvokedUrlCommand.h>
#import <Cordova/CDVScreenOrientationDelegate.h>
#import "CDVInAppBrowserOptions.h"
#import "CDVInAppBrowserNavigationController.h"
#ifdef __CORDOVA_4_0_0
#import <Cordova/CDVUIWebViewDelegate.h>
#else
#import <Cordova/CDVWebViewDelegate.h>
#endif
@class CDVUIInAppBrowserViewController;
@interface CDVUIInAppBrowser : CDVPlugin {
UIWindow * tmpWindow;
@private
NSString* _beforeload;
BOOL _waitForBeforeload;
}
@property (nonatomic, retain) CDVUIInAppBrowserViewController* inAppBrowserViewController;
@property (nonatomic, copy) NSString* callbackId;
@property (nonatomic, copy) NSRegularExpression *callbackIdPattern;
+ (id) getInstance;
- (void)open:(CDVInvokedUrlCommand*)command;
- (void)close:(CDVInvokedUrlCommand*)command;
- (void)injectScriptCode:(CDVInvokedUrlCommand*)command;
- (void)show:(CDVInvokedUrlCommand*)command;
- (void)hide:(CDVInvokedUrlCommand*)command;
- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command;
@end
@interface CDVUIInAppBrowserViewController : UIViewController <UIWebViewDelegate, CDVScreenOrientationDelegate>{
@private
NSString* _userAgent;
NSString* _prevUserAgent;
NSInteger _userAgentLockToken;
CDVInAppBrowserOptions *_browserOptions;
#ifdef __CORDOVA_4_0_0
CDVUIWebViewDelegate* _webViewDelegate;
#else
CDVWebViewDelegate* _webViewDelegate;
#endif
}
@property (nonatomic, strong) IBOutlet UIWebView* webView;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton;
@property (nonatomic, strong) IBOutlet UILabel* addressLabel;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* backButton;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* forwardButton;
@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner;
@property (nonatomic, strong) IBOutlet UIToolbar* toolbar;
@property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
@property (nonatomic, weak) CDVUIInAppBrowser* navigationDelegate;
@property (nonatomic) NSURL* currentURL;
- (void)close;
- (void)navigateTo:(NSURL*)url;
- (void)showLocationBar:(BOOL)show;
- (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition;
- (void)setCloseButtonTitle:(NSString*)title : (NSString*) colorString : (int) buttonIndex;
- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions;
@end

1129
src/ios/CDVUIInAppBrowser.m Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,80 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <Cordova/CDVPlugin.h>
#import <Cordova/CDVInvokedUrlCommand.h>
#import <Cordova/CDVScreenOrientationDelegate.h>
#import "CDVWKInAppBrowserUIDelegate.h"
#import "CDVInAppBrowserOptions.h"
#import "CDVInAppBrowserNavigationController.h"
@class CDVWKInAppBrowserViewController;
@interface CDVWKInAppBrowser : CDVPlugin {
@private
NSString* _beforeload;
BOOL _waitForBeforeload;
}
@property (nonatomic, retain) CDVWKInAppBrowser* instance;
@property (nonatomic, retain) CDVWKInAppBrowserViewController* inAppBrowserViewController;
@property (nonatomic, copy) NSString* callbackId;
@property (nonatomic, copy) NSRegularExpression *callbackIdPattern;
+ (id) getInstance;
- (void)open:(CDVInvokedUrlCommand*)command;
- (void)close:(CDVInvokedUrlCommand*)command;
- (void)injectScriptCode:(CDVInvokedUrlCommand*)command;
- (void)show:(CDVInvokedUrlCommand*)command;
- (void)hide:(CDVInvokedUrlCommand*)command;
- (void)loadAfterBeforeload:(CDVInvokedUrlCommand*)command;
@end
@interface CDVWKInAppBrowserViewController : UIViewController <CDVScreenOrientationDelegate,WKNavigationDelegate,WKUIDelegate,WKScriptMessageHandler>{
@private
NSString* _userAgent;
NSString* _prevUserAgent;
NSInteger _userAgentLockToken;
CDVInAppBrowserOptions *_browserOptions;
}
@property (nonatomic, strong) IBOutlet WKWebView* webView;
@property (nonatomic, strong) IBOutlet WKWebViewConfiguration* configuration;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* closeButton;
@property (nonatomic, strong) IBOutlet UILabel* addressLabel;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* backButton;
@property (nonatomic, strong) IBOutlet UIBarButtonItem* forwardButton;
@property (nonatomic, strong) IBOutlet UIActivityIndicatorView* spinner;
@property (nonatomic, strong) IBOutlet UIToolbar* toolbar;
@property (nonatomic, strong) IBOutlet CDVWKInAppBrowserUIDelegate* webViewUIDelegate;
@property (nonatomic, weak) id <CDVScreenOrientationDelegate> orientationDelegate;
@property (nonatomic, weak) CDVWKInAppBrowser* navigationDelegate;
@property (nonatomic) NSURL* currentURL;
- (void)close;
- (void)navigateTo:(NSURL*)url;
- (void)showLocationBar:(BOOL)show;
- (void)showToolBar:(BOOL)show : (NSString *) toolbarPosition;
- (void)setCloseButtonTitle:(NSString*)title : (NSString*) colorString;
- (id)initWithUserAgent:(NSString*)userAgent prevUserAgent:(NSString*)prevUserAgent browserOptions: (CDVInAppBrowserOptions*) browserOptions;
@end

1268
src/ios/CDVWKInAppBrowser.m Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,32 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import <WebKit/WebKit.h>
@interface CDVWKInAppBrowserUIDelegate : NSObject <WKUIDelegate>{
@private
UIViewController* _viewController;
}
@property (nonatomic, copy) NSString* title;
- (instancetype)initWithTitle:(NSString*)title;
-(void) setViewController:(UIViewController*) viewController;
@end

View File

@ -0,0 +1,127 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "CDVWKInAppBrowserUIDelegate.h"
@implementation CDVWKInAppBrowserUIDelegate
- (instancetype)initWithTitle:(NSString*)title
{
self = [super init];
if (self) {
self.title = title;
}
return self;
}
- (void) webView:(WKWebView*)webView runJavaScriptAlertPanelWithMessage:(NSString*)message
initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)(void))completionHandler
{
UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action)
{
completionHandler();
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:ok];
[[self getViewController] presentViewController:alert animated:YES completion:nil];
}
- (void) webView:(WKWebView*)webView runJavaScriptConfirmPanelWithMessage:(NSString*)message
initiatedByFrame:(WKFrameInfo*)frame completionHandler:(void (^)(BOOL result))completionHandler
{
UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
message:message
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action)
{
completionHandler(YES);
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:ok];
UIAlertAction* cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action)
{
completionHandler(NO);
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:cancel];
[[self getViewController] presentViewController:alert animated:YES completion:nil];
}
- (void) webView:(WKWebView*)webView runJavaScriptTextInputPanelWithPrompt:(NSString*)prompt
defaultText:(NSString*)defaultText initiatedByFrame:(WKFrameInfo*)frame
completionHandler:(void (^)(NSString* result))completionHandler
{
UIAlertController* alert = [UIAlertController alertControllerWithTitle:self.title
message:prompt
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* ok = [UIAlertAction actionWithTitle:NSLocalizedString(@"OK", @"OK")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action)
{
completionHandler(((UITextField*)alert.textFields[0]).text);
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:ok];
UIAlertAction* cancel = [UIAlertAction actionWithTitle:NSLocalizedString(@"Cancel", @"Cancel")
style:UIAlertActionStyleDefault
handler:^(UIAlertAction* action)
{
completionHandler(nil);
[alert dismissViewControllerAnimated:YES completion:nil];
}];
[alert addAction:cancel];
[alert addTextFieldWithConfigurationHandler:^(UITextField* textField) {
textField.text = defaultText;
}];
[[self getViewController] presentViewController:alert animated:YES completion:nil];
}
-(UIViewController*) getViewController
{
return _viewController;
}
-(void) setViewController:(UIViewController*) viewController
{
_viewController = viewController;
}
@end

View File

@ -20,7 +20,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
id="cordova-plugin-inappbrowser-tests"
version="2.0.3-dev">
version="3.0.1-dev">
<name>Cordova InAppBrowser Plugin Tests</name>
<license>Apache 2.0</license>
@ -29,5 +29,12 @@
<js-module src="tests.js" name="tests">
</js-module>
<platform name="ios">
<!-- The WKWebView implementation for inappbrowser requires the presence of this plugin -->
<dependency id="cordova-plugin-wkwebview-engine" />
<dependency id="cordova-plugin-wkwebview-engine-allowfileaccess" url="https://github.com/knight9999/cordova-plugin-wkwebview-engine-allowfileaccess.git" />
</platform>
<asset src="resources" target="cdvtests/iab-resources" />
</plugin>

View File

@ -23,6 +23,8 @@
var cordova = require('cordova');
var isWindows = cordova.platformId === 'windows';
var isIos = cordova.platformId === 'ios';
var isAndroid = cordova.platformId === 'android';
var isBrowser = cordova.platformId === 'browser';
window.alert = window.alert || navigator.notification.alert;
@ -32,127 +34,171 @@ if (isWindows && navigator && navigator.notification && navigator.notification.a
}
exports.defineAutoTests = function () {
var createTests = function (platformOpts) {
platformOpts = platformOpts || '';
describe('cordova.InAppBrowser', function () {
describe('cordova.InAppBrowser', function () {
it('inappbrowser.spec.1 should exist', function () {
expect(cordova.InAppBrowser).toBeDefined();
});
it('inappbrowser.spec.2 should contain open function', function () {
expect(cordova.InAppBrowser.open).toBeDefined();
expect(cordova.InAppBrowser.open).toEqual(jasmine.any(Function));
});
});
describe('open method', function () {
if (cordova.platformId === 'osx') {
pending('Open method not fully supported on OSX.');
return;
}
var iabInstance;
var originalTimeout;
var url = 'https://dist.apache.org/repos/dist/dev/cordova/';
var badUrl = 'http://bad-uri/';
beforeEach(function () {
// increase timeout to ensure test url could be loaded within test time
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
iabInstance = null;
});
afterEach(function (done) {
// restore original timeout
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
if (iabInstance !== null && iabInstance.close) {
iabInstance.close();
}
iabInstance = null;
// add some extra time so that iab dialog is closed
setTimeout(done, 2000);
});
function verifyEvent (evt, type) {
expect(evt).toBeDefined();
expect(evt.type).toEqual(type);
// `exit` event does not have url field, browser returns null url for CORS requests
if (type !== 'exit' && !isBrowser) {
expect(evt.url).toEqual(url);
}
}
function verifyLoadErrorEvent (evt) {
expect(evt).toBeDefined();
expect(evt.type).toEqual('loaderror');
expect(evt.url).toEqual(badUrl);
expect(evt.code).toEqual(jasmine.any(Number));
expect(evt.message).toEqual(jasmine.any(String));
}
it('inappbrowser.spec.3 should return InAppBrowser instance with required methods', function () {
iabInstance = cordova.InAppBrowser.open(url, '_blank');
expect(iabInstance).toBeDefined();
expect(iabInstance.addEventListener).toEqual(jasmine.any(Function));
expect(iabInstance.removeEventListener).toEqual(jasmine.any(Function));
expect(iabInstance.close).toEqual(jasmine.any(Function));
expect(iabInstance.show).toEqual(jasmine.any(Function));
expect(iabInstance.hide).toEqual(jasmine.any(Function));
expect(iabInstance.executeScript).toEqual(jasmine.any(Function));
expect(iabInstance.insertCSS).toEqual(jasmine.any(Function));
});
it('inappbrowser.spec.4 should support loadstart and loadstop events', function (done) {
var onLoadStart = jasmine.createSpy('loadstart event callback').and.callFake(function (evt) {
verifyEvent(evt, 'loadstart');
it('inappbrowser.spec.1 should exist', function () {
expect(cordova.InAppBrowser).toBeDefined();
});
iabInstance = cordova.InAppBrowser.open(url, '_blank');
iabInstance.addEventListener('loadstart', onLoadStart);
iabInstance.addEventListener('loadstop', function (evt) {
verifyEvent(evt, 'loadstop');
if (!isBrowser) {
it('inappbrowser.spec.2 should contain open function', function () {
expect(cordova.InAppBrowser.open).toBeDefined();
expect(cordova.InAppBrowser.open).toEqual(jasmine.any(Function));
});
});
describe('open method', function () {
if (cordova.platformId === 'osx') {
pending('Open method not fully supported on OSX.');
return;
}
var iabInstance;
var originalTimeout;
var url = 'https://dist.apache.org/repos/dist/dev/cordova/';
var badUrl = 'http://bad-uri/';
beforeEach(function () {
// increase timeout to ensure test url could be loaded within test time
originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = 30000;
iabInstance = null;
});
afterEach(function (done) {
// restore original timeout
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
if (iabInstance !== null && iabInstance.close) {
iabInstance.close();
}
iabInstance = null;
// add some extra time so that iab dialog is closed
setTimeout(done, 2000);
});
function verifyEvent (evt, type) {
expect(evt).toBeDefined();
expect(evt.type).toEqual(type);
// `exit` event does not have url field, browser returns null url for CORS requests
if (type !== 'exit' && !isBrowser) {
expect(evt.url).toEqual(url);
}
}
function verifyLoadErrorEvent (evt) {
expect(evt).toBeDefined();
expect(evt.type).toEqual('loaderror');
expect(evt.url).toEqual(badUrl);
expect(evt.code).toEqual(jasmine.any(Number));
expect(evt.message).toEqual(jasmine.any(String));
}
it('inappbrowser.spec.3 should return InAppBrowser instance with required methods', function () {
iabInstance = cordova.InAppBrowser.open(url, '_blank', platformOpts);
expect(iabInstance).toBeDefined();
expect(iabInstance.addEventListener).toEqual(jasmine.any(Function));
expect(iabInstance.removeEventListener).toEqual(jasmine.any(Function));
expect(iabInstance.close).toEqual(jasmine.any(Function));
expect(iabInstance.show).toEqual(jasmine.any(Function));
expect(iabInstance.hide).toEqual(jasmine.any(Function));
expect(iabInstance.executeScript).toEqual(jasmine.any(Function));
expect(iabInstance.insertCSS).toEqual(jasmine.any(Function));
});
it('inappbrowser.spec.4 should support loadstart and loadstop events', function (done) {
var onLoadStart = jasmine.createSpy('loadstart event callback').and.callFake(function (evt) {
verifyEvent(evt, 'loadstart');
});
iabInstance = cordova.InAppBrowser.open(url, '_blank', platformOpts);
iabInstance.addEventListener('loadstart', onLoadStart);
iabInstance.addEventListener('loadstop', function (evt) {
verifyEvent(evt, 'loadstop');
if (!isBrowser) {
// according to documentation, "loadstart" event is not supported on browser
// https://github.com/apache/cordova-plugin-inappbrowser#browser-quirks-1
expect(onLoadStart).toHaveBeenCalled();
}
done();
expect(onLoadStart).toHaveBeenCalled();
}
done();
});
});
});
it('inappbrowser.spec.5 should support exit event', function (done) {
iabInstance = cordova.InAppBrowser.open(url, '_blank');
iabInstance.addEventListener('exit', function (evt) {
verifyEvent(evt, 'exit');
done();
it('inappbrowser.spec.5 should support exit event', function (done) {
iabInstance = cordova.InAppBrowser.open(url, '_blank', platformOpts);
iabInstance.addEventListener('exit', function (evt) {
verifyEvent(evt, 'exit');
done();
});
iabInstance.close();
iabInstance = null;
});
iabInstance.close();
iabInstance = null;
});
it('inappbrowser.spec.6 should support loaderror event', function (done) {
if (isBrowser) {
it('inappbrowser.spec.6 should support loaderror event', function (done) {
if (isBrowser) {
// according to documentation, "loaderror" event is not supported on browser
// https://github.com/apache/cordova-plugin-inappbrowser#browser-quirks-1
pending('Browser platform doesn\'t support loaderror event');
}
iabInstance = cordova.InAppBrowser.open(badUrl, '_blank');
iabInstance.addEventListener('loaderror', function (evt) {
verifyLoadErrorEvent(evt);
done();
pending('Browser platform doesn\'t support loaderror event');
}
iabInstance = cordova.InAppBrowser.open(badUrl, '_blank', platformOpts);
iabInstance.addEventListener('loaderror', function (evt) {
verifyLoadErrorEvent(evt);
done();
});
});
it('inappbrowser.spec.7 should support message event', function (done) {
if (!isAndroid && !isIos) {
return pending(cordova.platformId + ' platform doesn\'t support message event');
}
var messageKey = 'my_message';
var messageValue = 'is_this';
iabInstance = cordova.InAppBrowser.open(url, '_blank', platformOpts);
iabInstance.addEventListener('message', function (evt) {
// Verify message event
expect(evt).toBeDefined();
expect(evt.type).toEqual('message');
expect(evt.data).toBeDefined();
expect(evt.data[messageKey]).toBeDefined();
expect(evt.data[messageKey]).toEqual(messageValue);
done();
});
iabInstance.addEventListener('loadstop', function (evt) {
var code = '(function(){\n' +
' var message = {' + messageKey + ': "' + messageValue + '"};\n' +
' webkit.messageHandlers.cordova_iab.postMessage(JSON.stringify(message));\n' +
'})()';
iabInstance.executeScript({ code: code });
});
});
});
});
};
if (isIos) {
createTests('usewkwebview=no');
createTests('usewkwebview=yes');
} else {
createTests();
}
};
exports.defineManualTests = function (contentEl, createActionButton) {
var platformOpts = '';
var platform_info = '';
if (isIos) {
platformOpts = 'usewkwebview=no';
platform_info = '<h1>Webview</h1>' +
'<p>Use this button to toggle the Webview implementation.</p>' +
'<div id="webviewToggle"></div>';
}
function doOpen (url, target, params, numExpectedRedirects, useWindowOpen) {
numExpectedRedirects = numExpectedRedirects || 0;
useWindowOpen = useWindowOpen || false;
@ -183,6 +229,9 @@ exports.defineManualTests = function (contentEl, createActionButton) {
console.log('Use window.open() for url');
iab = window.open(url, target, params, callbacks);
} else {
if (platformOpts) {
params += (params ? ',' : '') + platformOpts;
}
iab = cordova.InAppBrowser.open(url, target, params, callbacks);
}
if (!iab) {
@ -305,6 +354,9 @@ exports.defineManualTests = function (contentEl, createActionButton) {
var loadlistener = function (event) { alert('background window loaded '); }; // eslint-disable-line no-undef
function openHidden (url, startHidden) {
var shopt = (startHidden) ? 'hidden=yes' : '';
if (platformOpts) {
shopt += (shopt ? ',' : '') + platformOpts;
}
hiddenwnd = cordova.InAppBrowser.open(url, 'random_string', shopt);
if (!hiddenwnd) {
alert('cordova.InAppBrowser.open returned ' + hiddenwnd); // eslint-disable-line no-undef
@ -471,11 +523,11 @@ exports.defineManualTests = function (contentEl, createActionButton) {
// see http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences for details
if (window.MSApp && window.MSApp.execUnsafeLocalFunction) {
MSApp.execUnsafeLocalFunction(function () {
contentEl.innerHTML = info_div + local_tests + white_listed_tests + non_white_listed_tests + page_with_redirects_tests + pdf_url_tests + invalid_url_tests +
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 +
css_js_injection_tests + open_hidden_tests + clearing_cache_tests + video_tag_tests + local_with_anchor_tag_tests + hardwareback_tests;
});
} else {
contentEl.innerHTML = info_div + local_tests + white_listed_tests + non_white_listed_tests + page_with_redirects_tests + pdf_url_tests + invalid_url_tests +
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 +
css_js_injection_tests + open_hidden_tests + clearing_cache_tests + video_tag_tests + local_with_anchor_tag_tests + hardwareback_tests;
}
@ -489,6 +541,20 @@ exports.defineManualTests = function (contentEl, createActionButton) {
var injectjs = isWindows ? basePath + 'inject.js' : 'inject.js';
var injectcss = isWindows ? basePath + 'inject.css' : 'inject.css';
var videohtml = basePath + 'video.html';
if (isIos) {
createActionButton('Webview=UIWebView', function () {
var webviewOption = 'usewkwebview=';
var webviewToggle = document.getElementById('webviewToggle');
var button = webviewToggle.getElementsByClassName('topcoat-button')[0];
if (platformOpts === webviewOption + 'yes') {
platformOpts = webviewOption + 'no';
button.textContent = 'Webview=UIWebView';
} else {
platformOpts = webviewOption + 'yes';
button.textContent = 'Webview=WKWebView';
}
}, 'webviewToggle');
}
// Local
createActionButton('target=Default', function () {
@ -679,17 +745,17 @@ exports.defineManualTests = function (contentEl, createActionButton) {
doOpen('http://cordova.apache.org', '_blank', 'hardwareback=no');
}, 'openHardwareBackNo');
createActionButton('no hardwareback -> hardwareback=no -> no hardwareback', function () {
var ref = cordova.InAppBrowser.open('https://google.com', '_blank', 'location=yes');
var ref = cordova.InAppBrowser.open('https://google.com', '_blank', 'location=yes' + (platformOpts ? ',' + platformOpts : ''));
ref.addEventListener('loadstop', function () {
ref.close();
});
ref.addEventListener('exit', function () {
var ref2 = cordova.InAppBrowser.open('https://google.com', '_blank', 'location=yes,hardwareback=no');
var ref2 = cordova.InAppBrowser.open('https://google.com', '_blank', 'location=yes,hardwareback=no' + (platformOpts ? ',' + platformOpts : ''));
ref2.addEventListener('loadstop', function () {
ref2.close();
});
ref2.addEventListener('exit', function () {
cordova.InAppBrowser.open('https://google.com', '_blank', 'location=yes');
cordova.InAppBrowser.open('https://google.com', '_blank', 'location=yes' + (platformOpts ? ',' + platformOpts : ''));
});
});
}, 'openHardwareBackDefaultAfterNo');

166
types/index.d.ts vendored
View File

@ -5,6 +5,8 @@
//
// Copyright (c) Microsoft Open Technologies Inc
// Licensed under the MIT license.
// TypeScript Version: 2.3
type channel = "loadstart" | "loadstop" | "loaderror" | "exit" | "message";
interface Window {
/**
@ -15,34 +17,7 @@ interface Window {
* The options string must not contain any blank space, and each feature's
* name/value pairs must be separated by a comma. Feature names are case insensitive.
*/
open(url: string, target?: "_self", options?: string): InAppBrowser;
/**
* Opens a URL in a new InAppBrowser instance, the current browser instance, or the system browser.
* @param url The URL to load.
* @param target The target in which to load the URL, an optional parameter that defaults to _self.
* @param options Options for the InAppBrowser. Optional, defaulting to: location=yes.
* The options string must not contain any blank space, and each feature's
* name/value pairs must be separated by a comma. Feature names are case insensitive.
*/
open(url: string, target?: "_blank", options?: string): InAppBrowser;
/**
* Opens a URL in a new InAppBrowser instance, the current browser instance, or the system browser.
* @param url The URL to load.
* @param target The target in which to load the URL, an optional parameter that defaults to _self.
* @param options Options for the InAppBrowser. Optional, defaulting to: location=yes.
* The options string must not contain any blank space, and each feature's
* name/value pairs must be separated by a comma. Feature names are case insensitive.
*/
open(url: string, target?: "_system", options?: string): InAppBrowser;
/**
* Opens a URL in a new InAppBrowser instance, the current browser instance, or the system browser.
* @param url The URL to load.
* @param target The target in which to load the URL, an optional parameter that defaults to _self.
* @param options Options for the InAppBrowser. Optional, defaulting to: location=yes.
* The options string must not contain any blank space, and each feature's
* name/value pairs must be separated by a comma. Feature names are case insensitive.
*/
open(url: string, target?: string, options?: string, replace?: boolean): InAppBrowser;
open(url: string, target?: string, options?: string): InAppBrowser;
}
/**
@ -50,66 +25,21 @@ interface Window {
* NOTE: The InAppBrowser window behaves like a standard web browser, and can't access Cordova APIs.
*/
interface InAppBrowser extends Window {
onloadstart: (type: InAppBrowserEvent) => void;
onloadstop: (type: InAppBrowserEvent) => void;
onloaderror: (type: InAppBrowserEvent) => void;
onexit: (type: InAppBrowserEvent) => void;
onloadstart(type: Event): void;
onloadstop(type: InAppBrowserEvent): void;
onloaderror(type: InAppBrowserEvent): void;
onexit(type: InAppBrowserEvent): void;
// addEventListener overloads
/**
* Adds a listener for an event from the InAppBrowser.
* @param type the event to listen for
* loadstart: event fires when the InAppBrowser starts to load a URL.
* @param type loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an InAppBrowserEvent object as a parameter.
*/
addEventListener(type: "loadstart", callback: (event: InAppBrowserEvent) => void): void;
/**
* Adds a listener for an event from the InAppBrowser.
* @param type the event to listen for
* loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an InAppBrowserEvent object as a parameter.
*/
addEventListener(type: "loadstop", callback: (event: InAppBrowserEvent) => void): void;
/**
* Adds a listener for an event from the InAppBrowser.
* @param type the event to listen for
* loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an InAppBrowserEvent object as a parameter.
*/
addEventListener(type: "loaderror", callback: (event: InAppBrowserEvent) => void): void;
/**
* Adds a listener for an event from the InAppBrowser.
* @param type the event to listen for
* loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an InAppBrowserEvent object as a parameter.
*/
addEventListener(type: "exit", callback: (event: InAppBrowserEvent) => void): void;
/**
* Adds a listener for an event from the InAppBrowser.
* @param type the event to listen for
* loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an Event object as a parameter.
*/
addEventListener(type: string, callback: (event: Event) => void): void;
addEventListener(type: channel, callback: InAppBrowserEventListenerOrEventListenerObject): void;
// removeEventListener overloads
/**
* Removes a listener for an event from the InAppBrowser.
@ -121,51 +51,7 @@ interface InAppBrowser extends Window {
* @param callback the function that executes when the event fires. The function is
* passed an InAppBrowserEvent object as a parameter.
*/
removeEventListener(type: "loadstart", callback: (event: InAppBrowserEvent) => void): void;
/**
* Removes a listener for an event from the InAppBrowser.
* @param type The event to stop listening for.
* loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an InAppBrowserEvent object as a parameter.
*/
removeEventListener(type: "loadstop", callback: (event: InAppBrowserEvent) => void): void;
/**
* Removes a listener for an event from the InAppBrowser.
* @param type The event to stop listening for.
* loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an InAppBrowserEvent object as a parameter.
*/
removeEventListener(type: "loaderror", callback: (event: InAppBrowserEvent) => void): void;
/**
* Removes a listener for an event from the InAppBrowser.
* @param type The event to stop listening for.
* loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an InAppBrowserEvent object as a parameter.
*/
removeEventListener(type: "exit", callback: (event: InAppBrowserEvent) => void): void;
/**
* Removes a listener for an event from the InAppBrowser.
* @param type The event to stop listening for.
* loadstart: event fires when the InAppBrowser starts to load a URL.
* loadstop: event fires when the InAppBrowser finishes loading a URL.
* loaderror: event fires when the InAppBrowser encounters an error when loading a URL.
* exit: event fires when the InAppBrowser window is closed.
* @param callback the function that executes when the event fires. The function is
* passed an Event object as a parameter.
*/
removeEventListener(type: string, callback: (event: Event) => void): void;
removeEventListener(type: channel, callback: InAppBrowserEventListenerOrEventListenerObject): void;
/** Closes the InAppBrowser window. */
close(): void;
/** Hides the InAppBrowser window. Calling this has no effect if the InAppBrowser was already hidden. */
@ -184,29 +70,21 @@ interface InAppBrowser extends Window {
* For multi-line scripts, this is the return value of the last statement,
* or the last expression evaluated.
*/
executeScript(script: { code: string }, callback: (result: any) => void): void;
/**
* Injects JavaScript code into the InAppBrowser window.
* @param script Details of the script to run, specifying either a file or code key.
* @param callback The function that executes after the JavaScript code is injected.
* If the injected script is of type code, the callback executes with
* a single parameter, which is the return value of the script, wrapped in an Array.
* For multi-line scripts, this is the return value of the last statement,
* or the last expression evaluated.
*/
executeScript(script: { file: string }, callback: (result: any) => void): void;
executeScript(script: { code: string } | { file: string }, callback: (result: any) => void): void;
/**
* Injects CSS into the InAppBrowser window.
* @param css Details of the script to run, specifying either a file or code key.
* @param callback The function that executes after the CSS is injected.
*/
insertCSS(css: { code: string }, callback: () => void): void;
/**
* Injects CSS into the InAppBrowser window.
* @param css Details of the script to run, specifying either a file or code key.
* @param callback The function that executes after the CSS is injected.
*/
insertCSS(css: { file: string }, callback: () => void): void;
insertCSS(css: { code: string } | { file: string }, callback: () => void): void;
}
type InAppBrowserEventListenerOrEventListenerObject = InAppBrowserEventListener | InAppBrowserEventListenerObject;
type InAppBrowserEventListener = (evt: InAppBrowserEvent) => void;
interface InAppBrowserEventListenerObject {
handleEvent(evt: InAppBrowserEvent): void;
}
interface InAppBrowserEvent extends Event {
@ -219,3 +97,7 @@ interface InAppBrowserEvent extends Event {
/** the error message, only in the case of loaderror. */
message: string;
}
interface Cordova {
InAppBrowser: InAppBrowser;
}

View File

@ -33,19 +33,30 @@
function InAppBrowser () {
this.channels = {
'beforeload': channel.create('beforeload'),
'loadstart': channel.create('loadstart'),
'loadstop': channel.create('loadstop'),
'loaderror': channel.create('loaderror'),
'exit': channel.create('exit')
'exit': channel.create('exit'),
'customscheme': channel.create('customscheme'),
'message': channel.create('message')
};
}
InAppBrowser.prototype = {
_eventHandler: function (event) {
if (event && (event.type in this.channels)) {
this.channels[event.type].fire(event);
if (event.type === 'beforeload') {
this.channels[event.type].fire(event, this._loadAfterBeforeload);
} else {
this.channels[event.type].fire(event);
}
}
},
_loadAfterBeforeload: function (strUrl) {
strUrl = urlutil.makeAbsolute(strUrl);
exec(null, null, 'InAppBrowser', 'loadAfterBeforeload', [strUrl]);
},
close: function (eventname) {
exec(null, null, 'InAppBrowser', 'close', []);
},