manifoldjs-cordova
Version:
ManifoldJS Cordova Platform
260 lines (209 loc) • 10.6 kB
JavaScript
;
var path = require('path'),
url = require('url'),
util = require('util');
var Q = require('q');
var lib = require('manifoldjs-lib');
var CustomError = lib.CustomError,
fileTools = lib.fileTools,
manifestTools = lib.manifestTools,
PlatformBase = lib.PlatformBase,
processTools = lib.processTools,
projectTools = lib.projectTools,
exec = lib.processTools.exec,
utils = lib.utils;
var constants = require('./constants');
// ID or URL of the Hosted Web App plugin
// Specifies the location and version constraints (if applicable) of the plugin.
// Can be overriden by defining a CORDOVA_PLUGIN_HOSTEDWEBAPP environment variable. For example:
// SET "CORDOVA_PLUGIN_HOSTEDWEBAPP=cordova-plugin-hostedwebapp@0.4.5"
var pluginIdOrUrl = process.env.CORDOVA_PLUGIN_HOSTEDWEBAPP || 'cordova-plugin-hostedwebapp@>=0.3.0 <0.4.0';
function Platform (packageName, platforms) {
var self = this;
PlatformBase.call(this, constants.platform.id, constants.platform.name, packageName, __dirname);
// save platform list
self.platforms = platforms;
// returns the path to the cordova shell command
var cachedCordovaPath;
function getCordovaPath () {
if (!cachedCordovaPath) {
// npm command in Windows is a batch file and needs to include extension to be resolved by spawn call
var cordova = (process.platform === 'win32' ? 'cordova.cmd' : 'cordova');
return processTools.getCommandPath(__dirname, cordova)
.then(function (commandPath) {
cachedCordovaPath = commandPath;
if (!commandPath) {
return Q.reject(new Error('Failed to locate the Cordova shell command: \'' + cordova + '\'.'));
}
return cachedCordovaPath = commandPath;
});
}
return Q.resolve(cachedCordovaPath);
}
function createApp (rootDir, appName, packageName, cordovaAppName, callback) {
self.info('Creating the ' + constants.platform.name + ' project...');
return getCordovaPath().then(function (cordovaPath) {
return exec(cordovaPath, ['create', appName, packageName, cordovaAppName], { cwd: rootDir, statusMessage: 'Creating app ' });
})
.catch(function (err) {
return Q.reject(new CustomError('Failed to create the base Cordova application.', err));
})
.nodeify(callback);
}
function addPlatforms (rootDir, platforms, callback) {
var allPlatforms = platforms.join(' ');
self.info('Adding the following Cordova platforms: ' + allPlatforms + '...');
return getCordovaPath().then(function (cordovaPath) {
return exec(cordovaPath, ['platform', 'add'].concat(platforms), { cwd: rootDir, statusMessage: 'Adding platforms ' });
})
.catch(function (err) {
return Q.reject(new CustomError('Failed to add the Cordova platforms: ' + allPlatforms + '.', err));
})
.nodeify(callback);
}
function addPlugins (rootDir, options, callback) {
var pluginList = [pluginIdOrUrl];
if (options.crosswalk) {
pluginList.push('cordova-plugin-crosswalk-webview');
}
if (options.webAppToolkit) {
pluginList.push('cordova-plugin-webapptoolkit');
self.warn('\n*******************************************************************************');
self.warn('The WAT plugin requires you to perform manual steps before running the app');
self.warn('Follow the steps described here: https://github.com/manifoldjs/Web-App-ToolKit');
self.warn('*******************************************************************************\n');
}
pluginList.push('cordova-plugin-whitelist');
var allPlugins = pluginList.join(' ');
self.info('Adding the following plugins to the Cordova project: ' + allPlugins + '...');
return getCordovaPath().then(function (cordovaPath) {
return exec(cordovaPath, ['plugin', 'add'].concat(pluginList), { cwd: rootDir, statusMessage: 'Adding plugins ' });
})
.catch(function (err) {
return Q.reject(new CustomError('Failed to add one or more plugins.', err));
})
.nodeify(callback);
}
function processPlatforms (w3cManifestInfo, rootDir, platformDir, platforms) {
return Q.allSettled(platforms.map(function (platform) {
self.info('Processing the \'' + platform + '\' Cordova platform...');
var cordovaPlatformPath = path.join(platformDir, 'platforms', platform);
// copy the documentation file
return self.copyDocumentation(cordovaPlatformPath, platform)
// create top-level platform shortcut
.then(function () {
// don't create a shortcut for the Windows platform
if (platform.toUpperCase() !== 'WINDOWS') {
self.info('Creating a shortcut for the \'' + platform + '\' Cordova platform...');
var srcpath = path.resolve(platformDir, 'platforms', platform);
var dstpath = path.resolve(rootDir, platform);
return fileTools.createShortcut(srcpath, dstpath);
}
})
// write generation info (telemetry)
.then(function () {
return self.writeGenerationInfo(w3cManifestInfo, cordovaPlatformPath);
});
}));
}
// override create function
self.create = function (w3cManifestInfo, rootDir, options, callback) {
if (w3cManifestInfo.format !== lib.constants.BASE_MANIFEST_FORMAT) {
return Q.reject(new CustomError('The \'' + w3cManifestInfo.format + '\' manifest format is not valid for this platform.'));
}
var allPlatforms = self.platforms.map(function (platformId) {
return constants.platform.subPlatforms[platformId].name;
}).join(', ');
self.info('Generating the ' + allPlatforms + ' app(s)...');
var platformDir = path.join(rootDir, constants.platform.id);
// generate a reverse-domain-style package name from the manifest's start_url
var packageName = '';
url.parse(w3cManifestInfo.content.start_url)
.hostname
.replace(/-/g, '')
.split('.')
.map(function (segment) {
// BUG: Issue 149 aparently "in" is a reserved word for android package names
if(segment === 'in') {
segment = segment.replace('in', 'ind');
}
packageName = segment + (packageName ? '.' : '') + packageName;
});
var cordovaAppName = utils.sanitizeName(w3cManifestInfo.content.short_name);
packageName = utils.sanitizeName(packageName);
// package name must look like: com.company.name - required when start_url is http://localhost, for example
if (packageName.indexOf('.') < 0) {
packageName += '.manifoldjs';
}
// create the base Cordova app
return createApp(rootDir, constants.platform.id, packageName, cordovaAppName)
// persist the manifest
.then(function () {
self.info('Copying the ' + constants.platform.name + ' manifest to the app folder...');
var manifestFilePath = path.join(platformDir, 'manifest.json');
return manifestTools.writeToFile(w3cManifestInfo, manifestFilePath);
})
// add the plugins
.then (function () {
return addPlugins(platformDir, options);
})
// add the platforms
.then (function () {
return addPlatforms(platformDir, self.platforms);
})
// process individual platforms
.then (function () {
return processPlatforms(w3cManifestInfo, rootDir, platformDir, self.platforms);
})
// write generation info (telemetry)
.then(function () {
return self.writeGenerationInfo(w3cManifestInfo, platformDir);
})
.nodeify(callback);
};
// override package function
self.package = function (projectDir, options, callback) {
var allPlatforms = self.platforms.map(function (platformId) {
return constants.platform.subPlatforms[platformId].name;
}).join(', ');
self.info('Creating app packages for the following Cordova platforms: ' + allPlatforms + '...');
var validPlatforms = self.platforms.filter(function (platform) {
if (platform === constants.platform.subPlatforms.ios.id && process.platform !== 'darwin') {
self.warn('Packaging apps for the \'' + constants.platform.subPlatforms.ios.name + '\' is not supported in this environment.');
return false;
}
return true;
});
var platformDir = path.join(projectDir || process.cwd(), constants.platform.id);
return getCordovaPath().then(function (cordovaPath) {
return exec(cordovaPath, ['build'].concat(validPlatforms), { cwd: platformDir });
})
.nodeify(callback);
};
self.run = function (projectDir, options, callback) {
var platform = self.platforms[0];
if (platform === constants.platform.subPlatforms.windows && !utils.isWindows) {
return Q.reject(new Error('Windows projects can only be executed in Windows environments.')).nodeify(callback);
}
self.info('Running app for the ' + platform + ' platform...');
var platformDir = path.join(projectDir || process.cwd(), 'cordova');
return getCordovaPath().then(function (cordovaPath) {
return exec(cordovaPath, ['run', platform], { cwd: platformDir, statusMessage: 'Launching app ' });
})
.nodeify(callback);
};
self.open = function (projectDir, options, callback) {
var platform = self.platforms[0];
if (platform !== constants.platform.subPlatforms.windows.id) {
return Q.reject(new Error('The \'open\' command is not implemented for the \'' + platform + '\' platform.')).nodeify(callback);
}
if (platform === constants.platform.subPlatforms.windows.id && process.platform !== 'win32') {
return Q.reject(new Error('Visual Studio projects can only be opened in Windows environments.')).nodeify(callback);
}
var platformDir = path.join(projectDir || process.cwd(), constants.platform.id);
var projectFilename = path.join(platformDir, 'platforms', platform, 'CordovaApp.sln');
return projectTools.openVisualStudioProject(projectFilename).nodeify(callback);
};
}
util.inherits(Platform, PlatformBase);
module.exports = Platform;