Skip to content
This repository was archived by the owner on Jan 14, 2022. It is now read-only.

Commit a31b045

Browse files
author
msrodri
committed
Merge pull request #54 from manifoldjs/v0.2.0
v0.2.0
2 parents 423fd3d + 6ee0a11 commit a31b045

16 files changed

+1002
-193
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cordova-plugin-hostedwebapp",
3-
"version": "0.1.5",
3+
"version": "0.2.0",
44
"description": "Hosted Web App Plugin",
55
"cordova": {
66
"id": "cordova-plugin-hostedwebapp",

plugin.xml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
33
id="cordova-plugin-hostedwebapp"
4-
version="0.1.4">
4+
version="0.2.0">
55
<name>HostedWebApp</name>
66
<description>Hosted Web App Plugin</description>
77
<license>MIT License</license>
@@ -20,13 +20,15 @@
2020
<js-module src="www/hostedWebApp.js" name="hostedwebapp">
2121
<clobbers target="hostedwebapp" />
2222
</js-module>
23+
24+
<asset src="www/hostedapp-bridge.js" target="hostedapp-bridge.js" />
2325

2426
<engines>
2527
<engine name="cordova-windows" version="<=4.1.0" />
26-
<engine name="cordova-ios" version="<=3.9.1" />
28+
<engine name="cordova-ios" version="<=3.9.2" />
2729
<engine name="cordova-android" version="<=4.1.1" />
2830
</engines>
29-
31+
3032
<!-- android -->
3133
<platform name="android">
3234
<config-file target="res/xml/config.xml" parent="/*">

readme.md

Lines changed: 75 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ When the application is launched, the plugin automatically handles navigation to
3737

3838
> **Note:** Although the W3C specs for the Web App manifest consider absolute and relative URLs valid for the _start_url_ value (e.g. _http://www.racer2k.net/racer/start.html_ and _/start.html_ are both valid), the plugin requires this URL **to be an absolute URL**. Otherwise, the installed applications won't be able to navigate to the web site.
3939
40+
The plugin enables the injection of additional Cordova plugins and app-specific scripts that consume them allowing you to take advantage of native features in your hosted web apps.
41+
4042
Lastly, since network connectivity is essential to the operation of a hosted web application, the plugin implements a basic offline feature that will show an offline page whenever connectivity is lost and will prevent users from interacting with the application until the connection is restored.
4143

4244
## Installation
@@ -82,6 +84,68 @@ The plugin enables using content hosted in a web site inside a Cordova applicati
8284
> **Note:** The plugin updates the Cordova configuration file (config.xml) with the information in the W3C manifest. If the information in the manifest changes, you can reapply the updated manifest settings at any time by executing prepare. For example:
8385
`cordova prepare`
8486

87+
### Using Cordova Plugins in Hosted Web Apps
88+
The plugin supports the injection of Cordova and the plugin interface scripts into the pages of a hosted site. There are two different plugin modes: '_server_' and '_client_'. In '_client_' mode, the **cordova.js** file and the plugin interface script files are retrieved from the app package. In '_server_' mode, these files are downloaded from the server along with the rest of the app's content. The plugin also provides a mechanism for injecting scripts that can be used, among other things, to consume the plugins added to the app. Imported scripts can be retrieved from the app package or downloaded from a remote source.
89+
90+
Very briefly, these are the steps that are needed to use plugins:
91+
92+
- Add one or more Cordova plugins to the app.
93+
94+
- Enable API access in any pages where Cordova and the plugins will be used. This injects the Cordova runtime environment and is configured via a custom extension in the W3C manifest. The **match** and **platform** attributes specifies the pages and platforms where you will use Cordova.
95+
96+
```
97+
{
98+
...
99+
"mjs_api_access": [
100+
{ "match": "http://yoursite.com/path1/*", "platform": "android, ios, windows", "access": "cordova" },
101+
...
102+
]
103+
}
104+
```
105+
- Optionally, choose a plugin mode. The default mode is _client_.
106+
107+
**Client mode**
108+
```
109+
{
110+
...
111+
"mjs_cordova": {
112+
"plugin_mode": "client"
113+
}
114+
}
115+
```
116+
117+
**Server mode**
118+
```
119+
{
120+
...
121+
"mjs_cordova": {
122+
"plugin_mode": "server",
123+
"base_url": "js/cordova"
124+
}
125+
}
126+
```
127+
128+
(In '_server_' mode, the Cordova files and plugin interface scripts must be deployed to the site to the path specified in **base_url**. Also, the **cordova.js** and **cordova_plugins.js** files for each platform need to be renamed to specify the platform in their names so that **cordova.js** and **cordova_plugins.js** become, in the case of Android for example, **cordova-android.js** and **cordova_plugins-android.js** respectively.)
129+
130+
To inject scripts into the hosted web content:
131+
132+
- Update the app's manifest to list the imported scripts in a custom **mjs_import_scripts** section.
133+
```
134+
{
135+
...
136+
"mjs_import_scripts": [
137+
{ "src": "js/alerts.js" },
138+
{ "src": "http://yoursite.com/js/app/contacts.js" },
139+
{ "src": "js/camera.js", "match": "http://yoursite.com/profile/*" },
140+
...
141+
]
142+
}
143+
```
144+
145+
- For app-hosted scripts, copy the script files to the Cordova project. The path in **mjs_import_scripts** must be specified relative to the '_www_' folder of the project. Server-hosted scripts must be deployed to the site.
146+
147+
The following [wiki article](https://github.com/manifoldjs/ManifoldJS/wiki/Using-Cordova-Plugins-in-Hosted-Web-Apps) provides additional information about these features.
148+
85149
### Offline Feature
86150
The plugin implements a basic offline feature that will show an offline page whenever network connectivity is lost. By default, the page shows a suitable message alerting the user about the loss of connectivity. To customize the offline experience, a page named **offline.html** can be placed in the **www** folder of the application and it will be used instead.
87151
@@ -130,20 +194,18 @@ For example, the following manifest references icons from the _/resources_ path
130194
}
131195
</pre>
132196
133-
### URL Access Rules
134-
For a hosted web application, the W3C manifest defines a scope that restricts the URLs to which the application can navigate. Additionally, the manifest can include a proprietary setting named **mjs_access_whitelist** that defines an array of access rules each one consisting of a _url_ attribute that identifies the target of the rule and indicates whether URLs matching the rule should be navigated to by the application. Non-matching URLs will be launched externally.
197+
### Navigation Scope
198+
For a hosted web application, the W3C manifest defines a scope that restricts the URLs to which the application can navigate. Additionally, the manifest can include a proprietary setting named **mjs_extended_scope** that defines an array of scope rules each one indicating whether URLs matching the rule should be navigated to by the application. Non-matching URLs will be launched externally.
135199
136-
Typically, Cordova applications define access rules to implement a security policy that controls access to external domains. The access rules must not only allow access to the scope defined by the W3C manifest but also to external content used within the site, for example, to reference script files hosted by a CDN origin.
137-
138-
To configure the security policy, the plugin hook maps the scope and URL access rules in the W3C manifest (**manifest.json**) to suitable access elements in the Cordova configuration file (**config.xml**). For example:
200+
Typically, Cordova applications define scope rules to implement a security policy that controls access to external domains. To configure the security policy, the plugin hook maps the scope rules in the W3C manifest (**manifest.json**) to suitable `<allow-navigation>` elements in the Cordova configuration file (**config.xml**). For example:
139201
140202
**Manifest.json**
141203
<pre>
142204
...
143205
"start_url": "http://www.xyz.com/",
144206
"scope": "/",
145-
"mjs_access_whitelist": [
146-
{ "url": "http//googleapis.com/*" },
207+
"mjs_extended_scope": [
208+
{ "url": "http//otherdomain.com/*" },
147209
{ "url": "http//login.anotherdomain.com/" }
148210
]
149211
...
@@ -152,9 +214,9 @@ To configure the security policy, the plugin hook maps the scope and URL access
152214
**Config.xml**
153215
<pre>
154216
...
155-
&lt;access origin="http://www.xyz.com/*" /&gt;
156-
&lt;access origin="http://googleapis.com/*" /&gt;
157-
&lt;access origin="http://login.anotherdomain.com/" /&gt;
217+
&lt;allow-navigation href="http://www.xyz.com/*" /&gt;
218+
&lt;allow-navigation href="http://otherdomain.com/*" /&gt;
219+
&lt;allow-navigation href="http://login.anotherdomain.com/" /&gt;
158220
...
159221
</pre>
160222
@@ -198,13 +260,12 @@ Windows Phone 8.1
198260
iOS
199261
Android
200262
201-
### Windows 8.1 and Windows Phone 8.1 Quirks
263+
### Windows and Windows Phone Quirks
202264
203-
Cordova for Android and iOS platforms provide a security policy to control which network requests triggered by the page (css, js, images, XHRs, etc.) are allowed to be made; this means that they will be blocked if they are outside the scope and do not match any of the access rules defined in the manifest.
265+
Cordova for Android and iOS platforms provide a security policy to control which network requests triggered by the page (css, js, images, XHRs, etc.) are allowed to be made; this means that they will be blocked if they don't match the `origin` attribute of any of the `<access>` elements defined in the Cordova configuration file (**config.xml**).
204266
205267
The Windows and Windows Phone platforms do not provide control for these kind of requests, and they will be allowed.
206268
207-
208269
## Changelog
209270
210-
Releases are documented in [GitHub](https://github.com/manifoldjs/ManifoldCordova/releases).
271+
Releases are documented in [GitHub](https://github.com/manifoldjs/ManifoldCordova/releases).

scripts/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"builder": "node ./node_modules/mocha/bin/mocha --reporter mocha-teamcity-reporter"
1111
},
1212
"devDependencies": {
13-
"cordova-lib": "^5.0.0",
13+
"cordova-lib": "^5.4.0",
1414
"mocha": "^2.2.1",
1515
"mocha-teamcity-reporter": "0.0.4",
1616
"q": "^1.2.0"

scripts/rollbackWindowsWrapperFiles.js

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,15 @@ function deleteFile(path) {
4141

4242
// Configure Cordova configuration parser
4343
function configureParser(context) {
44-
var cordova_util = context.requireCordovaModule('cordova-lib/src/cordova/util'),
45-
ConfigParser = context.requireCordovaModule('cordova-lib/src/configparser/ConfigParser');
44+
var cordova_util = context.requireCordovaModule('cordova-lib/src/cordova/util');
45+
var ConfigParser;
46+
try {
47+
ConfigParser = context.requireCordovaModule('cordova-lib/node_modules/cordova-common').ConfigParser;
48+
} catch (err) {
49+
// Fallback to old location of config parser (old versions of cordova-lib)
50+
ConfigParser = context.requireCordovaModule('cordova-lib/src/configparser/ConfigParser');
51+
}
52+
4653
etree = context.requireCordovaModule('cordova-lib/node_modules/elementtree');
4754

4855
var xml = cordova_util.projectConfig(context.opts.projectRoot);

scripts/test/assets/fullAccessRules/manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"orientation": "landscape",
55
"display": "fullscreen",
66
"scope": "http://wat-docs.azurewebsites.net/*",
7-
"mjs_access_whitelist": [
8-
{ "url": "http://wat.codeplex.com", "external": true }
7+
"mjs_extended_scope": [
8+
"http://wat.codeplex.com"
99
]
1010
}

scripts/test/assets/xmlEmptyWidget/manifest.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"orientation": "landscape",
55
"display": "fullscreen",
66
"scope": "/scope-path/",
7-
"mjs_access_whitelist": [
8-
{ "url": "whitelist-rule-1" },
9-
{ "url": "whitelist-rule-2" }
10-
]
7+
"mjs_extended_scope": [
8+
"whitelist-rule-1",
9+
"whitelist-rule-2"
10+
]
1111
}

scripts/test/updateConfigurationBeforePrepare.js

Lines changed: 34 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,10 @@ function initializeContext(testDir) {
4343
return require('cordova-lib/src/cordova/util');
4444
}
4545

46+
if (moduleName === 'cordova-lib/node_modules/cordova-common') {
47+
return require('cordova-lib/node_modules/cordova-common');
48+
}
49+
4650
if (moduleName === 'cordova-lib/src/configparser/ConfigParser') {
4751
return require('cordova-lib/src/configparser/ConfigParser');
4852
}
@@ -228,119 +232,102 @@ describe('updateConfigurationBeforePrepare.js', function (){
228232
});
229233
});
230234

231-
it('Should remove "root" full access rules from config.xml', function (done){
235+
it('Should keep generic network access rules from config.xml', function (done){
232236
var testDir = path.join(workingDirectory, 'fullAccessRules');
233237
var configXML = path.join(testDir, 'config.xml');
234238
var ctx = initializeContext(testDir);
235239

236240
updateConfiguration(ctx).then(function () {
237241
var content = fs.readFileSync(configXML).toString();
238-
assert(content.indexOf('<allow-navigation href="http://*/*\" />') === -1);
239-
assert(content.indexOf('<allow-navigation href="https://*/*\" />') === -1);
240-
assert(content.indexOf('<allow-navigation href="*" />') === -1);
241-
assert(content.indexOf('<allow-intent href="https://*/*\" />') === -1);
242-
assert(content.indexOf('<allow-intent href="http://*/*\" />') === -1);
242+
assert(content.indexOf('<access origin="https://*/*" />') > 0);
243+
assert(content.indexOf('<access origin="http://*/*" />') > 0);
244+
245+
done();
246+
});
247+
});
248+
249+
it('Should remove generic allow-intent rules from config.xml', function (done){
250+
var testDir = path.join(workingDirectory, 'fullAccessRules');
251+
var configXML = path.join(testDir, 'config.xml');
252+
var ctx = initializeContext(testDir);
253+
254+
updateConfiguration(ctx).then(function () {
255+
var content = fs.readFileSync(configXML).toString();
256+
assert(content.indexOf('<allow-intent href="https://*/*" />') === -1);
257+
assert(content.indexOf('<allow-intent href="http://*/*" />') === -1);
243258
assert(content.indexOf('<allow-intent href="*" />') === -1);
244-
assert(content.indexOf('<access origin="https://*/*\" />') === -1);
245-
assert(content.indexOf('<access origin="http://*/*\" />') === -1);
246259

247260
done();
248261
});
249262
});
250263

251-
it('Should add access rules for web site domain in config.xml if scope is missing', function (done){
264+
it('Should add allow-navigation rule for web site domain in config.xml if scope is missing', function (done){
252265
var testDir = path.join(workingDirectory, 'normalFlow');
253266
var configXML = path.join(testDir, 'config.xml');
254267
var ctx = initializeContext(testDir);
255268

256269
updateConfiguration(ctx).then(function () {
257270
var content = fs.readFileSync(configXML).toString();
258271

259-
// rules for android
260-
assert(content.match(/<platform name="android">[\s\S]*<access hap-rule="yes" origin="http:\/\/wat-docs.azurewebsites.net\/\*" \/>[\s\S]*<\/platform>/));
261-
assert(content.match(/<platform name="android">[\s\S]*<allow-navigation hap-rule="yes" href="http:\/\/wat-docs.azurewebsites.net\/\*" \/>[\s\S]*<\/platform>/));
262-
263-
// rules for ios
264-
assert(content.match(/<platform name="ios">[\s\S]*<access hap-rule="yes" origin="http:\/\/wat-docs.azurewebsites.net\/\*" \/>[\s\S]*<\/platform>/));
272+
assert(content.indexOf('<allow-navigation hap-rule="yes" href="http://wat-docs.azurewebsites.net/*" />') > 0);
265273

266274
done();
267275
});
268276
});
269277

270-
it('Should add access rules for scope in config.xml if scope is a relative URL', function (done){
278+
it('Should add allow-navigation rule for scope in config.xml if scope is a relative URL', function (done){
271279
var testDir = path.join(workingDirectory, 'xmlEmptyWidget');
272280
var configXML = path.join(testDir, 'config.xml');
273281
var ctx = initializeContext(testDir);
274282

275283
updateConfiguration(ctx).then(function () {
276284
var content = fs.readFileSync(configXML).toString();
277285

278-
// rules for android
279-
assert(content.match(/<platform name="android">[\s\S]*<access hap-rule="yes" origin="http:\/\/wat-docs.azurewebsites.net\/scope-path\/\*" \/>[\s\S]*<\/platform>/));
280-
assert(content.match(/<platform name="android">[\s\S]*<allow-navigation hap-rule="yes" href="http:\/\/wat-docs.azurewebsites.net\/scope-path\/\*" \/>[\s\S]*<\/platform>/));
281-
282-
// rules for ios
283-
assert(content.match(/<platform name="ios">[\s\S]*<access hap-rule="yes" origin="http:\/\/wat-docs.azurewebsites.net\/scope-path\/\*" \/>[\s\S]*<\/platform>/));
286+
assert(content.indexOf('<allow-navigation hap-rule="yes" href="http://wat-docs.azurewebsites.net/scope-path/*" />') > 0);
284287

285288
done();
286289
});
287290
});
288291

289-
it('Should add access rules for scope in config.xml if scope is a full URL', function (done){
292+
it('Should add allow-navigation rules for scope in config.xml if scope is a full URL', function (done){
290293
var testDir = path.join(workingDirectory, 'fullUrlForScope');
291294
var configXML = path.join(testDir, 'config.xml');
292295
var ctx = initializeContext(testDir);
293296

294297
updateConfiguration(ctx).then(function () {
295298
var content = fs.readFileSync(configXML).toString();
296299

297-
// rules for android
298-
assert(content.match(/<platform name="android">[\s\S]*<access hap-rule="yes" origin="http:\/\/www.domain.com\/\*" \/>[\s\S]*<\/platform>/));
299-
assert(content.match(/<platform name="android">[\s\S]*<allow-navigation hap-rule="yes" href="http:\/\/www.domain.com\/\*" \/>[\s\S]*<\/platform>/));
300-
301-
// rules for ios
302-
assert(content.match(/<platform name="ios">[\s\S]*<access hap-rule="yes" origin="http:\/\/www.domain.com\/\*" \/>[\s\S]*<\/platform>/));
300+
assert(content.indexOf('<allow-navigation hap-rule="yes" href="http://www.domain.com/*" />') > 0);
303301

304302
done();
305303
});
306304
});
307305

308-
it('Should add access rules for scope in config.xml if scope is a full URL with wildcard as subdomain', function (done){
306+
it('Should add allow-navigation rule for scope in config.xml if scope is a full URL with wildcard as subdomain', function (done){
309307
var testDir = path.join(workingDirectory, 'wildcardSubdomainForScope');
310308
var configXML = path.join(testDir, 'config.xml');
311309
var ctx = initializeContext(testDir);
312310

313311
updateConfiguration(ctx).then(function () {
314312
var content = fs.readFileSync(configXML).toString();
315313

316-
// rules for android
317-
assert(content.match(/<platform name="android">[\s\S]*<access hap-rule="yes" origin="http:\/\/\*.domain.com" \/>[\s\S]*<\/platform>/));
318-
assert(content.match(/<platform name="android">[\s\S]*<allow-navigation hap-rule="yes" href="http:\/\/\*.domain.com" \/>[\s\S]*<\/platform>/));
319-
320-
// rules for ios
321-
assert(content.match(/<platform name="ios">[\s\S]*<access hap-rule="yes" origin="http:\/\/\*.domain.com" \/>[\s\S]*<\/platform>/));
322-
314+
assert(content.indexOf('<allow-navigation hap-rule="yes" href="http://*.domain.com" />') > 0);
315+
323316
done();
324317
});
325318
});
326319

327-
it('Should add access rules from mjs_access_whitelist list', function (done){
320+
it('Should add allow-navigation rules from mjs_access_whitelist list', function (done){
328321
var testDir = path.join(workingDirectory, 'xmlEmptyWidget');
329322
var configXML = path.join(testDir, 'config.xml');
330323
var ctx = initializeContext(testDir);
331324

332325
updateConfiguration(ctx).then(function () {
333326
var content = fs.readFileSync(configXML).toString();
334-
// rules for android
335-
assert(content.match(/<platform name="android">[\s\S]*<access hap-rule="yes" origin="whitelist-rule-1" \/>[\s\S]*<\/platform>/));
336-
assert(content.match(/<platform name="android">[\s\S]*<allow-navigation hap-rule="yes" href="whitelist-rule-1" \/>[\s\S]*<\/platform>/));
337-
assert(content.match(/<platform name="android">[\s\S]*<access hap-rule="yes" origin="whitelist-rule-2" \/>[\s\S]*<\/platform>/));
338-
assert(content.match(/<platform name="android">[\s\S]*<allow-navigation hap-rule="yes" href="whitelist-rule-2" \/>[\s\S]*<\/platform>/));
339327

340-
// rules for ios
341-
assert(content.match(/<platform name="ios">[\s\S]*<access hap-rule="yes" origin="whitelist-rule-1" \/>[\s\S]*<\/platform>/));
342-
assert(content.match(/<platform name="ios">[\s\S]*<access hap-rule="yes" origin="whitelist-rule-2" \/>[\s\S]*<\/platform>/));
343-
328+
assert(content.indexOf('<allow-navigation hap-rule="yes" href="whitelist-rule-1" />') > 0);
329+
assert(content.indexOf('<allow-navigation hap-rule="yes" href="whitelist-rule-2" />') > 0);
330+
344331
done();
345332
});
346333
});

0 commit comments

Comments
 (0)