mirror of
https://github.com/apache/cordova-android.git
synced 2025-02-22 00:32:55 +08:00
Merge branch 'master' into 4.0.x (build & create script updates)
Conflicts: bin/lib/check_reqs.js bin/lib/create.js bin/node_modules/which/package.json bin/templates/cordova/lib/build.js
This commit is contained in:
commit
4c1942e3fe
@ -19,7 +19,7 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var shell = 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'),
|
||||||
@ -27,92 +27,157 @@ var shell = require('shelljs'),
|
|||||||
which = require('which'),
|
which = require('which'),
|
||||||
ROOT = path.join(__dirname, '..', '..');
|
ROOT = path.join(__dirname, '..', '..');
|
||||||
|
|
||||||
|
var isWindows = process.platform == 'win32';
|
||||||
|
|
||||||
|
function forgivingWhichSync(cmd) {
|
||||||
|
try {
|
||||||
|
return which.sync(cmd);
|
||||||
|
} catch (e) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function tryCommand(cmd, errMsg) {
|
||||||
|
var d = Q.defer();
|
||||||
|
child_process.exec(cmd, function(err, stdout, stderr) {
|
||||||
|
if (err) d.reject(new Error(errMsg));
|
||||||
|
else d.resolve(stdout);
|
||||||
|
});
|
||||||
|
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() {
|
||||||
if(fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
|
if(fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
|
||||||
var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'framework', 'project.properties'));
|
var target = shelljs.grep(/target=android-[\d+]/, path.join(ROOT, 'framework', 'project.properties'));
|
||||||
return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
|
return target.split('=')[1].replace('\n', '').replace('\r', '').replace(' ', '');
|
||||||
} else if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
|
} else 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.
|
||||||
// this is called on the project itself, and can support Google APIs AND Vanilla Android
|
// this is called on the project itself, and can support Google APIs AND Vanilla Android
|
||||||
var target = shell.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties')) ||
|
var target = shelljs.grep(/target=android-[\d+]/, path.join(ROOT, 'project.properties')) ||
|
||||||
shell.grep(/target=Google Inc.:Google APIs:[\d+]/, path.join(ROOT, 'project.properties'));
|
shelljs.grep(/target=Google Inc.:Google APIs:[\d+]/, path.join(ROOT, 'project.properties'));
|
||||||
if(target == "" || !target) {
|
if(target == "" || !target) {
|
||||||
// Try Google Glass APIs
|
// Try Google Glass APIs
|
||||||
target = shell.grep(/target=Google Inc.:Glass Development Kit Preview:[\d+]/, path.join(ROOT, 'project.properties'));
|
target = shelljs.grep(/target=Google Inc.:Glass Development Kit Preview:[\d+]/, path.join(ROOT, 'project.properties'));
|
||||||
}
|
}
|
||||||
return target.split('=')[1].replace('\n', '').replace('\r', '');
|
return target.split('=')[1].replace('\n', '').replace('\r', '');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise. Called only by build and clean commands.
|
||||||
module.exports.sdk_dir = function() {
|
module.exports.check_ant = function() {
|
||||||
var d = Q.defer();
|
return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.');
|
||||||
which('android', function(err, path) {
|
};
|
||||||
if (err) {
|
|
||||||
d.reject(new Error('ERROR: Cannot find Android SDK. android command not found.'));
|
// Returns a promise. Called only by build and clean commands.
|
||||||
} else {
|
module.exports.check_gradle = function() {
|
||||||
var toolsDir = path.substring(0, path.lastIndexOf('/'));
|
var sdkDir = process.env['ANDROID_HOME'];
|
||||||
if (toolsDir.substring(toolsDir.length-6) != "/tools") {
|
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||||
d.reject(new Error('ERROR: Cannot find Android SDK. android command not found in tools dir.'));
|
if (!fs.existsSync(wrapperDir)) {
|
||||||
}
|
return Q.reject(new Error('Could not find gradle wrapper within android sdk. Might need to update your Android SDK.\n' +
|
||||||
d.resolve(toolsDir.substring(0, toolsDir.length-6));
|
'Looked here: ' + wrapperDir));
|
||||||
}
|
}
|
||||||
});
|
return Q.when();
|
||||||
return d.promise;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns a promise.
|
|
||||||
module.exports.check_ant = function() {
|
|
||||||
var d = Q.defer();
|
|
||||||
child_process.exec('ant -version', function(err, stdout, stderr) {
|
|
||||||
if (err) d.reject(new Error('ERROR : executing command \'ant\', make sure you have ant installed and added to your path.'));
|
|
||||||
else d.resolve();
|
|
||||||
});
|
|
||||||
return d.promise;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
module.exports.check_java = function() {
|
module.exports.check_java = function() {
|
||||||
var d = Q.defer();
|
var javacPath = forgivingWhichSync('javac');
|
||||||
child_process.exec('java -version', function(err, stdout, stderr) {
|
var hasJavaHome = !!process.env['JAVA_HOME'];
|
||||||
if(err) {
|
return Q().then(function() {
|
||||||
var msg =
|
if (hasJavaHome) {
|
||||||
'Failed to run \'java -version\', make sure your java environment is set up\n' +
|
// Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
|
||||||
'including JDK and JRE.\n' +
|
if (!javacPath) {
|
||||||
'Your JAVA_HOME variable is ' + process.env.JAVA_HOME + '\n';
|
process.env['PATH'] += path.delimiter + path.join(process.env['JAVA_HOME'], 'bin');
|
||||||
d.reject(new Error(msg + err));
|
}
|
||||||
|
} else {
|
||||||
|
if (javacPath) {
|
||||||
|
// OS X has a command for finding JAVA_HOME.
|
||||||
|
if (fs.existsSync('/usr/libexec/java_home')) {
|
||||||
|
return tryCommand('/usr/libexec/java_home', 'Failed to run: /usr/libexec/java_home')
|
||||||
|
.then(function(stdout) {
|
||||||
|
process.env['JAVA_HOME'] = stdout.trim();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// See if we can derive it from javac's location.
|
||||||
|
var maybeJavaHome = path.dirname(path.dirname(javacPath));
|
||||||
|
if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
|
||||||
|
process.env['JAVA_HOME'] = maybeJavaHome;
|
||||||
|
} else {
|
||||||
|
throw new Error('Could not find JAVA_HOME. Try setting the environment variable manually');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (isWindows) {
|
||||||
|
// Try to auto-detect java in the default install paths.
|
||||||
|
var firstJdkDir =
|
||||||
|
shelljs.ls(process.env['ProgramFiles'] + '\\java\\jdk*')[0] ||
|
||||||
|
shelljs.ls('C:\\Program Files\\java\\jdk*')[0] ||
|
||||||
|
shelljs.ls('C:\\Program Files (x86)\\java\\jdk*')[0];
|
||||||
|
if (firstJdkDir) {
|
||||||
|
// shelljs always uses / in paths.
|
||||||
|
firstJdkDir = firstJdkDir.replace(/\//g, path.sep);
|
||||||
|
if (!javacPath) {
|
||||||
|
process.env['PATH'] += path.delimiter + path.join(firstJdkDir, 'bin');
|
||||||
|
}
|
||||||
|
process.env['JAVA_HOME'] = firstJdkDir;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else d.resolve();
|
}).then(function() {
|
||||||
|
var msg =
|
||||||
|
'Failed to run "java -version", make sure your java environment is set up\n' +
|
||||||
|
'including JDK and JRE.\n' +
|
||||||
|
'Your JAVA_HOME variable is: ' + process.env['JAVA_HOME'];
|
||||||
|
return tryCommand('java -version', msg)
|
||||||
|
}).then(function() {
|
||||||
|
msg = 'Failed to run "javac -version", make sure you have a Java JDK (not just a JRE) installed.';
|
||||||
|
return tryCommand('javac -version', msg)
|
||||||
});
|
});
|
||||||
return d.promise;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
module.exports.check_android = function() {
|
module.exports.check_android = function() {
|
||||||
var valid_target = this.get_target();
|
return Q().then(function() {
|
||||||
var d = Q.defer();
|
var androidCmdPath = forgivingWhichSync('android');
|
||||||
child_process.exec('android list targets', function(err, stdout, stderr) {
|
var adbInPath = !!forgivingWhichSync('adb');
|
||||||
if (err) d.reject(stderr);
|
var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);
|
||||||
else d.resolve(stdout);
|
if (hasAndroidHome && !androidCmdPath) {
|
||||||
|
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
|
||||||
|
}
|
||||||
|
if (androidCmdPath && !hasAndroidHome) {
|
||||||
|
var parentDir = path.dirname(androidCmdPath);
|
||||||
|
if (path.basename(parentDir) == 'tools') {
|
||||||
|
process.env['ANDROID_HOME'] = path.dirname(parentDir);
|
||||||
|
hasAndroidHome = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (hasAndroidHome && !adbInPath) {
|
||||||
|
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
|
||||||
|
}
|
||||||
|
if (!process.env['ANDROID_HOME']) {
|
||||||
|
throw new Error('ANDROID_HOME is not set and "android" command not in your PATH. You must fulfill at least one of these conditions.');
|
||||||
|
}
|
||||||
|
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
|
||||||
|
throw new Error('ANDROID_HOME is set to a non-existant path: ' + process.env['ANDROID_HOME']);
|
||||||
|
}
|
||||||
|
// Check that the target sdk level is installed.
|
||||||
|
return module.exports.check_android_target(module.exports.get_target());
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return d.promise.then(function(output) {
|
module.exports.check_android_target = function(valid_target) {
|
||||||
|
var msg = 'Failed to run "android". Make sure you have the latest Android SDK installed, and that the "android" command (inside the tools/ folder) is added to your PATH.';
|
||||||
|
return tryCommand('android list targets', msg)
|
||||||
|
.then(function(output) {
|
||||||
if (!output.match(valid_target)) {
|
if (!output.match(valid_target)) {
|
||||||
return Q.reject(new Error('Please install Android target ' + valid_target.split('-')[1] + ' (the Android newest SDK). Make sure you have the latest Android tools installed as well. Run \"android\" from your command-line to install/update any missing SDKs or tools.'));
|
throw new Error('Please install Android target "' + valid_target + '".\n' +
|
||||||
}
|
'Hint: Run "android" from your command-line to open the SDK manager.');
|
||||||
return Q();
|
|
||||||
}, function(stderr) {
|
|
||||||
if (stderr.match(/command\snot\sfound/) || stderr.match(/is not recognized as an internal or external command/)) {
|
|
||||||
return Q.reject(new Error('The command \"android\" failed. Make sure you have the latest Android SDK installed, and the \"android\" command (inside the tools/ folder) is added to your path.'));
|
|
||||||
} else {
|
|
||||||
return Q.reject(new Error('An error occurred while listing Android targets. Error: ' + stderr ));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
module.exports.run = function() {
|
module.exports.run = function() {
|
||||||
return Q.all([this.check_ant(), this.check_java(), this.check_android()]);
|
return Q.all([this.check_java(), this.check_android()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,16 +83,47 @@ function copyJsAndLibrary(projectPath, shared, projectName) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function runAndroidUpdate(projectPath, target_api, shared) {
|
function extractSubProjectPaths(data) {
|
||||||
var targetFrameworkDir = getFrameworkDir(projectPath, shared);
|
var ret = {};
|
||||||
return exec('android update project --subprojects --path "' + projectPath + '" --target ' + target_api + ' --library "' + path.relative(projectPath, targetFrameworkDir) + '"');
|
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg
|
||||||
|
var m;
|
||||||
|
while (m = r.exec(data)) {
|
||||||
|
ret[m[1]] = 1;
|
||||||
|
}
|
||||||
|
return Object.keys(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyAntRules(projectPath) {
|
function writeProjectProperties(projectPath, target_api, shared) {
|
||||||
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
var dstPath = path.join(projectPath, 'project.properties');
|
||||||
if (fs.existsSync(path.join(srcDir, 'custom_rules.xml'))) {
|
var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
|
||||||
shell.cp('-f', path.join(srcDir, 'custom_rules.xml'), projectPath);
|
var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
|
||||||
|
var data = fs.readFileSync(srcPath, 'utf8');
|
||||||
|
data = data.replace(/^target=.*/m, 'target=' + target_api);
|
||||||
|
var subProjects = extractSubProjectPaths(data);
|
||||||
|
subProjects = subProjects.filter(function(p) {
|
||||||
|
return !(/^CordovaLib$/m.exec(p) ||
|
||||||
|
/[\\\/]cordova-android[\\\/]framework$/m.exec(p) ||
|
||||||
|
/^(\.\.[\\\/])+framework$/m.exec(p)
|
||||||
|
);
|
||||||
|
});
|
||||||
|
subProjects.unshift(shared ? path.relative(projectPath, path.join(ROOT, 'framework')) : 'CordovaLib');
|
||||||
|
data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
|
||||||
|
if (!/\n$/.exec(data)) {
|
||||||
|
data += '\n';
|
||||||
}
|
}
|
||||||
|
for (var i = 0; i < subProjects.length; ++i) {
|
||||||
|
data += 'android.library.reference.' + (i+1) + '=' + subProjects[i] + '\n';
|
||||||
|
}
|
||||||
|
fs.writeFileSync(dstPath, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyBuildRules(projectPath) {
|
||||||
|
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
||||||
|
shell.cp('-f', path.join(srcDir, 'custom_rules.xml'), projectPath);
|
||||||
|
|
||||||
|
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
|
||||||
|
shell.cp('-f', path.join(srcDir, 'libraries.gradle'), projectPath);
|
||||||
|
shell.cp('-f', path.join(srcDir, 'settings.gradle'), projectPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyScripts(projectPath) {
|
function copyScripts(projectPath) {
|
||||||
@ -206,7 +237,7 @@ exports.createProject = function(project_path, package_name, project_name, proje
|
|||||||
})
|
})
|
||||||
// Check that requirements are met and proper targets are installed
|
// Check that requirements are met and proper targets are installed
|
||||||
.then(function() {
|
.then(function() {
|
||||||
check_reqs.run();
|
return check_reqs.run();
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
// Log the given values for the project
|
// Log the given values for the project
|
||||||
console.log('Creating Cordova project for the Android platform:');
|
console.log('Creating Cordova project for the Android platform:');
|
||||||
@ -222,6 +253,7 @@ exports.createProject = function(project_path, package_name, project_name, proje
|
|||||||
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('-r', path.join(ROOT, 'framework', 'res', 'xml'), path.join(project_path, 'res'));
|
shell.cp('-r', path.join(ROOT, 'framework', 'res', 'xml'), path.join(project_path, 'res'));
|
||||||
|
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
|
||||||
|
|
||||||
shell.cp('-f', path.join(project_template_dir, 'build.gradle'), project_path);
|
shell.cp('-f', path.join(project_template_dir, 'build.gradle'), project_path);
|
||||||
shell.cp('-f', path.join(project_template_dir, 'libraries.gradle'), project_path);
|
shell.cp('-f', path.join(project_template_dir, 'libraries.gradle'), project_path);
|
||||||
@ -263,10 +295,10 @@ exports.createProject = function(project_path, package_name, project_name, proje
|
|||||||
shell.sed('-i', /__PACKAGE__/, package_name, manifest_path);
|
shell.sed('-i', /__PACKAGE__/, package_name, manifest_path);
|
||||||
shell.sed('-i', /__APILEVEL__/, target_api.split('-')[1], manifest_path);
|
shell.sed('-i', /__APILEVEL__/, target_api.split('-')[1], manifest_path);
|
||||||
copyScripts(project_path);
|
copyScripts(project_path);
|
||||||
copyAntRules(project_path);
|
copyBuildRules(project_path);
|
||||||
});
|
});
|
||||||
// Link it to local android install.
|
// Link it to local android install.
|
||||||
return runAndroidUpdate(project_path, target_api, use_shared_project);
|
writeProjectProperties(project_path, target_api);
|
||||||
}).then(function() {
|
}).then(function() {
|
||||||
console.log('Project successfully created.');
|
console.log('Project successfully created.');
|
||||||
});
|
});
|
||||||
@ -289,22 +321,20 @@ function extractProjectNameFromManifest(projectPath) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
exports.updateProject = function(projectPath) {
|
exports.updateProject = function(projectPath, shared) {
|
||||||
var version = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
|
var newVersion = fs.readFileSync(path.join(ROOT, 'VERSION'), 'utf-8').trim();
|
||||||
// Check that requirements are met and proper targets are installed
|
// Check that requirements are met and proper targets are installed
|
||||||
return check_reqs.run()
|
return check_reqs.run()
|
||||||
.then(function() {
|
.then(function() {
|
||||||
var projectName = extractProjectNameFromManifest(projectPath);
|
var projectName = extractProjectNameFromManifest(projectPath);
|
||||||
var target_api = check_reqs.get_target();
|
var target_api = check_reqs.get_target();
|
||||||
copyJsAndLibrary(projectPath, false, projectName);
|
copyJsAndLibrary(projectPath, shared, projectName);
|
||||||
copyScripts(projectPath);
|
copyScripts(projectPath);
|
||||||
copyAntRules(projectPath);
|
copyBuildRules(projectPath);
|
||||||
removeDebuggableFromManifest(projectPath);
|
removeDebuggableFromManifest(projectPath);
|
||||||
return runAndroidUpdate(projectPath, target_api, false)
|
writeProjectProperties(projectPath, target_api, shared);
|
||||||
.then(function() {
|
console.log('Android project is now at version ' + newVersion);
|
||||||
console.log('Android project is now at version ' + version);
|
console.log('If you updated from a pre-3.2.0 version and use an IDE, we now require that you import the "CordovaLib" library project.');
|
||||||
console.log('If you updated from a pre-3.2.0 version and use an IDE, we now require that you import the "CordovaLib" library project.');
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
2
bin/node_modules/which/package.json
generated
vendored
2
bin/node_modules/which/package.json
generated
vendored
@ -27,5 +27,5 @@
|
|||||||
},
|
},
|
||||||
"homepage": "https://github.com/isaacs/node-which",
|
"homepage": "https://github.com/isaacs/node-which",
|
||||||
"_id": "which@1.0.5",
|
"_id": "which@1.0.5",
|
||||||
"_from": "which@^1.0.5"
|
"_from": "which@"
|
||||||
}
|
}
|
||||||
|
@ -24,13 +24,17 @@ var build = require('./lib/build'),
|
|||||||
args = process.argv;
|
args = process.argv;
|
||||||
|
|
||||||
// Support basic help commands
|
// Support basic help commands
|
||||||
if(args[2] == '--help' || args[2] == '/?' || args[2] == '-h' ||
|
if(args[2] == '--help' ||
|
||||||
args[2] == 'help' || args[2] == '-help' || args[2] == '/help') {
|
args[2] == '/?' ||
|
||||||
|
args[2] == '-h' ||
|
||||||
|
args[2] == 'help' ||
|
||||||
|
args[2] == '-help' ||
|
||||||
|
args[2] == '/help') {
|
||||||
build.help();
|
build.help();
|
||||||
} else {
|
} else {
|
||||||
reqs.run().then(function() {
|
reqs.run().done(function() {
|
||||||
return build.run(args[2]);
|
return build.run(args.slice(2));
|
||||||
}).done(null, function(err) {
|
}, function(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
@ -19,18 +19,26 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var clean = require('./lib/clean'),
|
var build = require('./lib/build'),
|
||||||
reqs = require('./lib/check_reqs'),
|
reqs = require('./lib/check_reqs'),
|
||||||
args = process.argv;
|
args = process.argv;
|
||||||
|
var path = require('path');
|
||||||
|
|
||||||
// Usage support for when args are given
|
// Support basic help commands
|
||||||
if(args.length > 2) {
|
if(args[2] == '--help' ||
|
||||||
clean.help();
|
args[2] == '/?' ||
|
||||||
|
args[2] == '-h' ||
|
||||||
|
args[2] == 'help' ||
|
||||||
|
args[2] == '-help' ||
|
||||||
|
args[2] == '/help') {
|
||||||
|
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
|
||||||
|
console.log('Cleans the project directory.');
|
||||||
|
process.exit(0);
|
||||||
} else {
|
} else {
|
||||||
reqs.run().done(function() {
|
reqs.run().done(function() {
|
||||||
return clean.run();
|
return build.runClean(args.slice(2));
|
||||||
}, function(err) {
|
}, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error(err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
369
bin/templates/cordova/lib/build.js
vendored
369
bin/templates/cordova/lib/build.js
vendored
@ -26,79 +26,330 @@ var shell = require('shelljs'),
|
|||||||
fs = require('fs'),
|
fs = require('fs'),
|
||||||
which = require('which'),
|
which = require('which'),
|
||||||
ROOT = path.join(__dirname, '..', '..');
|
ROOT = path.join(__dirname, '..', '..');
|
||||||
|
var check_reqs = require('./check_reqs');
|
||||||
|
|
||||||
|
var LOCAL_PROPERTIES_TEMPLATE =
|
||||||
|
'# This file is automatically generated.\n' +
|
||||||
|
'# Do not modify this file -- YOUR CHANGES WILL BE ERASED!\n';
|
||||||
|
|
||||||
module.exports.getAntArgs = function(cmd) {
|
function find_files(directory, predicate) {
|
||||||
var args = [cmd, '-f', path.join(ROOT, 'build.xml')];
|
if (fs.existsSync(directory)) {
|
||||||
try {
|
var candidates = fs.readdirSync(directory).filter(predicate).map(function(p) {
|
||||||
// Specify sdk dir in case local properties are missing
|
p = path.join(directory, p);
|
||||||
args.push('-Dsdk.dir='+path.join(which.sync('android'), '../..'));
|
|
||||||
} catch(e) {
|
|
||||||
// Can't find android; don't push arg: assume all is okay
|
|
||||||
}
|
|
||||||
return args;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Builds the project with ant.
|
|
||||||
* Returns a promise.
|
|
||||||
*/
|
|
||||||
module.exports.run = function(build_type) {
|
|
||||||
//default build type
|
|
||||||
build_type = typeof build_type !== 'undefined' ? build_type : "--debug";
|
|
||||||
var args = module.exports.getAntArgs('debug');
|
|
||||||
switch(build_type) {
|
|
||||||
case '--debug' :
|
|
||||||
break;
|
|
||||||
case '--release' :
|
|
||||||
args[0] = 'release';
|
|
||||||
break;
|
|
||||||
case '--nobuild' :
|
|
||||||
console.log('Skipping build...');
|
|
||||||
return Q();
|
|
||||||
default :
|
|
||||||
return Q.reject('Build option \'' + build_type + '\' not recognized.');
|
|
||||||
}
|
|
||||||
var ret = Q();
|
|
||||||
return ret.then(function() {
|
|
||||||
return spawn('ant', args);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Gets the path to the apk file, if not such file exists then
|
|
||||||
* the script will error out. (should we error or just return undefined?)
|
|
||||||
*/
|
|
||||||
module.exports.get_apk = function() {
|
|
||||||
var binDir = path.join(ROOT, 'bin');
|
|
||||||
if (fs.existsSync(binDir)) {
|
|
||||||
var candidates = fs.readdirSync(binDir).filter(function(p) {
|
|
||||||
// Need to choose between release and debug .apk.
|
|
||||||
return path.extname(p) == '.apk';
|
|
||||||
}).map(function(p) {
|
|
||||||
p = path.join(binDir, p);
|
|
||||||
return { p: p, t: fs.statSync(p).mtime };
|
return { p: p, t: fs.statSync(p).mtime };
|
||||||
}).sort(function(a,b) {
|
}).sort(function(a,b) {
|
||||||
return a.t > b.t ? -1 :
|
return a.t > b.t ? -1 :
|
||||||
a.t < b.t ? 1 : 0;
|
a.t < b.t ? 1 : 0;
|
||||||
});
|
}).map(function(p) { return p.p; });
|
||||||
if (candidates.length === 0) {
|
return candidates;
|
||||||
console.error('ERROR : No .apk found in ' + binDir + ' directory');
|
|
||||||
process.exit(2);
|
|
||||||
}
|
|
||||||
console.log('Using apk: ' + candidates[0].p);
|
|
||||||
return candidates[0].p;
|
|
||||||
} else {
|
} else {
|
||||||
console.error('ERROR : unable to find project ' + binDir + ' directory, could not locate .apk');
|
console.error('ERROR : unable to find project ' + directory + ' directory, could not locate .apk');
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function hasCustomRules() {
|
||||||
|
return fs.existsSync(path.join(ROOT, 'custom_rules.xml'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractProjectNameFromManifest(projectPath) {
|
||||||
|
var manifestPath = path.join(projectPath, 'AndroidManifest.xml');
|
||||||
|
var manifestData = fs.readFileSync(manifestPath, 'utf8');
|
||||||
|
var m = /<activity[\s\S]*?android:name\s*=\s*"(.*?)"/i.exec(manifestData);
|
||||||
|
if (!m) {
|
||||||
|
throw new Error('Could not find activity name in ' + manifestPath);
|
||||||
|
}
|
||||||
|
return m[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
function extractSubProjectPaths() {
|
||||||
|
var data = fs.readFileSync(path.join(ROOT, 'project.properties'), 'utf8');
|
||||||
|
var ret = {};
|
||||||
|
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg
|
||||||
|
var m;
|
||||||
|
while (m = r.exec(data)) {
|
||||||
|
ret[m[1]] = 1;
|
||||||
|
}
|
||||||
|
return Object.keys(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
var builders = {
|
||||||
|
ant: {
|
||||||
|
getArgs: function(cmd) {
|
||||||
|
var args = [cmd, '-f', path.join(ROOT, 'build.xml')];
|
||||||
|
// custom_rules.xml is required for incremental builds.
|
||||||
|
if (hasCustomRules()) {
|
||||||
|
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
},
|
||||||
|
|
||||||
|
prepEnv: function() {
|
||||||
|
return check_reqs.check_ant()
|
||||||
|
.then(function() {
|
||||||
|
// Copy in build.xml on each build so that:
|
||||||
|
// A) we don't require the Android SDK at project creation time, and
|
||||||
|
// B) we always use the SDK's latest version of it.
|
||||||
|
var sdkDir = process.env['ANDROID_HOME'];
|
||||||
|
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
|
||||||
|
function writeBuildXml(projectPath) {
|
||||||
|
var newData = buildTemplate.replace('PROJECT_NAME', extractProjectNameFromManifest(ROOT));
|
||||||
|
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
|
||||||
|
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
|
||||||
|
fs.writeFileSync(path.join(projectPath, 'local.properties'), LOCAL_PROPERTIES_TEMPLATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var subProjects = extractSubProjectPaths();
|
||||||
|
writeBuildXml(ROOT);
|
||||||
|
for (var i = 0; i < subProjects.length; ++i) {
|
||||||
|
writeBuildXml(path.join(ROOT, subProjects[i]));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Builds the project with ant.
|
||||||
|
* Returns a promise.
|
||||||
|
*/
|
||||||
|
build: function(build_type) {
|
||||||
|
// Without our custom_rules.xml, we need to clean before building.
|
||||||
|
var ret = Q();
|
||||||
|
if (!hasCustomRules()) {
|
||||||
|
// clean will call check_ant() for us.
|
||||||
|
ret = this.clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
var builder = this;
|
||||||
|
var args = this.getArgs(build_type == 'debug' ? 'debug' : 'release');
|
||||||
|
return check_reqs.check_ant()
|
||||||
|
.then(function() {
|
||||||
|
return spawn('ant', args);
|
||||||
|
}).then(function() {
|
||||||
|
return builder.getOutputFiles();
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clean: function() {
|
||||||
|
var args = this.getArgs('clean');
|
||||||
|
return check_reqs.check_ant()
|
||||||
|
.then(function() {
|
||||||
|
return spawn('ant', args);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Find the recently-generated output APK files
|
||||||
|
// Ant only generates one output file; return it.
|
||||||
|
getOutputFiles: function() {
|
||||||
|
var binDir;
|
||||||
|
if(hasCustomRules()) {
|
||||||
|
binDir = path.join(ROOT, 'ant-build');
|
||||||
|
} else {
|
||||||
|
binDir = path.join(ROOT, 'bin');
|
||||||
|
}
|
||||||
|
var candidates = find_files(binDir, function(candidate) { return path.extname(candidate) == '.apk'; });
|
||||||
|
if (candidates.length === 0) {
|
||||||
|
console.error('ERROR : No .apk found in ' + binDir + ' directory');
|
||||||
|
process.exit(2);
|
||||||
|
}
|
||||||
|
console.log('Using apk: ' + candidates[0]);
|
||||||
|
return [candidates[0]];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
gradle: {
|
||||||
|
getArgs: function(cmd) {
|
||||||
|
var lintSteps = [
|
||||||
|
'lint',
|
||||||
|
'lintVitalRelease',
|
||||||
|
'compileLint',
|
||||||
|
'copyReleaseLint',
|
||||||
|
'copyDebugLint'
|
||||||
|
];
|
||||||
|
var args = [cmd, '-b', path.join(ROOT, 'build.gradle')];
|
||||||
|
// 10 seconds -> 6 seconds
|
||||||
|
args.push('-Dorg.gradle.daemon=true');
|
||||||
|
// Excluding lint: 6s-> 1.6s
|
||||||
|
for (var i = 0; i < lintSteps.length; ++i) {
|
||||||
|
args.push('-x', lintSteps[i]);
|
||||||
|
}
|
||||||
|
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
|
||||||
|
// args.push('-Dorg.gradle.parallel=true');
|
||||||
|
return args;
|
||||||
|
},
|
||||||
|
|
||||||
|
prepEnv: function() {
|
||||||
|
return check_reqs.check_gradle()
|
||||||
|
.then(function() {
|
||||||
|
// Copy the gradle wrapper on each build so that:
|
||||||
|
// A) we don't require the Android SDK at project creation time, and
|
||||||
|
// B) we always use the SDK's latest version of it.
|
||||||
|
var projectPath = ROOT;
|
||||||
|
// check_reqs ensures that this is set.
|
||||||
|
var sdkDir = process.env['ANDROID_HOME'];
|
||||||
|
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
|
||||||
|
if (process.platform == 'win32') {
|
||||||
|
shell.cp('-f', path.join(wrapperDir, 'gradlew.bat'), projectPath);
|
||||||
|
} else {
|
||||||
|
shell.cp('-f', path.join(wrapperDir, 'gradlew'), projectPath);
|
||||||
|
}
|
||||||
|
shell.rm('-rf', path.join(projectPath, 'gradle', 'wrapper'));
|
||||||
|
shell.mkdir('-p', path.join(projectPath, 'gradle'));
|
||||||
|
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(projectPath, 'gradle'));
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Builds the project with gradle.
|
||||||
|
* Returns a promise.
|
||||||
|
*/
|
||||||
|
build: function(build_type) {
|
||||||
|
var builder = this;
|
||||||
|
var wrapper = path.join(ROOT, 'gradlew');
|
||||||
|
var args = builder.getArgs('build');
|
||||||
|
return Q().then(function() {
|
||||||
|
return spawn(wrapper, args);
|
||||||
|
}).then(function() {
|
||||||
|
return builder.getOutputFiles(build_type);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
clean: function() {
|
||||||
|
var builder = this;
|
||||||
|
var wrapper = path.join(ROOT, 'gradlew');
|
||||||
|
var args = builder.getArgs('clean');
|
||||||
|
return Q().then(function() {
|
||||||
|
return spawn(wrapper, args);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
// Find the recently-generated output APK files
|
||||||
|
// Gradle can generate multiple output files; return all of them.
|
||||||
|
getOutputFiles: function(build_type) {
|
||||||
|
var binDir = path.join(ROOT, 'build', 'apk');
|
||||||
|
var candidates = find_files(binDir, function(candidate) {
|
||||||
|
// Need to choose between release and debug .apk.
|
||||||
|
if (build_type === 'debug') {
|
||||||
|
return (path.extname(candidate) == '.apk' && candidate.indexOf('-debug-') >= 0);
|
||||||
|
}
|
||||||
|
if (build_type === 'release') {
|
||||||
|
return (path.extname(candidate) == '.apk' && candidate.indexOf('-release-') >= 0);
|
||||||
|
}
|
||||||
|
return path.extname(candidate) == '.apk';
|
||||||
|
});
|
||||||
|
return candidates;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
none: {
|
||||||
|
prepEnv: function() {
|
||||||
|
return Q();
|
||||||
|
},
|
||||||
|
build: function() {
|
||||||
|
console.log('Skipping build...');
|
||||||
|
return Q();
|
||||||
|
},
|
||||||
|
clean: function() {
|
||||||
|
return Q();
|
||||||
|
},
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseOpts(options) {
|
||||||
|
// Backwards-compatibility: Allow a single string argument
|
||||||
|
if (typeof options == "string") options = [options];
|
||||||
|
|
||||||
|
var ret = {
|
||||||
|
buildType: 'debug',
|
||||||
|
buildMethod: process.env['ANDROID_BUILD'] || 'ant'
|
||||||
|
};
|
||||||
|
|
||||||
|
// Iterate through command line options
|
||||||
|
for (var i=0; options && (i < options.length); ++i) {
|
||||||
|
if (options[i].substring && options[i].substring(0,2) == "--") {
|
||||||
|
var option = options[i].substring(2);
|
||||||
|
switch(option) {
|
||||||
|
case 'debug':
|
||||||
|
case 'release':
|
||||||
|
ret.buildType = option;
|
||||||
|
break;
|
||||||
|
case 'ant':
|
||||||
|
case 'gradle':
|
||||||
|
ret.buildMethod = option;
|
||||||
|
break;
|
||||||
|
case 'nobuild' :
|
||||||
|
ret.buildMethod = 'none';
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
return Q.reject('Build option \'' + options[i] + '\' not recognized.');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Q.reject('Build option \'' + options[i] + '\' not recognized.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Builds the project with the specifed options
|
||||||
|
* Returns a promise.
|
||||||
|
*/
|
||||||
|
module.exports.runClean = function(options) {
|
||||||
|
var opts = parseOpts(options);
|
||||||
|
var builder = builders[opts.buildMethod];
|
||||||
|
return builder.prepEnv()
|
||||||
|
.then(function() {
|
||||||
|
return builder.clean();
|
||||||
|
}).then(function() {
|
||||||
|
shell.rm('-rf', path.join(ROOT, 'out'));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Builds the project with the specifed options
|
||||||
|
* Returns a promise.
|
||||||
|
*/
|
||||||
|
module.exports.run = function(options) {
|
||||||
|
var opts = parseOpts(options);
|
||||||
|
|
||||||
|
var builder = builders[opts.buildMethod];
|
||||||
|
return builder.prepEnv()
|
||||||
|
.then(function() {
|
||||||
|
return builder.build(opts.buildType);
|
||||||
|
}).then(function(apkFiles) {
|
||||||
|
// TODO: Rather than copy apks to out, it might be better to
|
||||||
|
// just write out what the last .apk build was. These files
|
||||||
|
// are used by get_apk().
|
||||||
|
var outputDir = path.join(ROOT, 'out');
|
||||||
|
shell.mkdir('-p', outputDir);
|
||||||
|
for (var i=0; i < apkFiles.length; ++i) {
|
||||||
|
shell.cp('-f', apkFiles[i], path.join(outputDir, path.basename(apkFiles[i])));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gets the path to the apk file, if not such file exists then
|
||||||
|
* the script will error out. (should we error or just return undefined?)
|
||||||
|
* This is called by the run script to install the apk to the device
|
||||||
|
*/
|
||||||
|
module.exports.get_apk = function(build_type) {
|
||||||
|
var outputDir = path.join(ROOT, 'out');
|
||||||
|
var candidates = find_files(outputDir, function() { return true; });
|
||||||
|
if (candidates.length === 0) {
|
||||||
|
console.error('ERROR : No .apk found in ' + outputDir + ' directory');
|
||||||
|
process.exit(2);
|
||||||
|
}
|
||||||
|
// TODO: Use build_type here.
|
||||||
|
console.log('Using apk: ' + candidates[0]);
|
||||||
|
return candidates[0];
|
||||||
|
};
|
||||||
|
|
||||||
module.exports.help = function() {
|
module.exports.help = function() {
|
||||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'build')) + ' [build_type]');
|
console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'build')) + ' [build_type]');
|
||||||
console.log('Build Types : ');
|
console.log('Build Types : ');
|
||||||
console.log(' \'--debug\': Default build, will build project in using ant debug');
|
console.log(' \'--debug\': Default build, will build project in debug mode');
|
||||||
console.log(' \'--release\': will build project using ant release');
|
console.log(' \'--release\': will build project for release');
|
||||||
|
console.log(' \'--ant\': Default build, will build project with ant');
|
||||||
|
console.log(' \'--gradle\': will build project with gradle');
|
||||||
console.log(' \'--nobuild\': will skip build process (can be used with run command)');
|
console.log(' \'--nobuild\': will skip build process (can be used with run command)');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
};
|
};
|
||||||
|
39
bin/templates/cordova/lib/clean.js
vendored
39
bin/templates/cordova/lib/clean.js
vendored
@ -1,39 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
var build = require('./build'),
|
|
||||||
spawn = require('./spawn'),
|
|
||||||
path = require('path');
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Cleans the project using ant
|
|
||||||
* Returns a promise.
|
|
||||||
*/
|
|
||||||
module.exports.run = function() {
|
|
||||||
var args = build.getAntArgs('clean');
|
|
||||||
return spawn('ant', args);
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports.help = function() {
|
|
||||||
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
|
|
||||||
console.log('Cleans the project directory.');
|
|
||||||
process.exit(0);
|
|
||||||
}
|
|
14
bin/templates/project/gitignore
Normal file
14
bin/templates/project/gitignore
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
# Non-project-specific build files:
|
||||||
|
build.xml
|
||||||
|
local.properties
|
||||||
|
/gradlew
|
||||||
|
/gradlew.bat
|
||||||
|
/gradle
|
||||||
|
# Ant builds
|
||||||
|
ant-built
|
||||||
|
ant-gen
|
||||||
|
# Eclipse builds
|
||||||
|
gen
|
||||||
|
out
|
||||||
|
# Gradle builds
|
||||||
|
/build
|
15
bin/templates/project/project.properties
Normal file
15
bin/templates/project/project.properties
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
# This file is automatically generated by Android Tools.
|
||||||
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system edit
|
||||||
|
# "ant.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
#
|
||||||
|
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||||
|
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||||
|
|
||||||
|
android.library.reference.1=CordovaLib
|
||||||
|
# Project target.
|
||||||
|
target=This_gets_replaced
|
@ -255,5 +255,15 @@
|
|||||||
<category android:name="android.intent.category.SAMPLE_CODE" />
|
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
<activity
|
||||||
|
android:windowSoftInputMode="adjustPan"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:configChanges="orientation|keyboardHidden"
|
||||||
|
android:name="org.apache.cordova.test.SabotagedActivity" >
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.SAMPLE_CODE" />
|
||||||
|
</intent-filter>
|
||||||
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -25,6 +25,7 @@ public class IntentUriOverrideTest extends ActivityInstrumentationTestCase2<Sabo
|
|||||||
private String BAD_URL = "file:///sdcard/download/wl-exploit.htm";
|
private String BAD_URL = "file:///sdcard/download/wl-exploit.htm";
|
||||||
|
|
||||||
|
|
||||||
|
@SuppressWarnings("deprecation")
|
||||||
public IntentUriOverrideTest()
|
public IntentUriOverrideTest()
|
||||||
{
|
{
|
||||||
super("org.apache.cordova.test",SabotagedActivity.class);
|
super("org.apache.cordova.test",SabotagedActivity.class);
|
||||||
|
Loading…
Reference in New Issue
Block a user