From acb3cc80b79017f3455689a294e687e033aa8b01 Mon Sep 17 00:00:00 2001 From: Anis Kadri Date: Mon, 29 Aug 2016 16:26:49 +0200 Subject: [PATCH] First attempt at supporting Android Studio --- bin/templates/cordova/Api.js | 27 ++++++++++++++++++++- bin/templates/cordova/lib/AndroidProject.js | 10 +++++++- bin/templates/cordova/lib/AndroidStudio.js | 26 ++++++++++++++++++++ bin/templates/cordova/lib/pluginHandlers.js | 17 +++++++++++++ bin/templates/cordova/lib/prepare.js | 13 ++++------ 5 files changed, 83 insertions(+), 10 deletions(-) create mode 100644 bin/templates/cordova/lib/AndroidStudio.js diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index 1a30d1a0..7a160433 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -18,8 +18,10 @@ */ var path = require('path'); +var fs = require('fs'); var AndroidProject = require('./lib/AndroidProject'); +var AndroidStudio = require('./lib/AndroidStudio'); var PluginManager = require('cordova-common').PluginManager; var CordovaLogger = require('cordova-common').CordovaLogger; @@ -40,6 +42,7 @@ function setupEvents(externalEventEmitter) { return selfEvents; } + /** * Class, that acts as abstraction over particular platform. Encapsulates the * platform's properties and methods. @@ -62,6 +65,7 @@ function Api(platform, platformRootDir, events) { this.locations = { root: self.root, www: path.join(self.root, 'assets/www'), + res: path.relative(self.root, path.join(self.root, 'res')), platformWww: path.join(self.root, 'platform_www'), configXml: path.join(self.root, 'res/xml/config.xml'), defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'), @@ -71,6 +75,17 @@ function Api(platform, platformRootDir, events) { cordovaJs: 'bin/templates/project/assets/www/cordova.js', cordovaJsSrc: 'cordova-js-src' }; + + // XXX Override some locations for Android Studio projects + if(AndroidStudio.isAndroidStudioProject(self.root) === true) { + selfEvents.emit('log', 'Android Studio project detected'); + this.android_studio = true; + this.locations.configXml = path.join(self.root, 'app/src/main/res/xml/config.xml'); + this.locations.strings = path.join(self.root, 'app/src/main/res/xml/strings.xml'); + this.locations.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml'); + this.locations.www = path.join(self.root, 'app/src/main/assets/www'); + this.locations.res = path.relative(self.root, path.join(self.root, 'app/src/main/res')); + } } /** @@ -193,6 +208,10 @@ Api.prototype.addPlugin = function (plugin, installOptions) { if (!installOptions.variables.PACKAGE_NAME) { installOptions.variables.PACKAGE_NAME = project.getPackageName(); } + + if(this.android_studio === true) { + installOptions.android_studio = true; + } return PluginManager.get(this.platform, this.locations, project) .addPlugin(plugin, installOptions) @@ -203,7 +222,7 @@ Api.prototype.addPlugin = function (plugin, installOptions) { require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles(); }.bind(this)) // CB-11022 Return truthy value to prevent running prepare after - .thenResolve(true); + .thenResolve(true) }; /** @@ -221,6 +240,12 @@ Api.prototype.addPlugin = function (plugin, installOptions) { */ Api.prototype.removePlugin = function (plugin, uninstallOptions) { var project = AndroidProject.getProjectFile(this.root); + + if(uninstallOptions && uninstallOptions.usePlatformWww === true && this.android_studio === true) { + uninstallOptions.usePlatformWww = false; + uninstallOptions.android_studio = true; + } + return PluginManager.get(this.platform, this.locations, project) .removePlugin(plugin, uninstallOptions) .then(function () { diff --git a/bin/templates/cordova/lib/AndroidProject.js b/bin/templates/cordova/lib/AndroidProject.js index b42f2a42..1fc3bdfc 100644 --- a/bin/templates/cordova/lib/AndroidProject.js +++ b/bin/templates/cordova/lib/AndroidProject.js @@ -21,6 +21,7 @@ var fs = require('fs'); var path = require('path'); var properties_parser = require('properties-parser'); var AndroidManifest = require('./AndroidManifest'); +var AndroidStudio = require('./AndroidStudio'); var pluginHandlers = require('./pluginHandlers'); var projectFileCache = {}; @@ -63,6 +64,9 @@ function AndroidProject(projectDir) { this.projectDir = projectDir; this.platformWww = path.join(this.projectDir, 'platform_www'); this.www = path.join(this.projectDir, 'assets/www'); + if(AndroidStudio.isAndroidStudioProject(projectDir) === true) { + this.www = path.join(this.projectDir, 'app/src/main/assets/www'); + } } AndroidProject.getProjectFile = function (projectDir) { @@ -89,7 +93,11 @@ AndroidProject.purgeCache = function (projectDir) { * @return {String} The name of the package */ AndroidProject.prototype.getPackageName = function() { - return new AndroidManifest(path.join(this.projectDir, 'AndroidManifest.xml')).getPackageId(); + var manifestPath = path.join(this.projectDir, 'AndroidManifest.xml'); + if(AndroidStudio.isAndroidStudioProject(this.projectDir) === true) { + manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml'); + } + return new AndroidManifest(manifestPath).getPackageId(); }; AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) { diff --git a/bin/templates/cordova/lib/AndroidStudio.js b/bin/templates/cordova/lib/AndroidStudio.js new file mode 100644 index 00000000..b26127bb --- /dev/null +++ b/bin/templates/cordova/lib/AndroidStudio.js @@ -0,0 +1,26 @@ +/* + * This is a simple routine that checks if project is an Android Studio Project + * + * @param {String} root Root folder of the project + */ + +var path = require('path'); +var fs = require('fs'); + +function isAndroidStudioProject(root) { + var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res', 'project.properties', 'platform_www']; + var androidStudioFiles = ['app', 'gradle', 'build', 'app/src/main/assets']; + for(file of eclipseFiles) { + if(fs.existsSync(path.join(root, file))) { + return false; + } + } + for(file of androidStudioFiles) { + if(!fs.existsSync(path.join(root, file))) { + return false; + } + } + return true; +} + +module.exports.isAndroidStudioProject = isAndroidStudioProject; diff --git a/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js index 8008dcbc..79a443a2 100644 --- a/bin/templates/cordova/lib/pluginHandlers.js +++ b/bin/templates/cordova/lib/pluginHandlers.js @@ -30,7 +30,13 @@ var handlers = { install:function(obj, plugin, project, options) { if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id)); if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id)); + var dest = path.join(obj.targetDir, path.basename(obj.src)); + + if(options && options.android_studio === true) { + dest = path.join("app/src/main/java", obj.targetDir.substring(4), path.basename(obj.src)); + } + if (options && options.force) { copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); } else { @@ -39,16 +45,27 @@ var handlers = { }, uninstall:function(obj, plugin, project, options) { var dest = path.join(obj.targetDir, path.basename(obj.src)); + + if(options && options.android_studio === true) { + dest = path.join("app/src/main/java", obj.targetDir.substring(4), path.basename(obj.src)); + } + deleteJava(project.projectDir, dest); } }, 'lib-file':{ install:function(obj, plugin, project, options) { var dest = path.join('libs', path.basename(obj.src)); + if(options && options.android_studio === true) { + dest = path.join("app/libs", path.basename(obj.src)); + } copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); }, uninstall:function(obj, plugin, project, options) { var dest = path.join('libs', path.basename(obj.src)); + if(options && options.android_studio === true) { + dest = path.join("app/libs", path.basename(obj.src)); + } removeFile(project.projectDir, dest); } }, diff --git a/bin/templates/cordova/lib/prepare.js b/bin/templates/cordova/lib/prepare.js index e2ae9f9a..bd0788a1 100644 --- a/bin/templates/cordova/lib/prepare.js +++ b/bin/templates/cordova/lib/prepare.js @@ -33,7 +33,6 @@ var PluginInfoProvider = require('cordova-common').PluginInfoProvider; module.exports.prepare = function (cordovaProject, options) { 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 munger = new PlatformMunger(this.platform, this.locations.root, platformJson, new PluginInfoProvider()); @@ -47,8 +46,8 @@ module.exports.prepare = function (cordovaProject, options) { return updateProjectAccordingTo(self._config, self.locations); }) .then(function () { - updateIcons(cordovaProject, platformResourcesDir); - updateSplashes(cordovaProject, platformResourcesDir); + updateIcons(cordovaProject, self.locations.res); + updateSplashes(cordovaProject, self.locations.res); }) .then(function () { events.emit('verbose', 'Prepared android project successfully'); @@ -61,20 +60,18 @@ module.exports.clean = function (options) { // 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) || + if ((options && options.noPrepare) || !fs.existsSync(this.locations.configXml) || !fs.existsSync(this.locations.configXml)) { return Q(); } var projectConfig = new ConfigParser(this.locations.configXml); - 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); + cleanIcons(projectRoot, projectConfig, self.locations.res); + cleanSplashes(projectRoot, projectConfig, self.locations.res); }); };