Made changes so cordova/build builds with the new project. Need to work on plugin installation.

This commit is contained in:
Joe Bowser 2017-04-11 13:47:40 -07:00
parent 8ead919fae
commit db87e0ae6a
7 changed files with 108 additions and 52 deletions

View File

@ -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!'));
}

View File

@ -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';

View File

@ -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));
}, [])

View File

@ -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) {

View File

@ -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.

View File

@ -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);

View File

@ -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.