cordova-code-swap
v2.0.8
Published
Allows fetching updates to js-part of app
Downloads
39
Readme
Cordova code swap
This library makes it possible to swap out the files that are used in your cordova webview.
It contains the code to be run on the client, a CLI and a API for programmatic usage.
Installation
npm install --save cordova-code-swap
Prerequisites
<!-- Required to copy files -->
<plugin name="cordova-plugin-file" spec="4.3.1" />
<!-- Required to download updates -->
<plugin name="cordova-plugin-file-transfer" spec="1.6.1" />
Getting started
The CLI can be installed globally with npm i -g cordova-code-swap
, but using the locally installed version through the script tag in package.json is recommended.
Dev mode
1: Run the CLI
$ ccs -i 'www/**/*' -o 'www' -d your-ip-address -r 'www/,' -a
2: Add client side code
Add this as the first code that is run in your cordova app:
var ccs = require('cordova-code-swap');
var ccsOptions = {
debug: { reloadServer: 'http://your-ip-address:port' } // this address is the output of the CLI
};
document.addEventListener('deviceready', function(){
ccs.initialize(ccsOptions)
.then(function() {
// run your code
});
});
Production mode
1: Run the CLI
$ ccs -i 'www/**/*' -o 'www' -r 'www/,'
2: Add client side code
Add this as the first code that is run in your cordova app. The code below will make the app download updates on the first run, and install them the next time the app is started.
var ccs = require('cordova-code-swap');
var urlToUpdateEndpoint = 'https://example.com/my-app/';
document.addEventListener('deviceready', function(){
ccs.initialize()
.then(function() { return ccs.install(); })
.finally(function() {
ccs.lookForUpdates(urlToUpdateEndpoint).then(download => download());
// run your code
});
});
Client API
ccs.initialize(...) -> Promise
Must be run before anything else!
Checks if a version has been downloaded earlier and should be loaded and returns a promise.
- Changes the window.location.href to the downloaded .html file if the iframe option is false. The returned promise never resolves so no further client code can be run while it is switching to the installed version.
- If running with the iframe options set to true, it will resolve with the url to the currently installed update.
ccs.lookForUpdates(...) -> Promise
Checks if the update server has an update and returns a promise.
If it does not, it rejects the promise with the error cordova-code-swap: No new updates found
.
If it encounters an error, it rejects the promise with the error.
If it finds an update, the promise is resolved with a download
function.
[lookForUpdates].then(function(download) { return download(); }) -> Promise
Downloads the update and returns a promise.
If it encounters an error, it rejects the promise with the error.
If it finished downloading without errors, the promise is resolved with an install
function.
The download
function can be called when you want to download the updated files.
The download
function has the property .updateInfo
tacked on. This contains the JSON-object it received from the server when looking for updates and can be used to better determine if you want to call download()
or not.
The download.updateInfo
object can e.g. look like this:
{
"content_url": "https://example.com/my-app-name/", //(or "content_url": "/relative/to/chcp.json")
"release": "1.3.3",
"installTime": "afterRestart",
"min_native_interface": 50
}
[download].then(function(install) { return install(); }) -> Promise
Returns a promise.
Switches to the new version by saving the current entry point in localStorage and changing window.location.href to the downloaded files.
ccs.install() -> Promise
Returns a promise.
If no update is previously downloaded it will reject the promise with the error: cordova-code-swap: Tried to install update, but no updates have been previously downloaded.
.
If an update is downloaded and pending installation, it will install that update and immediately switch to it.
Client options
Instance options
var instanceOptions = {
// how many of previously installed versions it should keep. Default is 1.
backupCount: 1,
// Setting iframe to true causes .initialize() and .install() to return
// the url of where the downloaded .html entry point recides.
// This can be useful if you want to run the downloaded app inside an iframe.
iframe: false,
// Debug mode is useful for local development, but must be disabled before
// submitting to the app-store/google-play
debug: {
// The server which it will look for real time updates from
reloadServer: 'http://my-ip:port/',
// When in debug mode, this function will be called with the
// new url to use in the iframe each time the app has
// installed an update
onIframeUpdate: function(url){},
// This setting will make the plugin swap out files in the
// same folder on each update to preserve code-breakpoints.
preserveBreakpoints: true
}
}
ccs.initialize(instanceOptions);
Update options
var updateOptions = {
// Path to your .html file, relative to the www-folder. Default is index.html
entryFile: 'index.html',
// Headers that will be sent with the requests to the update server
headers: {
key: value
},
// Timeout before it aborts requests to the update server in milliseconds.
// Default is 30 seconds.
timeout: 30000
}
ccs.lookForUpdates('http://example.com/', updateOptions);
Usage - all options exposed
var ccs = require('cordova-code-swap');
var urlToUpdateEndpoint = 'https://example.com/my-app/';
var myNativeVersion = getNativeVersionSomehow();
var updateOptions = {
entryFile: 'index.html',
headers: {
'x-request-from': 'Cordova-Code-Swap'
},
timeout: 10000
};
var instanceOptions = {
backupCount: 1,
iframe: true,
debug: {
reloadServer: 'http://my-ip:port/',
onIframeUpdate: function(){},
preserveBreakpoints: true
}
};
function progressCallback(percentageAsInt, downloadedFileName) {
console.log(percentageAsInt + '% done', 'Downloaded ' + downloadedFileName);
};
document.addEventListener('deviceready', function(){
ccs.initialize(instanceOptions) // must always be run before anything else
.then(function() {
return ccs.lookForUpdates(urlToUpdateEndpoint, updateOptions)
})
.catch(function(err) { /*handle the error*/ })
.then(function(download) {
if (download.updateInfo.min_native_interface > myNativeVersion) {
throw new Error('Update received from the server requires newer native version of the app to be installed.');
}
return download(progressCallback);
})
.catch(function(downloadErr) { /*handle the error*/ })
.then(function(install) { return install() })
.catch(function(installErr) { /*handle the error*/ });
// optional
ccs.install(); // <-- can be used after e.g. restarting the app if there is a downloaded update that has not been installed yet.
});
Programmatic API
If you don't want to use the CLI, but instead want to e.g. use it in a build system, this library offers a programmatic interface.
var ccs = require('cordova-code-swap/utils/createCCSFiles');
var ccsOptions = {
// the config that will be merged into chcp.json
config: {},
// "a" will be replaced with "b" in the generated manifest file paths
replace: ['a', 'b'],
// the ip:port the debug server will be run on, watches files and generates new manifest upon change
dev: '',
// make the app update every time the manifest updates (when running with dev option)
autoUpdate: false
};
var inputGlob = ['www/**/*']; // array of minimatch strings that will be included in the manifest file
var outputFolder = 'www'; // path to where chcp.json and chcp.manifest will be output to
ccs(inputGlob, outputFolder, ccsOptions) // returns promise that resolves with an emit function that tells the app to update
.then(function(emitUpdateNotification) {
// useful when not using ccsOptions.autoUpdate
emitUpdateNotification();
});