From d88df59c32ae7d1a55729477f5a22d9e7b4df111 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Thu, 30 Mar 2017 12:41:44 -0700 Subject: [PATCH 01/50] Adding the Studio Builder to build a project based on Android Studio, and deleting Ant, since Google does not support Ant Builds anymore. Sorry guys! --- .../cordova/lib/builders/AntBuilder.js | 156 ---------- .../cordova/lib/builders/StudioBuilder.js | 279 ++++++++++++++++++ .../cordova/lib/builders/builders.js | 2 +- 3 files changed, 280 insertions(+), 157 deletions(-) delete mode 100644 bin/templates/cordova/lib/builders/AntBuilder.js create mode 100644 bin/templates/cordova/lib/builders/StudioBuilder.js diff --git a/bin/templates/cordova/lib/builders/AntBuilder.js b/bin/templates/cordova/lib/builders/AntBuilder.js deleted file mode 100644 index 4e0f71ab..00000000 --- a/bin/templates/cordova/lib/builders/AntBuilder.js +++ /dev/null @@ -1,156 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. -*/ - -var Q = require('q'); -var fs = require('fs'); -var path = require('path'); -var util = require('util'); -var shell = require('shelljs'); -var spawn = require('cordova-common').superspawn.spawn; -var CordovaError = require('cordova-common').CordovaError; -var check_reqs = require('../check_reqs'); - -var SIGNING_PROPERTIES = '-signing.properties'; -var MARKER = 'YOUR CHANGES WILL BE ERASED!'; -var TEMPLATE = - '# This file is automatically generated.\n' + - '# Do not modify this file -- ' + MARKER + '\n'; - -var GenericBuilder = require('./GenericBuilder'); - -function AntBuilder (projectRoot) { - GenericBuilder.call(this, projectRoot); - - this.binDirs = {ant: this.binDirs.ant}; -} - -util.inherits(AntBuilder, GenericBuilder); - -AntBuilder.prototype.getArgs = function(cmd, opts) { - var args = [cmd, '-f', path.join(this.root, 'build.xml')]; - // custom_rules.xml is required for incremental builds. - if (hasCustomRules(this.root)) { - args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen'); - } - if(opts.packageInfo) { - args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES)); - } - return args; -}; - -AntBuilder.prototype.prepEnv = function(opts) { - var self = this; - return check_reqs.check_ant() - .then(function() { - // Copy in build.xml on each build so that: - // A) we don't require the Android SDK at project creation time, and - // B) we always use the SDK's latest version of it. - /*jshint -W069 */ - var sdkDir = process.env['ANDROID_HOME']; - /*jshint +W069 */ - var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8'); - function writeBuildXml(projectPath) { - var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest()); - fs.writeFileSync(path.join(projectPath, 'build.xml'), newData); - if (!fs.existsSync(path.join(projectPath, 'local.properties'))) { - fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE); - } - } - writeBuildXml(self.root); - var propertiesObj = self.readProjectProperties(); - var subProjects = propertiesObj.libs; - for (var i = 0; i < subProjects.length; ++i) { - writeBuildXml(path.join(self.root, subProjects[i])); - } - if (propertiesObj.systemLibs.length > 0) { - throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Use gradle instead.'); - } - - var propertiesFile = opts.buildType + SIGNING_PROPERTIES; - var propertiesFilePath = path.join(self.root, propertiesFile); - if (opts.packageInfo) { - fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties()); - } else if(isAutoGenerated(propertiesFilePath)) { - shell.rm('-f', propertiesFilePath); - } - }); -}; - -/* - * Builds the project with ant. - * Returns a promise. - */ -AntBuilder.prototype.build = function(opts) { - // Without our custom_rules.xml, we need to clean before building. - var ret = Q(); - if (!hasCustomRules(this.root)) { - // clean will call check_ant() for us. - ret = this.clean(opts); - } - - var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts); - return check_reqs.check_ant() - .then(function() { - return spawn('ant', args, {stdio: 'pipe'}); - }).progress(function (stdio){ - if (stdio.stderr) { - process.stderr.write(stdio.stderr); - } else { - process.stdout.write(stdio.stdout); - } - }).catch(function (error) { - if (error.toString().indexOf('Unable to resolve project target') >= 0) { - return check_reqs.check_android_target(error).then(function() { - // If due to some odd reason - check_android_target succeeds - // we should still fail here. - return Q.reject(error); - }); - } - return Q.reject(error); - }); -}; - -AntBuilder.prototype.clean = function(opts) { - var args = this.getArgs('clean', opts); - var self = this; - return check_reqs.check_ant() - .then(function() { - return spawn('ant', args, {stdio: 'inherit'}); - }) - .then(function () { - shell.rm('-rf', path.join(self.root, 'out')); - - ['debug', 'release'].forEach(function(config) { - var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES); - if(isAutoGenerated(propertiesFilePath)){ - shell.rm('-f', propertiesFilePath); - } - }); - }); -}; - -module.exports = AntBuilder; - -function hasCustomRules(projectRoot) { - return fs.existsSync(path.join(projectRoot, 'custom_rules.xml')); -} - -function isAutoGenerated(file) { - return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0; -} diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js new file mode 100644 index 00000000..6ec388ad --- /dev/null +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -0,0 +1,279 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +var Q = require('q'); +var fs = require('fs'); +var util = require('util'); +var path = require('path'); +var shell = require('shelljs'); +var spawn = require('cordova-common').superspawn.spawn; +var CordovaError = require('cordova-common').CordovaError; +var check_reqs = require('../check_reqs'); + +var GenericBuilder = require('./GenericBuilder'); + +var MARKER = 'YOUR CHANGES WILL BE ERASED!'; +var SIGNING_PROPERTIES = '-signing.properties'; +var TEMPLATE = + '# This file is automatically generated.\n' + + '# Do not modify this file -- ' + MARKER + '\n'; + +function StudioBuilder (projectRoot) { + GenericBuilder.call(this, projectRoot); + + this.binDirs = {gradle: this.binDirs.gradle}; +} + +util.inherits(StudioBuilder, GenericBuilder); + +StudioBuilder.prototype.getArgs = function(cmd, opts) { + if (cmd == 'release') { + cmd = 'cdvBuildRelease'; + } else if (cmd == 'debug') { + cmd = 'cdvBuildDebug'; + } + var args = [cmd, '-b', path.join(this.root, 'build.gradle')]; + if (opts.arch) { + args.push('-PcdvBuildArch=' + opts.arch); + } + + // 10 seconds -> 6 seconds + args.push('-Dorg.gradle.daemon=true'); + // to allow dex in process + args.push('-Dorg.gradle.jvmargs=-Xmx2048m'); + // allow NDK to be used - required by Gradle 1.5 plugin + args.push('-Pandroid.useDeprecatedNdk=true'); + args.push.apply(args, opts.extraArgs); + // Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet): + // args.push('-Dorg.gradle.parallel=true'); + return args; +}; + +/* + * This returns a promise + */ + +StudioBuilder.prototype.runGradleWrapper = function(gradle_cmd) { + var gradlePath = path.join(this.root, 'gradlew'); + var wrapperGradle = path.join(this.root, 'wrapper.gradle'); + if(fs.existsSync(gradlePath)) { + //Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows + } else { + return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'}); + } +}; + + +// Makes the project buildable, minus the gradle wrapper. +StudioBuilder.prototype.prepBuildFiles = function() { + // Update the version of build.gradle in each dependent library. + var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle'); + var propertiesObj = this.readProjectProperties(); + var subProjects = propertiesObj.libs; + var checkAndCopy = function(subProject, root) { + var subProjectGradle = path.join(root, subProject, 'build.gradle'); + // This is the future-proof way of checking if a file exists + // This must be synchronous to satisfy a Travis test + try { + fs.accessSync(subProjectGradle, fs.F_OK); + } catch (e) { + shell.cp('-f', pluginBuildGradle, subProjectGradle); + } + }; + for (var i = 0; i < subProjects.length; ++i) { + if (subProjects[i] !== 'CordovaLib') { + checkAndCopy(subProjects[i], this.root); + } + } + var name = this.extractRealProjectNameFromManifest(); + //Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149 + var settingsGradlePaths = subProjects.map(function(p){ + var realDir=p.replace(/[/\\]/g, ':'); + var libName=realDir.replace(name+'-',''); + var str='include ":'+libName+'"\n'; + if(realDir.indexOf(name+'-')!==-1) + str+='project(":'+libName+'").projectDir = new File("'+p+'")\n'; + return str; + }); + + // Write the settings.gradle file. + fs.writeFileSync(path.join(this.root, 'settings.gradle'), + '// GENERATED FILE - DO NOT EDIT\n' + + 'include ":"\n' + settingsGradlePaths.join('')); + // Update dependencies within build.gradle. + var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8'); + var depsList = ''; + var root = this.root; + var insertExclude = function(p) { + var gradlePath = path.join(root, p, 'build.gradle'); + var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8'); + if(projectGradleFile.indexOf('CordovaLib') != -1) { + depsList += '{\n exclude module:("CordovaLib")\n }\n'; + } + else { + depsList +='\n'; + } + }; + subProjects.forEach(function(p) { + console.log('Subproject Path: ' + p); + var libName=p.replace(/[/\\]/g, ':').replace(name+'-',''); + depsList += ' debugCompile(project(path: "' + libName + '", configuration: "debug"))'; + insertExclude(p); + depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))'; + insertExclude(p); + }); + // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390 + var SYSTEM_LIBRARY_MAPPINGS = [ + [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'], + [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+'] + ]; + propertiesObj.systemLibs.forEach(function(p) { + var mavenRef; + // It's already in gradle form if it has two ':'s + if (/:.*:/.exec(p)) { + mavenRef = p; + } else { + for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) { + var pair = SYSTEM_LIBRARY_MAPPINGS[i]; + if (pair[0].exec(p)) { + mavenRef = p.replace(pair[0], pair[1]); + break; + } + } + if (!mavenRef) { + throw new CordovaError('Unsupported system library (does not work with gradle): ' + p); + } + } + depsList += ' compile "' + mavenRef + '"\n'; + }); + buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2'); + var includeList = ''; + propertiesObj.gradleIncludes.forEach(function(includePath) { + includeList += 'apply from: "' + includePath + '"\n'; + }); + buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2'); + fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle); +}; + +StudioBuilder.prototype.prepEnv = function(opts) { + var self = this; + return check_reqs.check_gradle() + .then(function(gradlePath) { + return self.runGradleWrapper(gradlePath); + }).then(function() { + return self.prepBuildFiles(); + }).then(function() { + // We now copy the gradle out of the framework + // This is a dirty patch to get the build working + /* + var wrapperDir = path.join(self.root, 'CordovaLib'); + if (process.platform == 'win32') { + shell.rm('-f', path.join(self.root, 'gradlew.bat')); + shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root); + } else { + shell.rm('-f', path.join(self.root, 'gradlew')); + shell.cp(path.join(wrapperDir, 'gradlew'), self.root); + } + shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper')); + shell.mkdir('-p', path.join(self.root, 'gradle')); + shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle')); +*/ + // If the gradle distribution URL is set, make sure it points to version we want. + // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with. + // For some reason, using ^ and $ don't work. This does the job, though. + var distributionUrlRegex = /distributionUrl.*zip/; + /*jshint -W069 */ + var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-3.3-all.zip'; + /*jshint +W069 */ + var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties'); + shell.chmod('u+w', gradleWrapperPropertiesPath); + shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath); + + var propertiesFile = opts.buildType + SIGNING_PROPERTIES; + var propertiesFilePath = path.join(self.root, propertiesFile); + if (opts.packageInfo) { + fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties()); + } else if (isAutoGenerated(propertiesFilePath)) { + shell.rm('-f', propertiesFilePath); + } + }); +}; + +/* + * Builds the project with gradle. + * Returns a promise. + */ +StudioBuilder.prototype.build = function(opts) { + var wrapper = path.join(this.root, 'gradlew'); + var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts); + + return spawn(wrapper, args, {stdio: 'pipe'}) + .progress(function (stdio){ + if (stdio.stderr) { + /* + * Workaround for the issue with Java printing some unwanted information to + * stderr instead of stdout. + * This function suppresses 'Picked up _JAVA_OPTIONS' message from being + * printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for + * explanation. + */ + var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString()); + if (suppressThisLine) { + return; + } + process.stderr.write(stdio.stderr); + } else { + process.stdout.write(stdio.stdout); + } + }).catch(function (error) { + if (error.toString().indexOf('failed to find target with hash string') >= 0) { + return check_reqs.check_android_target(error).then(function() { + // If due to some odd reason - check_android_target succeeds + // we should still fail here. + return Q.reject(error); + }); + } + return Q.reject(error); + }); +}; + +StudioBuilder.prototype.clean = function(opts) { + var builder = this; + var wrapper = path.join(this.root, 'gradlew'); + var args = builder.getArgs('clean', opts); + return Q().then(function() { + return spawn(wrapper, args, {stdio: 'inherit'}); + }) + .then(function () { + shell.rm('-rf', path.join(builder.root, 'out')); + + ['debug', 'release'].forEach(function(config) { + var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES); + if(isAutoGenerated(propertiesFilePath)){ + shell.rm('-f', propertiesFilePath); + } + }); + }); +}; + +module.exports = StudioBuilder; + +function isAutoGenerated(file) { + return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0; +} diff --git a/bin/templates/cordova/lib/builders/builders.js b/bin/templates/cordova/lib/builders/builders.js index 4921c49a..d0e06373 100644 --- a/bin/templates/cordova/lib/builders/builders.js +++ b/bin/templates/cordova/lib/builders/builders.js @@ -20,8 +20,8 @@ var CordovaError = require('cordova-common').CordovaError; var knownBuilders = { - ant: 'AntBuilder', gradle: 'GradleBuilder', + studio: 'StudioBuilder', none: 'GenericBuilder' }; From 23d8d999257f9cf1331d81489c96f00fa134b3b5 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Thu, 30 Mar 2017 13:38:18 -0700 Subject: [PATCH 02/50] Moving Android Manifest finding to the Gradle and Studio builders. --- bin/lib/create.js | 3 +- .../cordova/lib/builders/GenericBuilder.js | 32 ------------------ .../cordova/lib/builders/GradleBuilder.js | 31 +++++++++++++++++ .../cordova/lib/builders/StudioBuilder.js | 33 +++++++++++++++++++ 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index 2fa0c8cd..cfd6395c 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -125,9 +125,10 @@ function writeProjectProperties(projectPath, target_api) { fs.writeFileSync(dstPath, data); } +// This makes no sense, what if you're building with a different build system? function prepBuildFiles(projectPath) { var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders')); - buildModule.getBuilder('gradle').prepBuildFiles(); + buildModule.getBuilder('studio').prepBuildFiles(); } function copyBuildRules(projectPath) { diff --git a/bin/templates/cordova/lib/builders/GenericBuilder.js b/bin/templates/cordova/lib/builders/GenericBuilder.js index 362da431..16a69f57 100644 --- a/bin/templates/cordova/lib/builders/GenericBuilder.js +++ b/bin/templates/cordova/lib/builders/GenericBuilder.js @@ -27,7 +27,6 @@ var CordovaError = require('cordova-common').CordovaError; function GenericBuilder (projectDir) { this.root = projectDir || path.resolve(__dirname, '../../..'); this.binDirs = { - ant: path.join(this.root, hasCustomRules(this.root) ? 'ant-build' : 'bin'), gradle: path.join(this.root, 'build', 'outputs', 'apk') }; } @@ -59,37 +58,6 @@ GenericBuilder.prototype.findOutputApks = function(build_type, arch) { .sort(apkSorter); }; -GenericBuilder.prototype.readProjectProperties = function () { - function findAllUniq(data, r) { - var s = {}; - var m; - while ((m = r.exec(data))) { - s[m[1]] = 1; - } - return Object.keys(s); - } - - var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8'); - return { - libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg), - gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg), - systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg) - }; -}; - -GenericBuilder.prototype.extractRealProjectNameFromManifest = function () { - var manifestPath = path.join(this.root, 'AndroidManifest.xml'); - var manifestData = fs.readFileSync(manifestPath, 'utf8'); - var m = / Date: Mon, 3 Apr 2017 15:21:48 -0700 Subject: [PATCH 03/50] Changing this so we pass lint --- framework/AndroidManifest.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/AndroidManifest.xml b/framework/AndroidManifest.xml index 3feb903c..26a0aed0 100755 --- a/framework/AndroidManifest.xml +++ b/framework/AndroidManifest.xml @@ -19,5 +19,5 @@ --> - + From 7b17abc5553ca14f69081a2175f787d4a0550f0f Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 4 Apr 2017 13:38:40 -0700 Subject: [PATCH 04/50] Fixing linting issues --- framework/src/org/apache/cordova/CordovaActivity.java | 1 + framework/src/org/apache/cordova/CordovaBridge.java | 5 +++++ .../src/org/apache/cordova/CordovaClientCertRequest.java | 9 +++++++++ .../src/org/apache/cordova/CordovaInterfaceImpl.java | 2 ++ framework/src/org/apache/cordova/CordovaWebViewImpl.java | 2 ++ .../org/apache/cordova/engine/SystemWebViewEngine.java | 3 +++ 6 files changed, 22 insertions(+) diff --git a/framework/src/org/apache/cordova/CordovaActivity.java b/framework/src/org/apache/cordova/CordovaActivity.java index 85eeb53a..e2ed1cb8 100755 --- a/framework/src/org/apache/cordova/CordovaActivity.java +++ b/framework/src/org/apache/cordova/CordovaActivity.java @@ -319,6 +319,7 @@ public class CordovaActivity extends Activity { /** * Called when view focus is changed */ + @SuppressLint("InlinedApi") @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); diff --git a/framework/src/org/apache/cordova/CordovaBridge.java b/framework/src/org/apache/cordova/CordovaBridge.java index 9459a113..28c407f3 100644 --- a/framework/src/org/apache/cordova/CordovaBridge.java +++ b/framework/src/org/apache/cordova/CordovaBridge.java @@ -18,6 +18,8 @@ */ package org.apache.cordova; +import android.annotation.SuppressLint; + import java.security.SecureRandom; import org.json.JSONArray; @@ -110,6 +112,9 @@ public class CordovaBridge { } /** Called by cordova.js to initialize the bridge. */ + //On old Androids SecureRandom isn't really secure, this is the least of your problems if + //you're running Android 4.3 and below in 2017 + @SuppressLint("TrulyRandom") int generateBridgeSecret() { SecureRandom randGen = new SecureRandom(); expectedBridgeSecret = randGen.nextInt(Integer.MAX_VALUE); diff --git a/framework/src/org/apache/cordova/CordovaClientCertRequest.java b/framework/src/org/apache/cordova/CordovaClientCertRequest.java index 5dd0ecae..ccda0272 100644 --- a/framework/src/org/apache/cordova/CordovaClientCertRequest.java +++ b/framework/src/org/apache/cordova/CordovaClientCertRequest.java @@ -22,10 +22,12 @@ import java.security.Principal; import java.security.PrivateKey; import java.security.cert.X509Certificate; +import android.annotation.SuppressLint; import android.webkit.ClientCertRequest; /** * Implementation of the ICordovaClientCertRequest for Android WebView. + * */ public class CordovaClientCertRequest implements ICordovaClientCertRequest { @@ -38,6 +40,7 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest { /** * Cancel this request */ + @SuppressLint("NewApi") public void cancel() { request.cancel(); @@ -46,6 +49,7 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest { /* * Returns the host name of the server requesting the certificate. */ + @SuppressLint("NewApi") public String getHost() { return request.getHost(); @@ -54,6 +58,7 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest { /* * Returns the acceptable types of asymmetric keys (can be null). */ + @SuppressLint("NewApi") public String[] getKeyTypes() { return request.getKeyTypes(); @@ -62,6 +67,7 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest { /* * Returns the port number of the server requesting the certificate. */ + @SuppressLint("NewApi") public int getPort() { return request.getPort(); @@ -70,6 +76,7 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest { /* * Returns the acceptable certificate issuers for the certificate matching the private key (can be null). */ + @SuppressLint("NewApi") public Principal[] getPrincipals() { return request.getPrincipals(); @@ -78,6 +85,7 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest { /* * Ignore the request for now. Do not remember user's choice. */ + @SuppressLint("NewApi") public void ignore() { request.ignore(); @@ -89,6 +97,7 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest { * @param privateKey The privateKey * @param chain The certificate chain */ + @SuppressLint("NewApi") public void proceed(PrivateKey privateKey, X509Certificate[] chain) { request.proceed(privateKey, chain); diff --git a/framework/src/org/apache/cordova/CordovaInterfaceImpl.java b/framework/src/org/apache/cordova/CordovaInterfaceImpl.java index 71dcb782..8fdbff5e 100644 --- a/framework/src/org/apache/cordova/CordovaInterfaceImpl.java +++ b/framework/src/org/apache/cordova/CordovaInterfaceImpl.java @@ -19,6 +19,7 @@ package org.apache.cordova; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.Intent; import android.content.pm.PackageManager; @@ -221,6 +222,7 @@ public class CordovaInterfaceImpl implements CordovaInterface { requestPermissions(plugin, requestCode, permissions); } + @SuppressLint("NewApi") public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) { int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode); getActivity().requestPermissions(permissions, mappedRequestCode); diff --git a/framework/src/org/apache/cordova/CordovaWebViewImpl.java b/framework/src/org/apache/cordova/CordovaWebViewImpl.java index 85a0b5f5..fb99c344 100644 --- a/framework/src/org/apache/cordova/CordovaWebViewImpl.java +++ b/framework/src/org/apache/cordova/CordovaWebViewImpl.java @@ -18,6 +18,7 @@ */ package org.apache.cordova; +import android.annotation.SuppressLint; import android.content.Context; import android.content.Intent; import android.net.Uri; @@ -91,6 +92,7 @@ public class CordovaWebViewImpl implements CordovaWebView { init(cordova, new ArrayList(), new CordovaPreferences()); } + @SuppressLint("Assert") @Override public void init(CordovaInterface cordova, List pluginEntries, CordovaPreferences preferences) { if (this.cordova != null) { diff --git a/framework/src/org/apache/cordova/engine/SystemWebViewEngine.java b/framework/src/org/apache/cordova/engine/SystemWebViewEngine.java index 3be7d940..00f08387 100755 --- a/framework/src/org/apache/cordova/engine/SystemWebViewEngine.java +++ b/framework/src/org/apache/cordova/engine/SystemWebViewEngine.java @@ -255,6 +255,9 @@ public class SystemWebViewEngine implements CordovaWebViewEngine { } } + // Yeah, we know, which is why we makes ure that we don't do this if the bridge is + // below JELLYBEAN_MR1. It'd be great if lint was just a little smarter. + @SuppressLint("AddJavascriptInterface") private static void exposeJsInterface(WebView webView, CordovaBridge bridge) { if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) { LOG.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old."); From f790aeb8f677eb047ce6e82fceaeb814cfc9d4fc Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 4 Apr 2017 15:18:46 -0700 Subject: [PATCH 05/50] Setting up the create command so we actually have all the directories in the right place, and define default variables in the top level build.gradle --- bin/lib/create.js | 22 +- bin/templates/project/app/build.gradle | 293 +++++++++++++++++++++++ bin/templates/project/build.gradle | 316 +++---------------------- 3 files changed, 337 insertions(+), 294 deletions(-) create mode 100644 bin/templates/project/app/build.gradle diff --git a/bin/lib/create.js b/bin/lib/create.js index cfd6395c..ca869900 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -26,7 +26,7 @@ var shell = require('shelljs'), check_reqs = require('./../templates/cordova/lib/check_reqs'), ROOT = path.join(__dirname, '..', '..'); -var MIN_SDK_VERSION = 16; +var MIN_SDK_VERSION = 19; var CordovaError = require('cordova-common').CordovaError; var AndroidManifest = require('../templates/cordova/lib/AndroidManifest'); @@ -45,7 +45,7 @@ function getFrameworkDir(projectPath, shared) { function copyJsAndLibrary(projectPath, shared, projectName) { var nestedCordovaLibPath = getFrameworkDir(projectPath, false); var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js'); - shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js')); + shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'app', 'src', 'main', 'assets', 'www', 'cordova.js')); // Copy the cordova.js file to platforms//platform_www/ // The www dir is nuked on each prepare so we keep cordova.js in platform_www @@ -135,6 +135,7 @@ function copyBuildRules(projectPath) { var srcDir = path.join(ROOT, 'bin', 'templates', 'project'); shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath); + shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), projectPath); shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); } @@ -260,9 +261,12 @@ exports.create = function(project_path, config, options, events) { setShellFatal(true, function() { var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project'); + var app_path = path.join(project_path, 'app', 'src', 'main'); + // copy project template - shell.cp('-r', path.join(project_template_dir, 'assets'), project_path); - shell.cp('-r', path.join(project_template_dir, 'res'), project_path); + shell.mkdir('-p', app_path); + shell.cp('-r', path.join(project_template_dir, 'assets'), app_path); + shell.cp('-r', path.join(project_template_dir, 'res'), app_path); shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore')); // Manually create directories that would be empty within the template (since git doesn't track directories). @@ -271,6 +275,14 @@ exports.create = function(project_path, config, options, events) { // copy cordova.js, cordova.jar copyJsAndLibrary(project_path, options.link, safe_activity_name); + //Set up ther Android Studio paths + var java_path = path.join(app_path, 'java'); + var assets_path = path.join(app_path, 'assets'); + var resource_path = path.join(app_path, 'res'); + shell.mkdir('-p', java_path); + shell.mkdir('-p', assets_path); + shell.mkdir('-p', resource_path); + // interpolate the activity name and package var packagePath = package_name.replace(/\./g, path.sep); var activity_dir = path.join(project_path, 'src', packagePath); @@ -278,7 +290,7 @@ exports.create = function(project_path, config, options, events) { shell.mkdir('-p', activity_dir); shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path); shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path); - shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml')); + shell.sed('-i', /__NAME__/, project_name, path.join(app_path, 'res', 'values', 'strings.xml')); shell.sed('-i', /__ID__/, package_name, activity_path); var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml')); diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle new file mode 100644 index 00000000..1d18ba1b --- /dev/null +++ b/bin/templates/project/app/build.gradle @@ -0,0 +1,293 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +apply plugin: 'com.android.application' + +buildscript { + repositories { + mavenCentral() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.0' + } +} + +// Allow plugins to declare Maven dependencies via build-extras.gradle. +allprojects { + repositories { + mavenCentral(); + jcenter() + } +} + +task wrapper(type: Wrapper) { + gradleVersion = '2.14.1' +} + +// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. +// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html +ext { + apply from: '../CordovaLib/cordova.gradle' + // The value for android.compileSdkVersion. + if (!project.hasProperty('cdvCompileSdkVersion')) { + cdvCompileSdkVersion = null; + } + // The value for android.buildToolsVersion. + if (!project.hasProperty('cdvBuildToolsVersion')) { + cdvBuildToolsVersion = null; + } + // Sets the versionCode to the given value. + if (!project.hasProperty('cdvVersionCode')) { + cdvVersionCode = null + } + // Sets the minSdkVersion to the given value. + if (!project.hasProperty('cdvMinSdkVersion')) { + cdvMinSdkVersion = null + } + // Whether to build architecture-specific APKs. + if (!project.hasProperty('cdvBuildMultipleApks')) { + cdvBuildMultipleApks = null + } + // .properties files to use for release signing. + if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) { + cdvReleaseSigningPropertiesFile = null + } + // .properties files to use for debug signing. + if (!project.hasProperty('cdvDebugSigningPropertiesFile')) { + cdvDebugSigningPropertiesFile = null + } + // Set by build.js script. + if (!project.hasProperty('cdvBuildArch')) { + cdvBuildArch = null + } + + // Plugin gradle extensions can append to this to have code run at the end. + cdvPluginPostBuildExtras = [] +} + +// PLUGIN GRADLE EXTENSIONS START +// PLUGIN GRADLE EXTENSIONS END + +def hasBuildExtras = file('build-extras.gradle').exists() +if (hasBuildExtras) { + apply from: 'build-extras.gradle' +} + +// Set property defaults after extension .gradle files. +if (ext.cdvCompileSdkVersion == null) { + ext.cdvCompileSdkVersion = project.ext.defaultCompileSdkVersion +} +if (ext.cdvBuildToolsVersion == null) { + ext.cdvBuildToolsVersion = project.ext.defaultBuildToolsVersion +} +if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) { + ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties' +} +if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) { + ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties' +} + +// Cast to appropriate types. +ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean(); +ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : defaultMinSdkVersion +ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode) + +def computeBuildTargetName(debugBuild) { + def ret = 'assemble' + if (cdvBuildMultipleApks && cdvBuildArch) { + def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch + ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1); + } + return ret + (debugBuild ? 'Debug' : 'Release') +} + +// Make cdvBuild a task that depends on the debug/arch-sepecific task. +task cdvBuildDebug +cdvBuildDebug.dependsOn { + return computeBuildTargetName(true) +} + +task cdvBuildRelease +cdvBuildRelease.dependsOn { + return computeBuildTargetName(false) +} + +task cdvPrintProps << { + println('cdvCompileSdkVersion=' + cdvCompileSdkVersion) + println('cdvBuildToolsVersion=' + cdvBuildToolsVersion) + println('cdvVersionCode=' + cdvVersionCode) + println('cdvMinSdkVersion=' + cdvMinSdkVersion) + println('cdvBuildMultipleApks=' + cdvBuildMultipleApks) + println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile) + println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile) + println('cdvBuildArch=' + cdvBuildArch) + println('computedVersionCode=' + android.defaultConfig.versionCode) + android.productFlavors.each { flavor -> + println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode) + } +} + +android { + + defaultConfig { + versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode")) + applicationId privateHelpers.extractStringFromManifest("package") + + if (cdvMinSdkVersion != null) { + minSdkVersion cdvMinSdkVersion + } + } + + lintOptions { + abortOnError false; + } + + compileSdkVersion cdvCompileSdkVersion + buildToolsVersion cdvBuildToolsVersion + + //This code exists for Crosswalk and other Native APIs. + //By default, we multiply the existing version code in the Android Manifest by 10 and + //add a number for each architecture. If you are not using Crosswalk or SQLite, you can + //ignore this chunk of code, and your version codes will be respected. + + if (Boolean.valueOf(cdvBuildMultipleApks)) { + productFlavors { + armv7 { + versionCode defaultConfig.versionCode*10 + 2 + ndk { + abiFilters "armeabi-v7a", "" + } + } + x86 { + versionCode defaultConfig.versionCode*10 + 4 + ndk { + abiFilters "x86", "" + } + } + all { + ndk { + abiFilters "all", "" + } + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_6 + targetCompatibility JavaVersion.VERSION_1_6 + } + + if (cdvReleaseSigningPropertiesFile) { + signingConfigs { + release { + // These must be set or Gradle will complain (even if they are overridden). + keyAlias = "" + keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph. + storeFile = null + storePassword = "__unset" + } + } + buildTypes { + release { + signingConfig signingConfigs.release + } + } + addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release) + } + if (cdvDebugSigningPropertiesFile) { + addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug) + } +} + +/* + * WARNING: Cordova Lib and platform scripts do management inside of this code here, + * if you are adding the dependencies manually, do so outside the comments, otherwise + * the Cordova tools will overwrite them + */ + + +dependencies { + compile fileTree(dir: 'libs', include: '*.jar') + // SUB-PROJECT DEPENDENCIES START + debugCompile(project(path: ":CordovaLib", configuration: "debug")) + releaseCompile(project(path: ":CordovaLib", configuration: "release")) + // SUB-PROJECT DEPENDENCIES END +} + +def promptForReleaseKeyPassword() { + if (!cdvReleaseSigningPropertiesFile) { + return; + } + if ('__unset'.equals(android.signingConfigs.release.storePassword)) { + android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ') + } + if ('__unset'.equals(android.signingConfigs.release.keyPassword)) { + android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: '); + } +} + +gradle.taskGraph.whenReady { taskGraph -> + taskGraph.getAllTasks().each() { task -> + if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') { + promptForReleaseKeyPassword() + } + } +} + +def addSigningProps(propsFilePath, signingConfig) { + def propsFile = file(propsFilePath) + def props = new Properties() + propsFile.withReader { reader -> + props.load(reader) + } + + def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile')) + if (!storeFile.isAbsolute()) { + storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile()) + } + if (!storeFile.exists()) { + throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath()) + } + signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias') + signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword)) + signingConfig.storeFile = storeFile + signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword)) + def storeType = props.get('storeType', props.get('key.store.type', '')) + if (!storeType) { + def filename = storeFile.getName().toLowerCase(); + if (filename.endsWith('.p12') || filename.endsWith('.pfx')) { + storeType = 'pkcs12' + } else { + storeType = signingConfig.storeType // "jks" + } + } + signingConfig.storeType = storeType +} + +for (def func : cdvPluginPostBuildExtras) { + func() +} + +// This can be defined within build-extras.gradle as: +// ext.postBuildExtras = { ... code here ... } +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} diff --git a/bin/templates/project/build.gradle b/bin/templates/project/build.gradle index ef229719..d5a8500e 100644 --- a/bin/templates/project/build.gradle +++ b/bin/templates/project/build.gradle @@ -1,311 +1,49 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at +/* Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 + http://www.apache.org/licenses/LICENSE-2.0 - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. */ -apply plugin: 'com.android.application' +// Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { repositories { - mavenCentral() jcenter() } - - // Switch the Android Gradle plugin version requirement depending on the - // installed version of Gradle. This dependency is documented at - // http://tools.android.com/tech-docs/new-build-system/version-compatibility - // and https://issues.apache.org/jira/browse/CB-8143 dependencies { - classpath 'com.android.tools.build:gradle:2.2.3' + classpath 'com.android.tools.build:gradle:2.3.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files } } -// Allow plugins to declare Maven dependencies via build-extras.gradle. allprojects { repositories { - mavenCentral(); jcenter() } -} -task wrapper(type: Wrapper) { - gradleVersion = '2.14.1' -} - -// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. -// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html -ext { - apply from: 'CordovaLib/cordova.gradle' - // The value for android.compileSdkVersion. - if (!project.hasProperty('cdvCompileSdkVersion')) { - cdvCompileSdkVersion = null; - } - // The value for android.buildToolsVersion. - if (!project.hasProperty('cdvBuildToolsVersion')) { - cdvBuildToolsVersion = null; - } - // Sets the versionCode to the given value. - if (!project.hasProperty('cdvVersionCode')) { - cdvVersionCode = null - } - // Sets the minSdkVersion to the given value. - if (!project.hasProperty('cdvMinSdkVersion')) { - cdvMinSdkVersion = null - } - // Whether to build architecture-specific APKs. - if (!project.hasProperty('cdvBuildMultipleApks')) { - cdvBuildMultipleApks = null - } - // .properties files to use for release signing. - if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) { - cdvReleaseSigningPropertiesFile = null - } - // .properties files to use for debug signing. - if (!project.hasProperty('cdvDebugSigningPropertiesFile')) { - cdvDebugSigningPropertiesFile = null - } - // Set by build.js script. - if (!project.hasProperty('cdvBuildArch')) { - cdvBuildArch = null - } - - // Plugin gradle extensions can append to this to have code run at the end. - cdvPluginPostBuildExtras = [] -} - -// PLUGIN GRADLE EXTENSIONS START -// PLUGIN GRADLE EXTENSIONS END - -def hasBuildExtras = file('build-extras.gradle').exists() -if (hasBuildExtras) { - apply from: 'build-extras.gradle' -} - -// Set property defaults after extension .gradle files. -if (ext.cdvCompileSdkVersion == null) { - ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget() -} -if (ext.cdvBuildToolsVersion == null) { - ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools() -} -if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) { - ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties' -} -if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) { - ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties' -} - -// Cast to appropriate types. -ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean(); -ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion) -ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode) - -def computeBuildTargetName(debugBuild) { - def ret = 'assemble' - if (cdvBuildMultipleApks && cdvBuildArch) { - def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch - ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1); - } - return ret + (debugBuild ? 'Debug' : 'Release') -} - -// Make cdvBuild a task that depends on the debug/arch-sepecific task. -task cdvBuildDebug -cdvBuildDebug.dependsOn { - return computeBuildTargetName(true) -} - -task cdvBuildRelease -cdvBuildRelease.dependsOn { - return computeBuildTargetName(false) -} - -task cdvPrintProps << { - println('cdvCompileSdkVersion=' + cdvCompileSdkVersion) - println('cdvBuildToolsVersion=' + cdvBuildToolsVersion) - println('cdvVersionCode=' + cdvVersionCode) - println('cdvMinSdkVersion=' + cdvMinSdkVersion) - println('cdvBuildMultipleApks=' + cdvBuildMultipleApks) - println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile) - println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile) - println('cdvBuildArch=' + cdvBuildArch) - println('computedVersionCode=' + android.defaultConfig.versionCode) - android.productFlavors.each { flavor -> - println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode) + //This replaces project.properties + project.ext { + defaultBuildToolsVersion="25.0.2" //String + defaultMinSdkVersion=19 //Integer - Minimum requirement is Android 4.4 + defaultTargetSdkVersion=25 //Integer - We ALWAYS target the latest by default + defaultCompileSdkVersion=25 //Integer - We ALWAYS compile with the latest by default } } -android { - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - java.srcDirs = ['src'] - resources.srcDirs = ['src'] - aidl.srcDirs = ['src'] - renderscript.srcDirs = ['src'] - res.srcDirs = ['res'] - assets.srcDirs = ['assets'] - jniLibs.srcDirs = ['libs'] - } - } - - defaultConfig { - versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode")) - applicationId privateHelpers.extractStringFromManifest("package") - - if (cdvMinSdkVersion != null) { - minSdkVersion cdvMinSdkVersion - } - } - - lintOptions { - abortOnError false; - } - - compileSdkVersion cdvCompileSdkVersion - buildToolsVersion cdvBuildToolsVersion - - if (Boolean.valueOf(cdvBuildMultipleApks)) { - productFlavors { - armv7 { - versionCode defaultConfig.versionCode*10 + 2 - ndk { - abiFilters "armeabi-v7a", "" - } - } - x86 { - versionCode defaultConfig.versionCode*10 + 4 - ndk { - abiFilters "x86", "" - } - } - all { - ndk { - abiFilters "all", "" - } - } - } - } - /* - - ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO! - - else if (!cdvVersionCode) { - def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion") - // Vary versionCode by the two most common API levels: - // 14 is ICS, which is the lowest API level for many apps. - // 20 is Lollipop, which is the lowest API level for the updatable system webview. - if (minSdkVersion >= 20) { - defaultConfig.versionCode += 9 - } else if (minSdkVersion >= 14) { - defaultConfig.versionCode += 8 - } - } - */ - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_6 - targetCompatibility JavaVersion.VERSION_1_6 - } - - if (cdvReleaseSigningPropertiesFile) { - signingConfigs { - release { - // These must be set or Gradle will complain (even if they are overridden). - keyAlias = "" - keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph. - storeFile = null - storePassword = "__unset" - } - } - buildTypes { - release { - signingConfig signingConfigs.release - } - } - addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release) - } - if (cdvDebugSigningPropertiesFile) { - addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug) - } -} - -dependencies { - compile fileTree(dir: 'libs', include: '*.jar') - // SUB-PROJECT DEPENDENCIES START - // SUB-PROJECT DEPENDENCIES END -} - -def promptForReleaseKeyPassword() { - if (!cdvReleaseSigningPropertiesFile) { - return; - } - if ('__unset'.equals(android.signingConfigs.release.storePassword)) { - android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ') - } - if ('__unset'.equals(android.signingConfigs.release.keyPassword)) { - android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: '); - } -} - -gradle.taskGraph.whenReady { taskGraph -> - taskGraph.getAllTasks().each() { task -> - if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') { - promptForReleaseKeyPassword() - } - } -} - -def addSigningProps(propsFilePath, signingConfig) { - def propsFile = file(propsFilePath) - def props = new Properties() - propsFile.withReader { reader -> - props.load(reader) - } - - def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile')) - if (!storeFile.isAbsolute()) { - storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile()) - } - if (!storeFile.exists()) { - throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath()) - } - signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias') - signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword)) - signingConfig.storeFile = storeFile - signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword)) - def storeType = props.get('storeType', props.get('key.store.type', '')) - if (!storeType) { - def filename = storeFile.getName().toLowerCase(); - if (filename.endsWith('.p12') || filename.endsWith('.pfx')) { - storeType = 'pkcs12' - } else { - storeType = signingConfig.storeType // "jks" - } - } - signingConfig.storeType = storeType -} - -for (def func : cdvPluginPostBuildExtras) { - func() -} - -// This can be defined within build-extras.gradle as: -// ext.postBuildExtras = { ... code here ... } -if (hasProperty('postBuildExtras')) { - postBuildExtras() +task clean(type: Delete) { + delete rootProject.buildDir } From b73c04f3c8424e6db57c3bb98c550cd4d976f473 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 4 Apr 2017 15:34:42 -0700 Subject: [PATCH 06/50] Updating gradle version in the build file --- bin/templates/project/app/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle index 1d18ba1b..5134793f 100644 --- a/bin/templates/project/app/build.gradle +++ b/bin/templates/project/app/build.gradle @@ -39,7 +39,7 @@ allprojects { } task wrapper(type: Wrapper) { - gradleVersion = '2.14.1' + gradleVersion = '3.3.0' } // Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. From 8ead919faea814e86e8f665e9122a35bcd82d869 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 4 Apr 2017 15:42:58 -0700 Subject: [PATCH 07/50] Managed to get the project to mostly compile, still need to re-work the build command to add the app project --- bin/lib/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index ca869900..d2b2e4dc 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -135,7 +135,7 @@ function copyBuildRules(projectPath) { var srcDir = path.join(ROOT, 'bin', 'templates', 'project'); shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath); - shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), projectPath); + shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), path.join(projectPath, 'app')); shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); } From db87e0ae6a25d8a337d10b41cb46574e2cb987b0 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 11 Apr 2017 13:47:40 -0700 Subject: [PATCH 08/50] Made changes so cordova/build builds with the new project. Need to work on plugin installation. --- bin/templates/cordova/lib/android_sdk.js | 77 +++++++++++++------ bin/templates/cordova/lib/build.js | 6 +- .../cordova/lib/builders/GenericBuilder.js | 2 + .../cordova/lib/builders/GradleBuilder.js | 26 ++++++- .../cordova/lib/builders/StudioBuilder.js | 27 +++---- bin/templates/cordova/lib/device.js | 2 +- bin/templates/cordova/lib/emulator.js | 20 +++-- 7 files changed, 108 insertions(+), 52 deletions(-) diff --git a/bin/templates/cordova/lib/android_sdk.js b/bin/templates/cordova/lib/android_sdk.js index a1a806a6..58d301ef 100755 --- a/bin/templates/cordova/lib/android_sdk.js +++ b/bin/templates/cordova/lib/android_sdk.js @@ -1,3 +1,5 @@ + + /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -66,38 +68,65 @@ module.exports.version_string_to_api_level = { '7.1.1': 25 }; -function parse_targets(output) { - var target_out = output.split('\n'); - var targets = []; - for (var i = target_out.length - 1; i >= 0; i--) { - if(target_out[i].match(/id:/)) { // if "id:" is in the line... - targets.push(target_out[i].match(/"(.+)"/)[1]); //.. match whatever is in quotes. - } - } - return targets; -} - module.exports.list_targets_with_android = function() { - return superspawn.spawn('android', ['list', 'target']) - .then(parse_targets); + return superspawn.spawn('android', ['list', 'targets']) + .then(function(stdout) { + var target_out = stdout.split('\n'); + var targets = []; + for (var i = target_out.length - 1; i >= 0; i--) { + if(target_out[i].match(/id:/)) { + targets.push(target_out[i].match(/"(.+)"/)[1]); + } + } + return targets; + }); }; -module.exports.list_targets_with_avdmanager = function() { - return superspawn.spawn('avdmanager', ['list', 'target']) - .then(parse_targets); +module.exports.list_targets_with_sdkmanager = function() { + return superspawn.spawn('sdkmanager', ['--list']) + .then(function(stdout) { + var parsing_installed_packages = false; + var lines = stdout.split('\n'); + var targets = []; + for (var i = 0, l = lines.length; i < l; i++) { + var line = lines[i]; + if (line.match(/Installed packages/)) { + parsing_installed_packages = true; + } else if (line.match(/Available Packages/) || line.match(/Available Updates/)) { + // we are done working through installed packages, exit + break; + } + if (parsing_installed_packages) { + // Match stock android platform + if (line.match(/platforms;android-\d+/)) { + targets.push(line.match(/(android-\d+)/)[1]); + } + // Match Google APIs + if (line.match(/addon-google_apis-google-\d+/)) { + var description = lines[i + 1]; + // munge description to match output from old android sdk tooling + var api_level = description.match(/Android (\d+)/); //[1]; + if (api_level) { + targets.push('Google Inc.:Google APIs:' + api_level[1]); + } + } + // TODO: match anything else? + } + } + return targets; + }); }; module.exports.list_targets = function() { - return module.exports.list_targets_with_avdmanager() + return module.exports.list_targets_with_android() .catch(function(err) { - // If there's an error, like avdmanager could not be found, we can try - // as a last resort, to run `android`, in case this is a super old - // SDK installation. - if (err && (err.code == 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) { - return module.exports.list_targets_with_android(); + // there's a chance `android` no longer works. + // lets see if `sdkmanager` is available and we can figure it out + var avail_regex = /"?android"? command is no longer available/; + if (err.code && ((err.stdout && err.stdout.match(avail_regex)) || (err.stderr && err.stderr.match(avail_regex)))) { + return module.exports.list_targets_with_sdkmanager(); } else throw err; - }) - .then(function(targets) { + }).then(function(targets) { if (targets.length === 0) { return Q.reject(new Error('No android targets (SDKs) installed!')); } diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js index bd613da2..e684e61f 100644 --- a/bin/templates/cordova/lib/build.js +++ b/bin/templates/cordova/lib/build.js @@ -35,7 +35,7 @@ function parseOpts(options, resolvedTarget, projectRoot) { options = options || {}; options.argv = nopt({ gradle: Boolean, - ant: Boolean, + studio: Boolean, prepenv: Boolean, versionCode: String, minSdkVersion: String, @@ -55,8 +55,8 @@ function parseOpts(options, resolvedTarget, projectRoot) { extraArgs: [] }; - if (options.argv.ant || options.argv.gradle) - ret.buildMethod = options.argv.ant ? 'ant' : 'gradle'; + if (options.argv.gradle || options.argv.studio) + ret.buildMethod = options.argv.studio ? 'studio' : 'gradle'; if (options.nobuild) ret.buildMethod = 'none'; diff --git a/bin/templates/cordova/lib/builders/GenericBuilder.js b/bin/templates/cordova/lib/builders/GenericBuilder.js index 16a69f57..0ae6fcab 100644 --- a/bin/templates/cordova/lib/builders/GenericBuilder.js +++ b/bin/templates/cordova/lib/builders/GenericBuilder.js @@ -27,6 +27,7 @@ var CordovaError = require('cordova-common').CordovaError; function GenericBuilder (projectDir) { this.root = projectDir || path.resolve(__dirname, '../../..'); this.binDirs = { + studio: path.join(this.root, 'app', 'build', 'outputs', 'apk'), gradle: path.join(this.root, 'build', 'outputs', 'apk') }; } @@ -52,6 +53,7 @@ GenericBuilder.prototype.findOutputApks = function(build_type, arch) { var self = this; return Object.keys(this.binDirs) .reduce(function (result, builderName) { + console.log('builderName:'+ builderName); var binDir = self.binDirs[builderName]; return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch)); }, []) diff --git a/bin/templates/cordova/lib/builders/GradleBuilder.js b/bin/templates/cordova/lib/builders/GradleBuilder.js index 809d5f7d..8357055f 100644 --- a/bin/templates/cordova/lib/builders/GradleBuilder.js +++ b/bin/templates/cordova/lib/builders/GradleBuilder.js @@ -79,6 +79,10 @@ GradleBuilder.prototype.runGradleWrapper = function(gradle_cmd) { } }; +/* + * We need to kill this in a fire. + */ + GradleBuilder.prototype.readProjectProperties = function () { function findAllUniq(data, r) { var s = {}; @@ -117,6 +121,9 @@ GradleBuilder.prototype.prepBuildFiles = function() { var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle'); var propertiesObj = this.readProjectProperties(); var subProjects = propertiesObj.libs; + + // Check and copy the gradle file into the subproject. + // Called by the loop below this function def. var checkAndCopy = function(subProject, root) { var subProjectGradle = path.join(root, subProject, 'build.gradle'); // This is the future-proof way of checking if a file exists @@ -127,11 +134,16 @@ GradleBuilder.prototype.prepBuildFiles = function() { shell.cp('-f', pluginBuildGradle, subProjectGradle); } }; + + // Some dependencies on Android don't use gradle, or don't have default + // gradle files. This copies a dummy gradle file into them for (var i = 0; i < subProjects.length; ++i) { - if (subProjects[i] !== 'CordovaLib') { + if (subProjects[i] !== 'CordovaLib' && subProjects[i] !== 'app') { checkAndCopy(subProjects[i], this.root); } } + + var name = this.extractRealProjectNameFromManifest(); //Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149 var settingsGradlePaths = subProjects.map(function(p){ @@ -151,6 +163,11 @@ GradleBuilder.prototype.prepBuildFiles = function() { var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8'); var depsList = ''; var root = this.root; + + + // Cordova Plugins can be written as library modules that would use Cordova as a + // dependency. Because we need to make sure that Cordova is compiled only once for + // dexing, we make sure to exclude CordovaLib from these modules var insertExclude = function(p) { var gradlePath = path.join(root, p, 'build.gradle'); var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8'); @@ -161,6 +178,7 @@ GradleBuilder.prototype.prepBuildFiles = function() { depsList +='\n'; } }; + subProjects.forEach(function(p) { console.log('Subproject Path: ' + p); var libName=p.replace(/[/\\]/g, ':').replace(name+'-',''); @@ -169,11 +187,14 @@ GradleBuilder.prototype.prepBuildFiles = function() { depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))'; insertExclude(p); }); + + // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390 var SYSTEM_LIBRARY_MAPPINGS = [ [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'], [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+'] ]; + propertiesObj.systemLibs.forEach(function(p) { var mavenRef; // It's already in gradle form if it has two ':'s @@ -193,6 +214,9 @@ GradleBuilder.prototype.prepBuildFiles = function() { } depsList += ' compile "' + mavenRef + '"\n'; }); + + //This code is dangerous and actually writes gradle declarations directly into the build.gradle + //Try not to mess with this if possible buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2'); var includeList = ''; propertiesObj.gradleIncludes.forEach(function(includePath) { diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js index 66ff0efa..2d3e3e51 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -37,7 +37,7 @@ var TEMPLATE = function StudioBuilder (projectRoot) { GenericBuilder.call(this, projectRoot); - this.binDirs = {gradle: this.binDirs.gradle}; + this.binDirs = {gradle: this.binDirs.studio}; } util.inherits(StudioBuilder, GenericBuilder); @@ -81,6 +81,9 @@ StudioBuilder.prototype.runGradleWrapper = function(gradle_cmd) { StudioBuilder.prototype.readProjectProperties = function () { + + console.log("Do we even have to do this?"); + function findAllUniq(data, r) { var s = {}; var m; @@ -145,10 +148,15 @@ StudioBuilder.prototype.prepBuildFiles = function() { return str; }); + + // We really shouldn't do this. // Write the settings.gradle file. - fs.writeFileSync(path.join(this.root, 'settings.gradle'), + /* + fs.writeFileSync(path.join(this.root, 'settings.gradle'), '// GENERATED FILE - DO NOT EDIT\n' + 'include ":"\n' + settingsGradlePaths.join('')); + */ + // Update dependencies within build.gradle. var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8'); var depsList = ''; @@ -212,21 +220,6 @@ StudioBuilder.prototype.prepEnv = function(opts) { }).then(function() { return self.prepBuildFiles(); }).then(function() { - // We now copy the gradle out of the framework - // This is a dirty patch to get the build working - /* - var wrapperDir = path.join(self.root, 'CordovaLib'); - if (process.platform == 'win32') { - shell.rm('-f', path.join(self.root, 'gradlew.bat')); - shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root); - } else { - shell.rm('-f', path.join(self.root, 'gradlew')); - shell.cp(path.join(wrapperDir, 'gradlew'), self.root); - } - shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper')); - shell.mkdir('-p', path.join(self.root, 'gradle')); - shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle')); -*/ // If the gradle distribution URL is set, make sure it points to version we want. // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with. // For some reason, using ^ and $ don't work. This does the job, though. diff --git a/bin/templates/cordova/lib/device.js b/bin/templates/cordova/lib/device.js index 4b171db6..47828f7f 100644 --- a/bin/templates/cordova/lib/device.js +++ b/bin/templates/cordova/lib/device.js @@ -85,7 +85,7 @@ module.exports.install = function(target, buildResults) { return module.exports.resolveTarget(target); }).then(function(resolvedTarget) { var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch); - var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml')); + var manifest = new AndroidManifest(path.join(__dirname, '../../app/src/main/AndroidManifest.xml')); var pkgName = manifest.getPackageId(); var launchName = pkgName + '/.' + manifest.getActivity().getName(); events.emit('log', 'Using apk: ' + apk_path); diff --git a/bin/templates/cordova/lib/emulator.js b/bin/templates/cordova/lib/emulator.js index 22209aa0..2f36b9a8 100644 --- a/bin/templates/cordova/lib/emulator.js +++ b/bin/templates/cordova/lib/emulator.js @@ -116,7 +116,7 @@ module.exports.list_images_using_avdmanager = function () { }; module.exports.list_images_using_android = function() { - return superspawn.spawn('android', ['list', 'avd']) + return superspawn.spawn('android', ['list', 'avds']) .then(function(output) { var response = output.split('\n'); var emulator_list = []; @@ -171,10 +171,20 @@ module.exports.list_images_using_android = function() { } */ module.exports.list_images = function() { - if (forgivingWhichSync('avdmanager')) { + if (forgivingWhichSync('android')) { + return module.exports.list_images_using_android() + .catch(function(err) { + // try to use `avdmanager` in case `android` reports it is no longer available. + // this likely means the target machine is using a newer version of + // the android sdk, and possibly `avdmanager` is available. + if (err.code == 1 && err.stdout.indexOf('android command is no longer available')) { + return module.exports.list_images_using_avdmanager(); + } else { + throw err; + } + }); + } else if (forgivingWhichSync('avdmanager')) { return module.exports.list_images_using_avdmanager(); - } else if (forgivingWhichSync('android')) { - return module.exports.list_images_using_android(); } else { return Q().then(function() { throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?'); @@ -218,7 +228,6 @@ module.exports.list_started = function() { }; // Returns a promise. -// TODO: we should remove this, there's a more robust method under android_sdk.js module.exports.list_targets = function() { return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()}) .then(function(output) { @@ -390,7 +399,6 @@ module.exports.create_image = function(name, target) { }); } else { console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.'); - // TODO: there's a more robust method for finding targets in android_sdk.js return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]]) .then(function() { // TODO: This seems like another error case, even though it always happens. From 69260fb96a8d606549caa8880abc5e7b444c4621 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 11 Apr 2017 14:41:27 -0700 Subject: [PATCH 09/50] Fix the overwriting of Fil's fix, blargh --- bin/templates/cordova/lib/android_sdk.js | 77 ++++++++---------------- 1 file changed, 24 insertions(+), 53 deletions(-) diff --git a/bin/templates/cordova/lib/android_sdk.js b/bin/templates/cordova/lib/android_sdk.js index 58d301ef..a1a806a6 100755 --- a/bin/templates/cordova/lib/android_sdk.js +++ b/bin/templates/cordova/lib/android_sdk.js @@ -1,5 +1,3 @@ - - /* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file @@ -68,65 +66,38 @@ module.exports.version_string_to_api_level = { '7.1.1': 25 }; -module.exports.list_targets_with_android = function() { - return superspawn.spawn('android', ['list', 'targets']) - .then(function(stdout) { - var target_out = stdout.split('\n'); - var targets = []; - for (var i = target_out.length - 1; i >= 0; i--) { - if(target_out[i].match(/id:/)) { - targets.push(target_out[i].match(/"(.+)"/)[1]); - } +function parse_targets(output) { + var target_out = output.split('\n'); + var targets = []; + for (var i = target_out.length - 1; i >= 0; i--) { + if(target_out[i].match(/id:/)) { // if "id:" is in the line... + targets.push(target_out[i].match(/"(.+)"/)[1]); //.. match whatever is in quotes. } - return targets; - }); + } + return targets; +} + +module.exports.list_targets_with_android = function() { + return superspawn.spawn('android', ['list', 'target']) + .then(parse_targets); }; -module.exports.list_targets_with_sdkmanager = function() { - return superspawn.spawn('sdkmanager', ['--list']) - .then(function(stdout) { - var parsing_installed_packages = false; - var lines = stdout.split('\n'); - var targets = []; - for (var i = 0, l = lines.length; i < l; i++) { - var line = lines[i]; - if (line.match(/Installed packages/)) { - parsing_installed_packages = true; - } else if (line.match(/Available Packages/) || line.match(/Available Updates/)) { - // we are done working through installed packages, exit - break; - } - if (parsing_installed_packages) { - // Match stock android platform - if (line.match(/platforms;android-\d+/)) { - targets.push(line.match(/(android-\d+)/)[1]); - } - // Match Google APIs - if (line.match(/addon-google_apis-google-\d+/)) { - var description = lines[i + 1]; - // munge description to match output from old android sdk tooling - var api_level = description.match(/Android (\d+)/); //[1]; - if (api_level) { - targets.push('Google Inc.:Google APIs:' + api_level[1]); - } - } - // TODO: match anything else? - } - } - return targets; - }); +module.exports.list_targets_with_avdmanager = function() { + return superspawn.spawn('avdmanager', ['list', 'target']) + .then(parse_targets); }; module.exports.list_targets = function() { - return module.exports.list_targets_with_android() + return module.exports.list_targets_with_avdmanager() .catch(function(err) { - // there's a chance `android` no longer works. - // lets see if `sdkmanager` is available and we can figure it out - var avail_regex = /"?android"? command is no longer available/; - if (err.code && ((err.stdout && err.stdout.match(avail_regex)) || (err.stderr && err.stderr.match(avail_regex)))) { - return module.exports.list_targets_with_sdkmanager(); + // If there's an error, like avdmanager could not be found, we can try + // as a last resort, to run `android`, in case this is a super old + // SDK installation. + if (err && (err.code == 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) { + return module.exports.list_targets_with_android(); } else throw err; - }).then(function(targets) { + }) + .then(function(targets) { if (targets.length === 0) { return Q.reject(new Error('No android targets (SDKs) installed!')); } From a216f0db751778953224067f25b8e0077bb7e760 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 4 Jan 2017 11:48:18 -0800 Subject: [PATCH 10/50] CB-11244: Changing directory creation, will most likely hide this behind a flag for the next release of Cordova-Android, and then make it default in the next major pending feedback --- bin/lib/create.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index d2b2e4dc..7b329427 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -276,6 +276,7 @@ exports.create = function(project_path, config, options, events) { copyJsAndLibrary(project_path, options.link, safe_activity_name); //Set up ther Android Studio paths + var app_path = path.join(project_path, 'app', 'src', 'main'); var java_path = path.join(app_path, 'java'); var assets_path = path.join(app_path, 'assets'); var resource_path = path.join(app_path, 'res'); @@ -285,8 +286,9 @@ exports.create = function(project_path, config, options, events) { // interpolate the activity name and package var packagePath = package_name.replace(/\./g, path.sep); - var activity_dir = path.join(project_path, 'src', packagePath); + var activity_dir = path.join(java_path, packagePath); var activity_path = path.join(activity_dir, safe_activity_name + '.java'); + shell.mkdir('-p', activity_dir); shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path); shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path); @@ -298,7 +300,7 @@ exports.create = function(project_path, config, options, events) { .setTargetSdkVersion(target_api.split('-')[1]) .getActivity().setName(safe_activity_name); - var manifest_path = path.join(project_path, 'AndroidManifest.xml'); + var manifest_path = path.join(app_path, 'AndroidManifest.xml'); manifest.write(manifest_path); copyScripts(project_path); From 69ab6a0e0d70e56c6fe0fe7529a211c51df09ab7 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 18 Apr 2017 14:29:02 -0700 Subject: [PATCH 11/50] Changing the project to add the app directory as a dependency --- .../cordova/lib/builders/StudioBuilder.js | 6 +----- bin/templates/project/project.properties | 20 +++++++++---------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js index 2d3e3e51..658876a9 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -149,13 +149,9 @@ StudioBuilder.prototype.prepBuildFiles = function() { }); - // We really shouldn't do this. - // Write the settings.gradle file. - /* - fs.writeFileSync(path.join(this.root, 'settings.gradle'), + fs.writeFileSync(path.join(this.root, 'settings.gradle'), '// GENERATED FILE - DO NOT EDIT\n' + 'include ":"\n' + settingsGradlePaths.join('')); - */ // Update dependencies within build.gradle. var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8'); diff --git a/bin/templates/project/project.properties b/bin/templates/project/project.properties index ddd3a060..6ea5ac23 100644 --- a/bin/templates/project/project.properties +++ b/bin/templates/project/project.properties @@ -1,15 +1,13 @@ -# This file is automatically generated by Android Tools. -# Do not modify this file -- YOUR CHANGES WILL BE ERASED! -# -# This file must be checked in Version Control Systems. -# -# To customize properties used by the Ant build system edit -# "ant.properties", and override values to adapt the script to your -# project structure. -# -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt +# This file was originally created by the Android Tools, but is now +# used by cordova-android to manage the state of the various third party +# libraries used in your application +# This is the Library Module that contains the Cordova Library, this is not +# required when using an AAR android.library.reference.1=CordovaLib + +# This is the application project. This is only required for Android Studio Gradle projects +android.library.reference.2=app + # Project target. target=This_gets_replaced From 8391af2e8f6d9bdab102f28c58f257b8b53d0c0f Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 18 Apr 2017 14:48:56 -0700 Subject: [PATCH 12/50] JsHint Fixes, deleting unused methods --- bin/lib/create.js | 1 - bin/templates/cordova/lib/builders/GenericBuilder.js | 5 ----- bin/templates/cordova/lib/builders/StudioBuilder.js | 2 -- 3 files changed, 8 deletions(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index 7b329427..e7c39bd6 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -276,7 +276,6 @@ exports.create = function(project_path, config, options, events) { copyJsAndLibrary(project_path, options.link, safe_activity_name); //Set up ther Android Studio paths - var app_path = path.join(project_path, 'app', 'src', 'main'); var java_path = path.join(app_path, 'java'); var assets_path = path.join(app_path, 'assets'); var resource_path = path.join(app_path, 'res'); diff --git a/bin/templates/cordova/lib/builders/GenericBuilder.js b/bin/templates/cordova/lib/builders/GenericBuilder.js index 0ae6fcab..9b5d07ac 100644 --- a/bin/templates/cordova/lib/builders/GenericBuilder.js +++ b/bin/templates/cordova/lib/builders/GenericBuilder.js @@ -22,7 +22,6 @@ var fs = require('fs'); var path = require('path'); var shell = require('shelljs'); var events = require('cordova-common').events; -var CordovaError = require('cordova-common').CordovaError; function GenericBuilder (projectDir) { this.root = projectDir || path.resolve(__dirname, '../../..'); @@ -32,10 +31,6 @@ function GenericBuilder (projectDir) { }; } -function hasCustomRules(projectRoot) { - return fs.existsSync(path.join(projectRoot, 'custom_rules.xml')); -} - GenericBuilder.prototype.prepEnv = function() { return Q(); }; diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js index 658876a9..adc90092 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -82,8 +82,6 @@ StudioBuilder.prototype.runGradleWrapper = function(gradle_cmd) { StudioBuilder.prototype.readProjectProperties = function () { - console.log("Do we even have to do this?"); - function findAllUniq(data, r) { var s = {}; var m; From 304a8991140f3f1ed76a9816b1a4d701537f89ea Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 19 Apr 2017 11:50:55 -0700 Subject: [PATCH 13/50] Fixed the specification of the builders in the run command by getting build to check what was being passed from run --- bin/templates/cordova/lib/build.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js index e684e61f..2fcf0b8e 100644 --- a/bin/templates/cordova/lib/build.js +++ b/bin/templates/cordova/lib/build.js @@ -58,6 +58,10 @@ function parseOpts(options, resolvedTarget, projectRoot) { if (options.argv.gradle || options.argv.studio) ret.buildMethod = options.argv.studio ? 'studio' : 'gradle'; + //This comes from cordova/run + if (options.studio) ret.buildMethod = 'studio'; + if (options.gradle) ret.buildMethod = 'gradle'; + if (options.nobuild) ret.buildMethod = 'none'; if (options.argv.versionCode) @@ -148,6 +152,7 @@ module.exports.runClean = function(options) { */ module.exports.run = function(options, optResolvedTarget) { var opts = parseOpts(options, optResolvedTarget, this.root); + console.log(opts.buildMethod); var builder = builders.getBuilder(opts.buildMethod); return builder.prepEnv(opts) .then(function() { From e621edfba755d31915da29a6113b0be2db56735f Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Fri, 21 Apr 2017 16:27:26 -0700 Subject: [PATCH 14/50] Fixing the Android Studio detection and making it automatically pick the right builder, good for upgrading Cordova --- bin/lib/create.js | 10 ++++++---- bin/templates/cordova/Api.js | 2 ++ bin/templates/cordova/lib/AndroidStudio.js | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index e7c39bd6..bb48791c 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -45,7 +45,9 @@ function getFrameworkDir(projectPath, shared) { function copyJsAndLibrary(projectPath, shared, projectName) { var nestedCordovaLibPath = getFrameworkDir(projectPath, false); var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js'); - shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'app', 'src', 'main', 'assets', 'www', 'cordova.js')); + var app_path = path.join(projectPath, 'app', 'src', 'main'); + + shell.cp('-f', srcCordovaJsPath, path.join(app_path, 'assets', 'www', 'cordova.js')); // Copy the cordova.js file to platforms//platform_www/ // The www dir is nuked on each prepare so we keep cordova.js in platform_www @@ -56,9 +58,9 @@ function copyJsAndLibrary(projectPath, shared, projectName) { // We need these files to build cordova.js if using browserify method. shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www')); - // Don't fail if there are no old jars. + // Don't fail if there are no old jars, because there hasn't been cordova JARs for years! setShellFatal(false, function() { - shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) { + shell.ls(path.join(app_path, 'libs', 'cordova-*.jar')).forEach(function(oldJar) { console.log('Deleting ' + oldJar); shell.rm('-f', oldJar); }); @@ -270,7 +272,7 @@ exports.create = function(project_path, config, options, events) { shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore')); // Manually create directories that would be empty within the template (since git doesn't track directories). - shell.mkdir(path.join(project_path, 'libs')); + shell.mkdir(path.join(app_path, 'libs')); // copy cordova.js, cordova.jar copyJsAndLibrary(project_path, options.link, safe_activity_name); diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index 8e4711cb..4422d074 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -343,6 +343,8 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) { */ Api.prototype.build = function (buildOptions) { var self = this; + if(this.android_studio) + buildOptions.studio = true; return require('./lib/check_reqs').run() .then(function () { return require('./lib/build').run.call(self, buildOptions); diff --git a/bin/templates/cordova/lib/AndroidStudio.js b/bin/templates/cordova/lib/AndroidStudio.js index 335b334b..2e7db00a 100644 --- a/bin/templates/cordova/lib/AndroidStudio.js +++ b/bin/templates/cordova/lib/AndroidStudio.js @@ -11,7 +11,7 @@ var fs = require('fs'); var CordovaError = require('cordova-common').CordovaError; module.exports.isAndroidStudioProject = function isAndroidStudioProject(root) { - var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res', 'project.properties', 'platform_www']; + var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res']; var androidStudioFiles = ['app', 'gradle', 'app/src/main/res']; // assume it is an AS project and not an Eclipse project From bd4ddcdeddf7a5b232023c4f53b60d2ab20e7a48 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Fri, 21 Apr 2017 17:02:27 -0700 Subject: [PATCH 15/50] Updated AndroidStudio to only look for the app directory to determine studio status --- bin/templates/cordova/lib/AndroidStudio.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/templates/cordova/lib/AndroidStudio.js b/bin/templates/cordova/lib/AndroidStudio.js index 2e7db00a..ee4cd3fe 100644 --- a/bin/templates/cordova/lib/AndroidStudio.js +++ b/bin/templates/cordova/lib/AndroidStudio.js @@ -12,7 +12,7 @@ var CordovaError = require('cordova-common').CordovaError; module.exports.isAndroidStudioProject = function isAndroidStudioProject(root) { var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res']; - var androidStudioFiles = ['app', 'gradle', 'app/src/main/res']; + var androidStudioFiles = ['app', 'app/src/main']; // assume it is an AS project and not an Eclipse project var isEclipse = false; From 28ebbb8f024f31a627af6b26ba23e41e7ce22f65 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 31 May 2017 10:23:35 -0700 Subject: [PATCH 16/50] CB-11244: Setup Api.js to support multiple builders based on project structure --- bin/templates/cordova/Api.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index 4422d074..a41f8606 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -58,6 +58,7 @@ function setupEvents(externalEventEmitter) { function Api(platform, platformRootDir, events) { this.platform = PLATFORM; this.root = path.resolve(__dirname, '..'); + this.builder = "gradle"; setupEvents(events); @@ -81,6 +82,7 @@ function Api(platform, platformRootDir, events) { // XXX Override some locations for Android Studio projects if(AndroidStudio.isAndroidStudioProject(self.root) === true) { selfEvents.emit('log', 'Android Studio project detected'); + this.builder="studio"; 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'); @@ -257,7 +259,8 @@ Api.prototype.addPlugin = function (plugin, installOptions) { if (plugin.getFrameworks(this.platform).length === 0) return; selfEvents.emit('verbose', 'Updating build files since android plugin contained '); - require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles(); + //This should pick the correct builder, not just get gradle + require('./lib/builders/builders').getBuilder(this.builder).prepBuildFiles(); }.bind(this)) // CB-11022 Return truthy value to prevent running prepare after .thenResolve(true); @@ -290,7 +293,7 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) { if (plugin.getFrameworks(this.platform).length === 0) return; selfEvents.emit('verbose', 'Updating build files since android plugin contained '); - require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles(); + require('./lib/builders/builders').getBuilder(this.builder).prepBuildFiles(); }.bind(this)) // CB-11022 Return truthy value to prevent running prepare after .thenResolve(true); From fb6cb51e64a2ea05ba65195023b702fb00b378c2 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 31 May 2017 10:37:47 -0700 Subject: [PATCH 17/50] Fixing lint errors --- bin/templates/cordova/Api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index a41f8606..fe720800 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -58,7 +58,7 @@ function setupEvents(externalEventEmitter) { function Api(platform, platformRootDir, events) { this.platform = PLATFORM; this.root = path.resolve(__dirname, '..'); - this.builder = "gradle"; + this.builder = 'gradle'; setupEvents(events); @@ -82,7 +82,7 @@ function Api(platform, platformRootDir, events) { // XXX Override some locations for Android Studio projects if(AndroidStudio.isAndroidStudioProject(self.root) === true) { selfEvents.emit('log', 'Android Studio project detected'); - this.builder="studio"; + this.builder='studio'; 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'); From 8f16df4c90bd4a9ea64f537d85db5ce6069b5c04 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 13 Jun 2017 08:27:46 -0700 Subject: [PATCH 18/50] Adding logic to upgrade both Classic and Android Studio style project structures --- bin/lib/create.js | 45 +++++++++++++++++++++++++++++++++------------ 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index bb48791c..2db60c1b 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -29,6 +29,7 @@ var shell = require('shelljs'), var MIN_SDK_VERSION = 19; var CordovaError = require('cordova-common').CordovaError; +var AndroidStudio = require('../templates/cordova/lib/AndroidStudio'); var AndroidManifest = require('../templates/cordova/lib/AndroidManifest'); function setShellFatal(value, func) { @@ -42,11 +43,14 @@ function getFrameworkDir(projectPath, shared) { return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib'); } -function copyJsAndLibrary(projectPath, shared, projectName) { +function copyJsAndLibrary(projectPath, shared, projectName, isLegacy) { var nestedCordovaLibPath = getFrameworkDir(projectPath, false); var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js'); var app_path = path.join(projectPath, 'app', 'src', 'main'); + if(isLegacy) + app_path = projectPath; + shell.cp('-f', srcCordovaJsPath, path.join(app_path, 'assets', 'www', 'cordova.js')); // Copy the cordova.js file to platforms//platform_www/ @@ -128,17 +132,23 @@ function writeProjectProperties(projectPath, target_api) { } // This makes no sense, what if you're building with a different build system? -function prepBuildFiles(projectPath) { +function prepBuildFiles(projectPath, builder) { var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders')); - buildModule.getBuilder('studio').prepBuildFiles(); + buildModule.getBuilder(builder).prepBuildFiles(); } -function copyBuildRules(projectPath) { +function copyBuildRules(projectPath, isLegacy) { var srcDir = path.join(ROOT, 'bin', 'templates', 'project'); - shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath); - shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), path.join(projectPath, 'app')); - shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); + if(isLegacy) { + //The project's build.gradle is identical to the earlier build.gradle, so it should still work + shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), projectPath); + shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); + } else { + shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath); + shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), path.join(projectPath, 'app')); + shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); + } } function copyScripts(projectPath) { @@ -309,7 +319,7 @@ exports.create = function(project_path, config, options, events) { }); // Link it to local android install. writeProjectProperties(project_path, target_api); - prepBuildFiles(project_path); + prepBuildFiles(project_path, 'studio'); events.emit('log', generateDoneMessage('create', options.link)); }).thenResolve(project_path); }; @@ -330,7 +340,18 @@ exports.update = function(projectPath, options, events) { return Q() .then(function() { - var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml')); + var isAndroidStudio = AndroidStudio.isAndroidStudioProject(projectPath); + var isLegacy = !isAndroidStudio; + var manifest = null; + var builder = 'gradle'; + + if(isAndroidStudio) { + manifest = new AndroidManifest(path.join(projectPath, 'app', 'main', 'AndroidManifest.xml')); + builder = 'studio'; + } else { + manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml')); + builder = 'gradle'; + } if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) { events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml'); @@ -342,11 +363,11 @@ exports.update = function(projectPath, options, events) { var projectName = manifest.getActivity().getName(); var target_api = check_reqs.get_target(); - copyJsAndLibrary(projectPath, options.link, projectName); + copyJsAndLibrary(projectPath, options.link, projectName, isLegacy); copyScripts(projectPath); - copyBuildRules(projectPath); + copyBuildRules(projectPath, isLegacy); writeProjectProperties(projectPath, target_api); - prepBuildFiles(projectPath); + prepBuildFiles(projectPath, builder); events.emit('log', generateDoneMessage('update', options.link)); }).thenResolve(projectPath); }; From 33feb00e8f383cd99ce59a052171d6d35c61094c Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 13 Jun 2017 10:11:41 -0700 Subject: [PATCH 19/50] Adding the if statement to see if we can support both structures with minimal editing, TODO: actually write tests for this somehow --- bin/templates/project/app/build.gradle | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle index 5134793f..78a1770d 100644 --- a/bin/templates/project/app/build.gradle +++ b/bin/templates/project/app/build.gradle @@ -45,7 +45,12 @@ task wrapper(type: Wrapper) { // Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. // Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html ext { - apply from: '../CordovaLib/cordova.gradle' + //This is a dirty hack to support legacy projects + if (file('../CordovaLib/cordova.gradle').exists()) { + apply from: '../CordovaLib/cordova.gradle' + } else { + apply from: 'CordovaLib/cordova.gradle' + } // The value for android.compileSdkVersion. if (!project.hasProperty('cdvCompileSdkVersion')) { cdvCompileSdkVersion = null; From c74192d578e647a8386ac8663d6c99521f28b110 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 13 Jun 2017 10:36:00 -0700 Subject: [PATCH 20/50] Adding conditional code into Gradle, this is a bit dirty since we can't explicitly test it but we'll just have to rely on jasmine --- bin/templates/project/app/build.gradle | 6 ++++-- framework/cordova.gradle | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle index 78a1770d..c9a42369 100644 --- a/bin/templates/project/app/build.gradle +++ b/bin/templates/project/app/build.gradle @@ -98,10 +98,12 @@ if (hasBuildExtras) { // Set property defaults after extension .gradle files. if (ext.cdvCompileSdkVersion == null) { - ext.cdvCompileSdkVersion = project.ext.defaultCompileSdkVersion + ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget() + //ext.cdvCompileSdkVersion = project.ext.defaultCompileSdkVersion } if (ext.cdvBuildToolsVersion == null) { - ext.cdvBuildToolsVersion = project.ext.defaultBuildToolsVersion + ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools() + //ext.cdvBuildToolsVersion = project.ext.defaultBuildToolsVersion } if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) { ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties' diff --git a/framework/cordova.gradle b/framework/cordova.gradle index 21a01bb5..0131a265 100644 --- a/framework/cordova.gradle +++ b/framework/cordova.gradle @@ -29,7 +29,11 @@ String doEnsureValueExists(filePath, props, key) { String doGetProjectTarget() { def props = new Properties() - file('project.properties').withReader { reader -> + def propertiesFile = 'project.properties'; + if(!(file(propertiesFile).exists())) { + propertiesFile = '../project.properties'; + } + file(propertiesFile).withReader { reader -> props.load(reader) } return doEnsureValueExists('project.properties', props, 'target') From b67e9905bccde0b6188bd2c6f16dae34d09b9d35 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 13 Jun 2017 11:58:00 -0700 Subject: [PATCH 21/50] This is probably a bad idea, but we need to split the gradle files into legacy and new style --- bin/lib/create.js | 2 +- bin/templates/project/app/build.gradle | 7 +- bin/templates/project/legacy/build.gradle | 309 ++++++++++++++++++++++ 3 files changed, 311 insertions(+), 7 deletions(-) create mode 100644 bin/templates/project/legacy/build.gradle diff --git a/bin/lib/create.js b/bin/lib/create.js index 2db60c1b..58766891 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -142,7 +142,7 @@ function copyBuildRules(projectPath, isLegacy) { if(isLegacy) { //The project's build.gradle is identical to the earlier build.gradle, so it should still work - shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), projectPath); + shell.cp('-f', path.join(srcDir, 'legacy', 'build.gradle'), projectPath); shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); } else { shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath); diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle index c9a42369..c36735f1 100644 --- a/bin/templates/project/app/build.gradle +++ b/bin/templates/project/app/build.gradle @@ -45,12 +45,7 @@ task wrapper(type: Wrapper) { // Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. // Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html ext { - //This is a dirty hack to support legacy projects - if (file('../CordovaLib/cordova.gradle').exists()) { - apply from: '../CordovaLib/cordova.gradle' - } else { - apply from: 'CordovaLib/cordova.gradle' - } + apply from: '../CordovaLib/cordova.gradle' // The value for android.compileSdkVersion. if (!project.hasProperty('cdvCompileSdkVersion')) { cdvCompileSdkVersion = null; diff --git a/bin/templates/project/legacy/build.gradle b/bin/templates/project/legacy/build.gradle new file mode 100644 index 00000000..245f7037 --- /dev/null +++ b/bin/templates/project/legacy/build.gradle @@ -0,0 +1,309 @@ +/* + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you under the Apache License, Version 2.0 (the + "License"); you may not use this file except in compliance + with the License. You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, + software distributed under the License is distributed on an + "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + KIND, either express or implied. See the License for the + specific language governing permissions and limitations + under the License. +*/ + +apply plugin: 'com.android.application' + +buildscript { + repositories { + mavenCentral() + jcenter() + } + + dependencies { + classpath 'com.android.tools.build:gradle:2.3.0' + } +} + +// Allow plugins to declare Maven dependencies via build-extras.gradle. +allprojects { + repositories { + mavenCentral(); + jcenter() + } +} + +task wrapper(type: Wrapper) { + gradleVersion = '3.3.0' +} + +// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. +// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html +ext { + apply from: 'CordovaLib/cordova.gradle' + // The value for android.compileSdkVersion. + if (!project.hasProperty('cdvCompileSdkVersion')) { + cdvCompileSdkVersion = null; + } + // The value for android.buildToolsVersion. + if (!project.hasProperty('cdvBuildToolsVersion')) { + cdvBuildToolsVersion = null; + } + // Sets the versionCode to the given value. + if (!project.hasProperty('cdvVersionCode')) { + cdvVersionCode = null + } + // Sets the minSdkVersion to the given value. + if (!project.hasProperty('cdvMinSdkVersion')) { + cdvMinSdkVersion = null + } + // Whether to build architecture-specific APKs. + if (!project.hasProperty('cdvBuildMultipleApks')) { + cdvBuildMultipleApks = null + } + // .properties files to use for release signing. + if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) { + cdvReleaseSigningPropertiesFile = null + } + // .properties files to use for debug signing. + if (!project.hasProperty('cdvDebugSigningPropertiesFile')) { + cdvDebugSigningPropertiesFile = null + } + // Set by build.js script. + if (!project.hasProperty('cdvBuildArch')) { + cdvBuildArch = null + } + + // Plugin gradle extensions can append to this to have code run at the end. + cdvPluginPostBuildExtras = [] +} + +// PLUGIN GRADLE EXTENSIONS START +// PLUGIN GRADLE EXTENSIONS END + +def hasBuildExtras = file('build-extras.gradle').exists() +if (hasBuildExtras) { + apply from: 'build-extras.gradle' +} + +// Set property defaults after extension .gradle files. +if (ext.cdvCompileSdkVersion == null) { + ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget() + //ext.cdvCompileSdkVersion = project.ext.defaultCompileSdkVersion +} +if (ext.cdvBuildToolsVersion == null) { + ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools() + //ext.cdvBuildToolsVersion = project.ext.defaultBuildToolsVersion +} +if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) { + ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties' +} +if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) { + ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties' +} + +// Cast to appropriate types. +ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean(); +ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : defaultMinSdkVersion +ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode) + +def computeBuildTargetName(debugBuild) { + def ret = 'assemble' + if (cdvBuildMultipleApks && cdvBuildArch) { + def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch + ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1); + } + return ret + (debugBuild ? 'Debug' : 'Release') +} + +// Make cdvBuild a task that depends on the debug/arch-sepecific task. +task cdvBuildDebug +cdvBuildDebug.dependsOn { + return computeBuildTargetName(true) +} + +task cdvBuildRelease +cdvBuildRelease.dependsOn { + return computeBuildTargetName(false) +} + +task cdvPrintProps << { + println('cdvCompileSdkVersion=' + cdvCompileSdkVersion) + println('cdvBuildToolsVersion=' + cdvBuildToolsVersion) + println('cdvVersionCode=' + cdvVersionCode) + println('cdvMinSdkVersion=' + cdvMinSdkVersion) + println('cdvBuildMultipleApks=' + cdvBuildMultipleApks) + println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile) + println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile) + println('cdvBuildArch=' + cdvBuildArch) + println('computedVersionCode=' + android.defaultConfig.versionCode) + android.productFlavors.each { flavor -> + println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode) + } +} + +android { + + //Define a sourceset only if we have a top level AndroidManifest.xml file + sourcesets { + main { + manifest.srcFile 'AndroidManifest.xml' + java.srcDirs = ['src'] + resources.srcDirs = ['src'] + aidl.srcDirs = ['src'] + renderscript.srcDirs = ['src'] + res.srcDirs = ['res'] + assets.srcDirs = ['assets'] + jniLibs.srcDirs = ['libs'] + } + } + + defaultConfig { + versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode")) + applicationId privateHelpers.extractStringFromManifest("package") + + if (cdvMinSdkVersion != null) { + minSdkVersion cdvMinSdkVersion + } + } + + lintOptions { + abortOnError false; + } + + compileSdkVersion cdvCompileSdkVersion + buildToolsVersion cdvBuildToolsVersion + + //This code exists for Crosswalk and other Native APIs. + //By default, we multiply the existing version code in the Android Manifest by 10 and + //add a number for each architecture. If you are not using Crosswalk or SQLite, you can + //ignore this chunk of code, and your version codes will be respected. + + if (Boolean.valueOf(cdvBuildMultipleApks)) { + productFlavors { + armv7 { + versionCode defaultConfig.versionCode*10 + 2 + ndk { + abiFilters "armeabi-v7a", "" + } + } + x86 { + versionCode defaultConfig.versionCode*10 + 4 + ndk { + abiFilters "x86", "" + } + } + all { + ndk { + abiFilters "all", "" + } + } + } + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_6 + targetCompatibility JavaVersion.VERSION_1_6 + } + + if (cdvReleaseSigningPropertiesFile) { + signingConfigs { + release { + // These must be set or Gradle will complain (even if they are overridden). + keyAlias = "" + keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph. + storeFile = null + storePassword = "__unset" + } + } + buildTypes { + release { + signingConfig signingConfigs.release + } + } + addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release) + } + if (cdvDebugSigningPropertiesFile) { + addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug) + } +} + +/* + * WARNING: Cordova Lib and platform scripts do management inside of this code here, + * if you are adding the dependencies manually, do so outside the comments, otherwise + * the Cordova tools will overwrite them + */ + + +dependencies { + compile fileTree(dir: 'libs', include: '*.jar') + // SUB-PROJECT DEPENDENCIES START + debugCompile(project(path: ":CordovaLib", configuration: "debug")) + releaseCompile(project(path: ":CordovaLib", configuration: "release")) + // SUB-PROJECT DEPENDENCIES END +} + +def promptForReleaseKeyPassword() { + if (!cdvReleaseSigningPropertiesFile) { + return; + } + if ('__unset'.equals(android.signingConfigs.release.storePassword)) { + android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ') + } + if ('__unset'.equals(android.signingConfigs.release.keyPassword)) { + android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: '); + } +} + +gradle.taskGraph.whenReady { taskGraph -> + taskGraph.getAllTasks().each() { task -> + if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') { + promptForReleaseKeyPassword() + } + } +} + +def addSigningProps(propsFilePath, signingConfig) { + def propsFile = file(propsFilePath) + def props = new Properties() + propsFile.withReader { reader -> + props.load(reader) + } + + def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile')) + if (!storeFile.isAbsolute()) { + storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile()) + } + if (!storeFile.exists()) { + throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath()) + } + signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias') + signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword)) + signingConfig.storeFile = storeFile + signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword)) + def storeType = props.get('storeType', props.get('key.store.type', '')) + if (!storeType) { + def filename = storeFile.getName().toLowerCase(); + if (filename.endsWith('.p12') || filename.endsWith('.pfx')) { + storeType = 'pkcs12' + } else { + storeType = signingConfig.storeType // "jks" + } + } + signingConfig.storeType = storeType +} + +for (def func : cdvPluginPostBuildExtras) { + func() +} + +// This can be defined within build-extras.gradle as: +// ext.postBuildExtras = { ... code here ... } +if (hasProperty('postBuildExtras')) { + postBuildExtras() +} From 40c9709445ef77fa97cc8d2d65cc961860a3046e Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 14 Jun 2017 09:34:15 -0700 Subject: [PATCH 22/50] OK, Going back to the old build.gradle for legacy projects --- bin/templates/project/legacy/build.gradle | 46 ++++++++++++----------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/bin/templates/project/legacy/build.gradle b/bin/templates/project/legacy/build.gradle index 245f7037..ef229719 100644 --- a/bin/templates/project/legacy/build.gradle +++ b/bin/templates/project/legacy/build.gradle @@ -25,8 +25,12 @@ buildscript { jcenter() } + // Switch the Android Gradle plugin version requirement depending on the + // installed version of Gradle. This dependency is documented at + // http://tools.android.com/tech-docs/new-build-system/version-compatibility + // and https://issues.apache.org/jira/browse/CB-8143 dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:2.2.3' } } @@ -39,7 +43,7 @@ allprojects { } task wrapper(type: Wrapper) { - gradleVersion = '3.3.0' + gradleVersion = '2.14.1' } // Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. @@ -94,11 +98,9 @@ if (hasBuildExtras) { // Set property defaults after extension .gradle files. if (ext.cdvCompileSdkVersion == null) { ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget() - //ext.cdvCompileSdkVersion = project.ext.defaultCompileSdkVersion } if (ext.cdvBuildToolsVersion == null) { ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools() - //ext.cdvBuildToolsVersion = project.ext.defaultBuildToolsVersion } if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) { ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties' @@ -109,7 +111,7 @@ if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.propert // Cast to appropriate types. ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean(); -ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : defaultMinSdkVersion +ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion) ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode) def computeBuildTargetName(debugBuild) { @@ -148,9 +150,7 @@ task cdvPrintProps << { } android { - - //Define a sourceset only if we have a top level AndroidManifest.xml file - sourcesets { + sourceSets { main { manifest.srcFile 'AndroidManifest.xml' java.srcDirs = ['src'] @@ -179,11 +179,6 @@ android { compileSdkVersion cdvCompileSdkVersion buildToolsVersion cdvBuildToolsVersion - //This code exists for Crosswalk and other Native APIs. - //By default, we multiply the existing version code in the Android Manifest by 10 and - //add a number for each architecture. If you are not using Crosswalk or SQLite, you can - //ignore this chunk of code, and your version codes will be respected. - if (Boolean.valueOf(cdvBuildMultipleApks)) { productFlavors { armv7 { @@ -205,6 +200,22 @@ android { } } } + /* + + ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO! + + else if (!cdvVersionCode) { + def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion") + // Vary versionCode by the two most common API levels: + // 14 is ICS, which is the lowest API level for many apps. + // 20 is Lollipop, which is the lowest API level for the updatable system webview. + if (minSdkVersion >= 20) { + defaultConfig.versionCode += 9 + } else if (minSdkVersion >= 14) { + defaultConfig.versionCode += 8 + } + } + */ compileOptions { sourceCompatibility JavaVersion.VERSION_1_6 @@ -233,18 +244,9 @@ android { } } -/* - * WARNING: Cordova Lib and platform scripts do management inside of this code here, - * if you are adding the dependencies manually, do so outside the comments, otherwise - * the Cordova tools will overwrite them - */ - - dependencies { compile fileTree(dir: 'libs', include: '*.jar') // SUB-PROJECT DEPENDENCIES START - debugCompile(project(path: ":CordovaLib", configuration: "debug")) - releaseCompile(project(path: ":CordovaLib", configuration: "release")) // SUB-PROJECT DEPENDENCIES END } From c0474e811dd6387beefe8b5b5b036ee773a87126 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 14 Jun 2017 10:16:05 -0700 Subject: [PATCH 23/50] Bump for travis test From 49b76f5c7138684455af69b030bce71f290de31f Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 14 Jun 2017 11:36:43 -0700 Subject: [PATCH 24/50] Fixing mangled commits that crept into this branch --- bin/templates/cordova/lib/emulator.js | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/bin/templates/cordova/lib/emulator.js b/bin/templates/cordova/lib/emulator.js index 2f36b9a8..22209aa0 100644 --- a/bin/templates/cordova/lib/emulator.js +++ b/bin/templates/cordova/lib/emulator.js @@ -116,7 +116,7 @@ module.exports.list_images_using_avdmanager = function () { }; module.exports.list_images_using_android = function() { - return superspawn.spawn('android', ['list', 'avds']) + return superspawn.spawn('android', ['list', 'avd']) .then(function(output) { var response = output.split('\n'); var emulator_list = []; @@ -171,20 +171,10 @@ module.exports.list_images_using_android = function() { } */ module.exports.list_images = function() { - if (forgivingWhichSync('android')) { - return module.exports.list_images_using_android() - .catch(function(err) { - // try to use `avdmanager` in case `android` reports it is no longer available. - // this likely means the target machine is using a newer version of - // the android sdk, and possibly `avdmanager` is available. - if (err.code == 1 && err.stdout.indexOf('android command is no longer available')) { - return module.exports.list_images_using_avdmanager(); - } else { - throw err; - } - }); - } else if (forgivingWhichSync('avdmanager')) { + if (forgivingWhichSync('avdmanager')) { return module.exports.list_images_using_avdmanager(); + } else if (forgivingWhichSync('android')) { + return module.exports.list_images_using_android(); } else { return Q().then(function() { throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?'); @@ -228,6 +218,7 @@ module.exports.list_started = function() { }; // Returns a promise. +// TODO: we should remove this, there's a more robust method under android_sdk.js module.exports.list_targets = function() { return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()}) .then(function(output) { @@ -399,6 +390,7 @@ module.exports.create_image = function(name, target) { }); } else { console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.'); + // TODO: there's a more robust method for finding targets in android_sdk.js return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]]) .then(function() { // TODO: This seems like another error case, even though it always happens. From 1cda7a9de000bc71f920412286646803fa539ef4 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Mon, 19 Jun 2017 14:34:03 -0700 Subject: [PATCH 25/50] CB-11244: Found bug in Api.js where xml/strings.xml is used instead of values/strings.xml --- bin/templates/cordova/Api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index fe720800..283a86d4 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -85,7 +85,7 @@ function Api(platform, platformRootDir, events) { this.builder='studio'; 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.strings = path.join(self.root, 'app/src/main/res/values/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.join(self.root, 'app/src/main/res'); From b20028c42b0363ec27df304ba74a7d3d6003ad9f Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Thu, 22 Jun 2017 13:46:18 -0700 Subject: [PATCH 26/50] The prepare step was broken, which breaks the CLI workflow. This was caused by hardcoding the Java directory, which is a very bad idea. --- bin/templates/cordova/Api.js | 3 +++ bin/templates/cordova/lib/prepare.js | 4 +++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index 283a86d4..7a68903d 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -74,6 +74,7 @@ function Api(platform, platformRootDir, events) { strings: path.join(self.root, 'res/values/strings.xml'), manifest: path.join(self.root, 'AndroidManifest.xml'), build: path.join(self.root, 'build'), + javaSrc: path.join(self.root, 'src'), // NOTE: Due to platformApi spec we need to return relative paths here cordovaJs: 'bin/templates/project/assets/www/cordova.js', cordovaJsSrc: 'cordova-js-src' @@ -87,6 +88,8 @@ function Api(platform, platformRootDir, events) { 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/values/strings.xml'); this.locations.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml'); + //We could have Java Source, we could have other languages + this.locations.javaSrc = path.join(self.root, 'app/src/main/java/'); this.locations.www = path.join(self.root, 'app/src/main/assets/www'); this.locations.res = path.join(self.root, 'app/src/main/res'); } diff --git a/bin/templates/cordova/lib/prepare.js b/bin/templates/cordova/lib/prepare.js index 0ba12411..1532cab9 100644 --- a/bin/templates/cordova/lib/prepare.js +++ b/bin/templates/cordova/lib/prepare.js @@ -193,7 +193,9 @@ function updateProjectAccordingTo(platformConfig, locations) { .setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android')) .write(); - var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java'); + //Java file paths shouldn't be hard coded + var javaPattern = path.join(locations.javaSrc, orig_pkg.replace(/\./g, '/'), '*.java'); + var java_files = shell.ls(javaPattern).filter(function(f) { return shell.grep(/extends\s+CordovaActivity/g, f); }); From a7304b9a19a7b7f760d1bba240648a35130b295a Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 27 Jun 2017 13:15:04 -0700 Subject: [PATCH 27/50] Finishing the linting --- bin/lib/create.js | 159 +++++++++--------- bin/templates/cordova/Api.js | 15 +- bin/templates/cordova/lib/AndroidStudio.js | 2 +- bin/templates/cordova/lib/build.js | 5 +- .../cordova/lib/builders/GenericBuilder.js | 5 +- .../cordova/lib/builders/GradleBuilder.js | 18 +- .../cordova/lib/builders/StudioBuilder.js | 144 ++++++++-------- bin/templates/cordova/lib/prepare.js | 4 +- 8 files changed, 172 insertions(+), 180 deletions(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index f57c62c3..f7be5941 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -43,13 +43,14 @@ function getFrameworkDir (projectPath, shared) { return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib'); } -function copyJsAndLibrary(projectPath, shared, projectName, isLegacy) { +function copyJsAndLibrary (projectPath, shared, projectName, isLegacy) { var nestedCordovaLibPath = getFrameworkDir(projectPath, false); var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js'); var app_path = path.join(projectPath, 'app', 'src', 'main'); - if(isLegacy) - app_path = projectPath; + if (isLegacy) { + app_path = projectPath; + } shell.cp('-f', srcCordovaJsPath, path.join(app_path, 'assets', 'www', 'cordova.js')); @@ -131,22 +132,22 @@ function writeProjectProperties (projectPath, target_api) { } // This makes no sense, what if you're building with a different build system? -function prepBuildFiles(projectPath, builder) { +function prepBuildFiles (projectPath, builder) { var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders')); buildModule.getBuilder(builder).prepBuildFiles(); } -function copyBuildRules(projectPath, isLegacy) { +function copyBuildRules (projectPath, isLegacy) { var srcDir = path.join(ROOT, 'bin', 'templates', 'project'); - if(isLegacy) { - //The project's build.gradle is identical to the earlier build.gradle, so it should still work - shell.cp('-f', path.join(srcDir, 'legacy', 'build.gradle'), projectPath); - shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); + if (isLegacy) { + // The project's build.gradle is identical to the earlier build.gradle, so it should still work + shell.cp('-f', path.join(srcDir, 'legacy', 'build.gradle'), projectPath); + shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); } else { - shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath); - shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), path.join(projectPath, 'app')); - shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); + shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath); + shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), path.join(projectPath, 'app')); + shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); } } @@ -261,66 +262,66 @@ exports.create = function (project_path, config, options, events) { validateProjectName(project_name); }).then(function () { // Log the given values for the project - events.emit('log', 'Creating Cordova project for the Android platform:'); - events.emit('log', '\tPath: ' + project_path); - events.emit('log', '\tPackage: ' + package_name); - events.emit('log', '\tName: ' + project_name); - events.emit('log', '\tActivity: ' + safe_activity_name); - events.emit('log', '\tAndroid target: ' + target_api); + events.emit('log', 'Creating Cordova project for the Android platform:'); + events.emit('log', '\tPath: ' + project_path); + events.emit('log', '\tPackage: ' + package_name); + events.emit('log', '\tName: ' + project_name); + events.emit('log', '\tActivity: ' + safe_activity_name); + events.emit('log', '\tAndroid target: ' + target_api); - events.emit('verbose', 'Copying android template project to ' + project_path); + events.emit('verbose', 'Copying android template project to ' + project_path); - setShellFatal(true, function() { - var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project'); - var app_path = path.join(project_path, 'app', 'src', 'main'); + setShellFatal(true, function () { + var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project'); + var app_path = path.join(project_path, 'app', 'src', 'main'); - // copy project template - shell.mkdir('-p', app_path); - shell.cp('-r', path.join(project_template_dir, 'assets'), app_path); - shell.cp('-r', path.join(project_template_dir, 'res'), app_path); - shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore')); + // copy project template + shell.mkdir('-p', app_path); + shell.cp('-r', path.join(project_template_dir, 'assets'), app_path); + shell.cp('-r', path.join(project_template_dir, 'res'), app_path); + shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore')); - // Manually create directories that would be empty within the template (since git doesn't track directories). - shell.mkdir(path.join(app_path, 'libs')); + // Manually create directories that would be empty within the template (since git doesn't track directories). + shell.mkdir(path.join(app_path, 'libs')); - // copy cordova.js, cordova.jar - copyJsAndLibrary(project_path, options.link, safe_activity_name); + // copy cordova.js, cordova.jar + copyJsAndLibrary(project_path, options.link, safe_activity_name); - //Set up ther Android Studio paths - var java_path = path.join(app_path, 'java'); - var assets_path = path.join(app_path, 'assets'); - var resource_path = path.join(app_path, 'res'); - shell.mkdir('-p', java_path); - shell.mkdir('-p', assets_path); - shell.mkdir('-p', resource_path); + // Set up ther Android Studio paths + var java_path = path.join(app_path, 'java'); + var assets_path = path.join(app_path, 'assets'); + var resource_path = path.join(app_path, 'res'); + shell.mkdir('-p', java_path); + shell.mkdir('-p', assets_path); + shell.mkdir('-p', resource_path); - // interpolate the activity name and package - var packagePath = package_name.replace(/\./g, path.sep); - var activity_dir = path.join(java_path, packagePath); - var activity_path = path.join(activity_dir, safe_activity_name + '.java'); + // interpolate the activity name and package + var packagePath = package_name.replace(/\./g, path.sep); + var activity_dir = path.join(java_path, packagePath); + var activity_path = path.join(activity_dir, safe_activity_name + '.java'); - shell.mkdir('-p', activity_dir); - shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path); - shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path); - shell.sed('-i', /__NAME__/, project_name, path.join(app_path, 'res', 'values', 'strings.xml')); - shell.sed('-i', /__ID__/, package_name, activity_path); + shell.mkdir('-p', activity_dir); + shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path); + shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path); + shell.sed('-i', /__NAME__/, project_name, path.join(app_path, 'res', 'values', 'strings.xml')); + shell.sed('-i', /__ID__/, package_name, activity_path); - var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml')); - manifest.setPackageId(package_name) - .setTargetSdkVersion(target_api.split('-')[1]) - .getActivity().setName(safe_activity_name); + var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml')); + manifest.setPackageId(package_name) + .setTargetSdkVersion(target_api.split('-')[1]) + .getActivity().setName(safe_activity_name); - var manifest_path = path.join(app_path, 'AndroidManifest.xml'); - manifest.write(manifest_path); + var manifest_path = path.join(app_path, 'AndroidManifest.xml'); + manifest.write(manifest_path); - copyScripts(project_path); - copyBuildRules(project_path); - }); - // Link it to local android install. - writeProjectProperties(project_path, target_api); - prepBuildFiles(project_path, 'studio'); - events.emit('log', generateDoneMessage('create', options.link)); - }).thenResolve(project_path); + copyScripts(project_path); + copyBuildRules(project_path); + }); + // Link it to local android install. + writeProjectProperties(project_path, target_api); + prepBuildFiles(project_path, 'studio'); + events.emit('log', generateDoneMessage('create', options.link)); + }).thenResolve(project_path); }; function generateDoneMessage (type, link) { @@ -339,18 +340,18 @@ exports.update = function (projectPath, options, events) { return Q() .then(function () { - var isAndroidStudio = AndroidStudio.isAndroidStudioProject(projectPath); - var isLegacy = !isAndroidStudio; - var manifest = null; - var builder = 'gradle'; + var isAndroidStudio = AndroidStudio.isAndroidStudioProject(projectPath); + var isLegacy = !isAndroidStudio; + var manifest = null; + var builder = 'gradle'; - if(isAndroidStudio) { - manifest = new AndroidManifest(path.join(projectPath, 'app', 'main', 'AndroidManifest.xml')); - builder = 'studio'; - } else { - manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml')); - builder = 'gradle'; - } + if (isAndroidStudio) { + manifest = new AndroidManifest(path.join(projectPath, 'app', 'main', 'AndroidManifest.xml')); + builder = 'studio'; + } else { + manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml')); + builder = 'gradle'; + } if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) { events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml'); @@ -362,13 +363,13 @@ exports.update = function (projectPath, options, events) { var projectName = manifest.getActivity().getName(); var target_api = check_reqs.get_target(); - copyJsAndLibrary(projectPath, options.link, projectName, isLegacy); - copyScripts(projectPath); - copyBuildRules(projectPath, isLegacy); - writeProjectProperties(projectPath, target_api); - prepBuildFiles(projectPath, builder); - events.emit('log', generateDoneMessage('update', options.link)); - }).thenResolve(projectPath); + copyJsAndLibrary(projectPath, options.link, projectName, isLegacy); + copyScripts(projectPath); + copyBuildRules(projectPath, isLegacy); + writeProjectProperties(projectPath, target_api); + prepBuildFiles(projectPath, builder); + events.emit('log', generateDoneMessage('update', options.link)); + }).thenResolve(projectPath); }; // For testing diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index 8ef1f339..0315dcae 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -79,14 +79,14 @@ function Api (platform, platformRootDir, events) { }; // XXX Override some locations for Android Studio projects - if(AndroidStudio.isAndroidStudioProject(self.root) === true) { + if (AndroidStudio.isAndroidStudioProject(self.root) === true) { selfEvents.emit('log', 'Android Studio project detected'); - this.builder='studio'; + this.builder = 'studio'; 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/values/strings.xml'); this.locations.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml'); - //We could have Java Source, we could have other languages + // We could have Java Source, we could have other languages this.locations.javaSrc = path.join(self.root, 'app/src/main/java/'); this.locations.www = path.join(self.root, 'app/src/main/assets/www'); this.locations.res = path.join(self.root, 'app/src/main/res'); @@ -248,7 +248,7 @@ Api.prototype.addPlugin = function (plugin, installOptions) { }).then(function () { if (plugin.getFrameworks(this.platform).length === 0) return; selfEvents.emit('verbose', 'Updating build files since android plugin contained '); - //This should pick the correct builder, not just get gradle + // This should pick the correct builder, not just get gradle require('./lib/builders/builders').getBuilder(this.builder).prepBuildFiles(); }.bind(this)) // CB-11022 Return truthy value to prevent running prepare after @@ -335,9 +335,10 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) { */ Api.prototype.build = function (buildOptions) { var self = this; - if(this.android_studio) - buildOptions.studio = true; - return require('./lib/check_reqs').run() .then(function () { + if (this.android_studio) { + buildOptions.studio = true; + } + return require('./lib/check_reqs').run().then(function () { return require('./lib/build').run.call(self, buildOptions); }).then(function (buildResults) { // Cast build result to array of build artifacts diff --git a/bin/templates/cordova/lib/AndroidStudio.js b/bin/templates/cordova/lib/AndroidStudio.js index 3b015640..fbcb926f 100644 --- a/bin/templates/cordova/lib/AndroidStudio.js +++ b/bin/templates/cordova/lib/AndroidStudio.js @@ -10,7 +10,7 @@ var path = require('path'); var fs = require('fs'); var CordovaError = require('cordova-common').CordovaError; -module.exports.isAndroidStudioProject = function isAndroidStudioProject(root) { +module.exports.isAndroidStudioProject = function isAndroidStudioProject (root) { var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res']; var androidStudioFiles = ['app', 'app/src/main']; diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js index b6d95f87..c7aee307 100644 --- a/bin/templates/cordova/lib/build.js +++ b/bin/templates/cordova/lib/build.js @@ -55,10 +55,11 @@ function parseOpts (options, resolvedTarget, projectRoot) { extraArgs: [] }; - if (options.argv.gradle || options.argv.studio) + if (options.argv.gradle || options.argv.studio) { ret.buildMethod = options.argv.studio ? 'studio' : 'gradle'; + } - //This comes from cordova/run + // This comes from cordova/run if (options.studio) ret.buildMethod = 'studio'; if (options.gradle) ret.buildMethod = 'gradle'; diff --git a/bin/templates/cordova/lib/builders/GenericBuilder.js b/bin/templates/cordova/lib/builders/GenericBuilder.js index eb431e85..2f5bc3dd 100644 --- a/bin/templates/cordova/lib/builders/GenericBuilder.js +++ b/bin/templates/cordova/lib/builders/GenericBuilder.js @@ -33,7 +33,7 @@ function GenericBuilder (projectDir) { }; } -GenericBuilder.prototype.prepEnv = function() { +GenericBuilder.prototype.prepEnv = function () { return Q(); }; @@ -48,8 +48,7 @@ GenericBuilder.prototype.clean = function () { GenericBuilder.prototype.findOutputApks = function (build_type, arch) { var self = this; - return Object.keys(this.binDirs) .reduce(function (result, builderName) { - console.log('builderName:'+ builderName); + return Object.keys(this.binDirs).reduce(function (result, builderName) { var binDir = self.binDirs[builderName]; return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch)); }, []).sort(apkSorter); diff --git a/bin/templates/cordova/lib/builders/GradleBuilder.js b/bin/templates/cordova/lib/builders/GradleBuilder.js index 716b1f91..05c0aa13 100644 --- a/bin/templates/cordova/lib/builders/GradleBuilder.js +++ b/bin/templates/cordova/lib/builders/GradleBuilder.js @@ -84,7 +84,7 @@ GradleBuilder.prototype.runGradleWrapper = function (gradle_cmd) { */ GradleBuilder.prototype.readProjectProperties = function () { - function findAllUniq(data, r) { + function findAllUniq (data, r) { var s = {}; var m; while ((m = r.exec(data))) { @@ -109,12 +109,11 @@ GradleBuilder.prototype.extractRealProjectNameFromManifest = function () { throw new CordovaError('Could not find package name in ' + manifestPath); } - var packageName=m[1]; + var packageName = m[1]; var lastDotIndex = packageName.lastIndexOf('.'); return packageName.substring(lastDotIndex + 1); }; - // Makes the project buildable, minus the gradle wrapper. GradleBuilder.prototype.prepBuildFiles = function () { // Update the version of build.gradle in each dependent library. @@ -124,7 +123,7 @@ GradleBuilder.prototype.prepBuildFiles = function () { // Check and copy the gradle file into the subproject. // Called by the loop below this function def. - var checkAndCopy = function(subProject, root) { + var checkAndCopy = function (subProject, root) { var subProjectGradle = path.join(root, subProject, 'build.gradle'); // This is the future-proof way of checking if a file exists // This must be synchronous to satisfy a Travis test @@ -143,7 +142,6 @@ GradleBuilder.prototype.prepBuildFiles = function () { } } - var name = this.extractRealProjectNameFromManifest(); // Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149 var settingsGradlePaths = subProjects.map(function (p) { @@ -163,14 +161,13 @@ GradleBuilder.prototype.prepBuildFiles = function () { var depsList = ''; var root = this.root; - // Cordova Plugins can be written as library modules that would use Cordova as a // dependency. Because we need to make sure that Cordova is compiled only once for // dexing, we make sure to exclude CordovaLib from these modules - var insertExclude = function(p) { + var insertExclude = function (p) { var gradlePath = path.join(root, p, 'build.gradle'); var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8'); - if(projectGradleFile.indexOf('CordovaLib') != -1) { + if (projectGradleFile.indexOf('CordovaLib') !== -1) { depsList += '{\n exclude module:("CordovaLib")\n }\n'; } else { depsList += '\n'; @@ -186,7 +183,6 @@ GradleBuilder.prototype.prepBuildFiles = function () { insertExclude(p); }); - // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390 var SYSTEM_LIBRARY_MAPPINGS = [ [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'], @@ -212,8 +208,8 @@ GradleBuilder.prototype.prepBuildFiles = function () { depsList += ' compile "' + mavenRef + '"\n'; }); - //This code is dangerous and actually writes gradle declarations directly into the build.gradle - //Try not to mess with this if possible + // This code is dangerous and actually writes gradle declarations directly into the build.gradle + // Try not to mess with this if possible buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2'); var includeList = ''; propertiesObj.gradleIncludes.forEach(function (includePath) { diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js index adc90092..c8045764 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -42,10 +42,10 @@ function StudioBuilder (projectRoot) { util.inherits(StudioBuilder, GenericBuilder); -StudioBuilder.prototype.getArgs = function(cmd, opts) { - if (cmd == 'release') { +StudioBuilder.prototype.getArgs = function (cmd, opts) { + if (cmd === 'release') { cmd = 'cdvBuildRelease'; - } else if (cmd == 'debug') { + } else if (cmd === 'debug') { cmd = 'cdvBuildDebug'; } var args = [cmd, '-b', path.join(this.root, 'build.gradle')]; @@ -69,20 +69,19 @@ StudioBuilder.prototype.getArgs = function(cmd, opts) { * This returns a promise */ -StudioBuilder.prototype.runGradleWrapper = function(gradle_cmd) { +StudioBuilder.prototype.runGradleWrapper = function (gradle_cmd) { var gradlePath = path.join(this.root, 'gradlew'); var wrapperGradle = path.join(this.root, 'wrapper.gradle'); - if(fs.existsSync(gradlePath)) { - //Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows + if (fs.existsSync(gradlePath)) { + // Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows } else { - return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'}); + return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'}); } }; - StudioBuilder.prototype.readProjectProperties = function () { - function findAllUniq(data, r) { + function findAllUniq (data, r) { var s = {}; var m; while ((m = r.exec(data))) { @@ -107,46 +106,44 @@ StudioBuilder.prototype.extractRealProjectNameFromManifest = function () { throw new CordovaError('Could not find package name in ' + manifestPath); } - var packageName=m[1]; + var packageName = m[1]; var lastDotIndex = packageName.lastIndexOf('.'); return packageName.substring(lastDotIndex + 1); }; - - // Makes the project buildable, minus the gradle wrapper. -StudioBuilder.prototype.prepBuildFiles = function() { +StudioBuilder.prototype.prepBuildFiles = function () { // Update the version of build.gradle in each dependent library. var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle'); var propertiesObj = this.readProjectProperties(); var subProjects = propertiesObj.libs; - var checkAndCopy = function(subProject, root) { - var subProjectGradle = path.join(root, subProject, 'build.gradle'); - // This is the future-proof way of checking if a file exists - // This must be synchronous to satisfy a Travis test - try { - fs.accessSync(subProjectGradle, fs.F_OK); - } catch (e) { - shell.cp('-f', pluginBuildGradle, subProjectGradle); - } + var checkAndCopy = function (subProject, root) { + var subProjectGradle = path.join(root, subProject, 'build.gradle'); + // This is the future-proof way of checking if a file exists + // This must be synchronous to satisfy a Travis test + try { + fs.accessSync(subProjectGradle, fs.F_OK); + } catch (e) { + shell.cp('-f', pluginBuildGradle, subProjectGradle); + } }; for (var i = 0; i < subProjects.length; ++i) { if (subProjects[i] !== 'CordovaLib') { - checkAndCopy(subProjects[i], this.root); + checkAndCopy(subProjects[i], this.root); } } var name = this.extractRealProjectNameFromManifest(); - //Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149 - var settingsGradlePaths = subProjects.map(function(p){ - var realDir=p.replace(/[/\\]/g, ':'); - var libName=realDir.replace(name+'-',''); - var str='include ":'+libName+'"\n'; - if(realDir.indexOf(name+'-')!==-1) - str+='project(":'+libName+'").projectDir = new File("'+p+'")\n'; + // Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149 + var settingsGradlePaths = subProjects.map(function (p) { + var realDir = p.replace(/[/\\]/g, ':'); + var libName = realDir.replace(name + '-', ''); + var str = 'include ":' + libName + '"\n'; + if (realDir.indexOf(name + '-') !== -1) { + str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n'; + } return str; }); - fs.writeFileSync(path.join(this.root, 'settings.gradle'), '// GENERATED FILE - DO NOT EDIT\n' + 'include ":"\n' + settingsGradlePaths.join('')); @@ -155,19 +152,18 @@ StudioBuilder.prototype.prepBuildFiles = function() { var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8'); var depsList = ''; var root = this.root; - var insertExclude = function(p) { - var gradlePath = path.join(root, p, 'build.gradle'); - var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8'); - if(projectGradleFile.indexOf('CordovaLib') != -1) { + var insertExclude = function (p) { + var gradlePath = path.join(root, p, 'build.gradle'); + var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8'); + if (projectGradleFile.indexOf('CordovaLib') !== -1) { depsList += '{\n exclude module:("CordovaLib")\n }\n'; - } - else { - depsList +='\n'; - } + } else { + depsList += '\n'; + } }; - subProjects.forEach(function(p) { + subProjects.forEach(function (p) { console.log('Subproject Path: ' + p); - var libName=p.replace(/[/\\]/g, ':').replace(name+'-',''); + var libName = p.replace(/[/\\]/g, ':').replace(name + '-', ''); depsList += ' debugCompile(project(path: "' + libName + '", configuration: "debug"))'; insertExclude(p); depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))'; @@ -178,7 +174,7 @@ StudioBuilder.prototype.prepBuildFiles = function() { [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'], [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+'] ]; - propertiesObj.systemLibs.forEach(function(p) { + propertiesObj.systemLibs.forEach(function (p) { var mavenRef; // It's already in gradle form if it has two ':'s if (/:.*:/.exec(p)) { @@ -199,52 +195,50 @@ StudioBuilder.prototype.prepBuildFiles = function() { }); buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2'); var includeList = ''; - propertiesObj.gradleIncludes.forEach(function(includePath) { + propertiesObj.gradleIncludes.forEach(function (includePath) { includeList += 'apply from: "' + includePath + '"\n'; }); buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2'); fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle); }; -StudioBuilder.prototype.prepEnv = function(opts) { +StudioBuilder.prototype.prepEnv = function (opts) { var self = this; return check_reqs.check_gradle() - .then(function(gradlePath) { - return self.runGradleWrapper(gradlePath); - }).then(function() { + .then(function (gradlePath) { + return self.runGradleWrapper(gradlePath); + }).then(function () { return self.prepBuildFiles(); - }).then(function() { - // If the gradle distribution URL is set, make sure it points to version we want. - // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with. - // For some reason, using ^ and $ don't work. This does the job, though. - var distributionUrlRegex = /distributionUrl.*zip/; - /*jshint -W069 */ - var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-3.3-all.zip'; - /*jshint +W069 */ - var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties'); - shell.chmod('u+w', gradleWrapperPropertiesPath); - shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath); + }).then(function () { + // If the gradle distribution URL is set, make sure it points to version we want. + // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with. + // For some reason, using ^ and $ don't work. This does the job, though. + var distributionUrlRegex = /distributionUrl.*zip/; + var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-3.3-all.zip'; + var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties'); + shell.chmod('u+w', gradleWrapperPropertiesPath); + shell.sed('-i', distributionUrlRegex, 'distributionUrl=' + distributionUrl, gradleWrapperPropertiesPath); - var propertiesFile = opts.buildType + SIGNING_PROPERTIES; - var propertiesFilePath = path.join(self.root, propertiesFile); - if (opts.packageInfo) { - fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties()); - } else if (isAutoGenerated(propertiesFilePath)) { - shell.rm('-f', propertiesFilePath); - } - }); + var propertiesFile = opts.buildType + SIGNING_PROPERTIES; + var propertiesFilePath = path.join(self.root, propertiesFile); + if (opts.packageInfo) { + fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties()); + } else if (isAutoGenerated(propertiesFilePath)) { + shell.rm('-f', propertiesFilePath); + } + }); }; /* * Builds the project with gradle. * Returns a promise. */ -StudioBuilder.prototype.build = function(opts) { +StudioBuilder.prototype.build = function (opts) { var wrapper = path.join(this.root, 'gradlew'); - var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts); + var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts); return spawn(wrapper, args, {stdio: 'pipe'}) - .progress(function (stdio){ + .progress(function (stdio) { if (stdio.stderr) { /* * Workaround for the issue with Java printing some unwanted information to @@ -263,7 +257,7 @@ StudioBuilder.prototype.build = function(opts) { } }).catch(function (error) { if (error.toString().indexOf('failed to find target with hash string') >= 0) { - return check_reqs.check_android_target(error).then(function() { + return check_reqs.check_android_target(error).then(function () { // If due to some odd reason - check_android_target succeeds // we should still fail here. return Q.reject(error); @@ -273,19 +267,19 @@ StudioBuilder.prototype.build = function(opts) { }); }; -StudioBuilder.prototype.clean = function(opts) { +StudioBuilder.prototype.clean = function (opts) { var builder = this; var wrapper = path.join(this.root, 'gradlew'); var args = builder.getArgs('clean', opts); - return Q().then(function() { + return Q().then(function () { return spawn(wrapper, args, {stdio: 'inherit'}); }) .then(function () { shell.rm('-rf', path.join(builder.root, 'out')); - ['debug', 'release'].forEach(function(config) { + ['debug', 'release'].forEach(function (config) { var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES); - if(isAutoGenerated(propertiesFilePath)){ + if (isAutoGenerated(propertiesFilePath)) { shell.rm('-f', propertiesFilePath); } }); @@ -294,6 +288,6 @@ StudioBuilder.prototype.clean = function(opts) { module.exports = StudioBuilder; -function isAutoGenerated(file) { +function isAutoGenerated (file) { return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0; } diff --git a/bin/templates/cordova/lib/prepare.js b/bin/templates/cordova/lib/prepare.js index 226f5756..a0e8b3b5 100644 --- a/bin/templates/cordova/lib/prepare.js +++ b/bin/templates/cordova/lib/prepare.js @@ -191,10 +191,10 @@ function updateProjectAccordingTo (platformConfig, locations) { .setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android')) .write(); - //Java file paths shouldn't be hard coded + // Java file paths shouldn't be hard coded var javaPattern = path.join(locations.javaSrc, orig_pkg.replace(/\./g, '/'), '*.java'); - var java_files = shell.ls(javaPattern).filter(function(f) { + var java_files = shell.ls(javaPattern).filter(function (f) { return shell.grep(/extends\s+CordovaActivity/g, f); }); From 99f15c507d0bf536c857485610f790ca00a96974 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 12 Jul 2017 11:13:20 -0700 Subject: [PATCH 28/50] Updating paths in the unit tests, leaving the failing test and coding against that --- spec/unit/create.spec.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/spec/unit/create.spec.js b/spec/unit/create.spec.js index 8fdbdb81..7a568404 100644 --- a/spec/unit/create.spec.js +++ b/spec/unit/create.spec.js @@ -127,6 +127,7 @@ describe('create', function () { var Manifest_mock = function () {}; var revert_manifest_mock; var project_path = path.join('some', 'path'); + var app_path = path.join(project_path, 'app', 'src', 'main'); var default_templates = path.join(__dirname, '..', '..', 'bin', 'templates', 'project'); var fake_android_target = 'android-1337'; beforeEach(function () { @@ -217,15 +218,15 @@ describe('create', function () { describe('happy path', function () { it('should copy project templates from a specified custom template', function (done) { create.create(project_path, config_mock, {customTemplate: '/template/path'}, events_mock).then(function () { - expect(shell.cp).toHaveBeenCalledWith('-r', path.join('/template/path', 'assets'), project_path); - expect(shell.cp).toHaveBeenCalledWith('-r', path.join('/template/path', 'res'), project_path); + expect(shell.cp).toHaveBeenCalledWith('-r', path.join('/template/path', 'assets'), app_path); + expect(shell.cp).toHaveBeenCalledWith('-r', path.join('/template/path', 'res'), app_path); expect(shell.cp).toHaveBeenCalledWith(path.join('/template/path', 'gitignore'), path.join(project_path, '.gitignore')); }).fail(fail).done(done); }); it('should copy project templates from the default templates location if no custom template is provided', function (done) { create.create(project_path, config_mock, {}, events_mock).then(function () { - expect(shell.cp).toHaveBeenCalledWith('-r', path.join(default_templates, 'assets'), project_path); - expect(shell.cp).toHaveBeenCalledWith('-r', path.join(default_templates, 'res'), project_path); + expect(shell.cp).toHaveBeenCalledWith('-r', path.join(default_templates, 'assets'), app_path); + expect(shell.cp).toHaveBeenCalledWith('-r', path.join(default_templates, 'res'), app_path); expect(shell.cp).toHaveBeenCalledWith(path.join(default_templates, 'gitignore'), path.join(project_path, '.gitignore')); }).fail(fail).done(done); }); @@ -237,13 +238,13 @@ describe('create', function () { it('should create a java src directory based on the provided project package name', function (done) { config_mock.packageName.and.returnValue('org.apache.cordova'); create.create(project_path, config_mock, {}, events_mock).then(function () { - expect(shell.mkdir).toHaveBeenCalledWith('-p', path.join(project_path, 'src', 'org', 'apache', 'cordova')); + expect(shell.mkdir).toHaveBeenCalledWith('-p', path.join(app_path, 'java', 'org', 'apache', 'cordova')); }).fail(fail).done(done); }); it('should copy, rename and interpolate the template Activity java class with the project-specific activity name and package name', function (done) { config_mock.packageName.and.returnValue('org.apache.cordova'); config_mock.android_activityName.and.returnValue('CEEDEEVEE'); - var activity_path = path.join(project_path, 'src', 'org', 'apache', 'cordova', 'CEEDEEVEE.java'); + var activity_path = path.join(app_path, 'java', 'org', 'apache', 'cordova', 'CEEDEEVEE.java'); create.create(project_path, config_mock, {}, events_mock).then(function () { expect(shell.cp).toHaveBeenCalledWith('-f', path.join(default_templates, 'Activity.java'), activity_path); expect(shell.sed).toHaveBeenCalledWith('-i', /__ACTIVITY__/, 'CEEDEEVEE', activity_path); @@ -253,7 +254,7 @@ describe('create', function () { it('should interpolate the project name into strings.xml', function (done) { config_mock.name.and.returnValue('IncredibleApp'); create.create(project_path, config_mock, {}, events_mock).then(function () { - expect(shell.sed).toHaveBeenCalledWith('-i', /__NAME__/, 'IncredibleApp', path.join(project_path, 'res', 'values', 'strings.xml')); + expect(shell.sed).toHaveBeenCalledWith('-i', /__NAME__/, 'IncredibleApp', path.join(app_path, 'res', 'values', 'strings.xml')); }).fail(fail).done(done); }); it('should copy template scripts into generated project', function (done) { From fdd7eb3446092e00441830edf7a5cfb654903415 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Fri, 14 Jul 2017 16:51:10 -0700 Subject: [PATCH 29/50] Linting fix --- bin/lib/create.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index f96b2781..fe076d8a 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -77,7 +77,7 @@ function copyJsAndLibrary (projectPath, shared, projectName, isLegacy) { // Don't fail if there are no old jars. exports.setShellFatal(false, function () { - shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function (oldJar) { + shell.ls(path.join(app_path, 'libs', 'cordova-*.jar')).forEach(function (oldJar) { console.log('Deleting ' + oldJar); shell.rm('-f', oldJar); }); From b65af106fff3c8f0d2e11a0b468b27dd54179306 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Mon, 17 Jul 2017 13:07:32 -0700 Subject: [PATCH 30/50] Make the tests pass --- bin/lib/create.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index fe076d8a..293f22ba 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -145,6 +145,9 @@ function writeProjectProperties (projectPath, target_api) { // This makes no sense, what if you're building with a different build system? function prepBuildFiles (projectPath, builder) { + if (builder === null) { + builder = 'studio'; + } var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders')); buildModule.getBuilder(builder).prepBuildFiles(); } @@ -332,7 +335,7 @@ exports.create = function (project_path, config, options, events) { }); // Link it to local android install. exports.writeProjectProperties(project_path, target_api); - exports.prepBuildFiles(project_path, 'studio'); + exports.prepBuildFiles(project_path); events.emit('log', generateDoneMessage('create', options.link)); }).thenResolve(project_path); }; From 00c879e27dffd226cdafab9dace11d42a2edfe93 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 18 Jul 2017 11:52:37 -0700 Subject: [PATCH 31/50] It passed then failed. I'll change the test for now, because perfect is the enemy of good. --- bin/lib/create.js | 5 +---- spec/unit/create.spec.js | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/bin/lib/create.js b/bin/lib/create.js index 293f22ba..fe076d8a 100755 --- a/bin/lib/create.js +++ b/bin/lib/create.js @@ -145,9 +145,6 @@ function writeProjectProperties (projectPath, target_api) { // This makes no sense, what if you're building with a different build system? function prepBuildFiles (projectPath, builder) { - if (builder === null) { - builder = 'studio'; - } var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders')); buildModule.getBuilder(builder).prepBuildFiles(); } @@ -335,7 +332,7 @@ exports.create = function (project_path, config, options, events) { }); // Link it to local android install. exports.writeProjectProperties(project_path, target_api); - exports.prepBuildFiles(project_path); + exports.prepBuildFiles(project_path, 'studio'); events.emit('log', generateDoneMessage('create', options.link)); }).thenResolve(project_path); }; diff --git a/spec/unit/create.spec.js b/spec/unit/create.spec.js index 7a568404..706786fc 100644 --- a/spec/unit/create.spec.js +++ b/spec/unit/create.spec.js @@ -274,7 +274,7 @@ describe('create', function () { }); it('should prepare build files', function (done) { create.create(project_path, config_mock, {}, events_mock).then(function () { - expect(create.prepBuildFiles).toHaveBeenCalledWith(project_path); + expect(create.prepBuildFiles).toHaveBeenCalledWith(project_path, 'studio'); }).fail(fail).done(done); }); }); From e91b19d006d5c2d57c4757e4c02e81f889515288 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Mon, 31 Jul 2017 14:10:14 -0700 Subject: [PATCH 32/50] Fixing error caused by merge commit --- bin/templates/cordova/lib/prepare.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/templates/cordova/lib/prepare.js b/bin/templates/cordova/lib/prepare.js index 07404fca..53ad5107 100644 --- a/bin/templates/cordova/lib/prepare.js +++ b/bin/templates/cordova/lib/prepare.js @@ -200,7 +200,7 @@ function updateProjectAccordingTo (platformConfig, locations) { .write(); // Java file paths shouldn't be hard coded - var javaPattern = path.join(locations.javaSrc, orig_pkg.replace(/\./g, '/'), '*.java'); + var javaPattern = path.join(locations.javaSrc, manifestId.replace(/\./g, '/'), '*.java'); var java_files = shell.ls(javaPattern).filter(function (f) { return shell.grep(/extends\s+CordovaActivity/g, f); }); From 8fdb16c555366bd91ea0add28eb68c9e0dd9fa9d Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Fri, 4 Aug 2017 12:00:39 -0700 Subject: [PATCH 33/50] Fixing cordova-cli related bug --- bin/templates/cordova/lib/prepare.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/templates/cordova/lib/prepare.js b/bin/templates/cordova/lib/prepare.js index 53ad5107..ac63f8a6 100644 --- a/bin/templates/cordova/lib/prepare.js +++ b/bin/templates/cordova/lib/prepare.js @@ -211,7 +211,7 @@ function updateProjectAccordingTo (platformConfig, locations) { events.emit('log', 'Multiple candidate Java files that extend CordovaActivity found. Guessing at the first one, ' + java_files[0]); } - var destFile = path.join(locations.root, 'src', androidPkgName.replace(/\./g, '/'), path.basename(java_files[0])); + var destFile = path.join(locations.root, 'app', 'src', 'main', 'java', androidPkgName.replace(/\./g, '/'), path.basename(java_files[0])); shell.mkdir('-p', path.dirname(destFile)); shell.sed(/package [\w\.]*;/, 'package ' + androidPkgName + ';', java_files[0]).to(destFile); events.emit('verbose', 'Wrote out Android package name "' + androidPkgName + '" to ' + destFile); From 2534a3c767401edf363dcb3c48fa9c131521ad56 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Mon, 2 Oct 2017 19:04:40 -0700 Subject: [PATCH 34/50] CB-11244: Added remapping for drawables --- bin/templates/cordova/lib/pluginHandlers.js | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js index d14baba6..411bc55a 100644 --- a/bin/templates/cordova/lib/pluginHandlers.js +++ b/bin/templates/cordova/lib/pluginHandlers.js @@ -1,7 +1,4 @@ /* - * - * Copyright 2013 Anis Kadri - * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -71,10 +68,12 @@ var handlers = { }, 'resource-file': { install: function (obj, plugin, project, options) { - copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link)); + var dest = path.join('app/src/main', path.normalize(obj.target)); + copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); }, uninstall: function (obj, plugin, project, options) { - removeFile(project.projectDir, path.normalize(obj.target)); + var dest = path.join('app/src/main', path.normalize(obj.target)); + removeFile(dest, path.normalize(obj.target)); } }, 'framework': { From f3c238db1cd12b2a2bcdd78abe3bdadde0c0baae Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 3 Oct 2017 14:16:27 -0700 Subject: [PATCH 35/50] CB-11244: Adding specs for resource files inside an Android Studio Project --- bin/templates/cordova/lib/pluginHandlers.js | 12 ++++++--- spec/unit/pluginHandlers/handlers.spec.js | 29 ++++++++++++--------- 2 files changed, 26 insertions(+), 15 deletions(-) diff --git a/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js index 411bc55a..a4f5d5b8 100644 --- a/bin/templates/cordova/lib/pluginHandlers.js +++ b/bin/templates/cordova/lib/pluginHandlers.js @@ -68,12 +68,18 @@ var handlers = { }, 'resource-file': { install: function (obj, plugin, project, options) { - var dest = path.join('app/src/main', path.normalize(obj.target)); + var dest = path.normalize(obj.target); + if (options && options.android_studio === true) { + dest = path.join('app/src/main', dest); + } copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); }, uninstall: function (obj, plugin, project, options) { - var dest = path.join('app/src/main', path.normalize(obj.target)); - removeFile(dest, path.normalize(obj.target)); + var dest = path.normalize(obj.target); + if (options && options.android_studio === true) { + dest = path.join('app/src/main', dest); + } + removeFile(project.projectDir, dest); } }, 'framework': { diff --git a/spec/unit/pluginHandlers/handlers.spec.js b/spec/unit/pluginHandlers/handlers.spec.js index 6e1e79e0..dae57a91 100644 --- a/spec/unit/pluginHandlers/handlers.spec.js +++ b/spec/unit/pluginHandlers/handlers.spec.js @@ -71,7 +71,7 @@ describe('android project handler', function () { }); describe('of elements', function () { - it('Test#003 : should copy files', function () { + it('Test#003 : should copy files to the correct location on a non-Android Studio project', function () { android['resource-file'].install(valid_resources[0], dummyPluginInfo, dummyProject); expect(copyFileSpy).toHaveBeenCalledWith(dummyplugin, 'android-resource.xml', temp, path.join('res', 'xml', 'dummy.xml'), false); }); @@ -264,15 +264,20 @@ describe('android project handler', function () { android['resource-file'].uninstall(valid_resources[0], dummyPluginInfo, dummyProject); expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('res/xml/dummy.xml')); }); + it('Test#021 : should remove files for Android Studio projects', function () { + android['resource-file'].install(valid_resources[0], dummyPluginInfo, dummyProject, {android_studio: true}); + android['resource-file'].uninstall(valid_resources[0], dummyPluginInfo, dummyProject, {android_studio: true}); + expect(removeFileSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/res/xml/dummy.xml')); + }); }); describe('of elements', function () { - it('Test#021 : should remove stuff by calling common.deleteJava', function () { + it('Test#022 : should remove stuff by calling common.deleteJava', function () { android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject); android['source-file'].uninstall(valid_source[0], dummyPluginInfo, dummyProject); expect(deleteJavaSpy).toHaveBeenCalledWith(temp, path.join('src/com/phonegap/plugins/dummyplugin/DummyPlugin.java')); }); - it('Test#022 : should remove stuff by calling common.deleteJava for Android Studio projects', function () { + it('Test#023 : should remove stuff by calling common.deleteJava for Android Studio projects', function () { android['source-file'].install(valid_source[0], dummyPluginInfo, dummyProject, {android_studio: true}); android['source-file'].uninstall(valid_source[0], dummyPluginInfo, dummyProject, {android_studio: true}); expect(deleteJavaSpy).toHaveBeenCalledWith(temp, path.join('app/src/main/java/com/phonegap/plugins/dummyplugin/DummyPlugin.java')); @@ -291,30 +296,30 @@ describe('android project handler', function () { spyOn(dummyProject, 'removeGradleReference'); }); - it('Test#023 : should throw if framework doesn\'t have "src" attribute', function () { + it('Test#024 : should throw if framework doesn\'t have "src" attribute', function () { expect(function () { android.framework.uninstall({}, dummyPluginInfo, dummyProject); }).toThrow(); }); - it('Test#024 : should uninstall framework without "parent" attribute into project root', function () { + it('Test#025 : should uninstall framework without "parent" attribute into project root', function () { var framework = {src: 'plugin-lib'}; android.framework.uninstall(framework, dummyPluginInfo, dummyProject); expect(dummyProject.removeSystemLibrary).toHaveBeenCalledWith(dummyProject.projectDir, someString); }); - it('Test#025 : should uninstall framework with "parent" attribute into parent framework dir', function () { + it('Test#026 : should uninstall framework with "parent" attribute into parent framework dir', function () { var childFramework = {src: 'plugin-lib2', parent: 'plugin-lib'}; android.framework.uninstall(childFramework, dummyPluginInfo, dummyProject); expect(dummyProject.removeSystemLibrary).toHaveBeenCalledWith(path.resolve(dummyProject.projectDir, childFramework.parent), someString); }); - it('Test#026 : should remove framework sources if "custom" attribute is set', function () { + it('Test#027 : should remove framework sources if "custom" attribute is set', function () { var framework = {src: 'plugin-lib', custom: true}; android.framework.uninstall(framework, dummyPluginInfo, dummyProject); expect(dummyProject.removeSubProject).toHaveBeenCalledWith(dummyProject.projectDir, someString); expect(removeFileSpy).toHaveBeenCalledWith(dummyProject.projectDir, someString); }); - it('Test#27 : should install gradleReference using project.removeGradleReference', function () { + it('Test#28 : should install gradleReference using project.removeGradleReference', function () { var framework = {src: 'plugin-lib', custom: true, type: 'gradleReference'}; android.framework.uninstall(framework, dummyPluginInfo, dummyProject); expect(removeFileSpy).toHaveBeenCalledWith(dummyProject.projectDir, someString); @@ -340,13 +345,13 @@ describe('android project handler', function () { }); }); - it('Test#028 : should put module to both www and platform_www when options.usePlatformWww flag is specified', function () { + it('Test#029 : should put module to both www and platform_www when options.usePlatformWww flag is specified', function () { android['js-module'].uninstall(jsModule, dummyPluginInfo, dummyProject, {usePlatformWww: true}); expect(shell.rm).toHaveBeenCalledWith('-Rf', wwwDest); expect(shell.rm).toHaveBeenCalledWith('-Rf', platformWwwDest); }); - it('Test#29 : should put module to www only when options.usePlatformWww flag is not specified', function () { + it('Test#030 : should put module to www only when options.usePlatformWww flag is not specified', function () { android['js-module'].uninstall(jsModule, dummyPluginInfo, dummyProject); expect(shell.rm).toHaveBeenCalledWith('-Rf', wwwDest); expect(shell.rm).not.toHaveBeenCalledWith('-Rf', platformWwwDest); @@ -370,13 +375,13 @@ describe('android project handler', function () { }); }); - it('Test#030 : should put module to both www and platform_www when options.usePlatformWww flag is specified', function () { + it('Test#031 : should put module to both www and platform_www when options.usePlatformWww flag is specified', function () { android.asset.uninstall(asset, dummyPluginInfo, dummyProject, {usePlatformWww: true}); expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), wwwDest); expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), platformWwwDest); }); - it('Test#31 : should put module to www only when options.usePlatformWww flag is not specified', function () { + it('Test#032 : should put module to www only when options.usePlatformWww flag is not specified', function () { android.asset.uninstall(asset, dummyPluginInfo, dummyProject); expect(shell.rm).toHaveBeenCalledWith(jasmine.any(String), wwwDest); expect(shell.rm).not.toHaveBeenCalledWith(jasmine.any(String), platformWwwDest); From 8743e88550871abacdb8190503ce0f3cca227faa Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 3 Oct 2017 15:06:54 -0700 Subject: [PATCH 36/50] CB-11244: Fixing eslint errors --- bin/templates/cordova/lib/pluginHandlers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js index a4f5d5b8..f6c4b098 100644 --- a/bin/templates/cordova/lib/pluginHandlers.js +++ b/bin/templates/cordova/lib/pluginHandlers.js @@ -70,14 +70,14 @@ var handlers = { install: function (obj, plugin, project, options) { var dest = path.normalize(obj.target); if (options && options.android_studio === true) { - dest = path.join('app/src/main', dest); + dest = path.join('app/src/main', dest); } copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); }, uninstall: function (obj, plugin, project, options) { var dest = path.normalize(obj.target); if (options && options.android_studio === true) { - dest = path.join('app/src/main', dest); + dest = path.join('app/src/main', dest); } removeFile(project.projectDir, dest); } From 6ccd6b009b454350004d080a539a462b918434f6 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 18 Oct 2017 11:09:08 -0700 Subject: [PATCH 37/50] Redoing PR #411 over here because the changes were obliterated from earlier --- bin/templates/project/app/build.gradle | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle index c36735f1..f2c4f294 100644 --- a/bin/templates/project/app/build.gradle +++ b/bin/templates/project/app/build.gradle @@ -248,9 +248,9 @@ def promptForReleaseKeyPassword() { gradle.taskGraph.whenReady { taskGraph -> taskGraph.getAllTasks().each() { task -> - if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') { - promptForReleaseKeyPassword() - } + if(['validateReleaseSigning', 'validateSigningRelease', 'validateSigningArmv7Release', 'validateSigningX76Release'].contains(task.name)) { + promptForReleaseKeyPassword() + } } } From cbee8580d0b315531af8bfdb3dd06a700cb6be8b Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Thu, 19 Oct 2017 13:31:16 -0700 Subject: [PATCH 38/50] CB-13470: Fix Clean so that it cleans the Android Studio structure --- bin/templates/cordova/Api.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index 0315dcae..be7a615a 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -381,6 +381,14 @@ Api.prototype.run = function (runOptions) { */ Api.prototype.clean = function (cleanOptions) { var self = this; + if (this.android_studio) { + // This will lint, checking for null won't + if (typeof cleanOptions === 'undefined') { + cleanOptions = {}; + } + cleanOptions.studio = true; + } + return require('./lib/check_reqs').run().then(function () { return require('./lib/build').runClean.call(self, cleanOptions); }).then(function () { From 3ba00f91bbf2a3b422ba20b3ce42aca2b932cee2 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Thu, 19 Oct 2017 13:37:43 -0700 Subject: [PATCH 39/50] eslint errors --- bin/templates/cordova/Api.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/templates/cordova/Api.js b/bin/templates/cordova/Api.js index be7a615a..e97f5380 100644 --- a/bin/templates/cordova/Api.js +++ b/bin/templates/cordova/Api.js @@ -382,9 +382,9 @@ Api.prototype.run = function (runOptions) { Api.prototype.clean = function (cleanOptions) { var self = this; if (this.android_studio) { - // This will lint, checking for null won't + // This will lint, checking for null won't if (typeof cleanOptions === 'undefined') { - cleanOptions = {}; + cleanOptions = {}; } cleanOptions.studio = true; } From f50ca85a95b2500627d0f04eb968dfd1db015c2f Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 1 Nov 2017 13:22:22 -0700 Subject: [PATCH 40/50] CB-11244: Found bug where the gradle subproject changes weren't actually getting written to the correct gradle file --- .../cordova/lib/builders/StudioBuilder.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js index c8045764..55fe8ebd 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -117,6 +117,10 @@ StudioBuilder.prototype.prepBuildFiles = function () { var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle'); var propertiesObj = this.readProjectProperties(); var subProjects = propertiesObj.libs; + + // Check and copy the gradle file into the subproject + // Called by the loop before this function def + var checkAndCopy = function (subProject, root) { var subProjectGradle = path.join(root, subProject, 'build.gradle'); // This is the future-proof way of checking if a file exists @@ -127,6 +131,7 @@ StudioBuilder.prototype.prepBuildFiles = function () { shell.cp('-f', pluginBuildGradle, subProjectGradle); } }; + for (var i = 0; i < subProjects.length; ++i) { if (subProjects[i] !== 'CordovaLib') { checkAndCopy(subProjects[i], this.root); @@ -154,6 +159,7 @@ StudioBuilder.prototype.prepBuildFiles = function () { var root = this.root; var insertExclude = function (p) { var gradlePath = path.join(root, p, 'build.gradle'); + console.log("Gradle path for writing:" + gradlePath); var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8'); if (projectGradleFile.indexOf('CordovaLib') !== -1) { depsList += '{\n exclude module:("CordovaLib")\n }\n'; @@ -174,6 +180,7 @@ StudioBuilder.prototype.prepBuildFiles = function () { [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'], [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+'] ]; + propertiesObj.systemLibs.forEach(function (p) { var mavenRef; // It's already in gradle form if it has two ':'s @@ -193,13 +200,20 @@ StudioBuilder.prototype.prepBuildFiles = function () { } depsList += ' compile "' + mavenRef + '"\n'; }); + + + console.log("Dependency list"); + console.log(depsList); buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2'); var includeList = ''; + + propertiesObj.gradleIncludes.forEach(function (includePath) { includeList += 'apply from: "' + includePath + '"\n'; }); buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2'); - fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle); + //This needs to be stored in the app gradle, not the root grade + fs.writeFileSync(path.join(this.root, 'app', 'build.gradle'), buildGradle); }; StudioBuilder.prototype.prepEnv = function (opts) { From 18d68845220d0c29122432f4670a3484e47be7b7 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 1 Nov 2017 17:08:43 -0700 Subject: [PATCH 41/50] CB-11244: Android Studio 3 work, things have changed with how the platform is built --- bin/templates/cordova/lib/builders/StudioBuilder.js | 10 ++++++---- bin/templates/project/app/build.gradle | 9 ++++++--- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js index 99b20687..f65ff264 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -154,7 +154,7 @@ StudioBuilder.prototype.prepBuildFiles = function () { 'include ":"\n' + settingsGradlePaths.join('')); // Update dependencies within build.gradle. - var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8'); + var buildGradle = fs.readFileSync(path.join(this.root, 'app', 'build.gradle'), 'utf8'); var depsList = ''; var root = this.root; var insertExclude = function (p) { @@ -170,8 +170,10 @@ StudioBuilder.prototype.prepBuildFiles = function () { subProjects.forEach(function (p) { console.log('Subproject Path: ' + p); var libName = p.replace(/[/\\]/g, ':').replace(name + '-', ''); - depsList += ' implementation(project(path: "' + libName + '", configuration: "release"))'; - insertExclude(p); + if(libName !== 'app') { + depsList += ' implementation(project(path: ":' + libName + '"))'; + insertExclude(p); + } }); // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390 var SYSTEM_LIBRARY_MAPPINGS = [ @@ -223,7 +225,7 @@ StudioBuilder.prototype.prepEnv = function (opts) { // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with. // For some reason, using ^ and $ don't work. This does the job, though. var distributionUrlRegex = /distributionUrl.*zip/; - var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-3.3-all.zip'; + var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-4.1-all.zip'; var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties'); shell.chmod('u+w', gradleWrapperPropertiesPath); shell.sed('-i', distributionUrlRegex, 'distributionUrl=' + distributionUrl, gradleWrapperPropertiesPath); diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle index f2c4f294..08e130d3 100644 --- a/bin/templates/project/app/build.gradle +++ b/bin/templates/project/app/build.gradle @@ -23,10 +23,13 @@ buildscript { repositories { mavenCentral() jcenter() + maven { + url "https://maven.google.com" + } } dependencies { - classpath 'com.android.tools.build:gradle:2.3.0' + classpath 'com.android.tools.build:gradle:3.0.0' } } @@ -39,7 +42,7 @@ allprojects { } task wrapper(type: Wrapper) { - gradleVersion = '3.3.0' + gradleVersion = '4.1.0' } // Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. @@ -227,7 +230,7 @@ android { dependencies { - compile fileTree(dir: 'libs', include: '*.jar') + implementation fileTree(dir: 'libs', include: '*.jar') // SUB-PROJECT DEPENDENCIES START debugCompile(project(path: ":CordovaLib", configuration: "debug")) releaseCompile(project(path: ":CordovaLib", configuration: "release")) From f54336eb61dcff459b377b34d01c8321047e0920 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 1 Nov 2017 17:18:41 -0700 Subject: [PATCH 42/50] eslint fix --- .../cordova/lib/builders/StudioBuilder.js | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js index f65ff264..7a618ec5 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -117,10 +117,10 @@ StudioBuilder.prototype.prepBuildFiles = function () { var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle'); var propertiesObj = this.readProjectProperties(); var subProjects = propertiesObj.libs; - + // Check and copy the gradle file into the subproject // Called by the loop before this function def - + var checkAndCopy = function (subProject, root) { var subProjectGradle = path.join(root, subProject, 'build.gradle'); // This is the future-proof way of checking if a file exists @@ -159,7 +159,6 @@ StudioBuilder.prototype.prepBuildFiles = function () { var root = this.root; var insertExclude = function (p) { var gradlePath = path.join(root, p, 'build.gradle'); - console.log("Gradle path for writing:" + gradlePath); var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8'); if (projectGradleFile.indexOf('CordovaLib') !== -1) { depsList += '{\n exclude module:("CordovaLib")\n }\n'; @@ -170,9 +169,9 @@ StudioBuilder.prototype.prepBuildFiles = function () { subProjects.forEach(function (p) { console.log('Subproject Path: ' + p); var libName = p.replace(/[/\\]/g, ':').replace(name + '-', ''); - if(libName !== 'app') { - depsList += ' implementation(project(path: ":' + libName + '"))'; - insertExclude(p); + if (libName !== 'app') { + depsList += ' implementation(project(path: ":' + libName + '"))'; + insertExclude(p); } }); // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390 @@ -204,12 +203,11 @@ StudioBuilder.prototype.prepBuildFiles = function () { buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2'); var includeList = ''; - propertiesObj.gradleIncludes.forEach(function (includePath) { includeList += 'apply from: "' + includePath + '"\n'; }); buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2'); - //This needs to be stored in the app gradle, not the root grade + // This needs to be stored in the app gradle, not the root grade fs.writeFileSync(path.join(this.root, 'app', 'build.gradle'), buildGradle); }; From 3acba59494641fd2ffd436500c2119f9c2031174 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 15 Nov 2017 11:39:32 -0800 Subject: [PATCH 43/50] CB-13297: This just works once you bump the project structure. Java 1.8 compatibility baked-in --- bin/templates/project/app/build.gradle | 4 ++-- framework/build.gradle | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle index 08e130d3..61f2b3e0 100644 --- a/bin/templates/project/app/build.gradle +++ b/bin/templates/project/app/build.gradle @@ -196,8 +196,8 @@ android { } compileOptions { - sourceCompatibility JavaVersion.VERSION_1_6 - targetCompatibility JavaVersion.VERSION_1_6 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } if (cdvReleaseSigningPropertiesFile) { diff --git a/framework/build.gradle b/framework/build.gradle index 31c53afe..7067612a 100644 --- a/framework/build.gradle +++ b/framework/build.gradle @@ -50,8 +50,8 @@ android { publishNonDefault true compileOptions { - sourceCompatibility JavaVersion.VERSION_1_6 - targetCompatibility JavaVersion.VERSION_1_6 + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 } sourceSets { From 5d57eff61219b65b9786a7723cf3c0e527951d4c Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 22 Nov 2017 11:39:40 -0800 Subject: [PATCH 44/50] CB-13601: Fixing the standalone run scripts to make sure this works without using the CLI --- bin/templates/cordova/lib/build.js | 4 +++- bin/templates/cordova/lib/emulator.js | 7 ++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js index c7aee307..a5299302 100644 --- a/bin/templates/cordova/lib/build.js +++ b/bin/templates/cordova/lib/build.js @@ -47,9 +47,11 @@ function parseOpts (options, resolvedTarget, projectRoot) { keystoreType: String }, {}, options.argv, 0); + + // Android Studio Build method is the default var ret = { buildType: options.release ? 'release' : 'debug', - buildMethod: process.env.ANDROID_BUILD || 'gradle', + buildMethod: process.env.ANDROID_BUILD || 'studio', prepEnv: options.argv.prepenv, arch: resolvedTarget && resolvedTarget.arch, extraArgs: [] diff --git a/bin/templates/cordova/lib/emulator.js b/bin/templates/cordova/lib/emulator.js index edb7c800..c8a1963d 100644 --- a/bin/templates/cordova/lib/emulator.js +++ b/bin/templates/cordova/lib/emulator.js @@ -432,7 +432,12 @@ module.exports.resolveTarget = function (target) { module.exports.install = function (givenTarget, buildResults) { var target; - var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml')); + // We need to find the proper path to the Android Manifest + var manifestPath = path.join(__dirname, '..', '..', 'app', 'src', 'main', 'AndroidManifest.xml'); + if (buildResults.buildMethod === 'gradle') { + mainfestPath = path.join(__dirname, '../../AndroidManifest.xml'); + } + var manifest = new AndroidManifest(manifestPath); var pkgName = manifest.getPackageId(); // resolve the target emulator From d8f10c33dcd1dbaf53c7b5bf8d35ab4b95e1996b Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 22 Nov 2017 11:47:05 -0800 Subject: [PATCH 45/50] CB-13601: Fixing lint error and mis-spelling of variable --- bin/templates/cordova/lib/build.js | 1 - bin/templates/cordova/lib/emulator.js | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/templates/cordova/lib/build.js b/bin/templates/cordova/lib/build.js index a5299302..e33cfae0 100644 --- a/bin/templates/cordova/lib/build.js +++ b/bin/templates/cordova/lib/build.js @@ -47,7 +47,6 @@ function parseOpts (options, resolvedTarget, projectRoot) { keystoreType: String }, {}, options.argv, 0); - // Android Studio Build method is the default var ret = { buildType: options.release ? 'release' : 'debug', diff --git a/bin/templates/cordova/lib/emulator.js b/bin/templates/cordova/lib/emulator.js index c8a1963d..0a23084e 100644 --- a/bin/templates/cordova/lib/emulator.js +++ b/bin/templates/cordova/lib/emulator.js @@ -435,7 +435,7 @@ module.exports.install = function (givenTarget, buildResults) { // We need to find the proper path to the Android Manifest var manifestPath = path.join(__dirname, '..', '..', 'app', 'src', 'main', 'AndroidManifest.xml'); if (buildResults.buildMethod === 'gradle') { - mainfestPath = path.join(__dirname, '../../AndroidManifest.xml'); + manifestPath = path.join(__dirname, '../../AndroidManifest.xml'); } var manifest = new AndroidManifest(manifestPath); var pkgName = manifest.getPackageId(); From 9d9bac397bfccc7c3421f61469ddeac362b016e4 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Wed, 22 Nov 2017 13:18:38 -0800 Subject: [PATCH 46/50] CB-13602: We were setting the path wrong, this is hacky but it works --- bin/templates/cordova/lib/builders/StudioBuilder.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/templates/cordova/lib/builders/StudioBuilder.js b/bin/templates/cordova/lib/builders/StudioBuilder.js index 7a618ec5..38923e14 100644 --- a/bin/templates/cordova/lib/builders/StudioBuilder.js +++ b/bin/templates/cordova/lib/builders/StudioBuilder.js @@ -204,7 +204,7 @@ StudioBuilder.prototype.prepBuildFiles = function () { var includeList = ''; propertiesObj.gradleIncludes.forEach(function (includePath) { - includeList += 'apply from: "' + includePath + '"\n'; + includeList += 'apply from: "../' + includePath + '"\n'; }); buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2'); // This needs to be stored in the app gradle, not the root grade From 0269e532df7fc00f6ad56f4f341b2eaaa0010c08 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 28 Nov 2017 11:31:04 -0800 Subject: [PATCH 47/50] CB-13741: Bump package.json so we can install plugins --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 23c68e5f..d8601d8e 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "license": "Apache-2.0", "dependencies": { "android-versions": "^1.2.1", - "cordova-common": "^2.1.0", + "cordova-common": "^2.2.0", "elementtree": "0.1.6", "nopt": "^3.0.1", "properties-parser": "^0.2.3", From a9e01f43095dfcea35a9d774f1c8a320b8aa6756 Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 28 Nov 2017 12:57:00 -0800 Subject: [PATCH 48/50] CB-13612: Fix the remapper so that XML files copy over and the Camera works again. --- bin/templates/cordova/lib/pluginHandlers.js | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js index f6c4b098..793f5d3f 100644 --- a/bin/templates/cordova/lib/pluginHandlers.js +++ b/bin/templates/cordova/lib/pluginHandlers.js @@ -30,8 +30,19 @@ var handlers = { var dest = path.join(obj.targetDir, path.basename(obj.src)); + // TODO: This code needs to be replaced, since the core plugins need to be re-mapped to a different location in + // a later plugins release. This is for legacy plugins to work with Cordova. + if (options && options.android_studio === true) { - dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src)); + // If a Java file is using the new directory structure, don't penalize it + if (!obj.targetDir.includes('app/src/main')) { + if (obj.src.endsWith('.java')) { + dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src)); + } else if (obj.src.endsWith('.xml')) { + // We are making a huge assumption here that XML files will be going to res/xml or values/xml + dest = path.join('app/src/main', obj.targetDir, path.basename(obj.src)); + } + } } if (options && options.force) { From adc7dab377c922e996c3fced308ea6621a7e17eb Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 28 Nov 2017 13:09:07 -0800 Subject: [PATCH 49/50] CB-13612: eslint fix --- bin/templates/cordova/lib/pluginHandlers.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bin/templates/cordova/lib/pluginHandlers.js b/bin/templates/cordova/lib/pluginHandlers.js index 793f5d3f..842489ae 100644 --- a/bin/templates/cordova/lib/pluginHandlers.js +++ b/bin/templates/cordova/lib/pluginHandlers.js @@ -30,17 +30,17 @@ var handlers = { var dest = path.join(obj.targetDir, path.basename(obj.src)); - // TODO: This code needs to be replaced, since the core plugins need to be re-mapped to a different location in + // TODO: This code needs to be replaced, since the core plugins need to be re-mapped to a different location in // a later plugins release. This is for legacy plugins to work with Cordova. if (options && options.android_studio === true) { // If a Java file is using the new directory structure, don't penalize it if (!obj.targetDir.includes('app/src/main')) { if (obj.src.endsWith('.java')) { - dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src)); + dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src)); } else if (obj.src.endsWith('.xml')) { - // We are making a huge assumption here that XML files will be going to res/xml or values/xml - dest = path.join('app/src/main', obj.targetDir, path.basename(obj.src)); + // We are making a huge assumption here that XML files will be going to res/xml or values/xml + dest = path.join('app/src/main', obj.targetDir, path.basename(obj.src)); } } } From c6cfeb15f40179b54d5fdf9f62e89666a937502e Mon Sep 17 00:00:00 2001 From: Joe Bowser Date: Tue, 28 Nov 2017 14:59:50 -0800 Subject: [PATCH 50/50] Fixed typo in the gradle file --- bin/templates/project/app/build.gradle | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/templates/project/app/build.gradle b/bin/templates/project/app/build.gradle index 8792e129..c5f5b233 100644 --- a/bin/templates/project/app/build.gradle +++ b/bin/templates/project/app/build.gradle @@ -229,7 +229,8 @@ android { if (cdvReleaseSigningPropertiesFile) { signingConfigs { release { - // These must be set or Gradle will complain (even if they are overridden). keyAlias = "" + // These must be set or Gradle will complain (even if they are overridden). + keyAlias = "" keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph. storeFile = null storePassword = "__unset"