mirror of
https://github.com/apache/cordova-android.git
synced 2025-01-19 07:02:51 +08:00
CB-11117: Use FileUpdater to optimize prepare for android platform
This commit is contained in:
parent
d125ece9e9
commit
72bbe9fdf0
7
bin/templates/cordova/Api.js
vendored
7
bin/templates/cordova/Api.js
vendored
@ -160,8 +160,8 @@ Api.prototype.getPlatformInfo = function () {
|
|||||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||||
* CordovaError instance.
|
* CordovaError instance.
|
||||||
*/
|
*/
|
||||||
Api.prototype.prepare = function (cordovaProject) {
|
Api.prototype.prepare = function (cordovaProject, prepareOptions) {
|
||||||
return require('./lib/prepare').prepare.call(this, cordovaProject);
|
return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -328,6 +328,9 @@ Api.prototype.clean = function(cleanOptions) {
|
|||||||
return require('./lib/check_reqs').run()
|
return require('./lib/check_reqs').run()
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return require('./lib/build').runClean.call(self, cleanOptions);
|
return require('./lib/build').runClean.call(self, cleanOptions);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return require('./lib/prepare').clean.call(self, cleanOptions);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -39,6 +39,9 @@ var opts = nopt({
|
|||||||
// Make buildOptions compatible with PlatformApi clean method spec
|
// Make buildOptions compatible with PlatformApi clean method spec
|
||||||
opts.argv = opts.argv.original;
|
opts.argv = opts.argv.original;
|
||||||
|
|
||||||
|
// Skip cleaning prepared files when not invoking via cordova CLI.
|
||||||
|
opts.noPrepare = true;
|
||||||
|
|
||||||
require('./loggingHelper').adjustLoggerLevel(opts);
|
require('./loggingHelper').adjustLoggerLevel(opts);
|
||||||
|
|
||||||
new Api().clean(opts)
|
new Api().clean(opts)
|
||||||
|
181
bin/templates/cordova/lib/prepare.js
vendored
181
bin/templates/cordova/lib/prepare.js
vendored
@ -26,13 +26,15 @@ var AndroidManifest = require('./AndroidManifest');
|
|||||||
var xmlHelpers = require('cordova-common').xmlHelpers;
|
var xmlHelpers = require('cordova-common').xmlHelpers;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
var ConfigParser = require('cordova-common').ConfigParser;
|
var ConfigParser = require('cordova-common').ConfigParser;
|
||||||
|
var FileUpdater = require('cordova-common').FileUpdater;
|
||||||
var PlatformJson = require('cordova-common').PlatformJson;
|
var PlatformJson = require('cordova-common').PlatformJson;
|
||||||
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
|
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
|
||||||
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
|
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
|
||||||
|
|
||||||
module.exports.prepare = function (cordovaProject) {
|
module.exports.prepare = function (cordovaProject, options) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
var platformResourcesDir = path.relative(cordovaProject.root, path.join(this.locations.root, 'res'));
|
||||||
|
|
||||||
var platformJson = PlatformJson.load(this.locations.root, this.platform);
|
var platformJson = PlatformJson.load(this.locations.root, this.platform);
|
||||||
var munger = new PlatformMunger(this.platform, this.locations.root, platformJson, new PluginInfoProvider());
|
var munger = new PlatformMunger(this.platform, this.locations.root, platformJson, new PluginInfoProvider());
|
||||||
@ -40,20 +42,43 @@ module.exports.prepare = function (cordovaProject) {
|
|||||||
this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
|
this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
|
||||||
|
|
||||||
// Update own www dir with project's www assets and plugins' assets and js-files
|
// Update own www dir with project's www assets and plugins' assets and js-files
|
||||||
return Q.when(updateWwwFrom(cordovaProject, this.locations))
|
return Q.when(updateWww(cordovaProject, this.locations))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
// update project according to config.xml changes.
|
// update project according to config.xml changes.
|
||||||
return updateProjectAccordingTo(self._config, self.locations);
|
return updateProjectAccordingTo(self._config, self.locations);
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
handleIcons(cordovaProject.projectConfig, self.root);
|
updateIcons(cordovaProject, platformResourcesDir);
|
||||||
handleSplashes(cordovaProject.projectConfig, self.root);
|
updateSplashes(cordovaProject, platformResourcesDir);
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
events.emit('verbose', 'Prepared android project successfully');
|
events.emit('verbose', 'Prepared android project successfully');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
module.exports.clean = function (options) {
|
||||||
|
|
||||||
|
// A cordovaProject isn't passed into the clean() function, because it might have
|
||||||
|
// been called from the platform shell script rather than the CLI. Check for the
|
||||||
|
// noPrepare option passed in by the non-CLI clean script. If that's present, or if
|
||||||
|
// there's no config.xml found at the project root, then don't clean prepared files.
|
||||||
|
var projectRoot = path.resolve(this.root, '../..');
|
||||||
|
var projectConfigFile = path.join(projectRoot, 'config.xml');
|
||||||
|
if ((options && options.noPrepare) || !fs.existsSync(projectConfigFile)) {
|
||||||
|
return Q();
|
||||||
|
}
|
||||||
|
|
||||||
|
var projectConfig = new ConfigParser(projectConfigFile);
|
||||||
|
var platformResourcesDir = path.relative(projectRoot, path.join(this.locations.root, 'res'));
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
return Q().then(function () {
|
||||||
|
cleanWww(projectRoot, self.locations);
|
||||||
|
cleanIcons(projectRoot, projectConfig, platformResourcesDir);
|
||||||
|
cleanSplashes(projectRoot, projectConfig, platformResourcesDir);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates config files in project based on app's config.xml and config munge,
|
* Updates config files in project based on app's config.xml and config munge,
|
||||||
* generated by plugins.
|
* generated by plugins.
|
||||||
@ -89,6 +114,13 @@ function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Logs all file operations via the verbose event stream, indented.
|
||||||
|
*/
|
||||||
|
function logFileOp(message) {
|
||||||
|
events.emit('verbose', ' ' + message);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates platform 'www' directory by replacing it with contents of
|
* Updates platform 'www' directory by replacing it with contents of
|
||||||
* 'platform_www' and app www. Also copies project's overrides' folder into
|
* 'platform_www' and app www. Also copies project's overrides' folder into
|
||||||
@ -98,21 +130,36 @@ function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
|
|||||||
* @param {Object} destinations An object that contains destination
|
* @param {Object} destinations An object that contains destination
|
||||||
* paths for www files.
|
* paths for www files.
|
||||||
*/
|
*/
|
||||||
function updateWwwFrom(cordovaProject, destinations) {
|
function updateWww(cordovaProject, destinations) {
|
||||||
shell.rm('-rf', destinations.www);
|
var sourceDirs = [
|
||||||
shell.mkdir('-p', destinations.www);
|
path.relative(cordovaProject.root, cordovaProject.locations.www),
|
||||||
// Copy source files from project's www directory
|
path.relative(cordovaProject.root, destinations.platformWww)
|
||||||
shell.cp('-rf', path.join(cordovaProject.locations.www, '*'), destinations.www);
|
];
|
||||||
// Override www sources by files in 'platform_www' directory
|
|
||||||
shell.cp('-rf', path.join(destinations.platformWww, '*'), destinations.www);
|
|
||||||
|
|
||||||
// If project contains 'merges' for our platform, use them as another overrides
|
// If project contains 'merges' for our platform, use them as another overrides
|
||||||
var merges_path = path.join(cordovaProject.root, 'merges', 'android');
|
var merges_path = path.join(cordovaProject.root, 'merges', 'android');
|
||||||
if (fs.existsSync(merges_path)) {
|
if (fs.existsSync(merges_path)) {
|
||||||
events.emit('verbose', 'Found "merges/android" folder. Copying its contents into the android project.');
|
events.emit('verbose', 'Found "merges/android" folder. Copying its contents into the android project.');
|
||||||
var overrides = path.join(merges_path, '*');
|
sourceDirs.push(path.join('merges', 'android'));
|
||||||
shell.cp('-rf', overrides, destinations.www);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var targetDir = path.relative(cordovaProject.root, destinations.www);
|
||||||
|
events.emit(
|
||||||
|
'verbose', 'Merging and updating files from [' + sourceDirs.join(', ') + '] to ' + targetDir);
|
||||||
|
FileUpdater.mergeAndUpdateDir(
|
||||||
|
sourceDirs, targetDir, { rootDir: cordovaProject.root }, logFileOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleans all files from the platform 'www' directory.
|
||||||
|
*/
|
||||||
|
function cleanWww(projectRoot, locations) {
|
||||||
|
var targetDir = path.relative(projectRoot, locations.www);
|
||||||
|
events.emit('verbose', 'Cleaning ' + targetDir);
|
||||||
|
|
||||||
|
// No source paths are specified, so mergeAndUpdateDir() will clear the target directory.
|
||||||
|
FileUpdater.mergeAndUpdateDir(
|
||||||
|
[], targetDir, { rootDir: projectRoot, all: true }, logFileOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -201,32 +248,24 @@ function default_versionCode(version) {
|
|||||||
return versionCode;
|
return versionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyImage(src, resourcesDir, density, name) {
|
function getImageResourcePath(resourcesDir, density, name, sourceName) {
|
||||||
var destFolder = path.join(resourcesDir, (density ? 'drawable-': 'drawable') + density);
|
if (/\.9\.png$/.test(sourceName)) {
|
||||||
var isNinePatch = !!/\.9\.png$/.exec(src);
|
name = name.replace(/\.png$/, '.9.png');
|
||||||
var ninePatchName = name.replace(/\.png$/, '.9.png');
|
|
||||||
|
|
||||||
// default template does not have default asset for this density
|
|
||||||
if (!fs.existsSync(destFolder)) {
|
|
||||||
fs.mkdirSync(destFolder);
|
|
||||||
}
|
}
|
||||||
|
var resourcePath = path.join(resourcesDir, (density ? 'drawable-' + density : 'drawable'), name);
|
||||||
var destFilePath = path.join(destFolder, isNinePatch ? ninePatchName : name);
|
return resourcePath;
|
||||||
events.emit('verbose', 'Copying image from ' + src + ' to ' + destFilePath);
|
|
||||||
shell.cp('-f', src, destFilePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSplashes(projectConfig, platformRoot) {
|
function updateSplashes(cordovaProject, platformResourcesDir) {
|
||||||
var resources = projectConfig.getSplashScreens('android');
|
var resources = cordovaProject.projectConfig.getSplashScreens('android');
|
||||||
// if there are "splash" elements in config.xml
|
|
||||||
if (resources.length > 0) {
|
|
||||||
deleteDefaultResourceAt(platformRoot, 'screen.png');
|
|
||||||
events.emit('verbose', 'splash screens: ' + JSON.stringify(resources));
|
|
||||||
|
|
||||||
// The source paths for icons and splashes are relative to
|
// if there are "splash" elements in config.xml
|
||||||
// project's config.xml location, so we use it as base path.
|
if (resources.length === 0) {
|
||||||
var projectRoot = path.dirname(projectConfig.path);
|
events.emit('verbose', 'This app does not have splash screens defined');
|
||||||
var destination = path.join(platformRoot, 'res');
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'screen.png');
|
||||||
|
|
||||||
var hadMdpi = false;
|
var hadMdpi = false;
|
||||||
resources.forEach(function (resource) {
|
resources.forEach(function (resource) {
|
||||||
@ -236,17 +275,37 @@ function handleSplashes(projectConfig, platformRoot) {
|
|||||||
if (resource.density == 'mdpi') {
|
if (resource.density == 'mdpi') {
|
||||||
hadMdpi = true;
|
hadMdpi = true;
|
||||||
}
|
}
|
||||||
copyImage(path.join(projectRoot, resource.src), destination, resource.density, 'screen.png');
|
var targetPath = getImageResourcePath(
|
||||||
|
platformResourcesDir, resource.density, 'screen.png', path.basename(resource.src));
|
||||||
|
resourceMap[targetPath] = resource.src;
|
||||||
});
|
});
|
||||||
|
|
||||||
// There's no "default" drawable, so assume default == mdpi.
|
// There's no "default" drawable, so assume default == mdpi.
|
||||||
if (!hadMdpi && resources.defaultResource) {
|
if (!hadMdpi && resources.defaultResource) {
|
||||||
copyImage(path.join(projectRoot, resources.defaultResource.src), destination, 'mdpi', 'screen.png');
|
var targetPath = getImageResourcePath(
|
||||||
|
platformResourcesDir, 'mdpi', 'screen.png', path.basename(resources.defaultResource.src));
|
||||||
|
resourceMap[targetPath] = resources.defaultResource.src;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
events.emit('verbose', 'Updating splash screens at ' + platformResourcesDir);
|
||||||
|
FileUpdater.updatePaths(
|
||||||
|
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanSplashes(projectRoot, projectConfig, platformResourcesDir) {
|
||||||
|
var resources = projectConfig.getSplashScreens('android');
|
||||||
|
if (resources.length > 0) {
|
||||||
|
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'screen.png');
|
||||||
|
events.emit('verbose', 'Cleaning splash screens at ' + platformResourcesDir);
|
||||||
|
|
||||||
|
// No source paths are specified in the map, so updatePaths() will delete the target files.
|
||||||
|
FileUpdater.updatePaths(
|
||||||
|
resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleIcons(projectConfig, platformRoot) {
|
function updateIcons(cordovaProject, platformResourcesDir) {
|
||||||
var icons = projectConfig.getIcons('android');
|
var icons = cordovaProject.projectConfig.getIcons('android');
|
||||||
|
|
||||||
// if there are icon elements in config.xml
|
// if there are icon elements in config.xml
|
||||||
if (icons.length === 0) {
|
if (icons.length === 0) {
|
||||||
@ -254,7 +313,7 @@ function handleIcons(projectConfig, platformRoot) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteDefaultResourceAt(platformRoot, 'icon.png');
|
var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'icon.png');
|
||||||
|
|
||||||
var android_icons = {};
|
var android_icons = {};
|
||||||
var default_icon;
|
var default_icon;
|
||||||
@ -303,25 +362,47 @@ function handleIcons(projectConfig, platformRoot) {
|
|||||||
|
|
||||||
// The source paths for icons and splashes are relative to
|
// The source paths for icons and splashes are relative to
|
||||||
// project's config.xml location, so we use it as base path.
|
// project's config.xml location, so we use it as base path.
|
||||||
var projectRoot = path.dirname(projectConfig.path);
|
|
||||||
var destination = path.join(platformRoot, 'res');
|
|
||||||
for (var density in android_icons) {
|
for (var density in android_icons) {
|
||||||
copyImage(path.join(projectRoot, android_icons[density].src), destination, density, 'icon.png');
|
var targetPath = getImageResourcePath(
|
||||||
|
platformResourcesDir, density, 'icon.png', path.basename(android_icons[density].src));
|
||||||
|
resourceMap[targetPath] = android_icons[density].src;
|
||||||
}
|
}
|
||||||
|
|
||||||
// There's no "default" drawable, so assume default == mdpi.
|
// There's no "default" drawable, so assume default == mdpi.
|
||||||
if (default_icon && !android_icons.mdpi) {
|
if (default_icon && !android_icons.mdpi) {
|
||||||
copyImage(path.join(projectRoot, default_icon.src), destination, 'mdpi', 'icon.png');
|
var defaultTargetPath = getImageResourcePath(
|
||||||
|
platformResourcesDir, 'mdpi', 'icon.png', path.basename(default_icon.src));
|
||||||
|
resourceMap[defaultTargetPath] = default_icon.src;
|
||||||
|
}
|
||||||
|
|
||||||
|
events.emit('verbose', 'Updating icons at ' + platformResourcesDir);
|
||||||
|
FileUpdater.updatePaths(
|
||||||
|
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanIcons(projectRoot, projectConfig, platformResourcesDir) {
|
||||||
|
var icons = projectConfig.getIcons('android');
|
||||||
|
if (icons.length > 0) {
|
||||||
|
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'icon.png');
|
||||||
|
events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);
|
||||||
|
|
||||||
|
// No source paths are specified in the map, so updatePaths() will delete the target files.
|
||||||
|
FileUpdater.updatePaths(
|
||||||
|
resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the default resource name from all drawable folders
|
/**
|
||||||
function deleteDefaultResourceAt(baseDir, resourceName) {
|
* Gets a map containing resources of a specified name from all drawable folders in a directory.
|
||||||
shell.ls(path.join(baseDir, 'res/drawable-*'))
|
*/
|
||||||
|
function mapImageResources(rootDir, subDir, resourceName) {
|
||||||
|
var pathMap = {};
|
||||||
|
shell.ls(path.join(rootDir, subDir, 'drawable-*'))
|
||||||
.forEach(function (drawableFolder) {
|
.forEach(function (drawableFolder) {
|
||||||
var imagePath = path.join(drawableFolder, resourceName);
|
var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName);
|
||||||
shell.rm('-f', [imagePath, imagePath.replace(/\.png$/, '.9.png')]);
|
pathMap[imagePath] = null;
|
||||||
events.emit('verbose', 'Deleted ' + imagePath);
|
|
||||||
});
|
});
|
||||||
|
return pathMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
"author": "Apache Software Foundation",
|
"author": "Apache Software Foundation",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cordova-common": "^1.2.0",
|
"cordova-common": "^1.3.0",
|
||||||
"elementtree": "^0.1.6",
|
"elementtree": "^0.1.6",
|
||||||
"nopt": "^3.0.1",
|
"nopt": "^3.0.1",
|
||||||
"properties-parser": "^0.2.3",
|
"properties-parser": "^0.2.3",
|
||||||
|
Loading…
Reference in New Issue
Block a user