mirror of
https://github.com/apache/cordova-android.git
synced 2025-03-28 18:02:44 +08:00
Fixed line endings
This commit is contained in:
parent
400282282f
commit
0ac822c577
2
LICENSE
2
LICENSE
@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
|
@ -5,9 +5,9 @@
|
|||||||
:: to you under the Apache License, Version 2.0 (the
|
:: to you under the Apache License, Version 2.0 (the
|
||||||
:: "License"); you may not use this file except in compliance
|
:: "License"); you may not use this file except in compliance
|
||||||
:: with the License. You may obtain a copy of the License at
|
:: 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,
|
:: Unless required by applicable law or agreed to in writing,
|
||||||
:: software distributed under the License is distributed on an
|
:: software distributed under the License is distributed on an
|
||||||
:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
:: "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
112
bin/create
112
bin/create
@ -1,56 +1,56 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var ConfigParser = require('cordova-common').ConfigParser;
|
var ConfigParser = require('cordova-common').ConfigParser;
|
||||||
var Api = require('./templates/cordova/Api');
|
var Api = require('./templates/cordova/Api');
|
||||||
|
|
||||||
var argv = require('nopt')({
|
var argv = require('nopt')({
|
||||||
'help' : Boolean,
|
'help' : Boolean,
|
||||||
'cli' : Boolean,
|
'cli' : Boolean,
|
||||||
'shared' : Boolean,
|
'shared' : Boolean,
|
||||||
'link' : Boolean,
|
'link' : Boolean,
|
||||||
'activity-name' : [String, undefined]
|
'activity-name' : [String, undefined]
|
||||||
});
|
});
|
||||||
|
|
||||||
if (argv.help || argv.argv.remain.length === 0) {
|
if (argv.help || argv.argv.remain.length === 0) {
|
||||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--activity-name <activity_name>] [--link]');
|
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--activity-name <activity_name>] [--link]');
|
||||||
console.log(' <path_to_new_project>: Path to your new Cordova Android project');
|
console.log(' <path_to_new_project>: Path to your new Cordova Android project');
|
||||||
console.log(' <package_name>: Package name, following reverse-domain style convention');
|
console.log(' <package_name>: Package name, following reverse-domain style convention');
|
||||||
console.log(' <project_name>: Project name');
|
console.log(' <project_name>: Project name');
|
||||||
console.log(' <template_path>: Path to a custom application template to use');
|
console.log(' <template_path>: Path to a custom application template to use');
|
||||||
console.log(' --activity-name <activity_name>: Activity name');
|
console.log(' --activity-name <activity_name>: Activity name');
|
||||||
console.log(' --link will use the CordovaLib project directly instead of making a copy.');
|
console.log(' --link will use the CordovaLib project directly instead of making a copy.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
var config = new ConfigParser(path.resolve(__dirname, 'templates/project/res/xml/config.xml'));
|
var config = new ConfigParser(path.resolve(__dirname, 'templates/project/res/xml/config.xml'));
|
||||||
|
|
||||||
if (argv.argv.remain[1]) config.setPackageName(argv.argv.remain[1]);
|
if (argv.argv.remain[1]) config.setPackageName(argv.argv.remain[1]);
|
||||||
if (argv.argv.remain[2]) config.setName(argv.argv.remain[2]);
|
if (argv.argv.remain[2]) config.setName(argv.argv.remain[2]);
|
||||||
if (argv['activity-name']) config.setName(argv['activity-name']);
|
if (argv['activity-name']) config.setName(argv['activity-name']);
|
||||||
|
|
||||||
var options = {
|
var options = {
|
||||||
link: argv.link || argv.shared,
|
link: argv.link || argv.shared,
|
||||||
customTemplate: argv.argv.remain[3],
|
customTemplate: argv.argv.remain[3],
|
||||||
activityName: argv['activity-name']
|
activityName: argv['activity-name']
|
||||||
};
|
};
|
||||||
|
|
||||||
Api.createPlatform(argv.argv.remain[0], config, options).done();
|
Api.createPlatform(argv.argv.remain[0], config, options).done();
|
||||||
|
@ -1,326 +1,326 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* jshint sub:true */
|
/* jshint sub:true */
|
||||||
|
|
||||||
var shelljs = require('shelljs'),
|
var shelljs = require('shelljs'),
|
||||||
child_process = require('child_process'),
|
child_process = require('child_process'),
|
||||||
Q = require('q'),
|
Q = require('q'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
ROOT = path.join(__dirname, '..', '..');
|
ROOT = path.join(__dirname, '..', '..');
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
var isWindows = process.platform == 'win32';
|
var isWindows = process.platform == 'win32';
|
||||||
|
|
||||||
function forgivingWhichSync(cmd) {
|
function forgivingWhichSync(cmd) {
|
||||||
try {
|
try {
|
||||||
return fs.realpathSync(shelljs.which(cmd));
|
return fs.realpathSync(shelljs.which(cmd));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function tryCommand(cmd, errMsg, catchStderr) {
|
function tryCommand(cmd, errMsg, catchStderr) {
|
||||||
var d = Q.defer();
|
var d = Q.defer();
|
||||||
child_process.exec(cmd, function(err, stdout, stderr) {
|
child_process.exec(cmd, function(err, stdout, stderr) {
|
||||||
if (err) d.reject(new CordovaError(errMsg));
|
if (err) d.reject(new CordovaError(errMsg));
|
||||||
// Sometimes it is necessary to return an stderr instead of stdout in case of success, since
|
// Sometimes it is necessary to return an stderr instead of stdout in case of success, since
|
||||||
// some commands prints theirs output to stderr instead of stdout. 'javac' is the example
|
// some commands prints theirs output to stderr instead of stdout. 'javac' is the example
|
||||||
else d.resolve((catchStderr ? stderr : stdout).trim());
|
else d.resolve((catchStderr ? stderr : stdout).trim());
|
||||||
});
|
});
|
||||||
return d.promise;
|
return d.promise;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get valid target from framework/project.properties
|
// Get valid target from framework/project.properties
|
||||||
module.exports.get_target = function() {
|
module.exports.get_target = function() {
|
||||||
function extractFromFile(filePath) {
|
function extractFromFile(filePath) {
|
||||||
var target = shelljs.grep(/\btarget=/, filePath);
|
var target = shelljs.grep(/\btarget=/, filePath);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
throw new Error('Could not find android target within: ' + filePath);
|
throw new Error('Could not find android target within: ' + filePath);
|
||||||
}
|
}
|
||||||
return target.split('=')[1].trim();
|
return target.split('=')[1].trim();
|
||||||
}
|
}
|
||||||
if (fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
|
if (fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
|
||||||
return extractFromFile(path.join(ROOT, 'framework', 'project.properties'));
|
return extractFromFile(path.join(ROOT, 'framework', 'project.properties'));
|
||||||
}
|
}
|
||||||
if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
|
if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
|
||||||
// if no target found, we're probably in a project and project.properties is in ROOT.
|
// if no target found, we're probably in a project and project.properties is in ROOT.
|
||||||
return extractFromFile(path.join(ROOT, 'project.properties'));
|
return extractFromFile(path.join(ROOT, 'project.properties'));
|
||||||
}
|
}
|
||||||
throw new Error('Could not find android target. File missing: ' + path.join(ROOT, 'project.properties'));
|
throw new Error('Could not find android target. File missing: ' + path.join(ROOT, 'project.properties'));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise. Called only by build and clean commands.
|
// Returns a promise. Called only by build and clean commands.
|
||||||
module.exports.check_ant = function() {
|
module.exports.check_ant = function() {
|
||||||
return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.')
|
return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.')
|
||||||
.then(function (output) {
|
.then(function (output) {
|
||||||
// Parse Ant version from command output
|
// Parse Ant version from command output
|
||||||
return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
|
return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise. Called only by build and clean commands.
|
// Returns a promise. Called only by build and clean commands.
|
||||||
module.exports.check_gradle = function() {
|
module.exports.check_gradle = function() {
|
||||||
var sdkDir = process.env['ANDROID_HOME'];
|
var sdkDir = process.env['ANDROID_HOME'];
|
||||||
if (!sdkDir)
|
if (!sdkDir)
|
||||||
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
|
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
|
||||||
'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
|
'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
|
||||||
|
|
||||||
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||||
if (!fs.existsSync(wrapperDir)) {
|
if (!fs.existsSync(wrapperDir)) {
|
||||||
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Might need to update your Android SDK.\n' +
|
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Might need to update your Android SDK.\n' +
|
||||||
'Looked here: ' + wrapperDir));
|
'Looked here: ' + wrapperDir));
|
||||||
}
|
}
|
||||||
return Q.when();
|
return Q.when();
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
module.exports.check_java = function() {
|
module.exports.check_java = function() {
|
||||||
var javacPath = forgivingWhichSync('javac');
|
var javacPath = forgivingWhichSync('javac');
|
||||||
var hasJavaHome = !!process.env['JAVA_HOME'];
|
var hasJavaHome = !!process.env['JAVA_HOME'];
|
||||||
return Q().then(function() {
|
return Q().then(function() {
|
||||||
if (hasJavaHome) {
|
if (hasJavaHome) {
|
||||||
// Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
|
// Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
|
||||||
if (!javacPath) {
|
if (!javacPath) {
|
||||||
process.env['PATH'] += path.delimiter + path.join(process.env['JAVA_HOME'], 'bin');
|
process.env['PATH'] += path.delimiter + path.join(process.env['JAVA_HOME'], 'bin');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (javacPath) {
|
if (javacPath) {
|
||||||
var msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
|
var msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
|
||||||
// OS X has a command for finding JAVA_HOME.
|
// OS X has a command for finding JAVA_HOME.
|
||||||
if (fs.existsSync('/usr/libexec/java_home')) {
|
if (fs.existsSync('/usr/libexec/java_home')) {
|
||||||
return tryCommand('/usr/libexec/java_home', msg)
|
return tryCommand('/usr/libexec/java_home', msg)
|
||||||
.then(function(stdout) {
|
.then(function(stdout) {
|
||||||
process.env['JAVA_HOME'] = stdout.trim();
|
process.env['JAVA_HOME'] = stdout.trim();
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// See if we can derive it from javac's location.
|
// See if we can derive it from javac's location.
|
||||||
// fs.realpathSync is require on Ubuntu, which symplinks from /usr/bin -> JDK
|
// fs.realpathSync is require on Ubuntu, which symplinks from /usr/bin -> JDK
|
||||||
var maybeJavaHome = path.dirname(path.dirname(javacPath));
|
var maybeJavaHome = path.dirname(path.dirname(javacPath));
|
||||||
if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
|
if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
|
||||||
process.env['JAVA_HOME'] = maybeJavaHome;
|
process.env['JAVA_HOME'] = maybeJavaHome;
|
||||||
} else {
|
} else {
|
||||||
throw new CordovaError(msg);
|
throw new CordovaError(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (isWindows) {
|
} else if (isWindows) {
|
||||||
// Try to auto-detect java in the default install paths.
|
// Try to auto-detect java in the default install paths.
|
||||||
var oldSilent = shelljs.config.silent;
|
var oldSilent = shelljs.config.silent;
|
||||||
shelljs.config.silent = true;
|
shelljs.config.silent = true;
|
||||||
var firstJdkDir =
|
var firstJdkDir =
|
||||||
shelljs.ls(process.env['ProgramFiles'] + '\\java\\jdk*')[0] ||
|
shelljs.ls(process.env['ProgramFiles'] + '\\java\\jdk*')[0] ||
|
||||||
shelljs.ls('C:\\Program Files\\java\\jdk*')[0] ||
|
shelljs.ls('C:\\Program Files\\java\\jdk*')[0] ||
|
||||||
shelljs.ls('C:\\Program Files (x86)\\java\\jdk*')[0];
|
shelljs.ls('C:\\Program Files (x86)\\java\\jdk*')[0];
|
||||||
shelljs.config.silent = oldSilent;
|
shelljs.config.silent = oldSilent;
|
||||||
if (firstJdkDir) {
|
if (firstJdkDir) {
|
||||||
// shelljs always uses / in paths.
|
// shelljs always uses / in paths.
|
||||||
firstJdkDir = firstJdkDir.replace(/\//g, path.sep);
|
firstJdkDir = firstJdkDir.replace(/\//g, path.sep);
|
||||||
if (!javacPath) {
|
if (!javacPath) {
|
||||||
process.env['PATH'] += path.delimiter + path.join(firstJdkDir, 'bin');
|
process.env['PATH'] += path.delimiter + path.join(firstJdkDir, 'bin');
|
||||||
}
|
}
|
||||||
process.env['JAVA_HOME'] = firstJdkDir;
|
process.env['JAVA_HOME'] = firstJdkDir;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
var msg =
|
var msg =
|
||||||
'Failed to run "java -version", make sure that you have a JDK installed.\n' +
|
'Failed to run "java -version", make sure that you have a JDK installed.\n' +
|
||||||
'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
|
'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
|
||||||
if (process.env['JAVA_HOME']) {
|
if (process.env['JAVA_HOME']) {
|
||||||
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
|
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
|
||||||
}
|
}
|
||||||
return tryCommand('java -version', msg)
|
return tryCommand('java -version', msg)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
// We use tryCommand with catchStderr = true, because
|
// We use tryCommand with catchStderr = true, because
|
||||||
// javac writes version info to stderr instead of stdout
|
// javac writes version info to stderr instead of stdout
|
||||||
return tryCommand('javac -version', msg, true);
|
return tryCommand('javac -version', msg, true);
|
||||||
}).then(function (output) {
|
}).then(function (output) {
|
||||||
var match = /javac ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
|
var match = /javac ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
|
||||||
return match && match[1];
|
return match && match[1];
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
module.exports.check_android = function() {
|
module.exports.check_android = function() {
|
||||||
return Q().then(function() {
|
return Q().then(function() {
|
||||||
var androidCmdPath = forgivingWhichSync('android');
|
var androidCmdPath = forgivingWhichSync('android');
|
||||||
var adbInPath = !!forgivingWhichSync('adb');
|
var adbInPath = !!forgivingWhichSync('adb');
|
||||||
var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);
|
var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);
|
||||||
function maybeSetAndroidHome(value) {
|
function maybeSetAndroidHome(value) {
|
||||||
if (!hasAndroidHome && fs.existsSync(value)) {
|
if (!hasAndroidHome && fs.existsSync(value)) {
|
||||||
hasAndroidHome = true;
|
hasAndroidHome = true;
|
||||||
process.env['ANDROID_HOME'] = value;
|
process.env['ANDROID_HOME'] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hasAndroidHome && !androidCmdPath) {
|
if (!hasAndroidHome && !androidCmdPath) {
|
||||||
if (isWindows) {
|
if (isWindows) {
|
||||||
// Android Studio 1.0 installer
|
// Android Studio 1.0 installer
|
||||||
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));
|
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));
|
||||||
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'sdk'));
|
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'sdk'));
|
||||||
// Android Studio pre-1.0 installer
|
// Android Studio pre-1.0 installer
|
||||||
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-studio', 'sdk'));
|
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-studio', 'sdk'));
|
||||||
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-studio', 'sdk'));
|
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-studio', 'sdk'));
|
||||||
// Stand-alone installer
|
// Stand-alone installer
|
||||||
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-sdk'));
|
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-sdk'));
|
||||||
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-sdk'));
|
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-sdk'));
|
||||||
} else if (process.platform == 'darwin') {
|
} else if (process.platform == 'darwin') {
|
||||||
// Android Studio 1.0 installer
|
// Android Studio 1.0 installer
|
||||||
maybeSetAndroidHome(path.join(process.env['HOME'], 'Library', 'Android', 'sdk'));
|
maybeSetAndroidHome(path.join(process.env['HOME'], 'Library', 'Android', 'sdk'));
|
||||||
// Android Studio pre-1.0 installer
|
// Android Studio pre-1.0 installer
|
||||||
maybeSetAndroidHome('/Applications/Android Studio.app/sdk');
|
maybeSetAndroidHome('/Applications/Android Studio.app/sdk');
|
||||||
// Stand-alone zip file that user might think to put under /Applications
|
// Stand-alone zip file that user might think to put under /Applications
|
||||||
maybeSetAndroidHome('/Applications/android-sdk-macosx');
|
maybeSetAndroidHome('/Applications/android-sdk-macosx');
|
||||||
maybeSetAndroidHome('/Applications/android-sdk');
|
maybeSetAndroidHome('/Applications/android-sdk');
|
||||||
}
|
}
|
||||||
if (process.env['HOME']) {
|
if (process.env['HOME']) {
|
||||||
// Stand-alone zip file that user might think to put under their home directory
|
// Stand-alone zip file that user might think to put under their home directory
|
||||||
maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk-macosx'));
|
maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk-macosx'));
|
||||||
maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk'));
|
maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasAndroidHome && !androidCmdPath) {
|
if (hasAndroidHome && !androidCmdPath) {
|
||||||
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
|
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
|
||||||
}
|
}
|
||||||
if (androidCmdPath && !hasAndroidHome) {
|
if (androidCmdPath && !hasAndroidHome) {
|
||||||
var parentDir = path.dirname(androidCmdPath);
|
var parentDir = path.dirname(androidCmdPath);
|
||||||
var grandParentDir = path.dirname(parentDir);
|
var grandParentDir = path.dirname(parentDir);
|
||||||
if (path.basename(parentDir) == 'tools') {
|
if (path.basename(parentDir) == 'tools') {
|
||||||
process.env['ANDROID_HOME'] = path.dirname(parentDir);
|
process.env['ANDROID_HOME'] = path.dirname(parentDir);
|
||||||
hasAndroidHome = true;
|
hasAndroidHome = true;
|
||||||
} else if (fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
|
} else if (fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
|
||||||
process.env['ANDROID_HOME'] = grandParentDir;
|
process.env['ANDROID_HOME'] = grandParentDir;
|
||||||
hasAndroidHome = true;
|
hasAndroidHome = true;
|
||||||
} else {
|
} else {
|
||||||
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
||||||
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
|
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
|
||||||
'Try reinstall Android SDK or update your PATH to include path to valid SDK directory.');
|
'Try reinstall Android SDK or update your PATH to include path to valid SDK directory.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasAndroidHome && !adbInPath) {
|
if (hasAndroidHome && !adbInPath) {
|
||||||
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
|
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
|
||||||
}
|
}
|
||||||
if (!process.env['ANDROID_HOME']) {
|
if (!process.env['ANDROID_HOME']) {
|
||||||
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
||||||
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
|
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
|
||||||
}
|
}
|
||||||
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
|
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
|
||||||
throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
|
throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
|
||||||
'\nTry update it manually to point to valid SDK directory.');
|
'\nTry update it manually to point to valid SDK directory.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.getAbsoluteAndroidCmd = function() {
|
module.exports.getAbsoluteAndroidCmd = function() {
|
||||||
return forgivingWhichSync('android').replace(/(\s)/g, '\\$1');
|
return forgivingWhichSync('android').replace(/(\s)/g, '\\$1');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.check_android_target = function(valid_target) {
|
module.exports.check_android_target = function(valid_target) {
|
||||||
// valid_target can look like:
|
// valid_target can look like:
|
||||||
// android-19
|
// android-19
|
||||||
// android-L
|
// android-L
|
||||||
// Google Inc.:Google APIs:20
|
// Google Inc.:Google APIs:20
|
||||||
// Google Inc.:Glass Development Kit Preview:20
|
// Google Inc.:Glass Development Kit Preview:20
|
||||||
if (!valid_target) valid_target = module.exports.get_target();
|
if (!valid_target) valid_target = module.exports.get_target();
|
||||||
var msg = 'Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable.';
|
var msg = 'Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable.';
|
||||||
return tryCommand('android list targets --compact', msg)
|
return tryCommand('android list targets --compact', msg)
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
var targets = output.split('\n');
|
var targets = output.split('\n');
|
||||||
if (targets.indexOf(valid_target) >= 0) {
|
if (targets.indexOf(valid_target) >= 0) {
|
||||||
return targets;
|
return targets;
|
||||||
}
|
}
|
||||||
|
|
||||||
var androidCmd = module.exports.getAbsoluteAndroidCmd();
|
var androidCmd = module.exports.getAbsoluteAndroidCmd();
|
||||||
throw new CordovaError('Please install Android target: "' + valid_target + '".\n\n' +
|
throw new CordovaError('Please install Android target: "' + valid_target + '".\n\n' +
|
||||||
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
|
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
|
||||||
'You will require:\n' +
|
'You will require:\n' +
|
||||||
'1. "SDK Platform" for ' + valid_target + '\n' +
|
'1. "SDK Platform" for ' + valid_target + '\n' +
|
||||||
'2. "Android SDK Platform-tools (latest)\n' +
|
'2. "Android SDK Platform-tools (latest)\n' +
|
||||||
'3. "Android SDK Build-tools" (latest)');
|
'3. "Android SDK Build-tools" (latest)');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
module.exports.run = function() {
|
module.exports.run = function() {
|
||||||
return Q.all([this.check_java(), this.check_android().then(this.check_android_target)])
|
return Q.all([this.check_java(), this.check_android().then(this.check_android_target)])
|
||||||
.then(function() {
|
.then(function() {
|
||||||
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
|
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
|
||||||
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
|
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Object thar represents one of requirements for current platform.
|
* Object thar represents one of requirements for current platform.
|
||||||
* @param {String} id The unique identifier for this requirements.
|
* @param {String} id The unique identifier for this requirements.
|
||||||
* @param {String} name The name of requirements. Human-readable field.
|
* @param {String} name The name of requirements. Human-readable field.
|
||||||
* @param {String} version The version of requirement installed. In some cases could be an array of strings
|
* @param {String} version The version of requirement installed. In some cases could be an array of strings
|
||||||
* (for example, check_android_target returns an array of android targets installed)
|
* (for example, check_android_target returns an array of android targets installed)
|
||||||
* @param {Boolean} installed Indicates whether the requirement is installed or not
|
* @param {Boolean} installed Indicates whether the requirement is installed or not
|
||||||
*/
|
*/
|
||||||
var Requirement = function (id, name, version, installed) {
|
var Requirement = function (id, name, version, installed) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.installed = installed || false;
|
this.installed = installed || false;
|
||||||
this.metadata = {
|
this.metadata = {
|
||||||
version: version,
|
version: version,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Methods that runs all checks one by one and returns a result of checks
|
* Methods that runs all checks one by one and returns a result of checks
|
||||||
* as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method
|
* as an array of Requirement objects. This method intended to be used by cordova-lib check_reqs method
|
||||||
*
|
*
|
||||||
* @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
|
* @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
|
||||||
*/
|
*/
|
||||||
module.exports.check_all = function() {
|
module.exports.check_all = function() {
|
||||||
|
|
||||||
var requirements = [
|
var requirements = [
|
||||||
new Requirement('java', 'Java JDK'),
|
new Requirement('java', 'Java JDK'),
|
||||||
new Requirement('androidSdk', 'Android SDK'),
|
new Requirement('androidSdk', 'Android SDK'),
|
||||||
new Requirement('androidTarget', 'Android target'),
|
new Requirement('androidTarget', 'Android target'),
|
||||||
new Requirement('gradle', 'Gradle')
|
new Requirement('gradle', 'Gradle')
|
||||||
];
|
];
|
||||||
|
|
||||||
var checkFns = [
|
var checkFns = [
|
||||||
this.check_java,
|
this.check_java,
|
||||||
this.check_android,
|
this.check_android,
|
||||||
this.check_android_target,
|
this.check_android_target,
|
||||||
this.check_gradle
|
this.check_gradle
|
||||||
];
|
];
|
||||||
|
|
||||||
// Then execute requirement checks one-by-one
|
// Then execute requirement checks one-by-one
|
||||||
return checkFns.reduce(function (promise, checkFn, idx) {
|
return checkFns.reduce(function (promise, checkFn, idx) {
|
||||||
// Update each requirement with results
|
// Update each requirement with results
|
||||||
var requirement = requirements[idx];
|
var requirement = requirements[idx];
|
||||||
return promise.then(checkFn)
|
return promise.then(checkFn)
|
||||||
.then(function (version) {
|
.then(function (version) {
|
||||||
requirement.installed = true;
|
requirement.installed = true;
|
||||||
requirement.metadata.version = version;
|
requirement.metadata.version = version;
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
requirement.metadata.reason = err instanceof Error ? err.message : err;
|
requirement.metadata.reason = err instanceof Error ? err.message : err;
|
||||||
});
|
});
|
||||||
}, Q())
|
}, Q())
|
||||||
.then(function () {
|
.then(function () {
|
||||||
// When chain is completed, return requirements array to upstream API
|
// When chain is completed, return requirements array to upstream API
|
||||||
return requirements;
|
return requirements;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -1,332 +1,332 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var shell = require('shelljs'),
|
var shell = require('shelljs'),
|
||||||
Q = require('q'),
|
Q = require('q'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
check_reqs = require('./check_reqs'),
|
check_reqs = require('./check_reqs'),
|
||||||
ROOT = path.join(__dirname, '..', '..');
|
ROOT = path.join(__dirname, '..', '..');
|
||||||
|
|
||||||
var MIN_SDK_VERSION = 14;
|
var MIN_SDK_VERSION = 14;
|
||||||
|
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
|
var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
|
||||||
|
|
||||||
function setShellFatal(value, func) {
|
function setShellFatal(value, func) {
|
||||||
var oldVal = shell.config.fatal;
|
var oldVal = shell.config.fatal;
|
||||||
shell.config.fatal = value;
|
shell.config.fatal = value;
|
||||||
func();
|
func();
|
||||||
shell.config.fatal = oldVal;
|
shell.config.fatal = oldVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFrameworkDir(projectPath, shared) {
|
function getFrameworkDir(projectPath, shared) {
|
||||||
return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
|
return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyJsAndLibrary(projectPath, shared, projectName) {
|
function copyJsAndLibrary(projectPath, shared, projectName) {
|
||||||
var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
|
var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
|
||||||
var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js');
|
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, 'assets', 'www', 'cordova.js'));
|
||||||
|
|
||||||
// Copy the cordova.js file to platforms/<platform>/platform_www/
|
// Copy the cordova.js file to platforms/<platform>/platform_www/
|
||||||
// The www dir is nuked on each prepare so we keep cordova.js in platform_www
|
// The www dir is nuked on each prepare so we keep cordova.js in platform_www
|
||||||
shell.mkdir('-p', path.join(projectPath, 'platform_www'));
|
shell.mkdir('-p', path.join(projectPath, 'platform_www'));
|
||||||
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'platform_www'));
|
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'platform_www'));
|
||||||
|
|
||||||
// Copy cordova-js-src directory into platform_www directory.
|
// Copy cordova-js-src directory into platform_www directory.
|
||||||
// We need these files to build cordova.js if using browserify method.
|
// 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'));
|
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.
|
||||||
setShellFatal(false, function() {
|
setShellFatal(false, function() {
|
||||||
shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
|
shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
|
||||||
console.log('Deleting ' + oldJar);
|
console.log('Deleting ' + oldJar);
|
||||||
shell.rm('-f', oldJar);
|
shell.rm('-f', oldJar);
|
||||||
});
|
});
|
||||||
var wasSymlink = true;
|
var wasSymlink = true;
|
||||||
try {
|
try {
|
||||||
// Delete the symlink if it was one.
|
// Delete the symlink if it was one.
|
||||||
fs.unlinkSync(nestedCordovaLibPath);
|
fs.unlinkSync(nestedCordovaLibPath);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
wasSymlink = false;
|
wasSymlink = false;
|
||||||
}
|
}
|
||||||
// Delete old library project if it existed.
|
// Delete old library project if it existed.
|
||||||
if (shared) {
|
if (shared) {
|
||||||
shell.rm('-rf', nestedCordovaLibPath);
|
shell.rm('-rf', nestedCordovaLibPath);
|
||||||
} else if (!wasSymlink) {
|
} else if (!wasSymlink) {
|
||||||
// Delete only the src, since Eclipse / Android Studio can't handle their project files being deleted.
|
// Delete only the src, since Eclipse / Android Studio can't handle their project files being deleted.
|
||||||
shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
|
shell.rm('-rf', path.join(nestedCordovaLibPath, 'src'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (shared) {
|
if (shared) {
|
||||||
var relativeFrameworkPath = path.relative(projectPath, getFrameworkDir(projectPath, true));
|
var relativeFrameworkPath = path.relative(projectPath, getFrameworkDir(projectPath, true));
|
||||||
fs.symlinkSync(relativeFrameworkPath, nestedCordovaLibPath, 'dir');
|
fs.symlinkSync(relativeFrameworkPath, nestedCordovaLibPath, 'dir');
|
||||||
} else {
|
} else {
|
||||||
shell.mkdir('-p', nestedCordovaLibPath);
|
shell.mkdir('-p', nestedCordovaLibPath);
|
||||||
shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
|
shell.cp('-f', path.join(ROOT, 'framework', 'AndroidManifest.xml'), nestedCordovaLibPath);
|
||||||
shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
|
shell.cp('-f', path.join(ROOT, 'framework', 'project.properties'), nestedCordovaLibPath);
|
||||||
shell.cp('-f', path.join(ROOT, 'framework', 'build.gradle'), nestedCordovaLibPath);
|
shell.cp('-f', path.join(ROOT, 'framework', 'build.gradle'), nestedCordovaLibPath);
|
||||||
shell.cp('-f', path.join(ROOT, 'framework', 'cordova.gradle'), nestedCordovaLibPath);
|
shell.cp('-f', path.join(ROOT, 'framework', 'cordova.gradle'), nestedCordovaLibPath);
|
||||||
shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
|
shell.cp('-r', path.join(ROOT, 'framework', 'src'), nestedCordovaLibPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function extractSubProjectPaths(data) {
|
function extractSubProjectPaths(data) {
|
||||||
var ret = {};
|
var ret = {};
|
||||||
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
|
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
|
||||||
var m;
|
var m;
|
||||||
while ((m = r.exec(data))) {
|
while ((m = r.exec(data))) {
|
||||||
ret[m[1]] = 1;
|
ret[m[1]] = 1;
|
||||||
}
|
}
|
||||||
return Object.keys(ret);
|
return Object.keys(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
function writeProjectProperties(projectPath, target_api) {
|
function writeProjectProperties(projectPath, target_api) {
|
||||||
var dstPath = path.join(projectPath, 'project.properties');
|
var dstPath = path.join(projectPath, 'project.properties');
|
||||||
var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
|
var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
|
||||||
var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
|
var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
|
||||||
|
|
||||||
var data = fs.readFileSync(srcPath, 'utf8');
|
var data = fs.readFileSync(srcPath, 'utf8');
|
||||||
data = data.replace(/^target=.*/m, 'target=' + target_api);
|
data = data.replace(/^target=.*/m, 'target=' + target_api);
|
||||||
var subProjects = extractSubProjectPaths(data);
|
var subProjects = extractSubProjectPaths(data);
|
||||||
subProjects = subProjects.filter(function(p) {
|
subProjects = subProjects.filter(function(p) {
|
||||||
return !(/^CordovaLib$/m.exec(p) ||
|
return !(/^CordovaLib$/m.exec(p) ||
|
||||||
/[\\\/]cordova-android[\\\/]framework$/m.exec(p) ||
|
/[\\\/]cordova-android[\\\/]framework$/m.exec(p) ||
|
||||||
/^(\.\.[\\\/])+framework$/m.exec(p)
|
/^(\.\.[\\\/])+framework$/m.exec(p)
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
subProjects.unshift('CordovaLib');
|
subProjects.unshift('CordovaLib');
|
||||||
data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
|
data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
|
||||||
if (!/\n$/.exec(data)) {
|
if (!/\n$/.exec(data)) {
|
||||||
data += '\n';
|
data += '\n';
|
||||||
}
|
}
|
||||||
for (var i = 0; i < subProjects.length; ++i) {
|
for (var i = 0; i < subProjects.length; ++i) {
|
||||||
data += 'android.library.reference.' + (i+1) + '=' + subProjects[i] + '\n';
|
data += 'android.library.reference.' + (i+1) + '=' + subProjects[i] + '\n';
|
||||||
}
|
}
|
||||||
fs.writeFileSync(dstPath, data);
|
fs.writeFileSync(dstPath, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepBuildFiles(projectPath) {
|
function prepBuildFiles(projectPath) {
|
||||||
var buildModule = require(path.join(path.resolve(projectPath), 'cordova', 'lib', 'build'));
|
var buildModule = require(path.join(path.resolve(projectPath), 'cordova', 'lib', 'build'));
|
||||||
buildModule.prepBuildFiles();
|
buildModule.prepBuildFiles();
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyBuildRules(projectPath) {
|
function copyBuildRules(projectPath) {
|
||||||
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
||||||
|
|
||||||
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
|
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyScripts(projectPath) {
|
function copyScripts(projectPath) {
|
||||||
var srcScriptsDir = path.join(ROOT, 'bin', 'templates', 'cordova');
|
var srcScriptsDir = path.join(ROOT, 'bin', 'templates', 'cordova');
|
||||||
var destScriptsDir = path.join(projectPath, 'cordova');
|
var destScriptsDir = path.join(projectPath, 'cordova');
|
||||||
// Delete old scripts directory if this is an update.
|
// Delete old scripts directory if this is an update.
|
||||||
shell.rm('-rf', destScriptsDir);
|
shell.rm('-rf', destScriptsDir);
|
||||||
// Copy in the new ones.
|
// Copy in the new ones.
|
||||||
shell.cp('-r', srcScriptsDir, projectPath);
|
shell.cp('-r', srcScriptsDir, projectPath);
|
||||||
shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
|
shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
|
||||||
shell.cp(path.join(ROOT, 'bin', 'check_reqs*'), destScriptsDir);
|
shell.cp(path.join(ROOT, 'bin', 'check_reqs*'), destScriptsDir);
|
||||||
shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
|
shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
|
||||||
shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
|
shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
|
||||||
shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
|
shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether a package name is acceptable for use as an android project.
|
* Test whether a package name is acceptable for use as an android project.
|
||||||
* Returns a promise, fulfilled if the package name is acceptable; rejected
|
* Returns a promise, fulfilled if the package name is acceptable; rejected
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
function validatePackageName(package_name) {
|
function validatePackageName(package_name) {
|
||||||
//Make the package conform to Java package types
|
//Make the package conform to Java package types
|
||||||
//http://developer.android.com/guide/topics/manifest/manifest-element.html#package
|
//http://developer.android.com/guide/topics/manifest/manifest-element.html#package
|
||||||
//Enforce underscore limitation
|
//Enforce underscore limitation
|
||||||
var msg = 'Error validating package name. ';
|
var msg = 'Error validating package name. ';
|
||||||
if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
|
if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
|
||||||
return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name'));
|
return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name'));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Class is a reserved word
|
//Class is a reserved word
|
||||||
if(/\b[Cc]lass\b/.test(package_name)) {
|
if(/\b[Cc]lass\b/.test(package_name)) {
|
||||||
return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
|
return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Q.resolve();
|
return Q.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether a project name is acceptable for use as an android class.
|
* Test whether a project name is acceptable for use as an android class.
|
||||||
* Returns a promise, fulfilled if the project name is acceptable; rejected
|
* Returns a promise, fulfilled if the project name is acceptable; rejected
|
||||||
* otherwise.
|
* otherwise.
|
||||||
*/
|
*/
|
||||||
function validateProjectName(project_name) {
|
function validateProjectName(project_name) {
|
||||||
var msg = 'Error validating project name. ';
|
var msg = 'Error validating project name. ';
|
||||||
//Make sure there's something there
|
//Make sure there's something there
|
||||||
if (project_name === '') {
|
if (project_name === '') {
|
||||||
return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
|
return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Enforce stupid name error
|
//Enforce stupid name error
|
||||||
if (project_name === 'CordovaActivity') {
|
if (project_name === 'CordovaActivity') {
|
||||||
return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
|
return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
|
||||||
}
|
}
|
||||||
|
|
||||||
//Classes in Java don't begin with numbers
|
//Classes in Java don't begin with numbers
|
||||||
if (/^[0-9]/.test(project_name)) {
|
if (/^[0-9]/.test(project_name)) {
|
||||||
return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
|
return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
|
||||||
}
|
}
|
||||||
|
|
||||||
return Q.resolve();
|
return Q.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates an android application with the given options.
|
* Creates an android application with the given options.
|
||||||
*
|
*
|
||||||
* @param {String} project_path Path to the new Cordova android project.
|
* @param {String} project_path Path to the new Cordova android project.
|
||||||
* @param {ConfigParser} config Instance of ConfigParser to retrieve basic
|
* @param {ConfigParser} config Instance of ConfigParser to retrieve basic
|
||||||
* project properties.
|
* project properties.
|
||||||
* @param {Object} [options={}] Various options
|
* @param {Object} [options={}] Various options
|
||||||
* @param {String} [options.activityName='MainActivity'] Name for the
|
* @param {String} [options.activityName='MainActivity'] Name for the
|
||||||
* activity
|
* activity
|
||||||
* @param {Boolean} [options.link=false] Specifies whether javascript files
|
* @param {Boolean} [options.link=false] Specifies whether javascript files
|
||||||
* and CordovaLib framework will be symlinked to created application.
|
* and CordovaLib framework will be symlinked to created application.
|
||||||
* @param {String} [options.customTemplate] Path to project template
|
* @param {String} [options.customTemplate] Path to project template
|
||||||
* (override)
|
* (override)
|
||||||
* @param {EventEmitter} [events] An EventEmitter instance for logging
|
* @param {EventEmitter} [events] An EventEmitter instance for logging
|
||||||
* events
|
* events
|
||||||
*
|
*
|
||||||
* @return {Promise<String>} Directory where application has been created
|
* @return {Promise<String>} Directory where application has been created
|
||||||
*/
|
*/
|
||||||
exports.create = function(project_path, config, options, events) {
|
exports.create = function(project_path, config, options, events) {
|
||||||
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
// Set default values for path, package and name
|
// Set default values for path, package and name
|
||||||
project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
|
project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
|
||||||
// Check if project already exists
|
// Check if project already exists
|
||||||
if(fs.existsSync(project_path)) {
|
if(fs.existsSync(project_path)) {
|
||||||
return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
|
return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
|
||||||
}
|
}
|
||||||
|
|
||||||
var package_name = config.packageName() || 'my.cordova.project';
|
var package_name = config.packageName() || 'my.cordova.project';
|
||||||
var project_name = config.name() ?
|
var project_name = config.name() ?
|
||||||
config.name().replace(/[^\w.]/g,'_') : 'CordovaExample';
|
config.name().replace(/[^\w.]/g,'_') : 'CordovaExample';
|
||||||
|
|
||||||
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
|
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
|
||||||
var target_api = check_reqs.get_target();
|
var target_api = check_reqs.get_target();
|
||||||
|
|
||||||
//Make the package conform to Java package types
|
//Make the package conform to Java package types
|
||||||
return validatePackageName(package_name)
|
return validatePackageName(package_name)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
validateProjectName(project_name);
|
validateProjectName(project_name);
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
// Log the given values for the project
|
// Log the given values for the project
|
||||||
events.emit('log', 'Creating Cordova project for the Android platform:');
|
events.emit('log', 'Creating Cordova project for the Android platform:');
|
||||||
events.emit('log', '\tPath: ' + project_path);
|
events.emit('log', '\tPath: ' + project_path);
|
||||||
events.emit('log', '\tPackage: ' + package_name);
|
events.emit('log', '\tPackage: ' + package_name);
|
||||||
events.emit('log', '\tName: ' + project_name);
|
events.emit('log', '\tName: ' + project_name);
|
||||||
events.emit('log', '\tActivity: ' + safe_activity_name);
|
events.emit('log', '\tActivity: ' + safe_activity_name);
|
||||||
events.emit('log', '\tAndroid target: ' + target_api);
|
events.emit('log', '\tAndroid target: ' + target_api);
|
||||||
|
|
||||||
events.emit('verbose', 'Copying template files...');
|
events.emit('verbose', 'Copying template files...');
|
||||||
|
|
||||||
setShellFatal(true, function() {
|
setShellFatal(true, function() {
|
||||||
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
|
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
|
||||||
// copy project template
|
// copy project template
|
||||||
shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
|
shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
|
||||||
shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
|
shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
|
||||||
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
|
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).
|
// 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(project_path, 'libs'));
|
||||||
|
|
||||||
// copy cordova.js, cordova.jar
|
// copy cordova.js, cordova.jar
|
||||||
copyJsAndLibrary(project_path, options.link, safe_activity_name);
|
copyJsAndLibrary(project_path, options.link, safe_activity_name);
|
||||||
|
|
||||||
// interpolate the activity name and package
|
// interpolate the activity name and package
|
||||||
var packagePath = package_name.replace(/\./g, path.sep);
|
var packagePath = package_name.replace(/\./g, path.sep);
|
||||||
var activity_dir = path.join(project_path, 'src', packagePath);
|
var activity_dir = path.join(project_path, 'src', packagePath);
|
||||||
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
|
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
|
||||||
shell.mkdir('-p', activity_dir);
|
shell.mkdir('-p', activity_dir);
|
||||||
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
|
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
|
||||||
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, 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(project_path, 'res', 'values', 'strings.xml'));
|
||||||
shell.sed('-i', /__ID__/, package_name, activity_path);
|
shell.sed('-i', /__ID__/, package_name, activity_path);
|
||||||
|
|
||||||
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
|
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
|
||||||
manifest.setPackageId(package_name)
|
manifest.setPackageId(package_name)
|
||||||
.setTargetSdkVersion(target_api.split('-')[1])
|
.setTargetSdkVersion(target_api.split('-')[1])
|
||||||
.getActivity().setName(safe_activity_name);
|
.getActivity().setName(safe_activity_name);
|
||||||
|
|
||||||
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
|
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
|
||||||
manifest.write(manifest_path);
|
manifest.write(manifest_path);
|
||||||
|
|
||||||
copyScripts(project_path);
|
copyScripts(project_path);
|
||||||
copyBuildRules(project_path);
|
copyBuildRules(project_path);
|
||||||
});
|
});
|
||||||
// Link it to local android install.
|
// Link it to local android install.
|
||||||
writeProjectProperties(project_path, target_api);
|
writeProjectProperties(project_path, target_api);
|
||||||
prepBuildFiles(project_path);
|
prepBuildFiles(project_path);
|
||||||
events.emit('log', generateDoneMessage('create', options.link));
|
events.emit('log', generateDoneMessage('create', options.link));
|
||||||
}).thenResolve(project_path);
|
}).thenResolve(project_path);
|
||||||
};
|
};
|
||||||
|
|
||||||
function generateDoneMessage(type, link) {
|
function generateDoneMessage(type, link) {
|
||||||
var pkg = require('../../package');
|
var pkg = require('../../package');
|
||||||
var msg = 'Android project ' + (type == 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
|
var msg = 'Android project ' + (type == 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
|
||||||
if (link) {
|
if (link) {
|
||||||
msg += ' and has a linked CordovaLib';
|
msg += ' and has a linked CordovaLib';
|
||||||
}
|
}
|
||||||
return msg;
|
return msg;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
exports.update = function(projectPath, options, events) {
|
exports.update = function(projectPath, options, events) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
return Q()
|
return Q()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
|
|
||||||
var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
|
var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
|
||||||
|
|
||||||
if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
|
if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
|
||||||
events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
|
events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
|
||||||
manifest.setMinSDKVersion(MIN_SDK_VERSION);
|
manifest.setMinSDKVersion(MIN_SDK_VERSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
manifest.setDebuggable(false).write();
|
manifest.setDebuggable(false).write();
|
||||||
|
|
||||||
var projectName = manifest.getActivity().getName();
|
var projectName = manifest.getActivity().getName();
|
||||||
var target_api = check_reqs.get_target();
|
var target_api = check_reqs.get_target();
|
||||||
|
|
||||||
copyJsAndLibrary(projectPath, options.link, projectName);
|
copyJsAndLibrary(projectPath, options.link, projectName);
|
||||||
copyScripts(projectPath);
|
copyScripts(projectPath);
|
||||||
copyBuildRules(projectPath);
|
copyBuildRules(projectPath);
|
||||||
writeProjectProperties(projectPath, target_api);
|
writeProjectProperties(projectPath, target_api);
|
||||||
prepBuildFiles(projectPath);
|
prepBuildFiles(projectPath);
|
||||||
events.emit('log', generateDoneMessage('update', options.link));
|
events.emit('log', generateDoneMessage('update', options.link));
|
||||||
}).thenResolve(projectPath);
|
}).thenResolve(projectPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// For testing
|
// For testing
|
||||||
exports.validatePackageName = validatePackageName;
|
exports.validatePackageName = validatePackageName;
|
||||||
exports.validateProjectName = validateProjectName;
|
exports.validateProjectName = validateProjectName;
|
||||||
|
984
bin/templates/cordova/Api.js
vendored
984
bin/templates/cordova/Api.js
vendored
@ -1,492 +1,492 @@
|
|||||||
/**
|
/**
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Q = require('q');
|
var Q = require('q');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var shell = require('shelljs');
|
var shell = require('shelljs');
|
||||||
|
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
var PlatformJson = require('cordova-common').PlatformJson;
|
var PlatformJson = require('cordova-common').PlatformJson;
|
||||||
var ActionStack = require('cordova-common').ActionStack;
|
var ActionStack = require('cordova-common').ActionStack;
|
||||||
var AndroidProject = require('./lib/AndroidProject');
|
var AndroidProject = require('./lib/AndroidProject');
|
||||||
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
|
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
|
||||||
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
|
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
|
||||||
|
|
||||||
var ConsoleLogger = require('./lib/ConsoleLogger');
|
var ConsoleLogger = require('./lib/ConsoleLogger');
|
||||||
var pluginHandlers = require('./lib/pluginHandlers');
|
var pluginHandlers = require('./lib/pluginHandlers');
|
||||||
|
|
||||||
var PLATFORM = 'android';
|
var PLATFORM = 'android';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class, that acts as abstraction over particular platform. Encapsulates the
|
* Class, that acts as abstraction over particular platform. Encapsulates the
|
||||||
* platform's properties and methods.
|
* platform's properties and methods.
|
||||||
*
|
*
|
||||||
* Platform that implements own PlatformApi instance _should implement all
|
* Platform that implements own PlatformApi instance _should implement all
|
||||||
* prototype methods_ of this class to be fully compatible with cordova-lib.
|
* prototype methods_ of this class to be fully compatible with cordova-lib.
|
||||||
*
|
*
|
||||||
* The PlatformApi instance also should define the following field:
|
* The PlatformApi instance also should define the following field:
|
||||||
*
|
*
|
||||||
* * platform: String that defines a platform name.
|
* * platform: String that defines a platform name.
|
||||||
*/
|
*/
|
||||||
function Api(platform, platformRootDir, events) {
|
function Api(platform, platformRootDir, events) {
|
||||||
this.platform = PLATFORM;
|
this.platform = PLATFORM;
|
||||||
this.root = path.resolve(__dirname, '..');
|
this.root = path.resolve(__dirname, '..');
|
||||||
this.events = events || ConsoleLogger.get();
|
this.events = events || ConsoleLogger.get();
|
||||||
// NOTE: trick to share one EventEmitter instance across all js code
|
// NOTE: trick to share one EventEmitter instance across all js code
|
||||||
require('cordova-common').events = this.events;
|
require('cordova-common').events = this.events;
|
||||||
|
|
||||||
this._platformJson = PlatformJson.load(this.root, platform);
|
this._platformJson = PlatformJson.load(this.root, platform);
|
||||||
this._pluginInfoProvider = new PluginInfoProvider();
|
this._pluginInfoProvider = new PluginInfoProvider();
|
||||||
this._munger = new PlatformMunger(this.platform, this.root, this._platformJson, this._pluginInfoProvider);
|
this._munger = new PlatformMunger(this.platform, this.root, this._platformJson, this._pluginInfoProvider);
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this.locations = {
|
this.locations = {
|
||||||
root: self.root,
|
root: self.root,
|
||||||
www: path.join(self.root, 'assets/www'),
|
www: path.join(self.root, 'assets/www'),
|
||||||
platformWww: path.join(self.root, 'platform_www'),
|
platformWww: path.join(self.root, 'platform_www'),
|
||||||
configXml: path.join(self.root, 'res/xml/config.xml'),
|
configXml: path.join(self.root, 'res/xml/config.xml'),
|
||||||
defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),
|
defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),
|
||||||
strings: path.join(self.root, 'res/values/strings.xml'),
|
strings: path.join(self.root, 'res/values/strings.xml'),
|
||||||
manifest: path.join(self.root, 'AndroidManifest.xml'),
|
manifest: path.join(self.root, 'AndroidManifest.xml'),
|
||||||
// NOTE: Due to platformApi spec we need to return relative paths here
|
// NOTE: Due to platformApi spec we need to return relative paths here
|
||||||
cordovaJs: 'bin/templates/project/assets/www/cordova.js',
|
cordovaJs: 'bin/templates/project/assets/www/cordova.js',
|
||||||
cordovaJsSrc: 'cordova-js-src'
|
cordovaJsSrc: 'cordova-js-src'
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs platform to specified directory and creates a platform project.
|
* Installs platform to specified directory and creates a platform project.
|
||||||
*
|
*
|
||||||
* @param {String} destination Destination directory, where insatll platform to
|
* @param {String} destination Destination directory, where insatll platform to
|
||||||
* @param {ConfigParser} [config] ConfgiParser instance, used to retrieve
|
* @param {ConfigParser} [config] ConfgiParser instance, used to retrieve
|
||||||
* project creation options, such as package id and project name.
|
* project creation options, such as package id and project name.
|
||||||
* @param {Object} [options] An options object. The most common options are:
|
* @param {Object} [options] An options object. The most common options are:
|
||||||
* @param {String} [options.customTemplate] A path to custom template, that
|
* @param {String} [options.customTemplate] A path to custom template, that
|
||||||
* should override the default one from platform.
|
* should override the default one from platform.
|
||||||
* @param {Boolean} [options.link] Flag that indicates that platform's
|
* @param {Boolean} [options.link] Flag that indicates that platform's
|
||||||
* sources will be linked to installed platform instead of copying.
|
* sources will be linked to installed platform instead of copying.
|
||||||
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
|
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
|
||||||
* logging purposes. If no EventEmitter provided, all events will be logged to
|
* logging purposes. If no EventEmitter provided, all events will be logged to
|
||||||
* console
|
* console
|
||||||
*
|
*
|
||||||
* @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
|
* @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
|
||||||
* instance or rejected with CordovaError.
|
* instance or rejected with CordovaError.
|
||||||
*/
|
*/
|
||||||
Api.createPlatform = function (destination, config, options, events) {
|
Api.createPlatform = function (destination, config, options, events) {
|
||||||
return require('../../lib/create')
|
return require('../../lib/create')
|
||||||
.create(destination, config, options, events || ConsoleLogger.get())
|
.create(destination, config, options, events || ConsoleLogger.get())
|
||||||
.then(function (destination) {
|
.then(function (destination) {
|
||||||
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
||||||
return new PlatformApi(PLATFORM, destination, events);
|
return new PlatformApi(PLATFORM, destination, events);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates already installed platform.
|
* Updates already installed platform.
|
||||||
*
|
*
|
||||||
* @param {String} destination Destination directory, where platform installed
|
* @param {String} destination Destination directory, where platform installed
|
||||||
* @param {Object} [options] An options object. The most common options are:
|
* @param {Object} [options] An options object. The most common options are:
|
||||||
* @param {String} [options.customTemplate] A path to custom template, that
|
* @param {String} [options.customTemplate] A path to custom template, that
|
||||||
* should override the default one from platform.
|
* should override the default one from platform.
|
||||||
* @param {Boolean} [options.link] Flag that indicates that platform's
|
* @param {Boolean} [options.link] Flag that indicates that platform's
|
||||||
* sources will be linked to installed platform instead of copying.
|
* sources will be linked to installed platform instead of copying.
|
||||||
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
|
* @param {EventEmitter} [events] An EventEmitter instance that will be used for
|
||||||
* logging purposes. If no EventEmitter provided, all events will be logged to
|
* logging purposes. If no EventEmitter provided, all events will be logged to
|
||||||
* console
|
* console
|
||||||
*
|
*
|
||||||
* @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
|
* @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
|
||||||
* instance or rejected with CordovaError.
|
* instance or rejected with CordovaError.
|
||||||
*/
|
*/
|
||||||
Api.updatePlatform = function (destination, options, events) {
|
Api.updatePlatform = function (destination, options, events) {
|
||||||
return require('../../lib/create')
|
return require('../../lib/create')
|
||||||
.update(destination, options, events || ConsoleLogger.get())
|
.update(destination, options, events || ConsoleLogger.get())
|
||||||
.then(function (destination) {
|
.then(function (destination) {
|
||||||
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
||||||
return new PlatformApi('android', destination, events);
|
return new PlatformApi('android', destination, events);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a CordovaPlatform object, that represents the platform structure.
|
* Gets a CordovaPlatform object, that represents the platform structure.
|
||||||
*
|
*
|
||||||
* @return {CordovaPlatform} A structure that contains the description of
|
* @return {CordovaPlatform} A structure that contains the description of
|
||||||
* platform's file structure and other properties of platform.
|
* platform's file structure and other properties of platform.
|
||||||
*/
|
*/
|
||||||
Api.prototype.getPlatformInfo = function () {
|
Api.prototype.getPlatformInfo = function () {
|
||||||
var result = {};
|
var result = {};
|
||||||
result.locations = this.locations;
|
result.locations = this.locations;
|
||||||
result.root = this.root;
|
result.root = this.root;
|
||||||
result.name = this.platform;
|
result.name = this.platform;
|
||||||
result.version = require('./version');
|
result.version = require('./version');
|
||||||
result.projectConfig = this._config;
|
result.projectConfig = this._config;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates installed platform with provided www assets and new app
|
* Updates installed platform with provided www assets and new app
|
||||||
* configuration. This method is required for CLI workflow and will be called
|
* configuration. This method is required for CLI workflow and will be called
|
||||||
* each time before build, so the changes, made to app configuration and www
|
* each time before build, so the changes, made to app configuration and www
|
||||||
* code, will be applied to platform.
|
* code, will be applied to platform.
|
||||||
*
|
*
|
||||||
* @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
|
* @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
|
||||||
* project structure and configuration, that should be applied to platform
|
* project structure and configuration, that should be applied to platform
|
||||||
* (contains project's www location and ConfigParser instance for project's
|
* (contains project's www location and ConfigParser instance for project's
|
||||||
* config).
|
* config).
|
||||||
*
|
*
|
||||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||||
* CordovaError instance.
|
* CordovaError instance.
|
||||||
*/
|
*/
|
||||||
Api.prototype.prepare = function (cordovaProject) {
|
Api.prototype.prepare = function (cordovaProject) {
|
||||||
return require('./lib/prepare').prepare.call(this, cordovaProject);
|
return require('./lib/prepare').prepare.call(this, cordovaProject);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs a new plugin into platform. This method only copies non-www files
|
* Installs a new plugin into platform. This method only copies non-www files
|
||||||
* (sources, libs, etc.) to platform. It also doesn't resolves the
|
* (sources, libs, etc.) to platform. It also doesn't resolves the
|
||||||
* dependencies of plugin. Both of handling of www files, such as assets and
|
* dependencies of plugin. Both of handling of www files, such as assets and
|
||||||
* js-files and resolving dependencies are the responsibility of caller.
|
* js-files and resolving dependencies are the responsibility of caller.
|
||||||
*
|
*
|
||||||
* @param {PluginInfo} plugin A PluginInfo instance that represents plugin
|
* @param {PluginInfo} plugin A PluginInfo instance that represents plugin
|
||||||
* that will be installed.
|
* that will be installed.
|
||||||
* @param {Object} installOptions An options object. Possible options below:
|
* @param {Object} installOptions An options object. Possible options below:
|
||||||
* @param {Boolean} installOptions.link: Flag that specifies that plugin
|
* @param {Boolean} installOptions.link: Flag that specifies that plugin
|
||||||
* sources will be symlinked to app's directory instead of copying (if
|
* sources will be symlinked to app's directory instead of copying (if
|
||||||
* possible).
|
* possible).
|
||||||
* @param {Object} installOptions.variables An object that represents
|
* @param {Object} installOptions.variables An object that represents
|
||||||
* variables that will be used to install plugin. See more details on plugin
|
* variables that will be used to install plugin. See more details on plugin
|
||||||
* variables in documentation:
|
* variables in documentation:
|
||||||
* https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
|
* https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
|
||||||
*
|
*
|
||||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||||
* CordovaError instance.
|
* CordovaError instance.
|
||||||
*/
|
*/
|
||||||
Api.prototype.addPlugin = function (plugin, installOptions) {
|
Api.prototype.addPlugin = function (plugin, installOptions) {
|
||||||
|
|
||||||
if (!plugin || plugin.constructor.name !== 'PluginInfo')
|
if (!plugin || plugin.constructor.name !== 'PluginInfo')
|
||||||
return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
|
return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
|
||||||
|
|
||||||
installOptions = installOptions || {};
|
installOptions = installOptions || {};
|
||||||
installOptions.variables = installOptions.variables || {};
|
installOptions.variables = installOptions.variables || {};
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var actions = new ActionStack();
|
var actions = new ActionStack();
|
||||||
var project = AndroidProject.getProjectFile(this.root);
|
var project = AndroidProject.getProjectFile(this.root);
|
||||||
|
|
||||||
// gather all files needs to be handled during install
|
// gather all files needs to be handled during install
|
||||||
plugin.getFilesAndFrameworks(this.platform)
|
plugin.getFilesAndFrameworks(this.platform)
|
||||||
.concat(plugin.getAssets(this.platform))
|
.concat(plugin.getAssets(this.platform))
|
||||||
.concat(plugin.getJsModules(this.platform))
|
.concat(plugin.getJsModules(this.platform))
|
||||||
.forEach(function(item) {
|
.forEach(function(item) {
|
||||||
actions.push(actions.createAction(
|
actions.push(actions.createAction(
|
||||||
pluginHandlers.getInstaller(item.itemType), [item, plugin, project, installOptions],
|
pluginHandlers.getInstaller(item.itemType), [item, plugin, project, installOptions],
|
||||||
pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, installOptions]));
|
pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, installOptions]));
|
||||||
});
|
});
|
||||||
|
|
||||||
// run through the action stack
|
// run through the action stack
|
||||||
return actions.process(this.platform)
|
return actions.process(this.platform)
|
||||||
.then(function () {
|
.then(function () {
|
||||||
if (project) {
|
if (project) {
|
||||||
project.write();
|
project.write();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add PACKAGE_NAME variable into vars
|
// Add PACKAGE_NAME variable into vars
|
||||||
if (!installOptions.variables.PACKAGE_NAME) {
|
if (!installOptions.variables.PACKAGE_NAME) {
|
||||||
installOptions.variables.PACKAGE_NAME = project.getPackageName();
|
installOptions.variables.PACKAGE_NAME = project.getPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
self._munger
|
self._munger
|
||||||
// Ignore passed `is_top_level` option since platform itself doesn't know
|
// Ignore passed `is_top_level` option since platform itself doesn't know
|
||||||
// anything about managing dependencies - it's responsibility of caller.
|
// anything about managing dependencies - it's responsibility of caller.
|
||||||
.add_plugin_changes(plugin, installOptions.variables, /*is_top_level=*/true, /*should_increment=*/true)
|
.add_plugin_changes(plugin, installOptions.variables, /*is_top_level=*/true, /*should_increment=*/true)
|
||||||
.save_all();
|
.save_all();
|
||||||
|
|
||||||
var targetDir = installOptions.usePlatformWww ?
|
var targetDir = installOptions.usePlatformWww ?
|
||||||
self.locations.platformWww :
|
self.locations.platformWww :
|
||||||
self.locations.www;
|
self.locations.www;
|
||||||
|
|
||||||
self._addModulesInfo(plugin, targetDir);
|
self._addModulesInfo(plugin, targetDir);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes an installed plugin from platform.
|
* Removes an installed plugin from platform.
|
||||||
*
|
*
|
||||||
* Since method accepts PluginInfo instance as input parameter instead of plugin
|
* Since method accepts PluginInfo instance as input parameter instead of plugin
|
||||||
* id, caller shoud take care of managing/storing PluginInfo instances for
|
* id, caller shoud take care of managing/storing PluginInfo instances for
|
||||||
* future uninstalls.
|
* future uninstalls.
|
||||||
*
|
*
|
||||||
* @param {PluginInfo} plugin A PluginInfo instance that represents plugin
|
* @param {PluginInfo} plugin A PluginInfo instance that represents plugin
|
||||||
* that will be installed.
|
* that will be installed.
|
||||||
*
|
*
|
||||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||||
* CordovaError instance.
|
* CordovaError instance.
|
||||||
*/
|
*/
|
||||||
Api.prototype.removePlugin = function (plugin, uninstallOptions) {
|
Api.prototype.removePlugin = function (plugin, uninstallOptions) {
|
||||||
|
|
||||||
if (!plugin || plugin.constructor.name !== 'PluginInfo')
|
if (!plugin || plugin.constructor.name !== 'PluginInfo')
|
||||||
return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
|
return Q.reject(new CordovaError('The parameter is incorrect. The first parameter to addPlugin should be a PluginInfo instance'));
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var actions = new ActionStack();
|
var actions = new ActionStack();
|
||||||
var project = AndroidProject.getProjectFile(this.root);
|
var project = AndroidProject.getProjectFile(this.root);
|
||||||
|
|
||||||
// queue up plugin files
|
// queue up plugin files
|
||||||
plugin.getFilesAndFrameworks(this.platform)
|
plugin.getFilesAndFrameworks(this.platform)
|
||||||
.concat(plugin.getAssets(this.platform))
|
.concat(plugin.getAssets(this.platform))
|
||||||
.concat(plugin.getJsModules(this.platform))
|
.concat(plugin.getJsModules(this.platform))
|
||||||
.forEach(function(item) {
|
.forEach(function(item) {
|
||||||
actions.push(actions.createAction(
|
actions.push(actions.createAction(
|
||||||
pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, uninstallOptions],
|
pluginHandlers.getUninstaller(item.itemType), [item, plugin, project, uninstallOptions],
|
||||||
pluginHandlers.getInstaller(item.itemType), [item, plugin, project, uninstallOptions]));
|
pluginHandlers.getInstaller(item.itemType), [item, plugin, project, uninstallOptions]));
|
||||||
});
|
});
|
||||||
|
|
||||||
// run through the action stack
|
// run through the action stack
|
||||||
return actions.process(this.platform)
|
return actions.process(this.platform)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (project) {
|
if (project) {
|
||||||
project.write();
|
project.write();
|
||||||
}
|
}
|
||||||
|
|
||||||
self._munger
|
self._munger
|
||||||
// Ignore passed `is_top_level` option since platform itself doesn't know
|
// Ignore passed `is_top_level` option since platform itself doesn't know
|
||||||
// anything about managing dependencies - it's responsibility of caller.
|
// anything about managing dependencies - it's responsibility of caller.
|
||||||
.remove_plugin_changes(plugin, /*is_top_level=*/true)
|
.remove_plugin_changes(plugin, /*is_top_level=*/true)
|
||||||
.save_all();
|
.save_all();
|
||||||
|
|
||||||
var targetDir = uninstallOptions.usePlatformWww ?
|
var targetDir = uninstallOptions.usePlatformWww ?
|
||||||
self.locations.platformWww :
|
self.locations.platformWww :
|
||||||
self.locations.www;
|
self.locations.www;
|
||||||
|
|
||||||
self._removeModulesInfo(plugin, targetDir);
|
self._removeModulesInfo(plugin, targetDir);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an application package for current platform.
|
* Builds an application package for current platform.
|
||||||
*
|
*
|
||||||
* @param {Object} buildOptions A build options. This object's structure is
|
* @param {Object} buildOptions A build options. This object's structure is
|
||||||
* highly depends on platform's specific. The most common options are:
|
* highly depends on platform's specific. The most common options are:
|
||||||
* @param {Boolean} buildOptions.debug Indicates that packages should be
|
* @param {Boolean} buildOptions.debug Indicates that packages should be
|
||||||
* built with debug configuration. This is set to true by default unless the
|
* built with debug configuration. This is set to true by default unless the
|
||||||
* 'release' option is not specified.
|
* 'release' option is not specified.
|
||||||
* @param {Boolean} buildOptions.release Indicates that packages should be
|
* @param {Boolean} buildOptions.release Indicates that packages should be
|
||||||
* built with release configuration. If not set to true, debug configuration
|
* built with release configuration. If not set to true, debug configuration
|
||||||
* will be used.
|
* will be used.
|
||||||
* @param {Boolean} buildOptions.device Specifies that built app is intended
|
* @param {Boolean} buildOptions.device Specifies that built app is intended
|
||||||
* to run on device
|
* to run on device
|
||||||
* @param {Boolean} buildOptions.emulator: Specifies that built app is
|
* @param {Boolean} buildOptions.emulator: Specifies that built app is
|
||||||
* intended to run on emulator
|
* intended to run on emulator
|
||||||
* @param {String} buildOptions.target Specifies the device id that will be
|
* @param {String} buildOptions.target Specifies the device id that will be
|
||||||
* used to run built application.
|
* used to run built application.
|
||||||
* @param {Boolean} buildOptions.nobuild Indicates that this should be a
|
* @param {Boolean} buildOptions.nobuild Indicates that this should be a
|
||||||
* dry-run call, so no build artifacts will be produced.
|
* dry-run call, so no build artifacts will be produced.
|
||||||
* @param {String[]} buildOptions.archs Specifies chip architectures which
|
* @param {String[]} buildOptions.archs Specifies chip architectures which
|
||||||
* app packages should be built for. List of valid architectures is depends on
|
* app packages should be built for. List of valid architectures is depends on
|
||||||
* platform.
|
* platform.
|
||||||
* @param {String} buildOptions.buildConfig The path to build configuration
|
* @param {String} buildOptions.buildConfig The path to build configuration
|
||||||
* file. The format of this file is depends on platform.
|
* file. The format of this file is depends on platform.
|
||||||
* @param {String[]} buildOptions.argv Raw array of command-line arguments,
|
* @param {String[]} buildOptions.argv Raw array of command-line arguments,
|
||||||
* passed to `build` command. The purpose of this property is to pass a
|
* passed to `build` command. The purpose of this property is to pass a
|
||||||
* platform-specific arguments, and eventually let platform define own
|
* platform-specific arguments, and eventually let platform define own
|
||||||
* arguments processing logic.
|
* arguments processing logic.
|
||||||
*
|
*
|
||||||
* @return {Promise<Object[]>} A promise either fulfilled with an array of build
|
* @return {Promise<Object[]>} A promise either fulfilled with an array of build
|
||||||
* artifacts (application packages) if package was built successfully,
|
* artifacts (application packages) if package was built successfully,
|
||||||
* or rejected with CordovaError. The resultant build artifact objects is not
|
* or rejected with CordovaError. The resultant build artifact objects is not
|
||||||
* strictly typed and may conatin arbitrary set of fields as in sample below.
|
* strictly typed and may conatin arbitrary set of fields as in sample below.
|
||||||
*
|
*
|
||||||
* {
|
* {
|
||||||
* architecture: 'x86',
|
* architecture: 'x86',
|
||||||
* buildType: 'debug',
|
* buildType: 'debug',
|
||||||
* path: '/path/to/build',
|
* path: '/path/to/build',
|
||||||
* type: 'app'
|
* type: 'app'
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* The return value in most cases will contain only one item but in some cases
|
* The return value in most cases will contain only one item but in some cases
|
||||||
* there could be multiple items in output array, e.g. when multiple
|
* there could be multiple items in output array, e.g. when multiple
|
||||||
* arhcitectures is specified.
|
* arhcitectures is specified.
|
||||||
*/
|
*/
|
||||||
Api.prototype.build = function (buildOptions) {
|
Api.prototype.build = function (buildOptions) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return require('./lib/check_reqs').run()
|
return require('./lib/check_reqs').run()
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return require('./lib/build').run.call(self, buildOptions);
|
return require('./lib/build').run.call(self, buildOptions);
|
||||||
})
|
})
|
||||||
.then(function (buildResults) {
|
.then(function (buildResults) {
|
||||||
// Cast build result to array of build artifacts
|
// Cast build result to array of build artifacts
|
||||||
return buildResults.apkPaths.map(function (apkPath) {
|
return buildResults.apkPaths.map(function (apkPath) {
|
||||||
return {
|
return {
|
||||||
buildType: buildResults.buildType,
|
buildType: buildResults.buildType,
|
||||||
buildMethod: buildResults.buildMethod,
|
buildMethod: buildResults.buildMethod,
|
||||||
path: apkPath,
|
path: apkPath,
|
||||||
type: 'apk'
|
type: 'apk'
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds an application package for current platform and runs it on
|
* Builds an application package for current platform and runs it on
|
||||||
* specified/default device. If no 'device'/'emulator'/'target' options are
|
* specified/default device. If no 'device'/'emulator'/'target' options are
|
||||||
* specified, then tries to run app on default device if connected, otherwise
|
* specified, then tries to run app on default device if connected, otherwise
|
||||||
* runs the app on emulator.
|
* runs the app on emulator.
|
||||||
*
|
*
|
||||||
* @param {Object} runOptions An options object. The structure is the same
|
* @param {Object} runOptions An options object. The structure is the same
|
||||||
* as for build options.
|
* as for build options.
|
||||||
*
|
*
|
||||||
* @return {Promise} A promise either fulfilled if package was built and ran
|
* @return {Promise} A promise either fulfilled if package was built and ran
|
||||||
* successfully, or rejected with CordovaError.
|
* successfully, or rejected with CordovaError.
|
||||||
*/
|
*/
|
||||||
Api.prototype.run = function(runOptions) {
|
Api.prototype.run = function(runOptions) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return require('./lib/check_reqs').run()
|
return require('./lib/check_reqs').run()
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return require('./lib/run').run.call(self, runOptions);
|
return require('./lib/run').run.call(self, runOptions);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleans out the build artifacts from platform's directory.
|
* Cleans out the build artifacts from platform's directory.
|
||||||
*
|
*
|
||||||
* @return {Promise} Return a promise either fulfilled, or rejected with
|
* @return {Promise} Return a promise either fulfilled, or rejected with
|
||||||
* CordovaError.
|
* CordovaError.
|
||||||
*/
|
*/
|
||||||
Api.prototype.clean = function(cleanOptions) {
|
Api.prototype.clean = function(cleanOptions) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return require('./lib/check_reqs').run()
|
return require('./lib/check_reqs').run()
|
||||||
.then(function () {
|
.then(function () {
|
||||||
return require('./lib/build').runClean.call(self, cleanOptions);
|
return require('./lib/build').runClean.call(self, cleanOptions);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a requirements check for current platform. Each platform defines its
|
* Performs a requirements check for current platform. Each platform defines its
|
||||||
* own set of requirements, which should be resolved before platform can be
|
* own set of requirements, which should be resolved before platform can be
|
||||||
* built successfully.
|
* built successfully.
|
||||||
*
|
*
|
||||||
* @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
|
* @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
|
||||||
* objects for current platform.
|
* objects for current platform.
|
||||||
*/
|
*/
|
||||||
Api.prototype.requirements = function() {
|
Api.prototype.requirements = function() {
|
||||||
return require('./lib/check_reqs').check_all();
|
return require('./lib/check_reqs').check_all();
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Api;
|
module.exports = Api;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the specified modules from list of installed modules and updates
|
* Removes the specified modules from list of installed modules and updates
|
||||||
* platform_json and cordova_plugins.js on disk.
|
* platform_json and cordova_plugins.js on disk.
|
||||||
*
|
*
|
||||||
* @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
|
* @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
|
||||||
* needs to be added.
|
* needs to be added.
|
||||||
* @param {String} targetDir The directory, where updated cordova_plugins.js
|
* @param {String} targetDir The directory, where updated cordova_plugins.js
|
||||||
* should be written to.
|
* should be written to.
|
||||||
*/
|
*/
|
||||||
Api.prototype._addModulesInfo = function(plugin, targetDir) {
|
Api.prototype._addModulesInfo = function(plugin, targetDir) {
|
||||||
var installedModules = this._platformJson.root.modules || [];
|
var installedModules = this._platformJson.root.modules || [];
|
||||||
|
|
||||||
var installedPaths = installedModules.map(function (installedModule) {
|
var installedPaths = installedModules.map(function (installedModule) {
|
||||||
return installedModule.file;
|
return installedModule.file;
|
||||||
});
|
});
|
||||||
|
|
||||||
var modulesToInstall = plugin.getJsModules(this.platform)
|
var modulesToInstall = plugin.getJsModules(this.platform)
|
||||||
.filter(function (moduleToInstall) {
|
.filter(function (moduleToInstall) {
|
||||||
return installedPaths.indexOf(moduleToInstall.file) === -1;
|
return installedPaths.indexOf(moduleToInstall.file) === -1;
|
||||||
}).map(function (moduleToInstall) {
|
}).map(function (moduleToInstall) {
|
||||||
var moduleName = plugin.id + '.' + ( moduleToInstall.name || moduleToInstall.src.match(/([^\/]+)\.js/)[1] );
|
var moduleName = plugin.id + '.' + ( moduleToInstall.name || moduleToInstall.src.match(/([^\/]+)\.js/)[1] );
|
||||||
var obj = {
|
var obj = {
|
||||||
file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
|
file: ['plugins', plugin.id, moduleToInstall.src].join('/'),
|
||||||
id: moduleName
|
id: moduleName
|
||||||
};
|
};
|
||||||
if (moduleToInstall.clobbers.length > 0) {
|
if (moduleToInstall.clobbers.length > 0) {
|
||||||
obj.clobbers = moduleToInstall.clobbers.map(function(o) { return o.target; });
|
obj.clobbers = moduleToInstall.clobbers.map(function(o) { return o.target; });
|
||||||
}
|
}
|
||||||
if (moduleToInstall.merges.length > 0) {
|
if (moduleToInstall.merges.length > 0) {
|
||||||
obj.merges = moduleToInstall.merges.map(function(o) { return o.target; });
|
obj.merges = moduleToInstall.merges.map(function(o) { return o.target; });
|
||||||
}
|
}
|
||||||
if (moduleToInstall.runs) {
|
if (moduleToInstall.runs) {
|
||||||
obj.runs = true;
|
obj.runs = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
});
|
});
|
||||||
|
|
||||||
this._platformJson.root.modules = installedModules.concat(modulesToInstall);
|
this._platformJson.root.modules = installedModules.concat(modulesToInstall);
|
||||||
this._writePluginModules(targetDir);
|
this._writePluginModules(targetDir);
|
||||||
this._platformJson.save();
|
this._platformJson.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Removes the specified modules from list of installed modules and updates
|
* Removes the specified modules from list of installed modules and updates
|
||||||
* platform_json and cordova_plugins.js on disk.
|
* platform_json and cordova_plugins.js on disk.
|
||||||
*
|
*
|
||||||
* @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
|
* @param {PluginInfo} plugin PluginInfo instance for plugin, which modules
|
||||||
* needs to be removed.
|
* needs to be removed.
|
||||||
* @param {String} targetDir The directory, where updated cordova_plugins.js
|
* @param {String} targetDir The directory, where updated cordova_plugins.js
|
||||||
* should be written to.
|
* should be written to.
|
||||||
*/
|
*/
|
||||||
Api.prototype._removeModulesInfo = function(plugin, targetDir) {
|
Api.prototype._removeModulesInfo = function(plugin, targetDir) {
|
||||||
var installedModules = this._platformJson.root.modules || [];
|
var installedModules = this._platformJson.root.modules || [];
|
||||||
var modulesToRemove = plugin.getJsModules(this.platform)
|
var modulesToRemove = plugin.getJsModules(this.platform)
|
||||||
.map(function (jsModule) {
|
.map(function (jsModule) {
|
||||||
return ['plugins', plugin.id, jsModule.src].join('/');
|
return ['plugins', plugin.id, jsModule.src].join('/');
|
||||||
});
|
});
|
||||||
|
|
||||||
var updatedModules = installedModules
|
var updatedModules = installedModules
|
||||||
.filter(function (installedModule) {
|
.filter(function (installedModule) {
|
||||||
return (modulesToRemove.indexOf(installedModule.file) === -1);
|
return (modulesToRemove.indexOf(installedModule.file) === -1);
|
||||||
});
|
});
|
||||||
|
|
||||||
this._platformJson.root.modules = updatedModules;
|
this._platformJson.root.modules = updatedModules;
|
||||||
this._writePluginModules(targetDir);
|
this._writePluginModules(targetDir);
|
||||||
this._platformJson.save();
|
this._platformJson.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches all installed modules, generates cordova_plugins contents and writes
|
* Fetches all installed modules, generates cordova_plugins contents and writes
|
||||||
* it to file.
|
* it to file.
|
||||||
*
|
*
|
||||||
* @param {String} targetDir Directory, where write cordova_plugins.js to.
|
* @param {String} targetDir Directory, where write cordova_plugins.js to.
|
||||||
* Ususally it is either <platform>/www or <platform>/platform_www
|
* Ususally it is either <platform>/www or <platform>/platform_www
|
||||||
* directories.
|
* directories.
|
||||||
*/
|
*/
|
||||||
Api.prototype._writePluginModules = function (targetDir) {
|
Api.prototype._writePluginModules = function (targetDir) {
|
||||||
var self = this;
|
var self = this;
|
||||||
// Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
|
// Write out moduleObjects as JSON wrapped in a cordova module to cordova_plugins.js
|
||||||
var final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
|
var final_contents = 'cordova.define(\'cordova/plugin_list\', function(require, exports, module) {\n';
|
||||||
final_contents += 'module.exports = ' + JSON.stringify(this._platformJson.root.modules, null, ' ') + ';\n';
|
final_contents += 'module.exports = ' + JSON.stringify(this._platformJson.root.modules, null, ' ') + ';\n';
|
||||||
final_contents += 'module.exports.metadata = \n';
|
final_contents += 'module.exports.metadata = \n';
|
||||||
final_contents += '// TOP OF METADATA\n';
|
final_contents += '// TOP OF METADATA\n';
|
||||||
|
|
||||||
var pluginMetadata = Object.keys(this._platformJson.root.installed_plugins)
|
var pluginMetadata = Object.keys(this._platformJson.root.installed_plugins)
|
||||||
.reduce(function (metadata, plugin) {
|
.reduce(function (metadata, plugin) {
|
||||||
metadata[plugin] = self._platformJson.root.installed_plugins[plugin].version;
|
metadata[plugin] = self._platformJson.root.installed_plugins[plugin].version;
|
||||||
return metadata;
|
return metadata;
|
||||||
}, {});
|
}, {});
|
||||||
|
|
||||||
final_contents += JSON.stringify(pluginMetadata, null, 4) + '\n';
|
final_contents += JSON.stringify(pluginMetadata, null, 4) + '\n';
|
||||||
final_contents += '// BOTTOM OF METADATA\n';
|
final_contents += '// BOTTOM OF METADATA\n';
|
||||||
final_contents += '});'; // Close cordova.define.
|
final_contents += '});'; // Close cordova.define.
|
||||||
|
|
||||||
shell.mkdir('-p', targetDir);
|
shell.mkdir('-p', targetDir);
|
||||||
fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
|
fs.writeFileSync(path.join(targetDir, 'cordova_plugins.js'), final_contents, 'utf-8');
|
||||||
};
|
};
|
||||||
|
156
bin/templates/cordova/lib/Adb.js
vendored
156
bin/templates/cordova/lib/Adb.js
vendored
@ -1,78 +1,78 @@
|
|||||||
|
|
||||||
var Q = require('q');
|
var Q = require('q');
|
||||||
var os = require('os');
|
var os = require('os');
|
||||||
var events = require('cordova-common').events;
|
var events = require('cordova-common').events;
|
||||||
var spawn = require('cordova-common').superspawn.spawn;
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
var Adb = {};
|
var Adb = {};
|
||||||
|
|
||||||
function isDevice(line) {
|
function isDevice(line) {
|
||||||
return line.match(/\w+\tdevice/) && !line.match(/emulator/);
|
return line.match(/\w+\tdevice/) && !line.match(/emulator/);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isEmulator(line) {
|
function isEmulator(line) {
|
||||||
return line.match(/device/) && line.match(/emulator/);
|
return line.match(/device/) && line.match(/emulator/);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists available/connected devices and emulators
|
* Lists available/connected devices and emulators
|
||||||
*
|
*
|
||||||
* @param {Object} opts Various options
|
* @param {Object} opts Various options
|
||||||
* @param {Boolean} opts.emulators Specifies whether this method returns
|
* @param {Boolean} opts.emulators Specifies whether this method returns
|
||||||
* emulators only
|
* emulators only
|
||||||
*
|
*
|
||||||
* @return {Promise<String[]>} list of available/connected
|
* @return {Promise<String[]>} list of available/connected
|
||||||
* devices/emulators
|
* devices/emulators
|
||||||
*/
|
*/
|
||||||
Adb.devices = function (opts) {
|
Adb.devices = function (opts) {
|
||||||
return spawn('adb', ['devices'], {cwd: os.tmpdir()})
|
return spawn('adb', ['devices'], {cwd: os.tmpdir()})
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
return output.split('\n').filter(function (line) {
|
return output.split('\n').filter(function (line) {
|
||||||
// Filter out either real devices or emulators, depending on options
|
// Filter out either real devices or emulators, depending on options
|
||||||
return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
|
return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
|
||||||
}).map(function (line) {
|
}).map(function (line) {
|
||||||
return line.replace(/\tdevice/, '').replace('\r', '');
|
return line.replace(/\tdevice/, '').replace('\r', '');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Adb.install = function (target, packagePath, opts) {
|
Adb.install = function (target, packagePath, opts) {
|
||||||
events.emit('verbose', 'Installing apk ' + packagePath + ' on ' + target + '...');
|
events.emit('verbose', 'Installing apk ' + packagePath + ' on ' + target + '...');
|
||||||
var args = ['-s', target, 'install'];
|
var args = ['-s', target, 'install'];
|
||||||
if (opts && opts.replace) args.push('-r');
|
if (opts && opts.replace) args.push('-r');
|
||||||
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
|
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
// 'adb install' seems to always returns no error, even if installation fails
|
// 'adb install' seems to always returns no error, even if installation fails
|
||||||
// so we catching output to detect installation failure
|
// so we catching output to detect installation failure
|
||||||
if (output.match(/Failure/))
|
if (output.match(/Failure/))
|
||||||
return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
|
return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Adb.uninstall = function (target, packageId) {
|
Adb.uninstall = function (target, packageId) {
|
||||||
events.emit('verbose', 'Uninstalling ' + packageId + ' from ' + target + '...');
|
events.emit('verbose', 'Uninstalling ' + packageId + ' from ' + target + '...');
|
||||||
return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
|
return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
|
||||||
};
|
};
|
||||||
|
|
||||||
Adb.shell = function (target, shellCommand) {
|
Adb.shell = function (target, shellCommand) {
|
||||||
events.emit('verbose', 'Running command "' + shellCommand + '" on ' + target + '...');
|
events.emit('verbose', 'Running command "' + shellCommand + '" on ' + target + '...');
|
||||||
var args = ['-s', target, 'shell'];
|
var args = ['-s', target, 'shell'];
|
||||||
shellCommand = shellCommand.split(/\s+/);
|
shellCommand = shellCommand.split(/\s+/);
|
||||||
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
|
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
|
||||||
.catch(function (output) {
|
.catch(function (output) {
|
||||||
return Q.reject(new CordovaError('Failed to execute shell command "' +
|
return Q.reject(new CordovaError('Failed to execute shell command "' +
|
||||||
shellCommand + '"" on device: ' + output));
|
shellCommand + '"" on device: ' + output));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Adb.start = function (target, activityName) {
|
Adb.start = function (target, activityName) {
|
||||||
events.emit('verbose', 'Starting application "' + activityName + '" on ' + target + '...');
|
events.emit('verbose', 'Starting application "' + activityName + '" on ' + target + '...');
|
||||||
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
|
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
|
||||||
.catch(function (output) {
|
.catch(function (output) {
|
||||||
return Q.reject(new CordovaError('Failed to start application "' +
|
return Q.reject(new CordovaError('Failed to start application "' +
|
||||||
activityName + '"" on device: ' + output));
|
activityName + '"" on device: ' + output));
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = Adb;
|
module.exports = Adb;
|
||||||
|
322
bin/templates/cordova/lib/AndroidManifest.js
vendored
322
bin/templates/cordova/lib/AndroidManifest.js
vendored
@ -1,161 +1,161 @@
|
|||||||
/**
|
/**
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var et = require('elementtree');
|
var et = require('elementtree');
|
||||||
var xml= require('cordova-common').xmlHelpers;
|
var xml= require('cordova-common').xmlHelpers;
|
||||||
|
|
||||||
var DEFAULT_ORIENTATION = 'default';
|
var DEFAULT_ORIENTATION = 'default';
|
||||||
|
|
||||||
/** Wraps an AndroidManifest file */
|
/** Wraps an AndroidManifest file */
|
||||||
function AndroidManifest(path) {
|
function AndroidManifest(path) {
|
||||||
this.path = path;
|
this.path = path;
|
||||||
this.doc = xml.parseElementtreeSync(path);
|
this.doc = xml.parseElementtreeSync(path);
|
||||||
if (this.doc.getroot().tag !== 'manifest') {
|
if (this.doc.getroot().tag !== 'manifest') {
|
||||||
throw new Error(path + ' has incorrect root node name (expected "manifest")');
|
throw new Error(path + ' has incorrect root node name (expected "manifest")');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidManifest.prototype.getVersionName = function() {
|
AndroidManifest.prototype.getVersionName = function() {
|
||||||
return this.doc.getroot().attrib['android:versionName'];
|
return this.doc.getroot().attrib['android:versionName'];
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.setVersionName = function(versionName) {
|
AndroidManifest.prototype.setVersionName = function(versionName) {
|
||||||
this.doc.getroot().attrib['android:versionName'] = versionName;
|
this.doc.getroot().attrib['android:versionName'] = versionName;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.getVersionCode = function() {
|
AndroidManifest.prototype.getVersionCode = function() {
|
||||||
return this.doc.getroot().attrib['android:versionCode'];
|
return this.doc.getroot().attrib['android:versionCode'];
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.setVersionCode = function(versionCode) {
|
AndroidManifest.prototype.setVersionCode = function(versionCode) {
|
||||||
this.doc.getroot().attrib['android:versionCode'] = versionCode;
|
this.doc.getroot().attrib['android:versionCode'] = versionCode;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.getPackageId = function() {
|
AndroidManifest.prototype.getPackageId = function() {
|
||||||
/*jshint -W069 */
|
/*jshint -W069 */
|
||||||
return this.doc.getroot().attrib['package'];
|
return this.doc.getroot().attrib['package'];
|
||||||
/*jshint +W069 */
|
/*jshint +W069 */
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.setPackageId = function(pkgId) {
|
AndroidManifest.prototype.setPackageId = function(pkgId) {
|
||||||
/*jshint -W069 */
|
/*jshint -W069 */
|
||||||
this.doc.getroot().attrib['package'] = pkgId;
|
this.doc.getroot().attrib['package'] = pkgId;
|
||||||
/*jshint +W069 */
|
/*jshint +W069 */
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.getActivity = function() {
|
AndroidManifest.prototype.getActivity = function() {
|
||||||
var activity = this.doc.getroot().find('./application/activity');
|
var activity = this.doc.getroot().find('./application/activity');
|
||||||
return {
|
return {
|
||||||
getName: function () {
|
getName: function () {
|
||||||
return activity.attrib['android:name'];
|
return activity.attrib['android:name'];
|
||||||
},
|
},
|
||||||
setName: function (name) {
|
setName: function (name) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
delete activity.attrib['android:name'];
|
delete activity.attrib['android:name'];
|
||||||
} else {
|
} else {
|
||||||
activity.attrib['android:name'] = name;
|
activity.attrib['android:name'] = name;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
getOrientation: function () {
|
getOrientation: function () {
|
||||||
return activity.attrib['android:screenOrientation'];
|
return activity.attrib['android:screenOrientation'];
|
||||||
},
|
},
|
||||||
setOrientation: function (orientation) {
|
setOrientation: function (orientation) {
|
||||||
if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {
|
if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {
|
||||||
delete activity.attrib['android:screenOrientation'];
|
delete activity.attrib['android:screenOrientation'];
|
||||||
} else {
|
} else {
|
||||||
activity.attrib['android:screenOrientation'] = orientation;
|
activity.attrib['android:screenOrientation'] = orientation;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
getLaunchMode: function () {
|
getLaunchMode: function () {
|
||||||
return activity.attrib['android:launchMode'];
|
return activity.attrib['android:launchMode'];
|
||||||
},
|
},
|
||||||
setLaunchMode: function (launchMode) {
|
setLaunchMode: function (launchMode) {
|
||||||
if (!launchMode) {
|
if (!launchMode) {
|
||||||
delete activity.attrib['android:launchMode'];
|
delete activity.attrib['android:launchMode'];
|
||||||
} else {
|
} else {
|
||||||
activity.attrib['android:launchMode'] = launchMode;
|
activity.attrib['android:launchMode'] = launchMode;
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
|
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
|
||||||
.forEach(function(sdkPrefName) {
|
.forEach(function(sdkPrefName) {
|
||||||
// Copy variable reference to avoid closure issues
|
// Copy variable reference to avoid closure issues
|
||||||
var prefName = sdkPrefName;
|
var prefName = sdkPrefName;
|
||||||
|
|
||||||
AndroidManifest.prototype['get' + capitalize(prefName)] = function() {
|
AndroidManifest.prototype['get' + capitalize(prefName)] = function() {
|
||||||
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
||||||
return usesSdk && usesSdk.attrib['android:' + prefName];
|
return usesSdk && usesSdk.attrib['android:' + prefName];
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {
|
AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {
|
||||||
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
||||||
|
|
||||||
if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
|
if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
|
||||||
usesSdk = new et.Element('uses-sdk');
|
usesSdk = new et.Element('uses-sdk');
|
||||||
this.doc.getroot().append(usesSdk);
|
this.doc.getroot().append(usesSdk);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefValue) {
|
if (prefValue) {
|
||||||
usesSdk.attrib['android:' + prefName] = prefValue;
|
usesSdk.attrib['android:' + prefName] = prefValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
AndroidManifest.prototype.getDebuggable = function() {
|
AndroidManifest.prototype.getDebuggable = function() {
|
||||||
return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
|
return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.setDebuggable = function(value) {
|
AndroidManifest.prototype.setDebuggable = function(value) {
|
||||||
var application = this.doc.getroot().find('./application');
|
var application = this.doc.getroot().find('./application');
|
||||||
if (value) {
|
if (value) {
|
||||||
application.attrib['android:debuggable'] = 'true';
|
application.attrib['android:debuggable'] = 'true';
|
||||||
} else {
|
} else {
|
||||||
// The default value is "false", so we can remove attribute at all.
|
// The default value is "false", so we can remove attribute at all.
|
||||||
delete application.attrib['android:debuggable'];
|
delete application.attrib['android:debuggable'];
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Writes manifest to disk syncronously. If filename is specified, then manifest
|
* Writes manifest to disk syncronously. If filename is specified, then manifest
|
||||||
* will be written to that file
|
* will be written to that file
|
||||||
*
|
*
|
||||||
* @param {String} [destPath] File to write manifest to. If omitted,
|
* @param {String} [destPath] File to write manifest to. If omitted,
|
||||||
* manifest will be written to file it has been read from.
|
* manifest will be written to file it has been read from.
|
||||||
*/
|
*/
|
||||||
AndroidManifest.prototype.write = function(destPath) {
|
AndroidManifest.prototype.write = function(destPath) {
|
||||||
fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
|
fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = AndroidManifest;
|
module.exports = AndroidManifest;
|
||||||
|
|
||||||
function capitalize (str) {
|
function capitalize (str) {
|
||||||
return str.charAt(0).toUpperCase() + str.slice(1);
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
}
|
}
|
||||||
|
368
bin/templates/cordova/lib/AndroidProject.js
vendored
368
bin/templates/cordova/lib/AndroidProject.js
vendored
@ -1,184 +1,184 @@
|
|||||||
/**
|
/**
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var properties_parser = require('properties-parser');
|
var properties_parser = require('properties-parser');
|
||||||
var AndroidManifest = require('./AndroidManifest');
|
var AndroidManifest = require('./AndroidManifest');
|
||||||
|
|
||||||
var projectFileCache = {};
|
var projectFileCache = {};
|
||||||
|
|
||||||
function addToPropertyList(projectProperties, key, value) {
|
function addToPropertyList(projectProperties, key, value) {
|
||||||
var i = 1;
|
var i = 1;
|
||||||
while (projectProperties.get(key + '.' + i))
|
while (projectProperties.get(key + '.' + i))
|
||||||
i++;
|
i++;
|
||||||
|
|
||||||
projectProperties.set(key + '.' + i, value);
|
projectProperties.set(key + '.' + i, value);
|
||||||
projectProperties.dirty = true;
|
projectProperties.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeFromPropertyList(projectProperties, key, value) {
|
function removeFromPropertyList(projectProperties, key, value) {
|
||||||
var i = 1;
|
var i = 1;
|
||||||
var currentValue;
|
var currentValue;
|
||||||
while ((currentValue = projectProperties.get(key + '.' + i))) {
|
while ((currentValue = projectProperties.get(key + '.' + i))) {
|
||||||
if (currentValue === value) {
|
if (currentValue === value) {
|
||||||
while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {
|
while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {
|
||||||
projectProperties.set(key + '.' + i, currentValue);
|
projectProperties.set(key + '.' + i, currentValue);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
projectProperties.set(key + '.' + i);
|
projectProperties.set(key + '.' + i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
projectProperties.dirty = true;
|
projectProperties.dirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRelativeLibraryPath (parentDir, subDir) {
|
function getRelativeLibraryPath (parentDir, subDir) {
|
||||||
var libraryPath = path.relative(parentDir, subDir);
|
var libraryPath = path.relative(parentDir, subDir);
|
||||||
return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
|
return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
function AndroidProject(projectDir) {
|
function AndroidProject(projectDir) {
|
||||||
this._propertiesEditors = {};
|
this._propertiesEditors = {};
|
||||||
this._subProjectDirs = {};
|
this._subProjectDirs = {};
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
this.projectDir = projectDir;
|
this.projectDir = projectDir;
|
||||||
this.platformWww = path.join(this.projectDir, 'platform_www');
|
this.platformWww = path.join(this.projectDir, 'platform_www');
|
||||||
this.www = path.join(this.projectDir, 'assets/www');
|
this.www = path.join(this.projectDir, 'assets/www');
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidProject.getProjectFile = function (projectDir) {
|
AndroidProject.getProjectFile = function (projectDir) {
|
||||||
if (!projectFileCache[projectDir]) {
|
if (!projectFileCache[projectDir]) {
|
||||||
projectFileCache[projectDir] = new AndroidProject(projectDir);
|
projectFileCache[projectDir] = new AndroidProject(projectDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
return projectFileCache[projectDir];
|
return projectFileCache[projectDir];
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.purgeCache = function (projectDir) {
|
AndroidProject.purgeCache = function (projectDir) {
|
||||||
if (projectDir) {
|
if (projectDir) {
|
||||||
delete projectFileCache[projectDir];
|
delete projectFileCache[projectDir];
|
||||||
} else {
|
} else {
|
||||||
projectFileCache = {};
|
projectFileCache = {};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the package name out of the Android Manifest file
|
* Reads the package name out of the Android Manifest file
|
||||||
*
|
*
|
||||||
* @param {String} projectDir The absolute path to the directory containing the project
|
* @param {String} projectDir The absolute path to the directory containing the project
|
||||||
*
|
*
|
||||||
* @return {String} The name of the package
|
* @return {String} The name of the package
|
||||||
*/
|
*/
|
||||||
AndroidProject.prototype.getPackageName = function() {
|
AndroidProject.prototype.getPackageName = function() {
|
||||||
return new AndroidManifest(path.join(this.projectDir, 'AndroidManifest.xml')).getPackageId();
|
return new AndroidManifest(path.join(this.projectDir, 'AndroidManifest.xml')).getPackageId();
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) {
|
AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) {
|
||||||
// All custom subprojects are prefixed with the last portion of the package id.
|
// All custom subprojects are prefixed with the last portion of the package id.
|
||||||
// This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.
|
// This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.
|
||||||
var packageName = this.getPackageName();
|
var packageName = this.getPackageName();
|
||||||
var lastDotIndex = packageName.lastIndexOf('.');
|
var lastDotIndex = packageName.lastIndexOf('.');
|
||||||
var prefix = packageName.substring(lastDotIndex + 1);
|
var prefix = packageName.substring(lastDotIndex + 1);
|
||||||
var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));
|
var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));
|
||||||
return subRelativeDir;
|
return subRelativeDir;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype.addSubProject = function(parentDir, subDir) {
|
AndroidProject.prototype.addSubProject = function(parentDir, subDir) {
|
||||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||||
var subProjectFile = path.resolve(subDir, 'project.properties');
|
var subProjectFile = path.resolve(subDir, 'project.properties');
|
||||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||||
// TODO: Setting the target needs to happen only for pre-3.7.0 projects
|
// TODO: Setting the target needs to happen only for pre-3.7.0 projects
|
||||||
if (fs.existsSync(subProjectFile)) {
|
if (fs.existsSync(subProjectFile)) {
|
||||||
var subProperties = this._getPropertiesFile(subProjectFile);
|
var subProperties = this._getPropertiesFile(subProjectFile);
|
||||||
subProperties.set('target', parentProperties.get('target'));
|
subProperties.set('target', parentProperties.get('target'));
|
||||||
subProperties.dirty = true;
|
subProperties.dirty = true;
|
||||||
this._subProjectDirs[subDir] = true;
|
this._subProjectDirs[subDir] = true;
|
||||||
}
|
}
|
||||||
addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
|
addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
|
||||||
|
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype.removeSubProject = function(parentDir, subDir) {
|
AndroidProject.prototype.removeSubProject = function(parentDir, subDir) {
|
||||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||||
removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
|
removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
|
||||||
delete this._subProjectDirs[subDir];
|
delete this._subProjectDirs[subDir];
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype.addGradleReference = function(parentDir, subDir) {
|
AndroidProject.prototype.addGradleReference = function(parentDir, subDir) {
|
||||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||||
addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
|
addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype.removeGradleReference = function(parentDir, subDir) {
|
AndroidProject.prototype.removeGradleReference = function(parentDir, subDir) {
|
||||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||||
removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
|
removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype.addSystemLibrary = function(parentDir, value) {
|
AndroidProject.prototype.addSystemLibrary = function(parentDir, value) {
|
||||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||||
addToPropertyList(parentProperties, 'cordova.system.library', value);
|
addToPropertyList(parentProperties, 'cordova.system.library', value);
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype.removeSystemLibrary = function(parentDir, value) {
|
AndroidProject.prototype.removeSystemLibrary = function(parentDir, value) {
|
||||||
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
var parentProjectFile = path.resolve(parentDir, 'project.properties');
|
||||||
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
var parentProperties = this._getPropertiesFile(parentProjectFile);
|
||||||
removeFromPropertyList(parentProperties, 'cordova.system.library', value);
|
removeFromPropertyList(parentProperties, 'cordova.system.library', value);
|
||||||
this._dirty = true;
|
this._dirty = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype.write = function() {
|
AndroidProject.prototype.write = function() {
|
||||||
if (!this._dirty) {
|
if (!this._dirty) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this._dirty = false;
|
this._dirty = false;
|
||||||
|
|
||||||
for (var filename in this._propertiesEditors) {
|
for (var filename in this._propertiesEditors) {
|
||||||
var editor = this._propertiesEditors[filename];
|
var editor = this._propertiesEditors[filename];
|
||||||
if (editor.dirty) {
|
if (editor.dirty) {
|
||||||
fs.writeFileSync(filename, editor.toString());
|
fs.writeFileSync(filename, editor.toString());
|
||||||
editor.dirty = false;
|
editor.dirty = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidProject.prototype._getPropertiesFile = function (filename) {
|
AndroidProject.prototype._getPropertiesFile = function (filename) {
|
||||||
if (!this._propertiesEditors[filename]) {
|
if (!this._propertiesEditors[filename]) {
|
||||||
if (fs.existsSync(filename)) {
|
if (fs.existsSync(filename)) {
|
||||||
this._propertiesEditors[filename] = properties_parser.createEditor(filename);
|
this._propertiesEditors[filename] = properties_parser.createEditor(filename);
|
||||||
} else {
|
} else {
|
||||||
this._propertiesEditors[filename] = properties_parser.createEditor();
|
this._propertiesEditors[filename] = properties_parser.createEditor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this._propertiesEditors[filename];
|
return this._propertiesEditors[filename];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
module.exports = AndroidProject;
|
module.exports = AndroidProject;
|
||||||
|
150
bin/templates/cordova/lib/ConsoleLogger.js
vendored
150
bin/templates/cordova/lib/ConsoleLogger.js
vendored
@ -1,75 +1,75 @@
|
|||||||
/**
|
/**
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var loggerInstance;
|
var loggerInstance;
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var EventEmitter = require('events').EventEmitter;
|
var EventEmitter = require('events').EventEmitter;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @class ConsoleLogger
|
* @class ConsoleLogger
|
||||||
* @extends EventEmitter
|
* @extends EventEmitter
|
||||||
*
|
*
|
||||||
* Implementing basic logging for platform. Inherits regular NodeJS
|
* Implementing basic logging for platform. Inherits regular NodeJS
|
||||||
* EventEmitter. All events, emitted on this class instance are immediately
|
* EventEmitter. All events, emitted on this class instance are immediately
|
||||||
* logged to console.
|
* logged to console.
|
||||||
*
|
*
|
||||||
* Also attaches handler to process' uncaught exceptions, so these exceptions
|
* Also attaches handler to process' uncaught exceptions, so these exceptions
|
||||||
* logged to console similar to regular error events.
|
* logged to console similar to regular error events.
|
||||||
*/
|
*/
|
||||||
function ConsoleLogger() {
|
function ConsoleLogger() {
|
||||||
EventEmitter.call(this);
|
EventEmitter.call(this);
|
||||||
|
|
||||||
var isVerbose = process.argv.indexOf('-d') >= 0 || process.argv.indexOf('--verbose') >= 0;
|
var isVerbose = process.argv.indexOf('-d') >= 0 || process.argv.indexOf('--verbose') >= 0;
|
||||||
// For CordovaError print only the message without stack trace unless we
|
// For CordovaError print only the message without stack trace unless we
|
||||||
// are in a verbose mode.
|
// are in a verbose mode.
|
||||||
process.on('uncaughtException', function(err){
|
process.on('uncaughtException', function(err){
|
||||||
if ((err instanceof CordovaError) && isVerbose) {
|
if ((err instanceof CordovaError) && isVerbose) {
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
} else {
|
} else {
|
||||||
console.error(err.message);
|
console.error(err.message);
|
||||||
}
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
this.on('results', console.log);
|
this.on('results', console.log);
|
||||||
this.on('verbose', function () {
|
this.on('verbose', function () {
|
||||||
if (isVerbose)
|
if (isVerbose)
|
||||||
console.log.apply(console, arguments);
|
console.log.apply(console, arguments);
|
||||||
});
|
});
|
||||||
this.on('info', console.log);
|
this.on('info', console.log);
|
||||||
this.on('log', console.log);
|
this.on('log', console.log);
|
||||||
this.on('warn', console.warn);
|
this.on('warn', console.warn);
|
||||||
}
|
}
|
||||||
util.inherits(ConsoleLogger, EventEmitter);
|
util.inherits(ConsoleLogger, EventEmitter);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns already instantiated/newly created instance of ConsoleLogger class.
|
* Returns already instantiated/newly created instance of ConsoleLogger class.
|
||||||
* This method should be used instead of creating ConsoleLogger directly,
|
* This method should be used instead of creating ConsoleLogger directly,
|
||||||
* otherwise we'll get multiple handlers attached to process'
|
* otherwise we'll get multiple handlers attached to process'
|
||||||
* uncaughtException
|
* uncaughtException
|
||||||
*
|
*
|
||||||
* @return {ConsoleLogger} New or already created instance of ConsoleLogger
|
* @return {ConsoleLogger} New or already created instance of ConsoleLogger
|
||||||
*/
|
*/
|
||||||
ConsoleLogger.get = function () {
|
ConsoleLogger.get = function () {
|
||||||
loggerInstance = loggerInstance || new ConsoleLogger();
|
loggerInstance = loggerInstance || new ConsoleLogger();
|
||||||
return loggerInstance;
|
return loggerInstance;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = ConsoleLogger;
|
module.exports = ConsoleLogger;
|
||||||
|
602
bin/templates/cordova/lib/build.js
vendored
602
bin/templates/cordova/lib/build.js
vendored
@ -1,301 +1,301 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Q = require('q'),
|
var Q = require('q'),
|
||||||
path = require('path'),
|
path = require('path'),
|
||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
nopt = require('nopt');
|
nopt = require('nopt');
|
||||||
|
|
||||||
var Adb = require('./Adb');
|
var Adb = require('./Adb');
|
||||||
|
|
||||||
var builders = require('./builders/builders');
|
var builders = require('./builders/builders');
|
||||||
var events = require('cordova-common').events;
|
var events = require('cordova-common').events;
|
||||||
var spawn = require('cordova-common').superspawn.spawn;
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
function parseOpts(options, resolvedTarget) {
|
function parseOpts(options, resolvedTarget) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.argv = nopt({
|
options.argv = nopt({
|
||||||
gradle: Boolean,
|
gradle: Boolean,
|
||||||
ant: Boolean,
|
ant: Boolean,
|
||||||
prepenv: Boolean,
|
prepenv: Boolean,
|
||||||
versionCode: String,
|
versionCode: String,
|
||||||
minSdkVersion: String,
|
minSdkVersion: String,
|
||||||
gradleArg: String,
|
gradleArg: String,
|
||||||
keystore: path,
|
keystore: path,
|
||||||
alias: String,
|
alias: String,
|
||||||
storePassword: String,
|
storePassword: String,
|
||||||
password: String,
|
password: String,
|
||||||
keystoreType: String
|
keystoreType: String
|
||||||
}, {}, options.argv, 0);
|
}, {}, options.argv, 0);
|
||||||
|
|
||||||
var ret = {
|
var ret = {
|
||||||
buildType: options.release ? 'release' : 'debug',
|
buildType: options.release ? 'release' : 'debug',
|
||||||
buildMethod: process.env.ANDROID_BUILD || 'gradle',
|
buildMethod: process.env.ANDROID_BUILD || 'gradle',
|
||||||
prepEnv: options.argv.prepenv,
|
prepEnv: options.argv.prepenv,
|
||||||
arch: resolvedTarget && resolvedTarget.arch,
|
arch: resolvedTarget && resolvedTarget.arch,
|
||||||
extraArgs: []
|
extraArgs: []
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.argv.ant || options.argv.gradle)
|
if (options.argv.ant || options.argv.gradle)
|
||||||
ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
|
ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
|
||||||
|
|
||||||
if (options.nobuild) ret.buildMethod = 'none';
|
if (options.nobuild) ret.buildMethod = 'none';
|
||||||
|
|
||||||
if (options.argv.versionCode)
|
if (options.argv.versionCode)
|
||||||
ret.extraArgs.push('-PcdvVersionCode=' + options.versionCode);
|
ret.extraArgs.push('-PcdvVersionCode=' + options.versionCode);
|
||||||
|
|
||||||
if (options.argv.minSdkVersion)
|
if (options.argv.minSdkVersion)
|
||||||
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.minSdkVersion);
|
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.minSdkVersion);
|
||||||
|
|
||||||
if (options.argv.gradleArg)
|
if (options.argv.gradleArg)
|
||||||
ret.extraArgs.push(options.gradleArg);
|
ret.extraArgs.push(options.gradleArg);
|
||||||
|
|
||||||
var packageArgs = {};
|
var packageArgs = {};
|
||||||
|
|
||||||
if (options.argv.keystore)
|
if (options.argv.keystore)
|
||||||
packageArgs.keystore = path.relative(this.root, path.resolve(options.argv.keystore));
|
packageArgs.keystore = path.relative(this.root, path.resolve(options.argv.keystore));
|
||||||
|
|
||||||
['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
|
['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
|
||||||
if (options.argv[flagName])
|
if (options.argv[flagName])
|
||||||
packageArgs[flagName] = options.argv[flagName];
|
packageArgs[flagName] = options.argv[flagName];
|
||||||
});
|
});
|
||||||
|
|
||||||
var buildConfig = options.buildConfig;
|
var buildConfig = options.buildConfig;
|
||||||
|
|
||||||
// If some values are not specified as command line arguments - use build config to supplement them.
|
// If some values are not specified as command line arguments - use build config to supplement them.
|
||||||
// Command line arguemnts have precedence over build config.
|
// Command line arguemnts have precedence over build config.
|
||||||
if (buildConfig) {
|
if (buildConfig) {
|
||||||
if (!fs.existsSync(buildConfig)) {
|
if (!fs.existsSync(buildConfig)) {
|
||||||
throw new Error('Specified build config file does not exist: ' + buildConfig);
|
throw new Error('Specified build config file does not exist: ' + buildConfig);
|
||||||
}
|
}
|
||||||
events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig));
|
events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig));
|
||||||
var config = JSON.parse(fs.readFileSync(buildConfig, 'utf8'));
|
var config = JSON.parse(fs.readFileSync(buildConfig, 'utf8'));
|
||||||
if (config.android && config.android[ret.buildType]) {
|
if (config.android && config.android[ret.buildType]) {
|
||||||
var androidInfo = config.android[ret.buildType];
|
var androidInfo = config.android[ret.buildType];
|
||||||
if(androidInfo.keystore && !packageArgs.keystore) {
|
if(androidInfo.keystore && !packageArgs.keystore) {
|
||||||
packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);
|
packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);
|
||||||
}
|
}
|
||||||
|
|
||||||
['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){
|
['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){
|
||||||
packageArgs[key] = packageArgs[key] || androidInfo[key];
|
packageArgs[key] = packageArgs[key] || androidInfo[key];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packageArgs.keystore && packageArgs.alias) {
|
if (packageArgs.keystore && packageArgs.alias) {
|
||||||
ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,
|
ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,
|
||||||
packageArgs.password, packageArgs.keystoreType);
|
packageArgs.password, packageArgs.keystoreType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ret.packageInfo) {
|
if(!ret.packageInfo) {
|
||||||
if(Object.keys(packageArgs).length > 0) {
|
if(Object.keys(packageArgs).length > 0) {
|
||||||
events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
|
events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Builds the project with the specifed options
|
* Builds the project with the specifed options
|
||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
module.exports.runClean = function(options) {
|
module.exports.runClean = function(options) {
|
||||||
var opts = parseOpts(options);
|
var opts = parseOpts(options);
|
||||||
var builder = builders.getBuilder(opts.buildMethod);
|
var builder = builders.getBuilder(opts.buildMethod);
|
||||||
return builder.prepEnv(opts)
|
return builder.prepEnv(opts)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return builder.clean(opts);
|
return builder.clean(opts);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the project with the specifed options.
|
* Builds the project with the specifed options.
|
||||||
*
|
*
|
||||||
* @param {BuildOptions} options A set of options. See PlatformApi.build
|
* @param {BuildOptions} options A set of options. See PlatformApi.build
|
||||||
* method documentation for reference.
|
* method documentation for reference.
|
||||||
* @param {Object} optResolvedTarget A deployment target. Used to pass
|
* @param {Object} optResolvedTarget A deployment target. Used to pass
|
||||||
* target architecture from upstream 'run' call. TODO: remove this option in
|
* target architecture from upstream 'run' call. TODO: remove this option in
|
||||||
* favor of setting buildOptions.archs field.
|
* favor of setting buildOptions.archs field.
|
||||||
*
|
*
|
||||||
* @return {Promise<Object>} Promise, resolved with built packages
|
* @return {Promise<Object>} Promise, resolved with built packages
|
||||||
* information.
|
* information.
|
||||||
*/
|
*/
|
||||||
module.exports.run = function(options, optResolvedTarget) {
|
module.exports.run = function(options, optResolvedTarget) {
|
||||||
var opts = parseOpts(options, optResolvedTarget);
|
var opts = parseOpts(options, optResolvedTarget);
|
||||||
var builder = builders.getBuilder(opts.buildMethod);
|
var builder = builders.getBuilder(opts.buildMethod);
|
||||||
var self = this;
|
var self = this;
|
||||||
return builder.prepEnv(opts)
|
return builder.prepEnv(opts)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
if (opts.prepEnv) {
|
if (opts.prepEnv) {
|
||||||
self.events.emit('verbose', 'Build file successfully prepared.');
|
self.events.emit('verbose', 'Build file successfully prepared.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return builder.build(opts)
|
return builder.build(opts)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
|
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
|
||||||
self.events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
|
self.events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
|
||||||
return {
|
return {
|
||||||
apkPaths: apkPaths,
|
apkPaths: apkPaths,
|
||||||
buildType: opts.buildType,
|
buildType: opts.buildType,
|
||||||
buildMethod: opts.buildMethod
|
buildMethod: opts.buildMethod
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Called by plugman after installing plugins, and by create script after creating project.
|
// Called by plugman after installing plugins, and by create script after creating project.
|
||||||
module.exports.prepBuildFiles = function() {
|
module.exports.prepBuildFiles = function() {
|
||||||
return builders.getBuilder('gradle').prepBuildFiles();
|
return builders.getBuilder('gradle').prepBuildFiles();
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Detects the architecture of a device/emulator
|
* Detects the architecture of a device/emulator
|
||||||
* Returns "arm" or "x86".
|
* Returns "arm" or "x86".
|
||||||
*/
|
*/
|
||||||
module.exports.detectArchitecture = function(target) {
|
module.exports.detectArchitecture = function(target) {
|
||||||
function helper() {
|
function helper() {
|
||||||
return Adb.shell(target, 'cat /proc/cpuinfo')
|
return Adb.shell(target, 'cat /proc/cpuinfo')
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
return /intel/i.exec(output) ? 'x86' : 'arm';
|
return /intel/i.exec(output) ? 'x86' : 'arm';
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// It sometimes happens (at least on OS X), that this command will hang forever.
|
// It sometimes happens (at least on OS X), that this command will hang forever.
|
||||||
// To fix it, either unplug & replug device, or restart adb server.
|
// To fix it, either unplug & replug device, or restart adb server.
|
||||||
return helper()
|
return helper()
|
||||||
.timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))
|
.timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))
|
||||||
.then(null, function(err) {
|
.then(null, function(err) {
|
||||||
if (/timed out/.exec('' + err)) {
|
if (/timed out/.exec('' + err)) {
|
||||||
// adb kill-server doesn't seem to do the trick.
|
// adb kill-server doesn't seem to do the trick.
|
||||||
// Could probably find a x-platform version of killall, but I'm not actually
|
// Could probably find a x-platform version of killall, but I'm not actually
|
||||||
// sure that this scenario even happens on non-OSX machines.
|
// sure that this scenario even happens on non-OSX machines.
|
||||||
return spawn('killall', ['adb'])
|
return spawn('killall', ['adb'])
|
||||||
.then(function() {
|
.then(function() {
|
||||||
events.emit('verbose', 'adb seems hung. retrying.');
|
events.emit('verbose', 'adb seems hung. retrying.');
|
||||||
return helper()
|
return helper()
|
||||||
.then(null, function() {
|
.then(null, function() {
|
||||||
// The double kill is sadly often necessary, at least on mac.
|
// The double kill is sadly often necessary, at least on mac.
|
||||||
events.emit('warn', 'Now device not found... restarting adb again.');
|
events.emit('warn', 'Now device not found... restarting adb again.');
|
||||||
return spawn('killall', ['adb'])
|
return spawn('killall', ['adb'])
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return helper()
|
return helper()
|
||||||
.then(null, function() {
|
.then(null, function() {
|
||||||
return Q.reject(new CordovaError('USB is flakey. Try unplugging & replugging the device.'));
|
return Q.reject(new CordovaError('USB is flakey. Try unplugging & replugging the device.'));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, function() {
|
}, function() {
|
||||||
// For non-killall OS's.
|
// For non-killall OS's.
|
||||||
return Q.reject(err);
|
return Q.reject(err);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
throw err;
|
throw err;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.findBestApkForArchitecture = function(buildResults, arch) {
|
module.exports.findBestApkForArchitecture = function(buildResults, arch) {
|
||||||
var paths = buildResults.apkPaths.filter(function(p) {
|
var paths = buildResults.apkPaths.filter(function(p) {
|
||||||
var apkName = path.basename(p);
|
var apkName = path.basename(p);
|
||||||
if (buildResults.buildType == 'debug') {
|
if (buildResults.buildType == 'debug') {
|
||||||
return /-debug/.exec(apkName);
|
return /-debug/.exec(apkName);
|
||||||
}
|
}
|
||||||
return !/-debug/.exec(apkName);
|
return !/-debug/.exec(apkName);
|
||||||
});
|
});
|
||||||
var archPattern = new RegExp('-' + arch);
|
var archPattern = new RegExp('-' + arch);
|
||||||
var hasArchPattern = /-x86|-arm/;
|
var hasArchPattern = /-x86|-arm/;
|
||||||
for (var i = 0; i < paths.length; ++i) {
|
for (var i = 0; i < paths.length; ++i) {
|
||||||
var apkName = path.basename(paths[i]);
|
var apkName = path.basename(paths[i]);
|
||||||
if (hasArchPattern.exec(apkName)) {
|
if (hasArchPattern.exec(apkName)) {
|
||||||
if (archPattern.exec(apkName)) {
|
if (archPattern.exec(apkName)) {
|
||||||
return paths[i];
|
return paths[i];
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return paths[i];
|
return paths[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
|
throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
|
||||||
};
|
};
|
||||||
|
|
||||||
function PackageInfo(keystore, alias, storePassword, password, keystoreType) {
|
function PackageInfo(keystore, alias, storePassword, password, keystoreType) {
|
||||||
this.keystore = {
|
this.keystore = {
|
||||||
'name': 'key.store',
|
'name': 'key.store',
|
||||||
'value': keystore
|
'value': keystore
|
||||||
};
|
};
|
||||||
this.alias = {
|
this.alias = {
|
||||||
'name': 'key.alias',
|
'name': 'key.alias',
|
||||||
'value': alias
|
'value': alias
|
||||||
};
|
};
|
||||||
if (storePassword) {
|
if (storePassword) {
|
||||||
this.storePassword = {
|
this.storePassword = {
|
||||||
'name': 'key.store.password',
|
'name': 'key.store.password',
|
||||||
'value': storePassword
|
'value': storePassword
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (password) {
|
if (password) {
|
||||||
this.password = {
|
this.password = {
|
||||||
'name': 'key.alias.password',
|
'name': 'key.alias.password',
|
||||||
'value': password
|
'value': password
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (keystoreType) {
|
if (keystoreType) {
|
||||||
this.keystoreType = {
|
this.keystoreType = {
|
||||||
'name': 'key.store.type',
|
'name': 'key.store.type',
|
||||||
'value': keystoreType
|
'value': keystoreType
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageInfo.prototype = {
|
PackageInfo.prototype = {
|
||||||
toProperties: function() {
|
toProperties: function() {
|
||||||
var self = this;
|
var self = this;
|
||||||
var result = '';
|
var result = '';
|
||||||
Object.keys(self).forEach(function(key) {
|
Object.keys(self).forEach(function(key) {
|
||||||
result += self[key].name;
|
result += self[key].name;
|
||||||
result += '=';
|
result += '=';
|
||||||
result += self[key].value.replace(/\\/g, '\\\\');
|
result += self[key].value.replace(/\\/g, '\\\\');
|
||||||
result += '\n';
|
result += '\n';
|
||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.help = function() {
|
module.exports.help = function() {
|
||||||
console.log('Usage: ' + path.relative(process.cwd(), path.join('../build')) + ' [flags] [Signed APK flags]');
|
console.log('Usage: ' + path.relative(process.cwd(), path.join('../build')) + ' [flags] [Signed APK flags]');
|
||||||
console.log('Flags:');
|
console.log('Flags:');
|
||||||
console.log(' \'--debug\': will build project in debug mode (default)');
|
console.log(' \'--debug\': will build project in debug mode (default)');
|
||||||
console.log(' \'--release\': will build project for release');
|
console.log(' \'--release\': will build project for release');
|
||||||
console.log(' \'--ant\': will build project with ant');
|
console.log(' \'--ant\': will build project with ant');
|
||||||
console.log(' \'--gradle\': will build project with gradle (default)');
|
console.log(' \'--gradle\': will build project with gradle (default)');
|
||||||
console.log(' \'--nobuild\': will skip build process (useful when using run command)');
|
console.log(' \'--nobuild\': will skip build process (useful when using run command)');
|
||||||
console.log(' \'--prepenv\': don\'t build, but copy in build scripts where necessary');
|
console.log(' \'--prepenv\': don\'t build, but copy in build scripts where necessary');
|
||||||
console.log(' \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
console.log(' \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
||||||
console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
||||||
console.log(' \'--gradleArg=<gradle command line arg>\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');
|
console.log(' \'--gradleArg=<gradle command line arg>\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
|
console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
|
||||||
console.log(' \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');
|
console.log(' \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');
|
||||||
console.log(' \'--alias=\': Alias for the key store. (Required)');
|
console.log(' \'--alias=\': Alias for the key store. (Required)');
|
||||||
console.log(' \'--storePassword=\': Password for the key store. (Optional - prompted)');
|
console.log(' \'--storePassword=\': Password for the key store. (Optional - prompted)');
|
||||||
console.log(' \'--password=\': Password for the key. (Optional - prompted)');
|
console.log(' \'--password=\': Password for the key. (Optional - prompted)');
|
||||||
console.log(' \'--keystoreType\': Type of the keystore. (Optional)');
|
console.log(' \'--keystoreType\': Type of the keystore. (Optional)');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
};
|
};
|
||||||
|
282
bin/templates/cordova/lib/builders/AntBuilder.js
vendored
282
bin/templates/cordova/lib/builders/AntBuilder.js
vendored
@ -1,141 +1,141 @@
|
|||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Q = require('q');
|
var Q = require('q');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var shell = require('shelljs');
|
var shell = require('shelljs');
|
||||||
var spawn = require('cordova-common').superspawn.spawn;
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
var check_reqs = require('../check_reqs');
|
var check_reqs = require('../check_reqs');
|
||||||
|
|
||||||
var SIGNING_PROPERTIES = '-signing.properties';
|
var SIGNING_PROPERTIES = '-signing.properties';
|
||||||
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
||||||
var TEMPLATE =
|
var TEMPLATE =
|
||||||
'# This file is automatically generated.\n' +
|
'# This file is automatically generated.\n' +
|
||||||
'# Do not modify this file -- ' + MARKER + '\n';
|
'# Do not modify this file -- ' + MARKER + '\n';
|
||||||
|
|
||||||
var GenericBuilder = require('./GenericBuilder');
|
var GenericBuilder = require('./GenericBuilder');
|
||||||
|
|
||||||
function AntBuilder (projectRoot) {
|
function AntBuilder (projectRoot) {
|
||||||
GenericBuilder.call(this, projectRoot);
|
GenericBuilder.call(this, projectRoot);
|
||||||
|
|
||||||
this.binDirs = {ant: this.binDirs.ant};
|
this.binDirs = {ant: this.binDirs.ant};
|
||||||
}
|
}
|
||||||
|
|
||||||
util.inherits(AntBuilder, GenericBuilder);
|
util.inherits(AntBuilder, GenericBuilder);
|
||||||
|
|
||||||
AntBuilder.prototype.getArgs = function(cmd, opts) {
|
AntBuilder.prototype.getArgs = function(cmd, opts) {
|
||||||
var args = [cmd, '-f', path.join(this.root, 'build.xml')];
|
var args = [cmd, '-f', path.join(this.root, 'build.xml')];
|
||||||
// custom_rules.xml is required for incremental builds.
|
// custom_rules.xml is required for incremental builds.
|
||||||
if (hasCustomRules()) {
|
if (hasCustomRules()) {
|
||||||
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
|
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
|
||||||
}
|
}
|
||||||
if(opts.packageInfo) {
|
if(opts.packageInfo) {
|
||||||
args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
|
args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
|
||||||
}
|
}
|
||||||
return args;
|
return args;
|
||||||
};
|
};
|
||||||
|
|
||||||
AntBuilder.prototype.prepEnv = function(opts) {
|
AntBuilder.prototype.prepEnv = function(opts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return check_reqs.check_ant()
|
return check_reqs.check_ant()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
// Copy in build.xml on each build so that:
|
// Copy in build.xml on each build so that:
|
||||||
// A) we don't require the Android SDK at project creation time, and
|
// A) we don't require the Android SDK at project creation time, and
|
||||||
// B) we always use the SDK's latest version of it.
|
// B) we always use the SDK's latest version of it.
|
||||||
/*jshint -W069 */
|
/*jshint -W069 */
|
||||||
var sdkDir = process.env['ANDROID_HOME'];
|
var sdkDir = process.env['ANDROID_HOME'];
|
||||||
/*jshint +W069 */
|
/*jshint +W069 */
|
||||||
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
|
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
|
||||||
function writeBuildXml(projectPath) {
|
function writeBuildXml(projectPath) {
|
||||||
var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
|
var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
|
||||||
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
|
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
|
||||||
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
|
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
|
||||||
fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);
|
fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
writeBuildXml(self.root);
|
writeBuildXml(self.root);
|
||||||
var propertiesObj = self.readProjectProperties();
|
var propertiesObj = self.readProjectProperties();
|
||||||
var subProjects = propertiesObj.libs;
|
var subProjects = propertiesObj.libs;
|
||||||
for (var i = 0; i < subProjects.length; ++i) {
|
for (var i = 0; i < subProjects.length; ++i) {
|
||||||
writeBuildXml(path.join(self.root, subProjects[i]));
|
writeBuildXml(path.join(self.root, subProjects[i]));
|
||||||
}
|
}
|
||||||
if (propertiesObj.systemLibs.length > 0) {
|
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. Please build using gradle.');
|
throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Please build using gradle.');
|
||||||
}
|
}
|
||||||
|
|
||||||
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
||||||
var propertiesFilePath = path.join(self.root, propertiesFile);
|
var propertiesFilePath = path.join(self.root, propertiesFile);
|
||||||
if (opts.packageInfo) {
|
if (opts.packageInfo) {
|
||||||
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
||||||
} else if(isAutoGenerated(propertiesFilePath)) {
|
} else if(isAutoGenerated(propertiesFilePath)) {
|
||||||
shell.rm('-f', propertiesFilePath);
|
shell.rm('-f', propertiesFilePath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Builds the project with ant.
|
* Builds the project with ant.
|
||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
AntBuilder.prototype.build = function(opts) {
|
AntBuilder.prototype.build = function(opts) {
|
||||||
// Without our custom_rules.xml, we need to clean before building.
|
// Without our custom_rules.xml, we need to clean before building.
|
||||||
var ret = Q();
|
var ret = Q();
|
||||||
if (!hasCustomRules()) {
|
if (!hasCustomRules()) {
|
||||||
// clean will call check_ant() for us.
|
// clean will call check_ant() for us.
|
||||||
ret = this.clean(opts);
|
ret = this.clean(opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
|
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
|
||||||
return check_reqs.check_ant()
|
return check_reqs.check_ant()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return spawn('ant', args, {stdio: 'inherit'});
|
return spawn('ant', args, {stdio: 'inherit'});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
AntBuilder.prototype.clean = function(opts) {
|
AntBuilder.prototype.clean = function(opts) {
|
||||||
var args = this.getArgs('clean', opts);
|
var args = this.getArgs('clean', opts);
|
||||||
var self = this;
|
var self = this;
|
||||||
return check_reqs.check_ant()
|
return check_reqs.check_ant()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return spawn('ant', args, {stdio: 'inherit'});
|
return spawn('ant', args, {stdio: 'inherit'});
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
shell.rm('-rf', path.join(self.root, 'out'));
|
shell.rm('-rf', path.join(self.root, 'out'));
|
||||||
|
|
||||||
['debug', 'release'].forEach(function(config) {
|
['debug', 'release'].forEach(function(config) {
|
||||||
var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
|
var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
|
||||||
if(isAutoGenerated(propertiesFilePath)){
|
if(isAutoGenerated(propertiesFilePath)){
|
||||||
shell.rm('-f', propertiesFilePath);
|
shell.rm('-f', propertiesFilePath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = AntBuilder;
|
module.exports = AntBuilder;
|
||||||
|
|
||||||
function hasCustomRules(projectRoot) {
|
function hasCustomRules(projectRoot) {
|
||||||
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
|
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
|
||||||
}
|
}
|
||||||
|
|
||||||
function isAutoGenerated(file) {
|
function isAutoGenerated(file) {
|
||||||
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
||||||
}
|
}
|
||||||
|
426
bin/templates/cordova/lib/builders/GradleBuilder.js
vendored
426
bin/templates/cordova/lib/builders/GradleBuilder.js
vendored
@ -1,213 +1,213 @@
|
|||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Q = require('q');
|
var Q = require('q');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var util = require('util');
|
var util = require('util');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var shell = require('shelljs');
|
var shell = require('shelljs');
|
||||||
var spawn = require('cordova-common').superspawn.spawn;
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
var check_reqs = require('../check_reqs');
|
var check_reqs = require('../check_reqs');
|
||||||
|
|
||||||
var GenericBuilder = require('./GenericBuilder');
|
var GenericBuilder = require('./GenericBuilder');
|
||||||
|
|
||||||
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
||||||
var SIGNING_PROPERTIES = '-signing.properties';
|
var SIGNING_PROPERTIES = '-signing.properties';
|
||||||
var TEMPLATE =
|
var TEMPLATE =
|
||||||
'# This file is automatically generated.\n' +
|
'# This file is automatically generated.\n' +
|
||||||
'# Do not modify this file -- ' + MARKER + '\n';
|
'# Do not modify this file -- ' + MARKER + '\n';
|
||||||
|
|
||||||
function GradleBuilder (projectRoot) {
|
function GradleBuilder (projectRoot) {
|
||||||
GenericBuilder.call(this, projectRoot);
|
GenericBuilder.call(this, projectRoot);
|
||||||
|
|
||||||
this.binDirs = {gradle: this.binDirs.gradle};
|
this.binDirs = {gradle: this.binDirs.gradle};
|
||||||
}
|
}
|
||||||
|
|
||||||
util.inherits(GradleBuilder, GenericBuilder);
|
util.inherits(GradleBuilder, GenericBuilder);
|
||||||
|
|
||||||
GradleBuilder.prototype.getArgs = function(cmd, opts) {
|
GradleBuilder.prototype.getArgs = function(cmd, opts) {
|
||||||
if (cmd == 'release') {
|
if (cmd == 'release') {
|
||||||
cmd = 'cdvBuildRelease';
|
cmd = 'cdvBuildRelease';
|
||||||
} else if (cmd == 'debug') {
|
} else if (cmd == 'debug') {
|
||||||
cmd = 'cdvBuildDebug';
|
cmd = 'cdvBuildDebug';
|
||||||
}
|
}
|
||||||
var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
|
var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
|
||||||
if (opts.arch) {
|
if (opts.arch) {
|
||||||
args.push('-PcdvBuildArch=' + opts.arch);
|
args.push('-PcdvBuildArch=' + opts.arch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 10 seconds -> 6 seconds
|
// 10 seconds -> 6 seconds
|
||||||
args.push('-Dorg.gradle.daemon=true');
|
args.push('-Dorg.gradle.daemon=true');
|
||||||
args.push.apply(args, opts.extraArgs);
|
args.push.apply(args, opts.extraArgs);
|
||||||
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
|
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
|
||||||
// args.push('-Dorg.gradle.parallel=true');
|
// args.push('-Dorg.gradle.parallel=true');
|
||||||
return args;
|
return args;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Makes the project buildable, minus the gradle wrapper.
|
// Makes the project buildable, minus the gradle wrapper.
|
||||||
GradleBuilder.prototype.prepBuildFiles = function() {
|
GradleBuilder.prototype.prepBuildFiles = function() {
|
||||||
// Update the version of build.gradle in each dependent library.
|
// Update the version of build.gradle in each dependent library.
|
||||||
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
|
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
|
||||||
var propertiesObj = this.readProjectProperties();
|
var propertiesObj = this.readProjectProperties();
|
||||||
var subProjects = propertiesObj.libs;
|
var subProjects = propertiesObj.libs;
|
||||||
for (var i = 0; i < subProjects.length; ++i) {
|
for (var i = 0; i < subProjects.length; ++i) {
|
||||||
if (subProjects[i] !== 'CordovaLib') {
|
if (subProjects[i] !== 'CordovaLib') {
|
||||||
shell.cp('-f', pluginBuildGradle, path.join(this.root, subProjects[i], 'build.gradle'));
|
shell.cp('-f', pluginBuildGradle, path.join(this.root, subProjects[i], 'build.gradle'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var name = this.extractRealProjectNameFromManifest();
|
var name = this.extractRealProjectNameFromManifest();
|
||||||
//Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
|
//Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
|
||||||
var settingsGradlePaths = subProjects.map(function(p){
|
var settingsGradlePaths = subProjects.map(function(p){
|
||||||
var realDir=p.replace(/[/\\]/g, ':');
|
var realDir=p.replace(/[/\\]/g, ':');
|
||||||
var libName=realDir.replace(name+'-','');
|
var libName=realDir.replace(name+'-','');
|
||||||
var str='include ":'+libName+'"\n';
|
var str='include ":'+libName+'"\n';
|
||||||
if(realDir.indexOf(name+'-')!==-1)
|
if(realDir.indexOf(name+'-')!==-1)
|
||||||
str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
|
str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
|
||||||
return str;
|
return str;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Write the settings.gradle file.
|
// 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' +
|
'// GENERATED FILE - DO NOT EDIT\n' +
|
||||||
'include ":"\n' + settingsGradlePaths.join(''));
|
'include ":"\n' + settingsGradlePaths.join(''));
|
||||||
// Update dependencies within build.gradle.
|
// Update dependencies within build.gradle.
|
||||||
var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
|
var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
|
||||||
var depsList = '';
|
var depsList = '';
|
||||||
subProjects.forEach(function(p) {
|
subProjects.forEach(function(p) {
|
||||||
var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
|
var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
|
||||||
depsList += ' debugCompile project(path: "' + libName + '", configuration: "debug")\n';
|
depsList += ' debugCompile project(path: "' + libName + '", configuration: "debug")\n';
|
||||||
depsList += ' releaseCompile project(path: "' + libName + '", configuration: "release")\n';
|
depsList += ' releaseCompile project(path: "' + libName + '", configuration: "release")\n';
|
||||||
});
|
});
|
||||||
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
|
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
|
||||||
var SYSTEM_LIBRARY_MAPPINGS = [
|
var SYSTEM_LIBRARY_MAPPINGS = [
|
||||||
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
|
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
|
||||||
[/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
|
[/^\/?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;
|
var mavenRef;
|
||||||
// It's already in gradle form if it has two ':'s
|
// It's already in gradle form if it has two ':'s
|
||||||
if (/:.*:/.exec(p)) {
|
if (/:.*:/.exec(p)) {
|
||||||
mavenRef = p;
|
mavenRef = p;
|
||||||
} else {
|
} else {
|
||||||
for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
|
for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
|
||||||
var pair = SYSTEM_LIBRARY_MAPPINGS[i];
|
var pair = SYSTEM_LIBRARY_MAPPINGS[i];
|
||||||
if (pair[0].exec(p)) {
|
if (pair[0].exec(p)) {
|
||||||
mavenRef = p.replace(pair[0], pair[1]);
|
mavenRef = p.replace(pair[0], pair[1]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!mavenRef) {
|
if (!mavenRef) {
|
||||||
throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
|
throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
depsList += ' compile "' + mavenRef + '"\n';
|
depsList += ' compile "' + mavenRef + '"\n';
|
||||||
});
|
});
|
||||||
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
|
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
|
||||||
var includeList = '';
|
var includeList = '';
|
||||||
propertiesObj.gradleIncludes.forEach(function(includePath) {
|
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');
|
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);
|
fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
|
||||||
};
|
};
|
||||||
|
|
||||||
GradleBuilder.prototype.prepEnv = function(opts) {
|
GradleBuilder.prototype.prepEnv = function(opts) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return check_reqs.check_gradle()
|
return check_reqs.check_gradle()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return self.prepBuildFiles();
|
return self.prepBuildFiles();
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
// Copy the gradle wrapper on each build so that:
|
// Copy the gradle wrapper on each build so that:
|
||||||
// A) we don't require the Android SDK at project creation time, and
|
// A) we don't require the Android SDK at project creation time, and
|
||||||
// B) we always use the SDK's latest version of it.
|
// B) we always use the SDK's latest version of it.
|
||||||
// check_reqs ensures that this is set.
|
// check_reqs ensures that this is set.
|
||||||
/*jshint -W069 */
|
/*jshint -W069 */
|
||||||
var sdkDir = process.env['ANDROID_HOME'];
|
var sdkDir = process.env['ANDROID_HOME'];
|
||||||
/*jshint +W069 */
|
/*jshint +W069 */
|
||||||
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||||
if (process.platform == 'win32') {
|
if (process.platform == 'win32') {
|
||||||
shell.rm('-f', path.join(self.root, 'gradlew.bat'));
|
shell.rm('-f', path.join(self.root, 'gradlew.bat'));
|
||||||
shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
|
shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
|
||||||
} else {
|
} else {
|
||||||
shell.rm('-f', path.join(self.root, 'gradlew'));
|
shell.rm('-f', path.join(self.root, 'gradlew'));
|
||||||
shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
|
shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
|
||||||
}
|
}
|
||||||
shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
|
shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
|
||||||
shell.mkdir('-p', path.join(self.root, 'gradle'));
|
shell.mkdir('-p', path.join(self.root, 'gradle'));
|
||||||
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), 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 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.
|
// 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.
|
// For some reason, using ^ and $ don't work. This does the job, though.
|
||||||
var distributionUrlRegex = /distributionUrl.*zip/;
|
var distributionUrlRegex = /distributionUrl.*zip/;
|
||||||
/*jshint -W069 */
|
/*jshint -W069 */
|
||||||
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'http\\://services.gradle.org/distributions/gradle-2.2.1-all.zip';
|
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'http\\://services.gradle.org/distributions/gradle-2.2.1-all.zip';
|
||||||
/*jshint +W069 */
|
/*jshint +W069 */
|
||||||
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
||||||
shell.chmod('u+w', gradleWrapperPropertiesPath);
|
shell.chmod('u+w', gradleWrapperPropertiesPath);
|
||||||
shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
|
shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
|
||||||
|
|
||||||
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
||||||
var propertiesFilePath = path.join(self.root, propertiesFile);
|
var propertiesFilePath = path.join(self.root, propertiesFile);
|
||||||
if (opts.packageInfo) {
|
if (opts.packageInfo) {
|
||||||
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
||||||
} else if (isAutoGenerated(propertiesFilePath)) {
|
} else if (isAutoGenerated(propertiesFilePath)) {
|
||||||
shell.rm('-f', propertiesFilePath);
|
shell.rm('-f', propertiesFilePath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Builds the project with gradle.
|
* Builds the project with gradle.
|
||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
GradleBuilder.prototype.build = function(opts) {
|
GradleBuilder.prototype.build = function(opts) {
|
||||||
var wrapper = path.join(this.root, 'gradlew');
|
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 Q().then(function() {
|
return Q().then(function() {
|
||||||
return spawn(wrapper, args, {stdio: 'inherit'});
|
return spawn(wrapper, args, {stdio: 'inherit'});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
GradleBuilder.prototype.clean = function(opts) {
|
GradleBuilder.prototype.clean = function(opts) {
|
||||||
var builder = this;
|
var builder = this;
|
||||||
var wrapper = path.join(this.root, 'gradlew');
|
var wrapper = path.join(this.root, 'gradlew');
|
||||||
var args = builder.getArgs('clean', opts);
|
var args = builder.getArgs('clean', opts);
|
||||||
return Q().then(function() {
|
return Q().then(function() {
|
||||||
return spawn(wrapper, args, {stdio: 'inherit'});
|
return spawn(wrapper, args, {stdio: 'inherit'});
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
shell.rm('-rf', path.join(builder.root, 'out'));
|
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);
|
var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
|
||||||
if(isAutoGenerated(propertiesFilePath)){
|
if(isAutoGenerated(propertiesFilePath)){
|
||||||
shell.rm('-f', propertiesFilePath);
|
shell.rm('-f', propertiesFilePath);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = GradleBuilder;
|
module.exports = GradleBuilder;
|
||||||
|
|
||||||
function isAutoGenerated(file) {
|
function isAutoGenerated(file) {
|
||||||
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
||||||
}
|
}
|
||||||
|
212
bin/templates/cordova/lib/device.js
vendored
212
bin/templates/cordova/lib/device.js
vendored
@ -1,106 +1,106 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Q = require('q'),
|
var Q = require('q'),
|
||||||
build = require('./build');
|
build = require('./build');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var Adb = require('./Adb');
|
var Adb = require('./Adb');
|
||||||
var AndroidManifest = require('./AndroidManifest');
|
var AndroidManifest = require('./AndroidManifest');
|
||||||
var spawn = require('cordova-common').superspawn.spawn;
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
var events = require('cordova-common').events;
|
var events = require('cordova-common').events;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a promise for the list of the device ID's found
|
* Returns a promise for the list of the device ID's found
|
||||||
* @param lookHarder When true, try restarting adb if no devices are found.
|
* @param lookHarder When true, try restarting adb if no devices are found.
|
||||||
*/
|
*/
|
||||||
module.exports.list = function(lookHarder) {
|
module.exports.list = function(lookHarder) {
|
||||||
return Adb.devices()
|
return Adb.devices()
|
||||||
.then(function(list) {
|
.then(function(list) {
|
||||||
if (list.length === 0 && lookHarder) {
|
if (list.length === 0 && lookHarder) {
|
||||||
// adb kill-server doesn't seem to do the trick.
|
// adb kill-server doesn't seem to do the trick.
|
||||||
// Could probably find a x-platform version of killall, but I'm not actually
|
// Could probably find a x-platform version of killall, but I'm not actually
|
||||||
// sure that this scenario even happens on non-OSX machines.
|
// sure that this scenario even happens on non-OSX machines.
|
||||||
return spawn('killall', ['adb'])
|
return spawn('killall', ['adb'])
|
||||||
.then(function() {
|
.then(function() {
|
||||||
events.emit('verbose', 'Restarting adb to see if more devices are detected.');
|
events.emit('verbose', 'Restarting adb to see if more devices are detected.');
|
||||||
return Adb.devices();
|
return Adb.devices();
|
||||||
}, function() {
|
}, function() {
|
||||||
// For non-killall OS's.
|
// For non-killall OS's.
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.resolveTarget = function(target) {
|
module.exports.resolveTarget = function(target) {
|
||||||
return this.list(true)
|
return this.list(true)
|
||||||
.then(function(device_list) {
|
.then(function(device_list) {
|
||||||
if (!device_list || !device_list.length) {
|
if (!device_list || !device_list.length) {
|
||||||
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
||||||
}
|
}
|
||||||
// default device
|
// default device
|
||||||
target = target || device_list[0];
|
target = target || device_list[0];
|
||||||
|
|
||||||
if (device_list.indexOf(target) < 0) {
|
if (device_list.indexOf(target) < 0) {
|
||||||
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
|
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return build.detectArchitecture(target)
|
return build.detectArchitecture(target)
|
||||||
.then(function(arch) {
|
.then(function(arch) {
|
||||||
return { target: target, arch: arch, isEmulator: false };
|
return { target: target, arch: arch, isEmulator: false };
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Installs a previously built application on the device
|
* Installs a previously built application on the device
|
||||||
* and launches it.
|
* and launches it.
|
||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
module.exports.install = function(target, buildResults) {
|
module.exports.install = function(target, buildResults) {
|
||||||
return Q().then(function() {
|
return Q().then(function() {
|
||||||
if (target && typeof target == 'object') {
|
if (target && typeof target == 'object') {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
return module.exports.resolveTarget(target);
|
return module.exports.resolveTarget(target);
|
||||||
}).then(function(resolvedTarget) {
|
}).then(function(resolvedTarget) {
|
||||||
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
|
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
|
||||||
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
||||||
var pkgName = manifest.getPackageId();
|
var pkgName = manifest.getPackageId();
|
||||||
var launchName = pkgName + '/.' + manifest.getActivity().getName();
|
var launchName = pkgName + '/.' + manifest.getActivity().getName();
|
||||||
events.emit('log', 'Using apk: ' + apk_path);
|
events.emit('log', 'Using apk: ' + apk_path);
|
||||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||||
// or the app doesn't installed at all, so no error catching needed.
|
// or the app doesn't installed at all, so no error catching needed.
|
||||||
return Adb.uninstall(resolvedTarget.target, pkgName)
|
return Adb.uninstall(resolvedTarget.target, pkgName)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
return Adb.install(resolvedTarget.target, apk_path, {replace: true});
|
return Adb.install(resolvedTarget.target, apk_path, {replace: true});
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
//unlock screen
|
//unlock screen
|
||||||
return Adb.shell(resolvedTarget.target, 'input keyevent 82');
|
return Adb.shell(resolvedTarget.target, 'input keyevent 82');
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
return Adb.start(resolvedTarget.target, launchName);
|
return Adb.start(resolvedTarget.target, launchName);
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
events.emit('log', 'LAUNCH SUCCESS');
|
events.emit('log', 'LAUNCH SUCCESS');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
744
bin/templates/cordova/lib/emulator.js
vendored
744
bin/templates/cordova/lib/emulator.js
vendored
@ -1,372 +1,372 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* jshint sub:true */
|
/* jshint sub:true */
|
||||||
|
|
||||||
var retry = require('./retry');
|
var retry = require('./retry');
|
||||||
var build = require('./build');
|
var build = require('./build');
|
||||||
var check_reqs = require('./check_reqs');
|
var check_reqs = require('./check_reqs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var Adb = require('./Adb');
|
var Adb = require('./Adb');
|
||||||
var AndroidManifest = require('./AndroidManifest');
|
var AndroidManifest = require('./AndroidManifest');
|
||||||
var events = require('cordova-common').events;
|
var events = require('cordova-common').events;
|
||||||
var spawn = require('cordova-common').superspawn.spawn;
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
var Q = require('q');
|
var Q = require('q');
|
||||||
var os = require('os');
|
var os = require('os');
|
||||||
var child_process = require('child_process');
|
var child_process = require('child_process');
|
||||||
|
|
||||||
// constants
|
// constants
|
||||||
var ONE_SECOND = 1000; // in milliseconds
|
var ONE_SECOND = 1000; // in milliseconds
|
||||||
var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
|
var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
|
||||||
var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
|
var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
|
||||||
var NUM_INSTALL_RETRIES = 3;
|
var NUM_INSTALL_RETRIES = 3;
|
||||||
var EXEC_KILL_SIGNAL = 'SIGKILL';
|
var EXEC_KILL_SIGNAL = 'SIGKILL';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Promise for a list of emulator images in the form of objects
|
* Returns a Promise for a list of emulator images in the form of objects
|
||||||
* {
|
* {
|
||||||
name : <emulator_name>,
|
name : <emulator_name>,
|
||||||
path : <path_to_emulator_image>,
|
path : <path_to_emulator_image>,
|
||||||
target : <api_target>,
|
target : <api_target>,
|
||||||
abi : <cpu>,
|
abi : <cpu>,
|
||||||
skin : <skin>
|
skin : <skin>
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
module.exports.list_images = function() {
|
module.exports.list_images = function() {
|
||||||
return spawn('android', ['list', 'avds'])
|
return spawn('android', ['list', 'avds'])
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
var response = output.split('\n');
|
var response = output.split('\n');
|
||||||
var emulator_list = [];
|
var emulator_list = [];
|
||||||
for (var i = 1; i < response.length; i++) {
|
for (var i = 1; i < response.length; i++) {
|
||||||
// To return more detailed information use img_obj
|
// To return more detailed information use img_obj
|
||||||
var img_obj = {};
|
var img_obj = {};
|
||||||
if (response[i].match(/Name:\s/)) {
|
if (response[i].match(/Name:\s/)) {
|
||||||
img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
|
img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
|
||||||
if (response[i + 1].match(/Path:\s/)) {
|
if (response[i + 1].match(/Path:\s/)) {
|
||||||
i++;
|
i++;
|
||||||
img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
|
img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
|
||||||
}
|
}
|
||||||
if (response[i + 1].match(/\(API\slevel\s/)) {
|
if (response[i + 1].match(/\(API\slevel\s/)) {
|
||||||
i++;
|
i++;
|
||||||
img_obj['target'] = response[i].replace('\r', '');
|
img_obj['target'] = response[i].replace('\r', '');
|
||||||
}
|
}
|
||||||
if (response[i + 1].match(/ABI:\s/)) {
|
if (response[i + 1].match(/ABI:\s/)) {
|
||||||
i++;
|
i++;
|
||||||
img_obj['abi'] = response[i].split('ABI: ')[1].replace('\r', '');
|
img_obj['abi'] = response[i].split('ABI: ')[1].replace('\r', '');
|
||||||
}
|
}
|
||||||
if (response[i + 1].match(/Skin:\s/)) {
|
if (response[i + 1].match(/Skin:\s/)) {
|
||||||
i++;
|
i++;
|
||||||
img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
|
img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
|
||||||
}
|
}
|
||||||
|
|
||||||
emulator_list.push(img_obj);
|
emulator_list.push(img_obj);
|
||||||
}
|
}
|
||||||
/* To just return a list of names use this
|
/* To just return a list of names use this
|
||||||
if (response[i].match(/Name:\s/)) {
|
if (response[i].match(/Name:\s/)) {
|
||||||
emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
|
emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
}
|
}
|
||||||
return emulator_list;
|
return emulator_list;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Will return the closest avd to the projects target
|
* Will return the closest avd to the projects target
|
||||||
* or undefined if no avds exist.
|
* or undefined if no avds exist.
|
||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
module.exports.best_image = function() {
|
module.exports.best_image = function() {
|
||||||
return this.list_images()
|
return this.list_images()
|
||||||
.then(function(images) {
|
.then(function(images) {
|
||||||
// Just return undefined if there is no images
|
// Just return undefined if there is no images
|
||||||
if (images.length === 0) return;
|
if (images.length === 0) return;
|
||||||
|
|
||||||
var closest = 9999;
|
var closest = 9999;
|
||||||
var best = images[0];
|
var best = images[0];
|
||||||
var project_target = check_reqs.get_target().replace('android-', '');
|
var project_target = check_reqs.get_target().replace('android-', '');
|
||||||
for (var i in images) {
|
for (var i in images) {
|
||||||
var target = images[i].target;
|
var target = images[i].target;
|
||||||
if(target) {
|
if(target) {
|
||||||
var num = target.split('(API level ')[1].replace(')', '');
|
var num = target.split('(API level ')[1].replace(')', '');
|
||||||
if (num == project_target) {
|
if (num == project_target) {
|
||||||
return images[i];
|
return images[i];
|
||||||
} else if (project_target - num < closest && project_target > num) {
|
} else if (project_target - num < closest && project_target > num) {
|
||||||
closest = project_target - num;
|
closest = project_target - num;
|
||||||
best = images[i];
|
best = images[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return best;
|
return best;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
module.exports.list_started = function() {
|
module.exports.list_started = function() {
|
||||||
return Adb.devices({emulators: true});
|
return Adb.devices({emulators: true});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
module.exports.list_targets = function() {
|
module.exports.list_targets = function() {
|
||||||
return spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
|
return spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
var target_out = output.split('\n');
|
var target_out = output.split('\n');
|
||||||
var targets = [];
|
var targets = [];
|
||||||
for (var i = target_out.length; i >= 0; i--) {
|
for (var i = target_out.length; i >= 0; i--) {
|
||||||
if(target_out[i].match(/id:/)) {
|
if(target_out[i].match(/id:/)) {
|
||||||
targets.push(targets[i].split(' ')[1]);
|
targets.push(targets[i].split(' ')[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return targets;
|
return targets;
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Starts an emulator with the given ID,
|
* Starts an emulator with the given ID,
|
||||||
* and returns the started ID of that emulator.
|
* and returns the started ID of that emulator.
|
||||||
* If no ID is given it will use the first image available,
|
* If no ID is given it will use the first image available,
|
||||||
* if no image is available it will error out (maybe create one?).
|
* if no image is available it will error out (maybe create one?).
|
||||||
*
|
*
|
||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
module.exports.start = function(emulator_ID) {
|
module.exports.start = function(emulator_ID) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
return Q().then(function() {
|
return Q().then(function() {
|
||||||
if (emulator_ID) return Q(emulator_ID);
|
if (emulator_ID) return Q(emulator_ID);
|
||||||
|
|
||||||
return self.best_image()
|
return self.best_image()
|
||||||
.then(function(best) {
|
.then(function(best) {
|
||||||
if (best && best.name) {
|
if (best && best.name) {
|
||||||
events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
|
events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
|
||||||
return best.name;
|
return best.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
var androidCmd = check_reqs.getAbsoluteAndroidCmd();
|
var androidCmd = check_reqs.getAbsoluteAndroidCmd();
|
||||||
return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
|
return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
|
||||||
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
|
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
|
||||||
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
|
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
|
||||||
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
|
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
|
||||||
});
|
});
|
||||||
}).then(function(emulatorId) {
|
}).then(function(emulatorId) {
|
||||||
var uuid = 'cordova_emulator_' + new Date().getTime();
|
var uuid = 'cordova_emulator_' + new Date().getTime();
|
||||||
var uuidProp = 'emu.uuid=' + uuid;
|
var uuidProp = 'emu.uuid=' + uuid;
|
||||||
var args = ['-avd', emulatorId, '-prop', uuidProp];
|
var args = ['-avd', emulatorId, '-prop', uuidProp];
|
||||||
// Don't wait for it to finish, since the emulator will probably keep running for a long time.
|
// Don't wait for it to finish, since the emulator will probably keep running for a long time.
|
||||||
child_process
|
child_process
|
||||||
.spawn('emulator', args, { stdio: 'inherit', detached: true })
|
.spawn('emulator', args, { stdio: 'inherit', detached: true })
|
||||||
.unref();
|
.unref();
|
||||||
|
|
||||||
// wait for emulator to start
|
// wait for emulator to start
|
||||||
events.emit('log', 'Waiting for emulator...');
|
events.emit('log', 'Waiting for emulator...');
|
||||||
return self.wait_for_emulator(uuid);
|
return self.wait_for_emulator(uuid);
|
||||||
}).then(function(emulatorId) {
|
}).then(function(emulatorId) {
|
||||||
if (!emulatorId)
|
if (!emulatorId)
|
||||||
return Q.reject(new CordovaError('Failed to start emulator'));
|
return Q.reject(new CordovaError('Failed to start emulator'));
|
||||||
|
|
||||||
//wait for emulator to boot up
|
//wait for emulator to boot up
|
||||||
process.stdout.write('Booting up emulator (this may take a while)...');
|
process.stdout.write('Booting up emulator (this may take a while)...');
|
||||||
return self.wait_for_boot(emulatorId)
|
return self.wait_for_boot(emulatorId)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
events.emit('log','BOOT COMPLETE');
|
events.emit('log','BOOT COMPLETE');
|
||||||
//unlock screen
|
//unlock screen
|
||||||
return Adb.shell(emulatorId, 'input keyevent 82');
|
return Adb.shell(emulatorId, 'input keyevent 82');
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
//return the new emulator id for the started emulators
|
//return the new emulator id for the started emulators
|
||||||
return emulatorId;
|
return emulatorId;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Waits for an emulator with given uuid to apear on the started-emulator list.
|
* Waits for an emulator with given uuid to apear on the started-emulator list.
|
||||||
* Returns a promise with this emulator's ID.
|
* Returns a promise with this emulator's ID.
|
||||||
*/
|
*/
|
||||||
module.exports.wait_for_emulator = function(uuid) {
|
module.exports.wait_for_emulator = function(uuid) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return self.list_started()
|
return self.list_started()
|
||||||
.then(function(new_started) {
|
.then(function(new_started) {
|
||||||
var emulator_id = null;
|
var emulator_id = null;
|
||||||
var promises = [];
|
var promises = [];
|
||||||
|
|
||||||
new_started.forEach(function (emulator) {
|
new_started.forEach(function (emulator) {
|
||||||
promises.push(
|
promises.push(
|
||||||
Adb.shell(emulator, 'getprop emu.uuid')
|
Adb.shell(emulator, 'getprop emu.uuid')
|
||||||
.then(function (output) {
|
.then(function (output) {
|
||||||
if (output.indexOf(uuid) >= 0) {
|
if (output.indexOf(uuid) >= 0) {
|
||||||
emulator_id = emulator;
|
emulator_id = emulator;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
return Q.all(promises).then(function () {
|
return Q.all(promises).then(function () {
|
||||||
return emulator_id || self.wait_for_emulator(uuid);
|
return emulator_id || self.wait_for_emulator(uuid);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Waits for the core android process of the emulator to start
|
* Waits for the core android process of the emulator to start
|
||||||
*/
|
*/
|
||||||
module.exports.wait_for_boot = function(emulator_id) {
|
module.exports.wait_for_boot = function(emulator_id) {
|
||||||
var self = this;
|
var self = this;
|
||||||
return Adb.shell(emulator_id, 'ps')
|
return Adb.shell(emulator_id, 'ps')
|
||||||
.then(function(output) {
|
.then(function(output) {
|
||||||
if (output.match(/android\.process\.acore/)) {
|
if (output.match(/android\.process\.acore/)) {
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
process.stdout.write('.');
|
process.stdout.write('.');
|
||||||
return Q.delay(3000).then(function() {
|
return Q.delay(3000).then(function() {
|
||||||
return self.wait_for_boot(emulator_id);
|
return self.wait_for_boot(emulator_id);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create avd
|
* Create avd
|
||||||
* TODO : Enter the stdin input required to complete the creation of an avd.
|
* TODO : Enter the stdin input required to complete the creation of an avd.
|
||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
module.exports.create_image = function(name, target) {
|
module.exports.create_image = function(name, target) {
|
||||||
console.log('Creating avd named ' + name);
|
console.log('Creating avd named ' + name);
|
||||||
if (target) {
|
if (target) {
|
||||||
return spawn('android', ['create', 'avd', '--name', name, '--target', target])
|
return spawn('android', ['create', 'avd', '--name', name, '--target', target])
|
||||||
.then(null, function(error) {
|
.then(null, function(error) {
|
||||||
console.error('ERROR : Failed to create emulator image : ');
|
console.error('ERROR : Failed to create emulator image : ');
|
||||||
console.error(' Do you have the latest android targets including ' + target + '?');
|
console.error(' Do you have the latest android targets including ' + target + '?');
|
||||||
console.error(error);
|
console.error(error);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
|
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
|
||||||
return spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
|
return spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
|
||||||
.then(function() {
|
.then(function() {
|
||||||
// TODO: This seems like another error case, even though it always happens.
|
// TODO: This seems like another error case, even though it always happens.
|
||||||
console.error('ERROR : Unable to create an avd emulator, no targets found.');
|
console.error('ERROR : Unable to create an avd emulator, no targets found.');
|
||||||
console.error('Please insure you have targets available by running the "android" command');
|
console.error('Please insure you have targets available by running the "android" command');
|
||||||
return Q.reject();
|
return Q.reject();
|
||||||
}, function(error) {
|
}, function(error) {
|
||||||
console.error('ERROR : Failed to create emulator image : ');
|
console.error('ERROR : Failed to create emulator image : ');
|
||||||
console.error(error);
|
console.error(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.resolveTarget = function(target) {
|
module.exports.resolveTarget = function(target) {
|
||||||
return this.list_started()
|
return this.list_started()
|
||||||
.then(function(emulator_list) {
|
.then(function(emulator_list) {
|
||||||
if (emulator_list.length < 1) {
|
if (emulator_list.length < 1) {
|
||||||
return Q.reject('No started emulators found, please start an emultor before deploying your project.');
|
return Q.reject('No started emulators found, please start an emultor before deploying your project.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// default emulator
|
// default emulator
|
||||||
target = target || emulator_list[0];
|
target = target || emulator_list[0];
|
||||||
if (emulator_list.indexOf(target) < 0) {
|
if (emulator_list.indexOf(target) < 0) {
|
||||||
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
|
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return build.detectArchitecture(target)
|
return build.detectArchitecture(target)
|
||||||
.then(function(arch) {
|
.then(function(arch) {
|
||||||
return {target:target, arch:arch, isEmulator:true};
|
return {target:target, arch:arch, isEmulator:true};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Installs a previously built application on the emulator and launches it.
|
* Installs a previously built application on the emulator and launches it.
|
||||||
* If no target is specified, then it picks one.
|
* If no target is specified, then it picks one.
|
||||||
* If no started emulators are found, error out.
|
* If no started emulators are found, error out.
|
||||||
* Returns a promise.
|
* Returns a promise.
|
||||||
*/
|
*/
|
||||||
module.exports.install = function(givenTarget, buildResults) {
|
module.exports.install = function(givenTarget, buildResults) {
|
||||||
|
|
||||||
var target;
|
var target;
|
||||||
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
||||||
var pkgName = manifest.getPackageId();
|
var pkgName = manifest.getPackageId();
|
||||||
|
|
||||||
// resolve the target emulator
|
// resolve the target emulator
|
||||||
return Q().then(function () {
|
return Q().then(function () {
|
||||||
if (givenTarget && typeof givenTarget == 'object') {
|
if (givenTarget && typeof givenTarget == 'object') {
|
||||||
return givenTarget;
|
return givenTarget;
|
||||||
} else {
|
} else {
|
||||||
return module.exports.resolveTarget(givenTarget);
|
return module.exports.resolveTarget(givenTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the resolved target
|
// set the resolved target
|
||||||
}).then(function (resolvedTarget) {
|
}).then(function (resolvedTarget) {
|
||||||
target = resolvedTarget;
|
target = resolvedTarget;
|
||||||
|
|
||||||
// install the app
|
// install the app
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
|
||||||
// or the app doesn't installed at all, so no error catching needed.
|
// or the app doesn't installed at all, so no error catching needed.
|
||||||
return Adb.uninstall(target.target, pkgName)
|
return Adb.uninstall(target.target, pkgName)
|
||||||
.then(function() {
|
.then(function() {
|
||||||
|
|
||||||
var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
|
var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
|
||||||
var execOptions = {
|
var execOptions = {
|
||||||
cwd: os.tmpdir(),
|
cwd: os.tmpdir(),
|
||||||
timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
|
timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
|
||||||
killSignal: EXEC_KILL_SIGNAL
|
killSignal: EXEC_KILL_SIGNAL
|
||||||
};
|
};
|
||||||
|
|
||||||
events.emit('log', 'Using apk: ' + apk_path);
|
events.emit('log', 'Using apk: ' + apk_path);
|
||||||
events.emit('verbose', 'Installing app on emulator...');
|
events.emit('verbose', 'Installing app on emulator...');
|
||||||
|
|
||||||
function exec(command, opts) {
|
function exec(command, opts) {
|
||||||
return Q.promise(function (resolve, reject) {
|
return Q.promise(function (resolve, reject) {
|
||||||
child_process.exec(command, opts, function(err, stdout, stderr) {
|
child_process.exec(command, opts, function(err, stdout, stderr) {
|
||||||
if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
|
if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
|
||||||
else resolve(stdout);
|
else resolve(stdout);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var retriedInstall = retry.retryPromise(
|
var retriedInstall = retry.retryPromise(
|
||||||
NUM_INSTALL_RETRIES,
|
NUM_INSTALL_RETRIES,
|
||||||
exec, 'adb -s ' + target.target + ' install -r "' + apk_path + '"', execOptions
|
exec, 'adb -s ' + target.target + ' install -r "' + apk_path + '"', execOptions
|
||||||
);
|
);
|
||||||
|
|
||||||
return retriedInstall.then(function (output) {
|
return retriedInstall.then(function (output) {
|
||||||
if (output.match(/Failure/)) {
|
if (output.match(/Failure/)) {
|
||||||
return Q.reject(new CordovaError('Failed to install apk to emulator: ' + output));
|
return Q.reject(new CordovaError('Failed to install apk to emulator: ' + output));
|
||||||
} else {
|
} else {
|
||||||
events.emit('log', 'INSTALL SUCCESS');
|
events.emit('log', 'INSTALL SUCCESS');
|
||||||
}
|
}
|
||||||
}, function (err) {
|
}, function (err) {
|
||||||
return Q.reject(new CordovaError('Failed to install apk to emulator: ' + err));
|
return Q.reject(new CordovaError('Failed to install apk to emulator: ' + err));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// unlock screen
|
// unlock screen
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
|
|
||||||
events.emit('verbose', 'Unlocking screen...');
|
events.emit('verbose', 'Unlocking screen...');
|
||||||
return Adb.shell(target.target, 'input keyevent 82');
|
return Adb.shell(target.target, 'input keyevent 82');
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
|
Adb.start(target.target, pkgName + '/.' + manifest.getActivity().getName());
|
||||||
// report success or failure
|
// report success or failure
|
||||||
}).then(function (output) {
|
}).then(function (output) {
|
||||||
events.emit('log', 'LAUNCH SUCCESS');
|
events.emit('log', 'LAUNCH SUCCESS');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
504
bin/templates/cordova/lib/pluginHandlers.js
vendored
504
bin/templates/cordova/lib/pluginHandlers.js
vendored
@ -1,252 +1,252 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Copyright 2013 Anis Kadri
|
* Copyright 2013 Anis Kadri
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* 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,
|
* Unless required by applicable law or agreed to in writing,
|
||||||
* software distributed under the License is distributed on an
|
* software distributed under the License is distributed on an
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
* KIND, either express or implied. See the License for the
|
* KIND, either express or implied. See the License for the
|
||||||
* specific language governing permissions and limitations
|
* specific language governing permissions and limitations
|
||||||
* under the License.
|
* under the License.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* jshint unused: vars */
|
/* jshint unused: vars */
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var shell = require('shelljs');
|
var shell = require('shelljs');
|
||||||
var events = require('cordova-common').events;
|
var events = require('cordova-common').events;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
var handlers = {
|
var handlers = {
|
||||||
'source-file':{
|
'source-file':{
|
||||||
install:function(obj, plugin, project, options) {
|
install:function(obj, plugin, project, options) {
|
||||||
if (!obj.src) throw new CordovaError('<source-file> element is missing "src" attribute for plugin: ' + plugin.id);
|
if (!obj.src) throw new CordovaError('<source-file> element is missing "src" attribute for plugin: ' + plugin.id);
|
||||||
if (!obj.targetDir) throw new CordovaError('<source-file> element is missing "target-dir" attribute for plugin: ' + plugin.id);
|
if (!obj.targetDir) throw new CordovaError('<source-file> element is missing "target-dir" attribute for plugin: ' + plugin.id);
|
||||||
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
||||||
copyNewFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
|
copyNewFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
|
||||||
},
|
},
|
||||||
uninstall:function(obj, plugin, project, options) {
|
uninstall:function(obj, plugin, project, options) {
|
||||||
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
||||||
deleteJava(project.projectDir, dest);
|
deleteJava(project.projectDir, dest);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'lib-file':{
|
'lib-file':{
|
||||||
install:function(obj, plugin, project, options) {
|
install:function(obj, plugin, project, options) {
|
||||||
var dest = path.join('libs', path.basename(obj.src));
|
var dest = path.join('libs', path.basename(obj.src));
|
||||||
copyFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
|
copyFile(plugin.dir, obj.src, project.projectDir, dest, options && options.link);
|
||||||
},
|
},
|
||||||
uninstall:function(obj, plugin, project, options) {
|
uninstall:function(obj, plugin, project, options) {
|
||||||
var dest = path.join('libs', path.basename(obj.src));
|
var dest = path.join('libs', path.basename(obj.src));
|
||||||
removeFile(project.projectDir, dest);
|
removeFile(project.projectDir, dest);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'resource-file':{
|
'resource-file':{
|
||||||
install:function(obj, plugin, project, options) {
|
install:function(obj, plugin, project, options) {
|
||||||
copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), options && options.link);
|
copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), options && options.link);
|
||||||
},
|
},
|
||||||
uninstall:function(obj, plugin, project, options) {
|
uninstall:function(obj, plugin, project, options) {
|
||||||
removeFile(project.projectDir, path.normalize(obj.target));
|
removeFile(project.projectDir, path.normalize(obj.target));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'framework': {
|
'framework': {
|
||||||
install:function(obj, plugin, project, options) {
|
install:function(obj, plugin, project, options) {
|
||||||
var src = obj.src;
|
var src = obj.src;
|
||||||
if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
|
if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
|
||||||
|
|
||||||
events.emit('verbose', 'Installing Android library: ' + src);
|
events.emit('verbose', 'Installing Android library: ' + src);
|
||||||
var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
|
var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
|
||||||
var subDir;
|
var subDir;
|
||||||
|
|
||||||
if (obj.custom) {
|
if (obj.custom) {
|
||||||
var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
|
var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
|
||||||
copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, options && options.link);
|
copyNewFile(plugin.dir, src, project.projectDir, subRelativeDir, options && options.link);
|
||||||
subDir = path.resolve(project.projectDir, subRelativeDir);
|
subDir = path.resolve(project.projectDir, subRelativeDir);
|
||||||
} else {
|
} else {
|
||||||
obj.type = 'sys';
|
obj.type = 'sys';
|
||||||
subDir = src;
|
subDir = src;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.type == 'gradleReference') {
|
if (obj.type == 'gradleReference') {
|
||||||
project.addGradleReference(parentDir, subDir);
|
project.addGradleReference(parentDir, subDir);
|
||||||
} else if (obj.type == 'sys') {
|
} else if (obj.type == 'sys') {
|
||||||
project.addSystemLibrary(parentDir, subDir);
|
project.addSystemLibrary(parentDir, subDir);
|
||||||
} else {
|
} else {
|
||||||
project.addSubProject(parentDir, subDir);
|
project.addSubProject(parentDir, subDir);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
uninstall:function(obj, plugin, project, options) {
|
uninstall:function(obj, plugin, project, options) {
|
||||||
var src = obj.src;
|
var src = obj.src;
|
||||||
if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
|
if (!src) throw new CordovaError('src not specified in <framework> for plugin: ' + plugin.id);
|
||||||
|
|
||||||
events.emit('verbose', 'Uninstalling Android library: ' + src);
|
events.emit('verbose', 'Uninstalling Android library: ' + src);
|
||||||
var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
|
var parentDir = obj.parent ? path.resolve(project.projectDir, obj.parent) : project.projectDir;
|
||||||
var subDir;
|
var subDir;
|
||||||
|
|
||||||
if (obj.custom) {
|
if (obj.custom) {
|
||||||
var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
|
var subRelativeDir = project.getCustomSubprojectRelativeDir(plugin.id, src);
|
||||||
removeFile(project.projectDir, subRelativeDir);
|
removeFile(project.projectDir, subRelativeDir);
|
||||||
subDir = path.resolve(project.projectDir, subRelativeDir);
|
subDir = path.resolve(project.projectDir, subRelativeDir);
|
||||||
// If it's the last framework in the plugin, remove the parent directory.
|
// If it's the last framework in the plugin, remove the parent directory.
|
||||||
var parDir = path.dirname(subDir);
|
var parDir = path.dirname(subDir);
|
||||||
if (fs.readdirSync(parDir).length === 0) {
|
if (fs.readdirSync(parDir).length === 0) {
|
||||||
fs.rmdirSync(parDir);
|
fs.rmdirSync(parDir);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
obj.type = 'sys';
|
obj.type = 'sys';
|
||||||
subDir = src;
|
subDir = src;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.type == 'gradleReference') {
|
if (obj.type == 'gradleReference') {
|
||||||
project.removeGradleReference(parentDir, subDir);
|
project.removeGradleReference(parentDir, subDir);
|
||||||
} else if (obj.type == 'sys') {
|
} else if (obj.type == 'sys') {
|
||||||
project.removeSystemLibrary(parentDir, subDir);
|
project.removeSystemLibrary(parentDir, subDir);
|
||||||
} else {
|
} else {
|
||||||
project.removeSubProject(parentDir, subDir);
|
project.removeSubProject(parentDir, subDir);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
asset:{
|
asset:{
|
||||||
install:function(obj, plugin, project, options) {
|
install:function(obj, plugin, project, options) {
|
||||||
if (!obj.src) {
|
if (!obj.src) {
|
||||||
throw new CordovaError('<asset> tag without required "src" attribute. plugin=' + plugin.dir);
|
throw new CordovaError('<asset> tag without required "src" attribute. plugin=' + plugin.dir);
|
||||||
}
|
}
|
||||||
if (!obj.target) {
|
if (!obj.target) {
|
||||||
throw new CordovaError('<asset> tag without required "target" attribute');
|
throw new CordovaError('<asset> tag without required "target" attribute');
|
||||||
}
|
}
|
||||||
|
|
||||||
var www = options.usePlatformWww ? project.platformWww : project.www;
|
var www = options.usePlatformWww ? project.platformWww : project.www;
|
||||||
copyFile(plugin.dir, obj.src, www, obj.target);
|
copyFile(plugin.dir, obj.src, www, obj.target);
|
||||||
},
|
},
|
||||||
uninstall:function(obj, plugin, project, options) {
|
uninstall:function(obj, plugin, project, options) {
|
||||||
var target = obj.target || obj.src;
|
var target = obj.target || obj.src;
|
||||||
|
|
||||||
if (!target) throw new CordovaError('<asset> tag without required "target" attribute');
|
if (!target) throw new CordovaError('<asset> tag without required "target" attribute');
|
||||||
|
|
||||||
var www = options.usePlatformWww ? project.platformWww : project.www;
|
var www = options.usePlatformWww ? project.platformWww : project.www;
|
||||||
removeFile(www, target);
|
removeFile(www, target);
|
||||||
removeFileF(path.resolve(www, 'plugins', plugin.id));
|
removeFileF(path.resolve(www, 'plugins', plugin.id));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'js-module': {
|
'js-module': {
|
||||||
install: function (obj, plugin, project, options) {
|
install: function (obj, plugin, project, options) {
|
||||||
// Copy the plugin's files into the www directory.
|
// Copy the plugin's files into the www directory.
|
||||||
var moduleSource = path.resolve(plugin.dir, obj.src);
|
var moduleSource = path.resolve(plugin.dir, obj.src);
|
||||||
var moduleName = plugin.id + '.' + (obj.name || path.parse(obj.src).name);
|
var moduleName = plugin.id + '.' + (obj.name || path.parse(obj.src).name);
|
||||||
|
|
||||||
// Read in the file, prepend the cordova.define, and write it back out.
|
// Read in the file, prepend the cordova.define, and write it back out.
|
||||||
var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
|
var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
|
||||||
if (moduleSource.match(/.*\.json$/)) {
|
if (moduleSource.match(/.*\.json$/)) {
|
||||||
scriptContent = 'module.exports = ' + scriptContent;
|
scriptContent = 'module.exports = ' + scriptContent;
|
||||||
}
|
}
|
||||||
scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
|
scriptContent = 'cordova.define("' + moduleName + '", function(require, exports, module) {\n' + scriptContent + '\n});\n';
|
||||||
|
|
||||||
var www = options.usePlatformWww ? project.platformWww : project.www;
|
var www = options.usePlatformWww ? project.platformWww : project.www;
|
||||||
var moduleDestination = path.resolve(www, 'plugins', plugin.id, obj.src);
|
var moduleDestination = path.resolve(www, 'plugins', plugin.id, obj.src);
|
||||||
shell.mkdir('-p', path.dirname(moduleDestination));
|
shell.mkdir('-p', path.dirname(moduleDestination));
|
||||||
fs.writeFileSync(moduleDestination, scriptContent, 'utf-8');
|
fs.writeFileSync(moduleDestination, scriptContent, 'utf-8');
|
||||||
},
|
},
|
||||||
uninstall: function (obj, plugin, project, options) {
|
uninstall: function (obj, plugin, project, options) {
|
||||||
var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
|
var pluginRelativePath = path.join('plugins', plugin.id, obj.src);
|
||||||
var www = options.usePlatformWww ? project.platformWww : project.www;
|
var www = options.usePlatformWww ? project.platformWww : project.www;
|
||||||
removeFileAndParents(www, pluginRelativePath);
|
removeFileAndParents(www, pluginRelativePath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.getInstaller = function (type) {
|
module.exports.getInstaller = function (type) {
|
||||||
if (handlers[type] && handlers[type].install) {
|
if (handlers[type] && handlers[type].install) {
|
||||||
return handlers[type].install;
|
return handlers[type].install;
|
||||||
}
|
}
|
||||||
|
|
||||||
events.emit('verbose', '<' + type + '> is not supported for android plugins');
|
events.emit('verbose', '<' + type + '> is not supported for android plugins');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.getUninstaller = function(type) {
|
module.exports.getUninstaller = function(type) {
|
||||||
if (handlers[type] && handlers[type].uninstall) {
|
if (handlers[type] && handlers[type].uninstall) {
|
||||||
return handlers[type].uninstall;
|
return handlers[type].uninstall;
|
||||||
}
|
}
|
||||||
|
|
||||||
events.emit('verbose', '<' + type + '> is not supported for android plugins');
|
events.emit('verbose', '<' + type + '> is not supported for android plugins');
|
||||||
};
|
};
|
||||||
|
|
||||||
function copyFile (plugin_dir, src, project_dir, dest, link) {
|
function copyFile (plugin_dir, src, project_dir, dest, link) {
|
||||||
src = path.resolve(plugin_dir, src);
|
src = path.resolve(plugin_dir, src);
|
||||||
if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
|
if (!fs.existsSync(src)) throw new CordovaError('"' + src + '" not found!');
|
||||||
|
|
||||||
// check that src path is inside plugin directory
|
// check that src path is inside plugin directory
|
||||||
var real_path = fs.realpathSync(src);
|
var real_path = fs.realpathSync(src);
|
||||||
var real_plugin_path = fs.realpathSync(plugin_dir);
|
var real_plugin_path = fs.realpathSync(plugin_dir);
|
||||||
if (real_path.indexOf(real_plugin_path) !== 0)
|
if (real_path.indexOf(real_plugin_path) !== 0)
|
||||||
throw new CordovaError('"' + src + '" not located within plugin!');
|
throw new CordovaError('"' + src + '" not located within plugin!');
|
||||||
|
|
||||||
dest = path.resolve(project_dir, dest);
|
dest = path.resolve(project_dir, dest);
|
||||||
|
|
||||||
// check that dest path is located in project directory
|
// check that dest path is located in project directory
|
||||||
if (dest.indexOf(project_dir) !== 0)
|
if (dest.indexOf(project_dir) !== 0)
|
||||||
throw new CordovaError('"' + dest + '" not located within project!');
|
throw new CordovaError('"' + dest + '" not located within project!');
|
||||||
|
|
||||||
shell.mkdir('-p', path.dirname(dest));
|
shell.mkdir('-p', path.dirname(dest));
|
||||||
|
|
||||||
if (link) {
|
if (link) {
|
||||||
fs.symlinkSync(path.relative(path.dirname(dest), src), dest);
|
fs.symlinkSync(path.relative(path.dirname(dest), src), dest);
|
||||||
} else if (fs.statSync(src).isDirectory()) {
|
} else if (fs.statSync(src).isDirectory()) {
|
||||||
// XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
|
// XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
|
||||||
shell.cp('-Rf', src+'/*', dest);
|
shell.cp('-Rf', src+'/*', dest);
|
||||||
} else {
|
} else {
|
||||||
shell.cp('-f', src, dest);
|
shell.cp('-f', src, dest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Same as copy file but throws error if target exists
|
// Same as copy file but throws error if target exists
|
||||||
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
|
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
|
||||||
var target_path = path.resolve(project_dir, dest);
|
var target_path = path.resolve(project_dir, dest);
|
||||||
if (fs.existsSync(target_path))
|
if (fs.existsSync(target_path))
|
||||||
throw new CordovaError('"' + target_path + '" already exists!');
|
throw new CordovaError('"' + target_path + '" already exists!');
|
||||||
|
|
||||||
copyFile(plugin_dir, src, project_dir, dest, !!link);
|
copyFile(plugin_dir, src, project_dir, dest, !!link);
|
||||||
}
|
}
|
||||||
|
|
||||||
// checks if file exists and then deletes. Error if doesn't exist
|
// checks if file exists and then deletes. Error if doesn't exist
|
||||||
function removeFile (project_dir, src) {
|
function removeFile (project_dir, src) {
|
||||||
var file = path.resolve(project_dir, src);
|
var file = path.resolve(project_dir, src);
|
||||||
shell.rm('-Rf', file);
|
shell.rm('-Rf', file);
|
||||||
}
|
}
|
||||||
|
|
||||||
// deletes file/directory without checking
|
// deletes file/directory without checking
|
||||||
function removeFileF (file) {
|
function removeFileF (file) {
|
||||||
shell.rm('-Rf', file);
|
shell.rm('-Rf', file);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sometimes we want to remove some java, and prune any unnecessary empty directories
|
// Sometimes we want to remove some java, and prune any unnecessary empty directories
|
||||||
function deleteJava (project_dir, destFile) {
|
function deleteJava (project_dir, destFile) {
|
||||||
removeFileAndParents(project_dir, destFile, 'src');
|
removeFileAndParents(project_dir, destFile, 'src');
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeFileAndParents (baseDir, destFile, stopper) {
|
function removeFileAndParents (baseDir, destFile, stopper) {
|
||||||
stopper = stopper || '.';
|
stopper = stopper || '.';
|
||||||
var file = path.resolve(baseDir, destFile);
|
var file = path.resolve(baseDir, destFile);
|
||||||
if (!fs.existsSync(file)) return;
|
if (!fs.existsSync(file)) return;
|
||||||
|
|
||||||
removeFileF(file);
|
removeFileF(file);
|
||||||
|
|
||||||
// check if directory is empty
|
// check if directory is empty
|
||||||
var curDir = path.dirname(file);
|
var curDir = path.dirname(file);
|
||||||
|
|
||||||
while(curDir !== path.resolve(baseDir, stopper)) {
|
while(curDir !== path.resolve(baseDir, stopper)) {
|
||||||
if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
|
if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
|
||||||
fs.rmdirSync(curDir);
|
fs.rmdirSync(curDir);
|
||||||
curDir = path.resolve(curDir, '..');
|
curDir = path.resolve(curDir, '..');
|
||||||
} else {
|
} else {
|
||||||
// directory not empty...do nothing
|
// directory not empty...do nothing
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
728
bin/templates/cordova/lib/prepare.js
vendored
728
bin/templates/cordova/lib/prepare.js
vendored
@ -1,364 +1,364 @@
|
|||||||
/**
|
/**
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Q = require('q');
|
var Q = require('q');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var shell = require('shelljs');
|
var shell = require('shelljs');
|
||||||
var events = require('cordova-common').events;
|
var events = require('cordova-common').events;
|
||||||
var AndroidManifest = require('./AndroidManifest');
|
var AndroidManifest = require('./AndroidManifest');
|
||||||
var xmlHelpers = require('cordova-common').xmlHelpers;
|
var xmlHelpers = require('cordova-common').xmlHelpers;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
var ConfigParser = require('cordova-common').ConfigParser;
|
var ConfigParser = require('cordova-common').ConfigParser;
|
||||||
|
|
||||||
module.exports.prepare = function (cordovaProject) {
|
module.exports.prepare = function (cordovaProject) {
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
this._config = updateConfigFilesFrom(cordovaProject.projectConfig,
|
this._config = updateConfigFilesFrom(cordovaProject.projectConfig,
|
||||||
this._munger, this.locations);
|
this._munger, this.locations);
|
||||||
|
|
||||||
// Update own www dir with project's www assets and plugins' assets and js-files
|
// Update own www dir with project's www assets and plugins' assets and js-files
|
||||||
return Q.when(updateWwwFrom(cordovaProject, this.locations))
|
return Q.when(updateWwwFrom(cordovaProject, this.locations))
|
||||||
.then(function () {
|
.then(function () {
|
||||||
// update project according to config.xml changes.
|
// update project according to config.xml changes.
|
||||||
return updateProjectAccordingTo(self._config, self.locations);
|
return updateProjectAccordingTo(self._config, self.locations);
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
handleIcons(cordovaProject.projectConfig, self.root);
|
handleIcons(cordovaProject.projectConfig, self.root);
|
||||||
handleSplashes(cordovaProject.projectConfig, self.root);
|
handleSplashes(cordovaProject.projectConfig, self.root);
|
||||||
})
|
})
|
||||||
.then(function () {
|
.then(function () {
|
||||||
self.events.emit('verbose', 'updated project successfully');
|
self.events.emit('verbose', 'updated project successfully');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates config files in project based on app's config.xml and config munge,
|
* Updates config files in project based on app's config.xml and config munge,
|
||||||
* generated by plugins.
|
* generated by plugins.
|
||||||
*
|
*
|
||||||
* @param {ConfigParser} sourceConfig A project's configuration that will
|
* @param {ConfigParser} sourceConfig A project's configuration that will
|
||||||
* be merged into platform's config.xml
|
* be merged into platform's config.xml
|
||||||
* @param {ConfigChanges} configMunger An initialized ConfigChanges instance
|
* @param {ConfigChanges} configMunger An initialized ConfigChanges instance
|
||||||
* for this platform.
|
* for this platform.
|
||||||
* @param {Object} locations A map of locations for this platform
|
* @param {Object} locations A map of locations for this platform
|
||||||
*
|
*
|
||||||
* @return {ConfigParser} An instance of ConfigParser, that
|
* @return {ConfigParser} An instance of ConfigParser, that
|
||||||
* represents current project's configuration. When returned, the
|
* represents current project's configuration. When returned, the
|
||||||
* configuration is already dumped to appropriate config.xml file.
|
* configuration is already dumped to appropriate config.xml file.
|
||||||
*/
|
*/
|
||||||
function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
|
function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
|
||||||
events.emit('verbose', 'Generating config.xml from defaults for platform "android"');
|
events.emit('verbose', 'Generating config.xml from defaults for platform "android"');
|
||||||
|
|
||||||
// First cleanup current config and merge project's one into own
|
// First cleanup current config and merge project's one into own
|
||||||
// Overwrite platform config.xml with defaults.xml.
|
// Overwrite platform config.xml with defaults.xml.
|
||||||
shell.cp('-f', locations.defaultConfigXml, locations.configXml);
|
shell.cp('-f', locations.defaultConfigXml, locations.configXml);
|
||||||
|
|
||||||
// Then apply config changes from global munge to all config files
|
// Then apply config changes from global munge to all config files
|
||||||
// in project (including project's config)
|
// in project (including project's config)
|
||||||
configMunger.reapply_global_munge().save_all();
|
configMunger.reapply_global_munge().save_all();
|
||||||
|
|
||||||
// Merge changes from app's config.xml into platform's one
|
// Merge changes from app's config.xml into platform's one
|
||||||
var config = new ConfigParser(locations.configXml);
|
var config = new ConfigParser(locations.configXml);
|
||||||
xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
|
xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
|
||||||
config.doc.getroot(), 'android', /*clobber=*/true);
|
config.doc.getroot(), 'android', /*clobber=*/true);
|
||||||
|
|
||||||
config.write();
|
config.write();
|
||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates platform 'www' directory by replacing it with contents of
|
* Updates platform 'www' directory by replacing it with contents of
|
||||||
* 'platform_www' and app www. Also copies project's overrides' folder into
|
* 'platform_www' and app www. Also copies project's overrides' folder into
|
||||||
* the platform 'www' folder
|
* the platform 'www' folder
|
||||||
*
|
*
|
||||||
* @param {Object} cordovaProject An object which describes cordova project.
|
* @param {Object} cordovaProject An object which describes cordova project.
|
||||||
* @param {Object} destinations An object that contains destination
|
* @param {Object} destinations An object that contains destination
|
||||||
* paths for www files.
|
* paths for www files.
|
||||||
*/
|
*/
|
||||||
function updateWwwFrom(cordovaProject, destinations) {
|
function updateWwwFrom(cordovaProject, destinations) {
|
||||||
shell.rm('-rf', destinations.www);
|
shell.rm('-rf', destinations.www);
|
||||||
shell.mkdir('-p', destinations.www);
|
shell.mkdir('-p', destinations.www);
|
||||||
// Copy source files from project's www directory
|
// Copy source files from project's www directory
|
||||||
shell.cp('-rf', path.join(cordovaProject.locations.www, '*'), destinations.www);
|
shell.cp('-rf', path.join(cordovaProject.locations.www, '*'), destinations.www);
|
||||||
// Override www sources by files in 'platform_www' directory
|
// Override www sources by files in 'platform_www' directory
|
||||||
shell.cp('-rf', path.join(destinations.platformWww, '*'), destinations.www);
|
shell.cp('-rf', path.join(destinations.platformWww, '*'), destinations.www);
|
||||||
|
|
||||||
// If project contains 'merges' for our platform, use them as another overrides
|
// If project contains 'merges' for our platform, use them as another overrides
|
||||||
var merges_path = path.join(cordovaProject.root, 'merges', 'android');
|
var merges_path = path.join(cordovaProject.root, 'merges', 'android');
|
||||||
if (fs.existsSync(merges_path)) {
|
if (fs.existsSync(merges_path)) {
|
||||||
events.emit('verbose', 'Found "merges" for android platform. Copying over existing "www" files.');
|
events.emit('verbose', 'Found "merges" for android platform. Copying over existing "www" files.');
|
||||||
var overrides = path.join(merges_path, '*');
|
var overrides = path.join(merges_path, '*');
|
||||||
shell.cp('-rf', overrides, destinations.www);
|
shell.cp('-rf', overrides, destinations.www);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Updates project structure and AndroidManifest according to project's configuration.
|
* Updates project structure and AndroidManifest according to project's configuration.
|
||||||
*
|
*
|
||||||
* @param {ConfigParser} platformConfig A project's configuration that will
|
* @param {ConfigParser} platformConfig A project's configuration that will
|
||||||
* be used to update project
|
* be used to update project
|
||||||
* @param {Object} locations A map of locations for this platform
|
* @param {Object} locations A map of locations for this platform
|
||||||
*/
|
*/
|
||||||
function updateProjectAccordingTo(platformConfig, locations) {
|
function updateProjectAccordingTo(platformConfig, locations) {
|
||||||
// Update app name by editing res/values/strings.xml
|
// Update app name by editing res/values/strings.xml
|
||||||
var name = platformConfig.name();
|
var name = platformConfig.name();
|
||||||
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
|
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
|
||||||
strings.find('string[@name="app_name"]').text = name;
|
strings.find('string[@name="app_name"]').text = name;
|
||||||
fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
|
fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
|
||||||
events.emit('verbose', 'Wrote out Android application name to "' + name + '"');
|
events.emit('verbose', 'Wrote out Android application name to "' + name + '"');
|
||||||
|
|
||||||
// Java packages cannot support dashes
|
// Java packages cannot support dashes
|
||||||
var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
|
var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
|
||||||
|
|
||||||
var manifest = new AndroidManifest(locations.manifest);
|
var manifest = new AndroidManifest(locations.manifest);
|
||||||
var orig_pkg = manifest.getPackageId();
|
var orig_pkg = manifest.getPackageId();
|
||||||
|
|
||||||
manifest.getActivity()
|
manifest.getActivity()
|
||||||
.setOrientation(findOrientationValue(platformConfig))
|
.setOrientation(findOrientationValue(platformConfig))
|
||||||
.setLaunchMode(findAndroidLaunchModePreference(platformConfig));
|
.setLaunchMode(findAndroidLaunchModePreference(platformConfig));
|
||||||
|
|
||||||
manifest.setVersionName(platformConfig.version())
|
manifest.setVersionName(platformConfig.version())
|
||||||
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
|
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
|
||||||
.setPackageId(pkg)
|
.setPackageId(pkg)
|
||||||
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
|
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
|
||||||
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
|
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
|
||||||
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
|
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
|
||||||
.write();
|
.write();
|
||||||
|
|
||||||
var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
|
var javaPattern = path.join(locations.root, 'src', 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);
|
return shell.grep(/extends\s+CordovaActivity/g, f);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (java_files.length === 0) {
|
if (java_files.length === 0) {
|
||||||
throw new CordovaError('No Java files found which extend CordovaActivity.');
|
throw new CordovaError('No Java files found which extend CordovaActivity.');
|
||||||
} else if(java_files.length > 1) {
|
} else if(java_files.length > 1) {
|
||||||
events.emit('log', 'Multiple candidate Java files (.java files which extend CordovaActivity) found. Guessing at the first one, ' + java_files[0]);
|
events.emit('log', 'Multiple candidate Java files (.java files which extend CordovaActivity) found. Guessing at the first one, ' + java_files[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
|
var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
|
||||||
shell.mkdir('-p', path.dirname(destFile));
|
shell.mkdir('-p', path.dirname(destFile));
|
||||||
shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
|
shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
|
||||||
events.emit('verbose', 'Wrote out Android package name to "' + pkg + '"');
|
events.emit('verbose', 'Wrote out Android package name to "' + pkg + '"');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Consturct the default value for versionCode as
|
// Consturct the default value for versionCode as
|
||||||
// PATCH + MINOR * 100 + MAJOR * 10000
|
// PATCH + MINOR * 100 + MAJOR * 10000
|
||||||
// see http://developer.android.com/tools/publishing/versioning.html
|
// see http://developer.android.com/tools/publishing/versioning.html
|
||||||
function default_versionCode(version) {
|
function default_versionCode(version) {
|
||||||
var nums = version.split('-')[0].split('.');
|
var nums = version.split('-')[0].split('.');
|
||||||
var versionCode = 0;
|
var versionCode = 0;
|
||||||
if (+nums[0]) {
|
if (+nums[0]) {
|
||||||
versionCode += +nums[0] * 10000;
|
versionCode += +nums[0] * 10000;
|
||||||
}
|
}
|
||||||
if (+nums[1]) {
|
if (+nums[1]) {
|
||||||
versionCode += +nums[1] * 100;
|
versionCode += +nums[1] * 100;
|
||||||
}
|
}
|
||||||
if (+nums[2]) {
|
if (+nums[2]) {
|
||||||
versionCode += +nums[2];
|
versionCode += +nums[2];
|
||||||
}
|
}
|
||||||
return versionCode;
|
return versionCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyImage(src, resourcesDir, density, name) {
|
function copyImage(src, resourcesDir, density, name) {
|
||||||
var destFolder = path.join(resourcesDir, (density ? 'drawable-': 'drawable') + density);
|
var destFolder = path.join(resourcesDir, (density ? 'drawable-': 'drawable') + density);
|
||||||
var isNinePatch = !!/\.9\.png$/.exec(src);
|
var isNinePatch = !!/\.9\.png$/.exec(src);
|
||||||
var ninePatchName = name.replace(/\.png$/, '.9.png');
|
var ninePatchName = name.replace(/\.png$/, '.9.png');
|
||||||
|
|
||||||
// default template does not have default asset for this density
|
// default template does not have default asset for this density
|
||||||
if (!fs.existsSync(destFolder)) {
|
if (!fs.existsSync(destFolder)) {
|
||||||
fs.mkdirSync(destFolder);
|
fs.mkdirSync(destFolder);
|
||||||
}
|
}
|
||||||
|
|
||||||
var destFilePath = path.join(destFolder, isNinePatch ? ninePatchName : name);
|
var destFilePath = path.join(destFolder, isNinePatch ? ninePatchName : name);
|
||||||
events.emit('verbose', 'copying image from ' + src + ' to ' + destFilePath);
|
events.emit('verbose', 'copying image from ' + src + ' to ' + destFilePath);
|
||||||
shell.cp('-f', src, destFilePath);
|
shell.cp('-f', src, destFilePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSplashes(projectConfig, platformRoot) {
|
function handleSplashes(projectConfig, platformRoot) {
|
||||||
var resources = projectConfig.getSplashScreens('android');
|
var resources = projectConfig.getSplashScreens('android');
|
||||||
// if there are "splash" elements in config.xml
|
// if there are "splash" elements in config.xml
|
||||||
if (resources.length > 0) {
|
if (resources.length > 0) {
|
||||||
deleteDefaultResourceAt(platformRoot, 'screen.png');
|
deleteDefaultResourceAt(platformRoot, 'screen.png');
|
||||||
events.emit('verbose', 'splash screens: ' + JSON.stringify(resources));
|
events.emit('verbose', 'splash screens: ' + JSON.stringify(resources));
|
||||||
|
|
||||||
// The source paths for icons and splashes are relative to
|
// The source paths for icons and splashes are relative to
|
||||||
// project's config.xml location, so we use it as base path.
|
// project's config.xml location, so we use it as base path.
|
||||||
var projectRoot = path.dirname(projectConfig.path);
|
var projectRoot = path.dirname(projectConfig.path);
|
||||||
var destination = path.join(platformRoot, 'res');
|
var destination = path.join(platformRoot, 'res');
|
||||||
|
|
||||||
var hadMdpi = false;
|
var hadMdpi = false;
|
||||||
resources.forEach(function (resource) {
|
resources.forEach(function (resource) {
|
||||||
if (!resource.density) {
|
if (!resource.density) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (resource.density == 'mdpi') {
|
if (resource.density == 'mdpi') {
|
||||||
hadMdpi = true;
|
hadMdpi = true;
|
||||||
}
|
}
|
||||||
copyImage(path.join(projectRoot, resource.src), destination, resource.density, 'screen.png');
|
copyImage(path.join(projectRoot, resource.src), destination, resource.density, 'screen.png');
|
||||||
});
|
});
|
||||||
// There's no "default" drawable, so assume default == mdpi.
|
// There's no "default" drawable, so assume default == mdpi.
|
||||||
if (!hadMdpi && resources.defaultResource) {
|
if (!hadMdpi && resources.defaultResource) {
|
||||||
copyImage(path.join(projectRoot, resources.defaultResource.src), destination, 'mdpi', 'screen.png');
|
copyImage(path.join(projectRoot, resources.defaultResource.src), destination, 'mdpi', 'screen.png');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleIcons(projectConfig, platformRoot) {
|
function handleIcons(projectConfig, platformRoot) {
|
||||||
var icons = projectConfig.getIcons('android');
|
var icons = projectConfig.getIcons('android');
|
||||||
|
|
||||||
// if there are icon elements in config.xml
|
// if there are icon elements in config.xml
|
||||||
if (icons.length === 0) {
|
if (icons.length === 0) {
|
||||||
events.emit('verbose', 'This app does not have launcher icons defined');
|
events.emit('verbose', 'This app does not have launcher icons defined');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteDefaultResourceAt(platformRoot, 'icon.png');
|
deleteDefaultResourceAt(platformRoot, 'icon.png');
|
||||||
|
|
||||||
var android_icons = {};
|
var android_icons = {};
|
||||||
var default_icon;
|
var default_icon;
|
||||||
// http://developer.android.com/design/style/iconography.html
|
// http://developer.android.com/design/style/iconography.html
|
||||||
var sizeToDensityMap = {
|
var sizeToDensityMap = {
|
||||||
36: 'ldpi',
|
36: 'ldpi',
|
||||||
48: 'mdpi',
|
48: 'mdpi',
|
||||||
72: 'hdpi',
|
72: 'hdpi',
|
||||||
96: 'xhdpi',
|
96: 'xhdpi',
|
||||||
144: 'xxhdpi',
|
144: 'xxhdpi',
|
||||||
192: 'xxxhdpi'
|
192: 'xxxhdpi'
|
||||||
};
|
};
|
||||||
// find the best matching icon for a given density or size
|
// find the best matching icon for a given density or size
|
||||||
// @output android_icons
|
// @output android_icons
|
||||||
var parseIcon = function(icon, icon_size) {
|
var parseIcon = function(icon, icon_size) {
|
||||||
// do I have a platform icon for that density already
|
// do I have a platform icon for that density already
|
||||||
var density = icon.density || sizeToDensityMap[icon_size];
|
var density = icon.density || sizeToDensityMap[icon_size];
|
||||||
if (!density) {
|
if (!density) {
|
||||||
// invalid icon defition ( or unsupported size)
|
// invalid icon defition ( or unsupported size)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var previous = android_icons[density];
|
var previous = android_icons[density];
|
||||||
if (previous && previous.platform) {
|
if (previous && previous.platform) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
android_icons[density] = icon;
|
android_icons[density] = icon;
|
||||||
};
|
};
|
||||||
|
|
||||||
// iterate over all icon elements to find the default icon and call parseIcon
|
// iterate over all icon elements to find the default icon and call parseIcon
|
||||||
for (var i=0; i<icons.length; i++) {
|
for (var i=0; i<icons.length; i++) {
|
||||||
var icon = icons[i];
|
var icon = icons[i];
|
||||||
var size = icon.width;
|
var size = icon.width;
|
||||||
if (!size) {
|
if (!size) {
|
||||||
size = icon.height;
|
size = icon.height;
|
||||||
}
|
}
|
||||||
if (!size && !icon.density) {
|
if (!size && !icon.density) {
|
||||||
if (default_icon) {
|
if (default_icon) {
|
||||||
events.emit('verbose', 'more than one default icon: ' + JSON.stringify(icon));
|
events.emit('verbose', 'more than one default icon: ' + JSON.stringify(icon));
|
||||||
} else {
|
} else {
|
||||||
default_icon = icon;
|
default_icon = icon;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
parseIcon(icon, size);
|
parseIcon(icon, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// The source paths for icons and splashes are relative to
|
// The source paths for icons and splashes are relative to
|
||||||
// project's config.xml location, so we use it as base path.
|
// project's config.xml location, so we use it as base path.
|
||||||
var projectRoot = path.dirname(projectConfig.path);
|
var projectRoot = path.dirname(projectConfig.path);
|
||||||
var destination = path.join(platformRoot, 'res');
|
var destination = path.join(platformRoot, 'res');
|
||||||
for (var density in android_icons) {
|
for (var density in android_icons) {
|
||||||
copyImage(path.join(projectRoot, android_icons[density].src), destination, density, 'icon.png');
|
copyImage(path.join(projectRoot, android_icons[density].src), destination, density, 'icon.png');
|
||||||
}
|
}
|
||||||
// There's no "default" drawable, so assume default == mdpi.
|
// There's no "default" drawable, so assume default == mdpi.
|
||||||
if (default_icon && !android_icons.mdpi) {
|
if (default_icon && !android_icons.mdpi) {
|
||||||
copyImage(path.join(projectRoot, default_icon.src), destination, 'mdpi', 'icon.png');
|
copyImage(path.join(projectRoot, default_icon.src), destination, 'mdpi', 'icon.png');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the default resource name from all drawable folders
|
// remove the default resource name from all drawable folders
|
||||||
function deleteDefaultResourceAt(baseDir, resourceName) {
|
function deleteDefaultResourceAt(baseDir, resourceName) {
|
||||||
shell.ls(path.join(baseDir, 'res/drawable-*'))
|
shell.ls(path.join(baseDir, 'res/drawable-*'))
|
||||||
.forEach(function (drawableFolder) {
|
.forEach(function (drawableFolder) {
|
||||||
var imagePath = path.join(drawableFolder, resourceName);
|
var imagePath = path.join(drawableFolder, resourceName);
|
||||||
shell.rm('-f', [imagePath, imagePath.replace(/\.png$/, '.9.png')]);
|
shell.rm('-f', [imagePath, imagePath.replace(/\.png$/, '.9.png')]);
|
||||||
events.emit('verbose', 'Deleted ' + imagePath);
|
events.emit('verbose', 'Deleted ' + imagePath);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
|
* Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
|
||||||
* preference value and warns if it doesn't seems to be valid
|
* preference value and warns if it doesn't seems to be valid
|
||||||
*
|
*
|
||||||
* @param {ConfigParser} platformConfig A configParser instance for
|
* @param {ConfigParser} platformConfig A configParser instance for
|
||||||
* platform.
|
* platform.
|
||||||
*
|
*
|
||||||
* @return {String} Preference's value from config.xml or
|
* @return {String} Preference's value from config.xml or
|
||||||
* default value, if there is no such preference. The default value is
|
* default value, if there is no such preference. The default value is
|
||||||
* 'singleTop'
|
* 'singleTop'
|
||||||
*/
|
*/
|
||||||
function findAndroidLaunchModePreference(platformConfig) {
|
function findAndroidLaunchModePreference(platformConfig) {
|
||||||
var launchMode = platformConfig.getPreference('AndroidLaunchMode');
|
var launchMode = platformConfig.getPreference('AndroidLaunchMode');
|
||||||
if (!launchMode) {
|
if (!launchMode) {
|
||||||
// Return a default value
|
// Return a default value
|
||||||
return 'singleTop';
|
return 'singleTop';
|
||||||
}
|
}
|
||||||
|
|
||||||
var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
|
var expectedValues = ['standard', 'singleTop', 'singleTask', 'singleInstance'];
|
||||||
var valid = expectedValues.indexOf(launchMode) >= 0;
|
var valid = expectedValues.indexOf(launchMode) >= 0;
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
// Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
|
// Note: warn, but leave the launch mode as developer wanted, in case the list of options changes in the future
|
||||||
events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +
|
events.emit('warn', 'Unrecognized value for AndroidLaunchMode preference: ' +
|
||||||
launchMode + '. Expected values are: ' + expectedValues.join(', '));
|
launchMode + '. Expected values are: ' + expectedValues.join(', '));
|
||||||
}
|
}
|
||||||
|
|
||||||
return launchMode;
|
return launchMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Queries ConfigParser object for the orientation <preference> value. Warns if
|
* Queries ConfigParser object for the orientation <preference> value. Warns if
|
||||||
* global preference value is not supported by platform.
|
* global preference value is not supported by platform.
|
||||||
*
|
*
|
||||||
* @param {Object} platformConfig ConfigParser object
|
* @param {Object} platformConfig ConfigParser object
|
||||||
*
|
*
|
||||||
* @return {String} Global/platform-specific orientation in lower-case
|
* @return {String} Global/platform-specific orientation in lower-case
|
||||||
* (or empty string if both are undefined).
|
* (or empty string if both are undefined).
|
||||||
*/
|
*/
|
||||||
function findOrientationValue(platformConfig) {
|
function findOrientationValue(platformConfig) {
|
||||||
|
|
||||||
var ORIENTATION_DEFAULT = 'default';
|
var ORIENTATION_DEFAULT = 'default';
|
||||||
|
|
||||||
var orientation = platformConfig.getPreference('orientation');
|
var orientation = platformConfig.getPreference('orientation');
|
||||||
if (!orientation) {
|
if (!orientation) {
|
||||||
return ORIENTATION_DEFAULT;
|
return ORIENTATION_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
var GLOBAL_ORIENTATIONS = ['default', 'portrait','landscape'];
|
var GLOBAL_ORIENTATIONS = ['default', 'portrait','landscape'];
|
||||||
function isSupported(orientation) {
|
function isSupported(orientation) {
|
||||||
return GLOBAL_ORIENTATIONS.indexOf(orientation.toLowerCase()) >= 0;
|
return GLOBAL_ORIENTATIONS.indexOf(orientation.toLowerCase()) >= 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the given global orientation is supported
|
// Check if the given global orientation is supported
|
||||||
if (orientation && isSupported(orientation)) {
|
if (orientation && isSupported(orientation)) {
|
||||||
return orientation;
|
return orientation;
|
||||||
}
|
}
|
||||||
|
|
||||||
events.emit('warn', 'Unsupported global orientation: ' + orientation +
|
events.emit('warn', 'Unsupported global orientation: ' + orientation +
|
||||||
'. Defaulting to value: ' + ORIENTATION_DEFAULT);
|
'. Defaulting to value: ' + ORIENTATION_DEFAULT);
|
||||||
return ORIENTATION_DEFAULT;
|
return ORIENTATION_DEFAULT;
|
||||||
}
|
}
|
||||||
|
70
bin/update
70
bin/update
@ -1,35 +1,35 @@
|
|||||||
#!/usr/bin/env node
|
#!/usr/bin/env node
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
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,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var Api = require('./templates/cordova/Api');
|
var Api = require('./templates/cordova/Api');
|
||||||
var args = require('nopt')({
|
var args = require('nopt')({
|
||||||
'link': Boolean,
|
'link': Boolean,
|
||||||
'shared': Boolean,
|
'shared': Boolean,
|
||||||
'help': Boolean
|
'help': Boolean
|
||||||
});
|
});
|
||||||
|
|
||||||
if (args.help || args.argv.remain.length === 0) {
|
if (args.help || args.argv.remain.length === 0) {
|
||||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'update')) + ' <path_to_project> [--link]');
|
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'update')) + ' <path_to_project> [--link]');
|
||||||
console.log(' --link will use the CordovaLib project directly instead of making a copy.');
|
console.log(' --link will use the CordovaLib project directly instead of making a copy.');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Api.updatePlatform(args.argv.remain[0], {link: (args.link || args.shared)}).done();
|
Api.updatePlatform(args.argv.remain[0], {link: (args.link || args.shared)}).done();
|
||||||
|
92
package.json
92
package.json
@ -1,46 +1,46 @@
|
|||||||
{
|
{
|
||||||
"name": "cordova-android",
|
"name": "cordova-android",
|
||||||
"version": "5.0.0-dev",
|
"version": "5.0.0-dev",
|
||||||
"description": "cordova-android release",
|
"description": "cordova-android release",
|
||||||
"bin": {
|
"bin": {
|
||||||
"create": "bin/create"
|
"create": "bin/create"
|
||||||
},
|
},
|
||||||
"main": "bin/templates/cordova/Api.js",
|
"main": "bin/templates/cordova/Api.js",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://git-wip-us.apache.org/repos/asf/cordova-android.git"
|
"url": "https://git-wip-us.apache.org/repos/asf/cordova-android.git"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"android",
|
"android",
|
||||||
"cordova",
|
"cordova",
|
||||||
"apache"
|
"apache"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "npm run jshint && jasmine-node --color spec",
|
"test": "npm run jshint && jasmine-node --color spec",
|
||||||
"test-build": "rm -rf \"test create\" && node ./bin/create \"test create\" com.test.app 応用 && \"./test create/cordova/build\" && rm -rf \"test create\"",
|
"test-build": "rm -rf \"test create\" && node ./bin/create \"test create\" com.test.app 応用 && \"./test create/cordova/build\" && rm -rf \"test create\"",
|
||||||
"jshint": "node node_modules/jshint/bin/jshint bin && node node_modules/jshint/bin/jshint spec"
|
"jshint": "node node_modules/jshint/bin/jshint bin && node node_modules/jshint/bin/jshint spec"
|
||||||
},
|
},
|
||||||
"author": "Apache Software Foundation",
|
"author": "Apache Software Foundation",
|
||||||
"license": "Apache version 2.0",
|
"license": "Apache version 2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cordova-common": "^0.1.0",
|
"cordova-common": "^0.1.0",
|
||||||
"elementtree": "^0.1.6",
|
"elementtree": "^0.1.6",
|
||||||
"nopt": "^3.0.1",
|
"nopt": "^3.0.1",
|
||||||
"properties-parser": "^0.3.0",
|
"properties-parser": "^0.3.0",
|
||||||
"q": "^1.4.1",
|
"q": "^1.4.1",
|
||||||
"shelljs": "^0.5.3"
|
"shelljs": "^0.5.3"
|
||||||
},
|
},
|
||||||
"bundledDependencies": [
|
"bundledDependencies": [
|
||||||
"cordova-common",
|
"cordova-common",
|
||||||
"elementtree",
|
"elementtree",
|
||||||
"nopt",
|
"nopt",
|
||||||
"properties-parser",
|
"properties-parser",
|
||||||
"q",
|
"q",
|
||||||
"shelljs"
|
"shelljs"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"jasmine-node": "^1.14.5",
|
"jasmine-node": "^1.14.5",
|
||||||
"jshint": "^2.6.0",
|
"jshint": "^2.6.0",
|
||||||
"promise-matchers": "~0"
|
"promise-matchers": "~0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user