You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by st...@apache.org on 2017/05/02 00:09:03 UTC
[43/68] [abbrv] cordova-lib git commit: CB-11242: updated tests and
fixtures
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/build.gradle
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/build.gradle b/cordova-lib/spec-plugman/projects/android/build.gradle
new file mode 100644
index 0000000..d8d92c5
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/build.gradle
@@ -0,0 +1,313 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+apply plugin: 'com.android.application'
+
+buildscript {
+ repositories {
+ mavenCentral()
+ jcenter()
+ }
+
+ // Switch the Android Gradle plugin version requirement depending on the
+ // installed version of Gradle. This dependency is documented at
+ // http://tools.android.com/tech-docs/new-build-system/version-compatibility
+ // and https://issues.apache.org/jira/browse/CB-8143
+ dependencies {
+ classpath 'com.android.tools.build:gradle:2.2.3'
+ }
+}
+
+// Allow plugins to declare Maven dependencies via build-extras.gradle.
+allprojects {
+ repositories {
+ mavenCentral();
+ jcenter()
+ }
+}
+
+task wrapper(type: Wrapper) {
+ gradleVersion = '2.14.1'
+}
+
+// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
+// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html
+ext {
+ apply from: 'CordovaLib/cordova.gradle'
+ // The value for android.compileSdkVersion.
+ if (!project.hasProperty('cdvCompileSdkVersion')) {
+ cdvCompileSdkVersion = null;
+ }
+ // The value for android.buildToolsVersion.
+ if (!project.hasProperty('cdvBuildToolsVersion')) {
+ cdvBuildToolsVersion = null;
+ }
+ // Sets the versionCode to the given value.
+ if (!project.hasProperty('cdvVersionCode')) {
+ cdvVersionCode = null
+ }
+ // Sets the minSdkVersion to the given value.
+ if (!project.hasProperty('cdvMinSdkVersion')) {
+ cdvMinSdkVersion = null
+ }
+ // Whether to build architecture-specific APKs.
+ if (!project.hasProperty('cdvBuildMultipleApks')) {
+ cdvBuildMultipleApks = null
+ }
+ // .properties files to use for release signing.
+ if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
+ cdvReleaseSigningPropertiesFile = null
+ }
+ // .properties files to use for debug signing.
+ if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {
+ cdvDebugSigningPropertiesFile = null
+ }
+ // Set by build.js script.
+ if (!project.hasProperty('cdvBuildArch')) {
+ cdvBuildArch = null
+ }
+
+ // Plugin gradle extensions can append to this to have code run at the end.
+ cdvPluginPostBuildExtras = []
+}
+
+// PLUGIN GRADLE EXTENSIONS START
+// PLUGIN GRADLE EXTENSIONS END
+
+def hasBuildExtras = file('build-extras.gradle').exists()
+if (hasBuildExtras) {
+ apply from: 'build-extras.gradle'
+}
+
+// Set property defaults after extension .gradle files.
+if (ext.cdvCompileSdkVersion == null) {
+ ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
+}
+if (ext.cdvBuildToolsVersion == null) {
+ ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
+}
+if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) {
+ ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties'
+}
+if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) {
+ ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties'
+}
+
+// Cast to appropriate types.
+ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
+ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)
+ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
+
+def computeBuildTargetName(debugBuild) {
+ def ret = 'assemble'
+ if (cdvBuildMultipleApks && cdvBuildArch) {
+ def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch
+ ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);
+ }
+ return ret + (debugBuild ? 'Debug' : 'Release')
+}
+
+// Make cdvBuild a task that depends on the debug/arch-sepecific task.
+task cdvBuildDebug
+cdvBuildDebug.dependsOn {
+ return computeBuildTargetName(true)
+}
+
+task cdvBuildRelease
+cdvBuildRelease.dependsOn {
+ return computeBuildTargetName(false)
+}
+
+task cdvPrintProps << {
+ println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
+ println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
+ println('cdvVersionCode=' + cdvVersionCode)
+ println('cdvMinSdkVersion=' + cdvMinSdkVersion)
+ println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
+ println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
+ println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
+ println('cdvBuildArch=' + cdvBuildArch)
+ println('computedVersionCode=' + android.defaultConfig.versionCode)
+ android.productFlavors.each { flavor ->
+ println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
+ }
+}
+
+android {
+ sourceSets {
+ main {
+ manifest.srcFile 'AndroidManifest.xml'
+ java.srcDirs = ['src']
+ resources.srcDirs = ['src']
+ aidl.srcDirs = ['src']
+ renderscript.srcDirs = ['src']
+ res.srcDirs = ['res']
+ assets.srcDirs = ['assets']
+ jniLibs.srcDirs = ['libs']
+ }
+ }
+
+ defaultConfig {
+ versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
+ applicationId privateHelpers.extractStringFromManifest("package")
+
+ if (cdvMinSdkVersion != null) {
+ minSdkVersion cdvMinSdkVersion
+ }
+ }
+
+ lintOptions {
+ abortOnError false;
+ }
+
+ compileSdkVersion cdvCompileSdkVersion
+ buildToolsVersion cdvBuildToolsVersion
+
+ if (Boolean.valueOf(cdvBuildMultipleApks)) {
+ productFlavors {
+ armv7 {
+ versionCode defaultConfig.versionCode*10 + 2
+ ndk {
+ abiFilters "armeabi-v7a", ""
+ }
+ }
+ x86 {
+ versionCode defaultConfig.versionCode*10 + 4
+ ndk {
+ abiFilters "x86", ""
+ }
+ }
+ all {
+ ndk {
+ abiFilters "all", ""
+ }
+ }
+ }
+ }
+ /*
+
+ ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO!
+
+ else if (!cdvVersionCode) {
+ def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
+ // Vary versionCode by the two most common API levels:
+ // 14 is ICS, which is the lowest API level for many apps.
+ // 20 is Lollipop, which is the lowest API level for the updatable system webview.
+ if (minSdkVersion >= 20) {
+ defaultConfig.versionCode += 9
+ } else if (minSdkVersion >= 14) {
+ defaultConfig.versionCode += 8
+ }
+ }
+ */
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_6
+ targetCompatibility JavaVersion.VERSION_1_6
+ }
+
+ if (cdvReleaseSigningPropertiesFile) {
+ signingConfigs {
+ release {
+ // These must be set or Gradle will complain (even if they are overridden).
+ keyAlias = ""
+ keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph.
+ storeFile = null
+ storePassword = "__unset"
+ }
+ }
+ buildTypes {
+ release {
+ signingConfig signingConfigs.release
+ }
+ }
+ addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)
+ }
+ if (cdvDebugSigningPropertiesFile) {
+ addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: '*.jar')
+ // SUB-PROJECT DEPENDENCIES START
+ debugCompile(project(path: "CordovaLib", configuration: "debug"))
+ releaseCompile(project(path: "CordovaLib", configuration: "release"))
+ // SUB-PROJECT DEPENDENCIES END
+}
+
+def promptForReleaseKeyPassword() {
+ if (!cdvReleaseSigningPropertiesFile) {
+ return;
+ }
+ if ('__unset'.equals(android.signingConfigs.release.storePassword)) {
+ android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')
+ }
+ if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {
+ android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');
+ }
+}
+
+gradle.taskGraph.whenReady { taskGraph ->
+ taskGraph.getAllTasks().each() { task ->
+ if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') {
+ promptForReleaseKeyPassword()
+ }
+ }
+}
+
+def addSigningProps(propsFilePath, signingConfig) {
+ def propsFile = file(propsFilePath)
+ def props = new Properties()
+ propsFile.withReader { reader ->
+ props.load(reader)
+ }
+
+ def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
+ if (!storeFile.isAbsolute()) {
+ storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
+ }
+ if (!storeFile.exists()) {
+ throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
+ }
+ signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
+ signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
+ signingConfig.storeFile = storeFile
+ signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
+ def storeType = props.get('storeType', props.get('key.store.type', ''))
+ if (!storeType) {
+ def filename = storeFile.getName().toLowerCase();
+ if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
+ storeType = 'pkcs12'
+ } else {
+ storeType = signingConfig.storeType // "jks"
+ }
+ }
+ signingConfig.storeType = storeType
+}
+
+for (def func : cdvPluginPostBuildExtras) {
+ func()
+}
+
+// This can be defined within build-extras.gradle as:
+// ext.postBuildExtras = { ... code here ... }
+if (hasProperty('postBuildExtras')) {
+ postBuildExtras()
+}
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/.jshintrc
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/.jshintrc b/cordova-lib/spec-plugman/projects/android/cordova/.jshintrc
new file mode 100644
index 0000000..89a121c
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/.jshintrc
@@ -0,0 +1,10 @@
+{
+ "node": true
+ , "bitwise": true
+ , "undef": true
+ , "trailing": true
+ , "quotmark": true
+ , "indent": 4
+ , "unused": "vars"
+ , "latedef": "nofunc"
+}
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/Api.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/Api.js b/cordova-lib/spec-plugman/projects/android/cordova/Api.js
new file mode 100644
index 0000000..8e4711c
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/Api.js
@@ -0,0 +1,415 @@
+/**
+ 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 path = require('path');
+var Q = require('q');
+
+var AndroidProject = require('./lib/AndroidProject');
+var AndroidStudio = require('./lib/AndroidStudio');
+var PluginManager = require('cordova-common').PluginManager;
+
+var CordovaLogger = require('cordova-common').CordovaLogger;
+var selfEvents = require('cordova-common').events;
+
+var PLATFORM = 'android';
+
+
+function setupEvents(externalEventEmitter) {
+ if (externalEventEmitter) {
+ // This will make the platform internal events visible outside
+ selfEvents.forwardEventsTo(externalEventEmitter);
+ return externalEventEmitter;
+ }
+
+ // There is no logger if external emitter is not present,
+ // so attach a console logger
+ CordovaLogger.get().subscribe(selfEvents);
+ return selfEvents;
+}
+
+
+/**
+ * Class, that acts as abstraction over particular platform. Encapsulates the
+ * platform's properties and methods.
+ *
+ * Platform that implements own PlatformApi instance _should implement all
+ * prototype methods_ of this class to be fully compatible with cordova-lib.
+ *
+ * The PlatformApi instance also should define the following field:
+ *
+ * * platform: String that defines a platform name.
+ */
+function Api(platform, platformRootDir, events) {
+ this.platform = PLATFORM;
+ this.root = path.resolve(__dirname, '..');
+
+ setupEvents(events);
+
+ var self = this;
+
+ this.locations = {
+ root: self.root,
+ www: path.join(self.root, 'assets/www'),
+ res: path.join(self.root, 'res'),
+ platformWww: path.join(self.root, 'platform_www'),
+ configXml: path.join(self.root, 'res/xml/config.xml'),
+ defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),
+ strings: path.join(self.root, 'res/values/strings.xml'),
+ manifest: path.join(self.root, 'AndroidManifest.xml'),
+ build: path.join(self.root, 'build'),
+ // NOTE: Due to platformApi spec we need to return relative paths here
+ cordovaJs: 'bin/templates/project/assets/www/cordova.js',
+ cordovaJsSrc: 'cordova-js-src'
+ };
+
+ // XXX Override some locations for Android Studio projects
+ if(AndroidStudio.isAndroidStudioProject(self.root) === true) {
+ selfEvents.emit('log', 'Android Studio project detected');
+ this.android_studio = true;
+ this.locations.configXml = path.join(self.root, 'app/src/main/res/xml/config.xml');
+ this.locations.strings = path.join(self.root, 'app/src/main/res/xml/strings.xml');
+ this.locations.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml');
+ this.locations.www = path.join(self.root, 'app/src/main/assets/www');
+ this.locations.res = path.join(self.root, 'app/src/main/res');
+ }
+}
+
+/**
+ * Installs platform to specified directory and creates a platform project.
+ *
+ * @param {String} destination Destination directory, where insatll platform to
+ * @param {ConfigParser} [config] ConfgiParser instance, used to retrieve
+ * project creation options, such as package id and project name.
+ * @param {Object} [options] An options object. The most common options are:
+ * @param {String} [options.customTemplate] A path to custom template, that
+ * should override the default one from platform.
+ * @param {Boolean} [options.link] Flag that indicates that platform's
+ * sources will be linked to installed platform instead of copying.
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ * logging purposes. If no EventEmitter provided, all events will be logged to
+ * console
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ * instance or rejected with CordovaError.
+ */
+Api.createPlatform = function (destination, config, options, events) {
+ events = setupEvents(events);
+ var result;
+ try {
+ result = require('../../lib/create')
+ .create(destination, config, options, events)
+ .then(function (destination) {
+ var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
+ return new PlatformApi(PLATFORM, destination, events);
+ });
+ }
+ catch (e) {
+ events.emit('error','createPlatform is not callable from the android project API.');
+ throw(e);
+ }
+ return result;
+};
+
+/**
+ * Updates already installed platform.
+ *
+ * @param {String} destination Destination directory, where platform installed
+ * @param {Object} [options] An options object. The most common options are:
+ * @param {String} [options.customTemplate] A path to custom template, that
+ * should override the default one from platform.
+ * @param {Boolean} [options.link] Flag that indicates that platform's
+ * sources will be linked to installed platform instead of copying.
+ * @param {EventEmitter} [events] An EventEmitter instance that will be used for
+ * logging purposes. If no EventEmitter provided, all events will be logged to
+ * console
+ *
+ * @return {Promise<PlatformApi>} Promise either fulfilled with PlatformApi
+ * instance or rejected with CordovaError.
+ */
+Api.updatePlatform = function (destination, options, events) {
+ events = setupEvents(events);
+ var result;
+ try {
+ result = require('../../lib/create')
+ .update(destination, options, events)
+ .then(function (destination) {
+ var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
+ return new PlatformApi('android', destination, events);
+ });
+ }
+ catch (e) {
+ events.emit('error','updatePlatform is not callable from the android project API, you will need to do this manually.');
+ throw(e);
+ }
+ return result;
+};
+
+/**
+ * Gets a CordovaPlatform object, that represents the platform structure.
+ *
+ * @return {CordovaPlatform} A structure that contains the description of
+ * platform's file structure and other properties of platform.
+ */
+Api.prototype.getPlatformInfo = function () {
+ var result = {};
+ result.locations = this.locations;
+ result.root = this.root;
+ result.name = this.platform;
+ result.version = require('./version');
+ result.projectConfig = this._config;
+
+ return result;
+};
+
+/**
+ * Updates installed platform with provided www assets and new app
+ * 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
+ * code, will be applied to platform.
+ *
+ * @param {CordovaProject} cordovaProject A CordovaProject instance, that defines a
+ * project structure and configuration, that should be applied to platform
+ * (contains project's www location and ConfigParser instance for project's
+ * config).
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+Api.prototype.prepare = function (cordovaProject, prepareOptions) {
+ return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);
+};
+
+/**
+ * Installs a new plugin into platform. This method only copies non-www files
+ * (sources, libs, etc.) to platform. It also doesn't resolves the
+ * dependencies of plugin. Both of handling of www files, such as assets and
+ * js-files and resolving dependencies are the responsibility of caller.
+ *
+ * @param {PluginInfo} plugin A PluginInfo instance that represents plugin
+ * that will be installed.
+ * @param {Object} installOptions An options object. Possible options below:
+ * @param {Boolean} installOptions.link: Flag that specifies that plugin
+ * sources will be symlinked to app's directory instead of copying (if
+ * possible).
+ * @param {Object} installOptions.variables An object that represents
+ * variables that will be used to install plugin. See more details on plugin
+ * variables in documentation:
+ * https://cordova.apache.org/docs/en/4.0.0/plugin_ref_spec.md.html
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+Api.prototype.addPlugin = function (plugin, installOptions) {
+ var project = AndroidProject.getProjectFile(this.root);
+ var self = this;
+
+ installOptions = installOptions || {};
+ installOptions.variables = installOptions.variables || {};
+ // Add PACKAGE_NAME variable into vars
+ if (!installOptions.variables.PACKAGE_NAME) {
+ installOptions.variables.PACKAGE_NAME = project.getPackageName();
+ }
+
+ if(this.android_studio === true) {
+ installOptions.android_studio = true;
+ }
+
+ return Q()
+ .then(function () {
+ //CB-11964: Do a clean when installing the plugin code to get around
+ //the Gradle bug introduced by the Android Gradle Plugin Version 2.2
+ //TODO: Delete when the next version of Android Gradle plugin comes out
+
+ // Since clean doesn't just clean the build, it also wipes out www, we need
+ // to pass additional options.
+
+ // Do some basic argument parsing
+ var opts = {};
+
+ // Skip cleaning prepared files when not invoking via cordova CLI.
+ opts.noPrepare = true;
+
+ if(!AndroidStudio.isAndroidStudioProject(self.root) && !project.isClean()) {
+ return self.clean(opts);
+ }
+ })
+ .then(function () {
+ return PluginManager.get(self.platform, self.locations, project)
+ .addPlugin(plugin, installOptions);
+ })
+ .then(function () {
+ if (plugin.getFrameworks(this.platform).length === 0) return;
+
+ selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
+ require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
+ }.bind(this))
+ // CB-11022 Return truthy value to prevent running prepare after
+ .thenResolve(true);
+};
+
+/**
+ * Removes an installed plugin from platform.
+ *
+ * Since method accepts PluginInfo instance as input parameter instead of plugin
+ * id, caller shoud take care of managing/storing PluginInfo instances for
+ * future uninstalls.
+ *
+ * @param {PluginInfo} plugin A PluginInfo instance that represents plugin
+ * that will be installed.
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError instance.
+ */
+Api.prototype.removePlugin = function (plugin, uninstallOptions) {
+ var project = AndroidProject.getProjectFile(this.root);
+
+ if(uninstallOptions && uninstallOptions.usePlatformWww === true && this.android_studio === true) {
+ uninstallOptions.usePlatformWww = false;
+ uninstallOptions.android_studio = true;
+ }
+
+ return PluginManager.get(this.platform, this.locations, project)
+ .removePlugin(plugin, uninstallOptions)
+ .then(function () {
+ if (plugin.getFrameworks(this.platform).length === 0) return;
+
+ selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
+ require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
+ }.bind(this))
+ // CB-11022 Return truthy value to prevent running prepare after
+ .thenResolve(true);
+};
+
+/**
+ * Builds an application package for current platform.
+ *
+ * @param {Object} buildOptions A build options. This object's structure is
+ * highly depends on platform's specific. The most common options are:
+ * @param {Boolean} buildOptions.debug Indicates that packages should be
+ * built with debug configuration. This is set to true by default unless the
+ * 'release' option is not specified.
+ * @param {Boolean} buildOptions.release Indicates that packages should be
+ * built with release configuration. If not set to true, debug configuration
+ * will be used.
+ * @param {Boolean} buildOptions.device Specifies that built app is intended
+ * to run on device
+ * @param {Boolean} buildOptions.emulator: Specifies that built app is
+ * intended to run on emulator
+ * @param {String} buildOptions.target Specifies the device id that will be
+ * used to run built application.
+ * @param {Boolean} buildOptions.nobuild Indicates that this should be a
+ * dry-run call, so no build artifacts will be produced.
+ * @param {String[]} buildOptions.archs Specifies chip architectures which
+ * app packages should be built for. List of valid architectures is depends on
+ * platform.
+ * @param {String} buildOptions.buildConfig The path to build configuration
+ * file. The format of this file is depends on platform.
+ * @param {String[]} buildOptions.argv Raw array of command-line arguments,
+ * passed to `build` command. The purpose of this property is to pass a
+ * platform-specific arguments, and eventually let platform define own
+ * arguments processing logic.
+ *
+ * @return {Promise<Object[]>} A promise either fulfilled with an array of build
+ * artifacts (application packages) if package was built successfully,
+ * or rejected with CordovaError. The resultant build artifact objects is not
+ * strictly typed and may conatin arbitrary set of fields as in sample below.
+ *
+ * {
+ * architecture: 'x86',
+ * buildType: 'debug',
+ * path: '/path/to/build',
+ * type: 'app'
+ * }
+ *
+ * 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
+ * arhcitectures is specified.
+ */
+Api.prototype.build = function (buildOptions) {
+ var self = this;
+ return require('./lib/check_reqs').run()
+ .then(function () {
+ return require('./lib/build').run.call(self, buildOptions);
+ })
+ .then(function (buildResults) {
+ // Cast build result to array of build artifacts
+ return buildResults.apkPaths.map(function (apkPath) {
+ return {
+ buildType: buildResults.buildType,
+ buildMethod: buildResults.buildMethod,
+ path: apkPath,
+ type: 'apk'
+ };
+ });
+ });
+};
+
+/**
+ * Builds an application package for current platform and runs it on
+ * specified/default device. If no 'device'/'emulator'/'target' options are
+ * specified, then tries to run app on default device if connected, otherwise
+ * runs the app on emulator.
+ *
+ * @param {Object} runOptions An options object. The structure is the same
+ * as for build options.
+ *
+ * @return {Promise} A promise either fulfilled if package was built and ran
+ * successfully, or rejected with CordovaError.
+ */
+Api.prototype.run = function(runOptions) {
+ var self = this;
+ return require('./lib/check_reqs').run()
+ .then(function () {
+ return require('./lib/run').run.call(self, runOptions);
+ });
+};
+
+/**
+ * Cleans out the build artifacts from platform's directory, and also
+ * cleans out the platform www directory if called without options specified.
+ *
+ * @return {Promise} Return a promise either fulfilled, or rejected with
+ * CordovaError.
+ */
+Api.prototype.clean = function(cleanOptions) {
+ var self = this;
+ return require('./lib/check_reqs').run()
+ .then(function () {
+ return require('./lib/build').runClean.call(self, cleanOptions);
+ })
+ .then(function () {
+ return require('./lib/prepare').clean.call(self, cleanOptions);
+ });
+};
+
+
+
+/**
+ * Performs a requirements check for current platform. Each platform defines its
+ * own set of requirements, which should be resolved before platform can be
+ * built successfully.
+ *
+ * @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
+ * objects for current platform.
+ */
+Api.prototype.requirements = function() {
+ return require('./lib/check_reqs').check_all();
+};
+
+module.exports = Api;
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/android_sdk_version
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/android_sdk_version b/cordova-lib/spec-plugman/projects/android/cordova/android_sdk_version
new file mode 100755
index 0000000..34ed28f
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/android_sdk_version
@@ -0,0 +1,29 @@
+#!/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 android_sdk = require('./lib/android_sdk');
+
+android_sdk.print_newest_available_sdk_target().done(null, function(err) {
+ console.error(err);
+ process.exit(2);
+});
+
+
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/build
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/build b/cordova-lib/spec-plugman/projects/android/cordova/build
new file mode 100755
index 0000000..222e84a
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/build
@@ -0,0 +1,50 @@
+#!/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 args = process.argv;
+var Api = require('./Api');
+var nopt = require('nopt');
+var path = require('path');
+
+// Support basic help commands
+if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)
+ require('./lib/build').help();
+
+// Do some basic argument parsing
+var buildOpts = nopt({
+ 'verbose' : Boolean,
+ 'silent' : Boolean,
+ 'debug' : Boolean,
+ 'release' : Boolean,
+ 'nobuild': Boolean,
+ 'buildConfig' : path
+}, { 'd' : '--verbose' });
+
+// Make buildOptions compatible with PlatformApi build method spec
+buildOpts.argv = buildOpts.argv.original;
+
+require('./loggingHelper').adjustLoggerLevel(buildOpts);
+
+new Api().build(buildOpts)
+.catch(function(err) {
+ console.error(err.stack);
+ process.exit(2);
+});
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/build.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/build.bat b/cordova-lib/spec-plugman/projects/android/cordova/build.bat
new file mode 100644
index 0000000..46e966a
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/build.bat
@@ -0,0 +1,26 @@
+:: 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.
+
+@ECHO OFF
+SET script_path="%~dp0build"
+IF EXIST %script_path% (
+ node %script_path% %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'build' script in 'cordova' folder, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/check_reqs
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/check_reqs b/cordova-lib/spec-plugman/projects/android/cordova/check_reqs
new file mode 100755
index 0000000..372a383
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/check_reqs
@@ -0,0 +1,31 @@
+#!/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 check_reqs = require('./lib/check_reqs');
+
+check_reqs.run().done(
+ function success() {
+ console.log('Looks like your environment fully supports cordova-android development!');
+ }, function fail(err) {
+ console.log(err);
+ process.exit(2);
+ }
+);
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/check_reqs.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/check_reqs.bat b/cordova-lib/spec-plugman/projects/android/cordova/check_reqs.bat
new file mode 100644
index 0000000..cb2c6f5
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/check_reqs.bat
@@ -0,0 +1,26 @@
+:: 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.
+
+@ECHO OFF
+SET script_path="%~dp0check_reqs"
+IF EXIST %script_path% (
+ node "%script_path%" %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'check_reqs' script in 'bin' folder, aborting...>&2
+ EXIT /B 1
+)
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/clean
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/clean b/cordova-lib/spec-plugman/projects/android/cordova/clean
new file mode 100755
index 0000000..22065cc
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/clean
@@ -0,0 +1,51 @@
+#!/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 Api = require('./Api');
+var path = require('path');
+var nopt = require('nopt');
+
+// Support basic help commands
+if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
+ console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
+ console.log('Cleans the project directory.');
+ process.exit(0);
+}
+
+// Do some basic argument parsing
+var opts = nopt({
+ 'verbose' : Boolean,
+ 'silent' : Boolean
+}, { 'd' : '--verbose' });
+
+// Make buildOptions compatible with PlatformApi clean method spec
+opts.argv = opts.argv.original;
+
+// Skip cleaning prepared files when not invoking via cordova CLI.
+opts.noPrepare = true;
+
+require('./loggingHelper').adjustLoggerLevel(opts);
+
+new Api().clean(opts)
+.catch(function(err) {
+ console.error(err.stack);
+ process.exit(2);
+});
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/clean.bat
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/clean.bat b/cordova-lib/spec-plugman/projects/android/cordova/clean.bat
new file mode 100644
index 0000000..445ef6e
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/clean.bat
@@ -0,0 +1,26 @@
+:: 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.
+
+@ECHO OFF
+SET script_path="%~dp0clean"
+IF EXIST %script_path% (
+ node %script_path% %*
+) ELSE (
+ ECHO.
+ ECHO ERROR: Could not find 'clean' script in 'cordova' folder, aborting...>&2
+ EXIT /B 1
+)
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/defaults.xml
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/defaults.xml b/cordova-lib/spec-plugman/projects/android/cordova/defaults.xml
new file mode 100644
index 0000000..5286ab9
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/defaults.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ 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.
+-->
+<widget xmlns = "http://www.w3.org/ns/widgets"
+ id = "io.cordova.helloCordova"
+ version = "2.0.0">
+
+ <!-- Preferences for Android -->
+ <preference name="loglevel" value="DEBUG" />
+</widget>
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/Adb.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/Adb.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/Adb.js
new file mode 100644
index 0000000..84ae707
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/Adb.js
@@ -0,0 +1,105 @@
+/**
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var Q = require('q');
+var os = require('os');
+var events = require('cordova-common').events;
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+
+var Adb = {};
+
+function isDevice(line) {
+ return line.match(/\w+\tdevice/) && !line.match(/emulator/);
+}
+
+function isEmulator(line) {
+ return line.match(/device/) && line.match(/emulator/);
+}
+
+/**
+ * Lists available/connected devices and emulators
+ *
+ * @param {Object} opts Various options
+ * @param {Boolean} opts.emulators Specifies whether this method returns
+ * emulators only
+ *
+ * @return {Promise<String[]>} list of available/connected
+ * devices/emulators
+ */
+Adb.devices = function (opts) {
+ return spawn('adb', ['devices'], {cwd: os.tmpdir()})
+ .then(function(output) {
+ return output.split('\n').filter(function (line) {
+ // Filter out either real devices or emulators, depending on options
+ return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
+ }).map(function (line) {
+ return line.replace(/\tdevice/, '').replace('\r', '');
+ });
+ });
+};
+
+Adb.install = function (target, packagePath, opts) {
+ events.emit('verbose', 'Installing apk ' + packagePath + ' on target ' + target + '...');
+ var args = ['-s', target, 'install'];
+ if (opts && opts.replace) args.push('-r');
+ return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
+ .then(function(output) {
+ // 'adb install' seems to always returns no error, even if installation fails
+ // so we catching output to detect installation failure
+ if (output.match(/Failure/)) {
+ if (output.match(/INSTALL_PARSE_FAILED_NO_CERTIFICATES/)) {
+ output += '\n\n' + 'Sign the build using \'-- --keystore\' or \'--buildConfig\'' +
+ ' or sign and deploy the unsigned apk manually using Android tools.';
+ } else if (output.match(/INSTALL_FAILED_VERSION_DOWNGRADE/)) {
+ output += '\n\n' + 'You\'re trying to install apk with a lower versionCode that is already installed.' +
+ '\nEither uninstall an app or increment the versionCode.';
+ }
+
+ return Q.reject(new CordovaError('Failed to install apk to device: ' + output));
+ }
+ });
+};
+
+Adb.uninstall = function (target, packageId) {
+ events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');
+ return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
+};
+
+Adb.shell = function (target, shellCommand) {
+ events.emit('verbose', 'Running adb shell command "' + shellCommand + '" on target ' + target + '...');
+ var args = ['-s', target, 'shell'];
+ shellCommand = shellCommand.split(/\s+/);
+ return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
+ .catch(function (output) {
+ return Q.reject(new CordovaError('Failed to execute shell command "' +
+ shellCommand + '"" on device: ' + output));
+ });
+};
+
+Adb.start = function (target, activityName) {
+ events.emit('verbose', 'Starting application "' + activityName + '" on target ' + target + '...');
+ return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
+ .catch(function (output) {
+ return Q.reject(new CordovaError('Failed to start application "' +
+ activityName + '"" on device: ' + output));
+ });
+};
+
+module.exports = Adb;
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidManifest.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidManifest.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidManifest.js
new file mode 100644
index 0000000..8248f59
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidManifest.js
@@ -0,0 +1,161 @@
+/**
+ 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 fs = require('fs');
+var et = require('elementtree');
+var xml= require('cordova-common').xmlHelpers;
+
+var DEFAULT_ORIENTATION = 'default';
+
+/** Wraps an AndroidManifest file */
+function AndroidManifest(path) {
+ this.path = path;
+ this.doc = xml.parseElementtreeSync(path);
+ if (this.doc.getroot().tag !== 'manifest') {
+ throw new Error('AndroidManifest at ' + path + ' has incorrect root node name (expected "manifest")');
+ }
+}
+
+AndroidManifest.prototype.getVersionName = function() {
+ return this.doc.getroot().attrib['android:versionName'];
+};
+
+AndroidManifest.prototype.setVersionName = function(versionName) {
+ this.doc.getroot().attrib['android:versionName'] = versionName;
+ return this;
+};
+
+AndroidManifest.prototype.getVersionCode = function() {
+ return this.doc.getroot().attrib['android:versionCode'];
+};
+
+AndroidManifest.prototype.setVersionCode = function(versionCode) {
+ this.doc.getroot().attrib['android:versionCode'] = versionCode;
+ return this;
+};
+
+AndroidManifest.prototype.getPackageId = function() {
+ /*jshint -W069 */
+ return this.doc.getroot().attrib['package'];
+ /*jshint +W069 */
+};
+
+AndroidManifest.prototype.setPackageId = function(pkgId) {
+ /*jshint -W069 */
+ this.doc.getroot().attrib['package'] = pkgId;
+ /*jshint +W069 */
+ return this;
+};
+
+AndroidManifest.prototype.getActivity = function() {
+ var activity = this.doc.getroot().find('./application/activity');
+ return {
+ getName: function () {
+ return activity.attrib['android:name'];
+ },
+ setName: function (name) {
+ if (!name) {
+ delete activity.attrib['android:name'];
+ } else {
+ activity.attrib['android:name'] = name;
+ }
+ return this;
+ },
+ getOrientation: function () {
+ return activity.attrib['android:screenOrientation'];
+ },
+ setOrientation: function (orientation) {
+ if (!orientation || orientation.toLowerCase() === DEFAULT_ORIENTATION) {
+ delete activity.attrib['android:screenOrientation'];
+ } else {
+ activity.attrib['android:screenOrientation'] = orientation;
+ }
+ return this;
+ },
+ getLaunchMode: function () {
+ return activity.attrib['android:launchMode'];
+ },
+ setLaunchMode: function (launchMode) {
+ if (!launchMode) {
+ delete activity.attrib['android:launchMode'];
+ } else {
+ activity.attrib['android:launchMode'] = launchMode;
+ }
+ return this;
+ }
+ };
+};
+
+['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
+.forEach(function(sdkPrefName) {
+ // Copy variable reference to avoid closure issues
+ var prefName = sdkPrefName;
+
+ AndroidManifest.prototype['get' + capitalize(prefName)] = function() {
+ var usesSdk = this.doc.getroot().find('./uses-sdk');
+ return usesSdk && usesSdk.attrib['android:' + prefName];
+ };
+
+ AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {
+ var usesSdk = this.doc.getroot().find('./uses-sdk');
+
+ if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
+ usesSdk = new et.Element('uses-sdk');
+ this.doc.getroot().append(usesSdk);
+ }
+
+ if (prefValue) {
+ usesSdk.attrib['android:' + prefName] = prefValue;
+ }
+
+ return this;
+ };
+});
+
+AndroidManifest.prototype.getDebuggable = function() {
+ return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
+};
+
+AndroidManifest.prototype.setDebuggable = function(value) {
+ var application = this.doc.getroot().find('./application');
+ if (value) {
+ application.attrib['android:debuggable'] = 'true';
+ } else {
+ // The default value is "false", so we can remove attribute at all.
+ delete application.attrib['android:debuggable'];
+ }
+ return this;
+};
+
+/**
+ * Writes manifest to disk syncronously. If filename is specified, then manifest
+ * will be written to that file
+ *
+ * @param {String} [destPath] File to write manifest to. If omitted,
+ * manifest will be written to file it has been read from.
+ */
+AndroidManifest.prototype.write = function(destPath) {
+ fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
+};
+
+module.exports = AndroidManifest;
+
+function capitalize (str) {
+ return str.charAt(0).toUpperCase() + str.slice(1);
+}
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidProject.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidProject.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidProject.js
new file mode 100644
index 0000000..fa1c612
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidProject.js
@@ -0,0 +1,210 @@
+/**
+ 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 fs = require('fs');
+var path = require('path');
+var properties_parser = require('properties-parser');
+var AndroidManifest = require('./AndroidManifest');
+var AndroidStudio = require('./AndroidStudio');
+var pluginHandlers = require('./pluginHandlers');
+
+var projectFileCache = {};
+
+function addToPropertyList(projectProperties, key, value) {
+ var i = 1;
+ while (projectProperties.get(key + '.' + i))
+ i++;
+
+ projectProperties.set(key + '.' + i, value);
+ projectProperties.dirty = true;
+}
+
+function removeFromPropertyList(projectProperties, key, value) {
+ var i = 1;
+ var currentValue;
+ while ((currentValue = projectProperties.get(key + '.' + i))) {
+ if (currentValue === value) {
+ while ((currentValue = projectProperties.get(key + '.' + (i + 1)))) {
+ projectProperties.set(key + '.' + i, currentValue);
+ i++;
+ }
+ projectProperties.set(key + '.' + i);
+ break;
+ }
+ i++;
+ }
+ projectProperties.dirty = true;
+}
+
+function getRelativeLibraryPath (parentDir, subDir) {
+ var libraryPath = path.relative(parentDir, subDir);
+ return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
+}
+
+function AndroidProject(projectDir) {
+ this._propertiesEditors = {};
+ this._subProjectDirs = {};
+ this._dirty = false;
+ this.projectDir = projectDir;
+ this.platformWww = path.join(this.projectDir, 'platform_www');
+ this.www = path.join(this.projectDir, 'assets/www');
+ if(AndroidStudio.isAndroidStudioProject(projectDir) === true) {
+ this.www = path.join(this.projectDir, 'app/src/main/assets/www');
+ }
+}
+
+AndroidProject.getProjectFile = function (projectDir) {
+ if (!projectFileCache[projectDir]) {
+ projectFileCache[projectDir] = new AndroidProject(projectDir);
+ }
+
+ return projectFileCache[projectDir];
+};
+
+AndroidProject.purgeCache = function (projectDir) {
+ if (projectDir) {
+ delete projectFileCache[projectDir];
+ } else {
+ projectFileCache = {};
+ }
+};
+
+/**
+ * Reads the package name out of the Android Manifest file
+ *
+ * @param {String} projectDir The absolute path to the directory containing the project
+ *
+ * @return {String} The name of the package
+ */
+AndroidProject.prototype.getPackageName = function() {
+ var manifestPath = path.join(this.projectDir, 'AndroidManifest.xml');
+ if(AndroidStudio.isAndroidStudioProject(this.projectDir) === true) {
+ manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml');
+ }
+ return new AndroidManifest(manifestPath).getPackageId();
+};
+
+AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, src) {
+ // 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.
+ var packageName = this.getPackageName();
+ var lastDotIndex = packageName.lastIndexOf('.');
+ var prefix = packageName.substring(lastDotIndex + 1);
+ var subRelativeDir = path.join(plugin_id, prefix + '-' + path.basename(src));
+ return subRelativeDir;
+};
+
+AndroidProject.prototype.addSubProject = function(parentDir, subDir) {
+ var parentProjectFile = path.resolve(parentDir, 'project.properties');
+ var subProjectFile = path.resolve(subDir, 'project.properties');
+ var parentProperties = this._getPropertiesFile(parentProjectFile);
+ // TODO: Setting the target needs to happen only for pre-3.7.0 projects
+ if (fs.existsSync(subProjectFile)) {
+ var subProperties = this._getPropertiesFile(subProjectFile);
+ subProperties.set('target', parentProperties.get('target'));
+ subProperties.dirty = true;
+ this._subProjectDirs[subDir] = true;
+ }
+ addToPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
+
+ this._dirty = true;
+};
+
+AndroidProject.prototype.removeSubProject = function(parentDir, subDir) {
+ var parentProjectFile = path.resolve(parentDir, 'project.properties');
+ var parentProperties = this._getPropertiesFile(parentProjectFile);
+ removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
+ delete this._subProjectDirs[subDir];
+ this._dirty = true;
+};
+
+AndroidProject.prototype.addGradleReference = function(parentDir, subDir) {
+ var parentProjectFile = path.resolve(parentDir, 'project.properties');
+ var parentProperties = this._getPropertiesFile(parentProjectFile);
+ addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
+ this._dirty = true;
+};
+
+AndroidProject.prototype.removeGradleReference = function(parentDir, subDir) {
+ var parentProjectFile = path.resolve(parentDir, 'project.properties');
+ var parentProperties = this._getPropertiesFile(parentProjectFile);
+ removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
+ this._dirty = true;
+};
+
+AndroidProject.prototype.addSystemLibrary = function(parentDir, value) {
+ var parentProjectFile = path.resolve(parentDir, 'project.properties');
+ var parentProperties = this._getPropertiesFile(parentProjectFile);
+ addToPropertyList(parentProperties, 'cordova.system.library', value);
+ this._dirty = true;
+};
+
+AndroidProject.prototype.removeSystemLibrary = function(parentDir, value) {
+ var parentProjectFile = path.resolve(parentDir, 'project.properties');
+ var parentProperties = this._getPropertiesFile(parentProjectFile);
+ removeFromPropertyList(parentProperties, 'cordova.system.library', value);
+ this._dirty = true;
+};
+
+AndroidProject.prototype.write = function() {
+ if (!this._dirty) {
+ return;
+ }
+ this._dirty = false;
+
+ for (var filename in this._propertiesEditors) {
+ var editor = this._propertiesEditors[filename];
+ if (editor.dirty) {
+ fs.writeFileSync(filename, editor.toString());
+ editor.dirty = false;
+ }
+ }
+};
+
+AndroidProject.prototype._getPropertiesFile = function (filename) {
+ if (!this._propertiesEditors[filename]) {
+ if (fs.existsSync(filename)) {
+ this._propertiesEditors[filename] = properties_parser.createEditor(filename);
+ } else {
+ this._propertiesEditors[filename] = properties_parser.createEditor();
+ }
+ }
+
+ return this._propertiesEditors[filename];
+};
+
+AndroidProject.prototype.getInstaller = function (type) {
+ return pluginHandlers.getInstaller(type);
+};
+
+AndroidProject.prototype.getUninstaller = function (type) {
+ return pluginHandlers.getUninstaller(type);
+};
+
+/*
+ * This checks if an Android project is clean or has old build artifacts
+ */
+
+AndroidProject.prototype.isClean = function() {
+ var build_path = path.join(this.projectDir, 'build');
+ //If the build directory doesn't exist, it's clean
+ return !(fs.existsSync(build_path));
+};
+
+module.exports = AndroidProject;
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidStudio.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidStudio.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidStudio.js
new file mode 100644
index 0000000..335b334
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/AndroidStudio.js
@@ -0,0 +1,42 @@
+/*
+ * This is a simple routine that checks if project is an Android Studio Project
+ *
+ * @param {String} root Root folder of the project
+ */
+
+/*jshint esnext: false */
+
+var path = require('path');
+var fs = require('fs');
+var CordovaError = require('cordova-common').CordovaError;
+
+module.exports.isAndroidStudioProject = function isAndroidStudioProject(root) {
+ var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res', 'project.properties', 'platform_www'];
+ var androidStudioFiles = ['app', 'gradle', 'app/src/main/res'];
+
+ // assume it is an AS project and not an Eclipse project
+ var isEclipse = false;
+ var isAS = true;
+
+ if(!fs.existsSync(root)) {
+ throw new CordovaError('AndroidStudio.js:inAndroidStudioProject root does not exist: ' + root);
+ }
+
+ // if any of the following exists, then we are not an ASProj
+ eclipseFiles.forEach(function(file) {
+ if(fs.existsSync(path.join(root, file))) {
+ isEclipse = true;
+ }
+ });
+
+ // if it is NOT an eclipse project, check that all required files exist
+ if(!isEclipse) {
+ androidStudioFiles.forEach(function(file){
+ if(!fs.existsSync(path.join(root, file))) {
+ console.log('missing file :: ' + file);
+ isAS = false;
+ }
+ });
+ }
+ return (!isEclipse && isAS);
+};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/build.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/build.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/build.js
new file mode 100644
index 0000000..bd613da
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/build.js
@@ -0,0 +1,301 @@
+#!/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 Q = require('q'),
+ path = require('path'),
+ fs = require('fs'),
+ nopt = require('nopt');
+
+var Adb = require('./Adb');
+
+var builders = require('./builders/builders');
+var events = require('cordova-common').events;
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+
+function parseOpts(options, resolvedTarget, projectRoot) {
+ options = options || {};
+ options.argv = nopt({
+ gradle: Boolean,
+ ant: Boolean,
+ prepenv: Boolean,
+ versionCode: String,
+ minSdkVersion: String,
+ gradleArg: [String, Array],
+ keystore: path,
+ alias: String,
+ storePassword: String,
+ password: String,
+ keystoreType: String
+ }, {}, options.argv, 0);
+
+ var ret = {
+ buildType: options.release ? 'release' : 'debug',
+ buildMethod: process.env.ANDROID_BUILD || 'gradle',
+ prepEnv: options.argv.prepenv,
+ arch: resolvedTarget && resolvedTarget.arch,
+ extraArgs: []
+ };
+
+ if (options.argv.ant || options.argv.gradle)
+ ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
+
+ if (options.nobuild) ret.buildMethod = 'none';
+
+ if (options.argv.versionCode)
+ ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode);
+
+ if (options.argv.minSdkVersion)
+ ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion);
+
+ if (options.argv.gradleArg) {
+ ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
+ }
+
+ var packageArgs = {};
+
+ if (options.argv.keystore)
+ packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore));
+
+ ['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
+ if (options.argv[flagName])
+ packageArgs[flagName] = options.argv[flagName];
+ });
+
+ var buildConfig = options.buildConfig;
+
+ // If some values are not specified as command line arguments - use build config to supplement them.
+ // Command line arguemnts have precedence over build config.
+ if (buildConfig) {
+ if (!fs.existsSync(buildConfig)) {
+ throw new Error('Specified build config file does not exist: ' + buildConfig);
+ }
+ events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig));
+ var buildjson = fs.readFileSync(buildConfig, 'utf8');
+ var config = JSON.parse(buildjson.replace(/^\ufeff/, '')); // Remove BOM
+ if (config.android && config.android[ret.buildType]) {
+ var androidInfo = config.android[ret.buildType];
+ if(androidInfo.keystore && !packageArgs.keystore) {
+ if(androidInfo.keystore.substr(0,1) === '~') {
+ androidInfo.keystore = process.env.HOME + androidInfo.keystore.substr(1);
+ }
+ packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);
+ events.emit('log', 'Reading the keystore from: ' + packageArgs.keystore);
+ }
+
+ ['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){
+ packageArgs[key] = packageArgs[key] || androidInfo[key];
+ });
+ }
+ }
+
+ if (packageArgs.keystore && packageArgs.alias) {
+ ret.packageInfo = new PackageInfo(packageArgs.keystore, packageArgs.alias, packageArgs.storePassword,
+ packageArgs.password, packageArgs.keystoreType);
+ }
+
+ if(!ret.packageInfo) {
+ if(Object.keys(packageArgs).length > 0) {
+ events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Builds the project with the specifed options
+ * Returns a promise.
+ */
+module.exports.runClean = function(options) {
+ var opts = parseOpts(options, null, this.root);
+ var builder = builders.getBuilder(opts.buildMethod);
+ return builder.prepEnv(opts)
+ .then(function() {
+ return builder.clean(opts);
+ });
+};
+
+/**
+ * Builds the project with the specifed options.
+ *
+ * @param {BuildOptions} options A set of options. See PlatformApi.build
+ * method documentation for reference.
+ * @param {Object} optResolvedTarget A deployment target. Used to pass
+ * target architecture from upstream 'run' call. TODO: remove this option in
+ * favor of setting buildOptions.archs field.
+ *
+ * @return {Promise<Object>} Promise, resolved with built packages
+ * information.
+ */
+module.exports.run = function(options, optResolvedTarget) {
+ var opts = parseOpts(options, optResolvedTarget, this.root);
+ var builder = builders.getBuilder(opts.buildMethod);
+ return builder.prepEnv(opts)
+ .then(function() {
+ if (opts.prepEnv) {
+ events.emit('verbose', 'Build file successfully prepared.');
+ return;
+ }
+ return builder.build(opts)
+ .then(function() {
+ var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
+ events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
+ return {
+ apkPaths: apkPaths,
+ buildType: opts.buildType,
+ buildMethod: opts.buildMethod
+ };
+ });
+ });
+};
+
+/*
+ * Detects the architecture of a device/emulator
+ * Returns "arm" or "x86".
+ */
+module.exports.detectArchitecture = function(target) {
+ function helper() {
+ return Adb.shell(target, 'cat /proc/cpuinfo')
+ .then(function(output) {
+ return /intel/i.exec(output) ? 'x86' : 'arm';
+ });
+ }
+ // 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.
+ return helper()
+ .timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))
+ .then(null, function(err) {
+ if (/timed out/.exec('' + err)) {
+ // adb kill-server doesn't seem to do the trick.
+ // Could probably find a x-platform version of killall, but I'm not actually
+ // sure that this scenario even happens on non-OSX machines.
+ events.emit('verbose', 'adb timed out while detecting device/emulator architecture. Killing adb and trying again.');
+ return spawn('killall', ['adb'])
+ .then(function() {
+ return helper()
+ .then(null, function() {
+ // The double kill is sadly often necessary, at least on mac.
+ events.emit('warn', 'adb timed out a second time while detecting device/emulator architecture. Killing adb and trying again.');
+ return spawn('killall', ['adb'])
+ .then(function() {
+ return helper()
+ .then(null, function() {
+ return Q.reject(new CordovaError('adb timed out a third time while detecting device/emulator architecture. Try unplugging & replugging the device.'));
+ });
+ });
+ });
+ }, function() {
+ // For non-killall OS's.
+ return Q.reject(err);
+ });
+ }
+ throw err;
+ });
+};
+
+module.exports.findBestApkForArchitecture = function(buildResults, arch) {
+ var paths = buildResults.apkPaths.filter(function(p) {
+ var apkName = path.basename(p);
+ if (buildResults.buildType == 'debug') {
+ return /-debug/.exec(apkName);
+ }
+ return !/-debug/.exec(apkName);
+ });
+ var archPattern = new RegExp('-' + arch);
+ var hasArchPattern = /-x86|-arm/;
+ for (var i = 0; i < paths.length; ++i) {
+ var apkName = path.basename(paths[i]);
+ if (hasArchPattern.exec(apkName)) {
+ if (archPattern.exec(apkName)) {
+ return paths[i];
+ }
+ } else {
+ return paths[i];
+ }
+ }
+ throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
+};
+
+function PackageInfo(keystore, alias, storePassword, password, keystoreType) {
+ this.keystore = {
+ 'name': 'key.store',
+ 'value': keystore
+ };
+ this.alias = {
+ 'name': 'key.alias',
+ 'value': alias
+ };
+ if (storePassword) {
+ this.storePassword = {
+ 'name': 'key.store.password',
+ 'value': storePassword
+ };
+ }
+ if (password) {
+ this.password = {
+ 'name': 'key.alias.password',
+ 'value': password
+ };
+ }
+ if (keystoreType) {
+ this.keystoreType = {
+ 'name': 'key.store.type',
+ 'value': keystoreType
+ };
+ }
+}
+
+PackageInfo.prototype = {
+ toProperties: function() {
+ var self = this;
+ var result = '';
+ Object.keys(self).forEach(function(key) {
+ result += self[key].name;
+ result += '=';
+ result += self[key].value.replace(/\\/g, '\\\\');
+ result += '\n';
+ });
+ return result;
+ }
+};
+
+module.exports.help = function() {
+ console.log('Usage: ' + path.relative(process.cwd(), path.join('../build')) + ' [flags] [Signed APK flags]');
+ console.log('Flags:');
+ console.log(' \'--debug\': will build project in debug mode (default)');
+ console.log(' \'--release\': will build project for release');
+ console.log(' \'--ant\': will build project with ant');
+ console.log(' \'--gradle\': will build project with gradle (default)');
+ 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(' \'--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(' \'--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('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(' \'--alias=\': Alias for the key store. (Required)');
+ console.log(' \'--storePassword=\': Password for the key store. (Optional - prompted)');
+ console.log(' \'--password=\': Password for the key. (Optional - prompted)');
+ console.log(' \'--keystoreType\': Type of the keystore. (Optional)');
+ process.exit(0);
+};
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/AntBuilder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/AntBuilder.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/AntBuilder.js
new file mode 100644
index 0000000..4e0f71a
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/AntBuilder.js
@@ -0,0 +1,156 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var util = require('util');
+var shell = require('shelljs');
+var spawn = require('cordova-common').superspawn.spawn;
+var CordovaError = require('cordova-common').CordovaError;
+var check_reqs = require('../check_reqs');
+
+var SIGNING_PROPERTIES = '-signing.properties';
+var MARKER = 'YOUR CHANGES WILL BE ERASED!';
+var TEMPLATE =
+ '# This file is automatically generated.\n' +
+ '# Do not modify this file -- ' + MARKER + '\n';
+
+var GenericBuilder = require('./GenericBuilder');
+
+function AntBuilder (projectRoot) {
+ GenericBuilder.call(this, projectRoot);
+
+ this.binDirs = {ant: this.binDirs.ant};
+}
+
+util.inherits(AntBuilder, GenericBuilder);
+
+AntBuilder.prototype.getArgs = function(cmd, opts) {
+ var args = [cmd, '-f', path.join(this.root, 'build.xml')];
+ // custom_rules.xml is required for incremental builds.
+ if (hasCustomRules(this.root)) {
+ args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
+ }
+ if(opts.packageInfo) {
+ args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
+ }
+ return args;
+};
+
+AntBuilder.prototype.prepEnv = function(opts) {
+ var self = this;
+ return check_reqs.check_ant()
+ .then(function() {
+ // Copy in build.xml on each build so that:
+ // A) we don't require the Android SDK at project creation time, and
+ // B) we always use the SDK's latest version of it.
+ /*jshint -W069 */
+ var sdkDir = process.env['ANDROID_HOME'];
+ /*jshint +W069 */
+ var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
+ function writeBuildXml(projectPath) {
+ var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
+ fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
+ if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
+ fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);
+ }
+ }
+ writeBuildXml(self.root);
+ var propertiesObj = self.readProjectProperties();
+ var subProjects = propertiesObj.libs;
+ for (var i = 0; i < subProjects.length; ++i) {
+ writeBuildXml(path.join(self.root, subProjects[i]));
+ }
+ if (propertiesObj.systemLibs.length > 0) {
+ throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Use gradle instead.');
+ }
+
+ var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
+ var propertiesFilePath = path.join(self.root, propertiesFile);
+ if (opts.packageInfo) {
+ fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
+ } else if(isAutoGenerated(propertiesFilePath)) {
+ shell.rm('-f', propertiesFilePath);
+ }
+ });
+};
+
+/*
+ * Builds the project with ant.
+ * Returns a promise.
+ */
+AntBuilder.prototype.build = function(opts) {
+ // Without our custom_rules.xml, we need to clean before building.
+ var ret = Q();
+ if (!hasCustomRules(this.root)) {
+ // clean will call check_ant() for us.
+ ret = this.clean(opts);
+ }
+
+ var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
+ return check_reqs.check_ant()
+ .then(function() {
+ return spawn('ant', args, {stdio: 'pipe'});
+ }).progress(function (stdio){
+ if (stdio.stderr) {
+ process.stderr.write(stdio.stderr);
+ } else {
+ process.stdout.write(stdio.stdout);
+ }
+ }).catch(function (error) {
+ if (error.toString().indexOf('Unable to resolve project target') >= 0) {
+ return check_reqs.check_android_target(error).then(function() {
+ // If due to some odd reason - check_android_target succeeds
+ // we should still fail here.
+ return Q.reject(error);
+ });
+ }
+ return Q.reject(error);
+ });
+};
+
+AntBuilder.prototype.clean = function(opts) {
+ var args = this.getArgs('clean', opts);
+ var self = this;
+ return check_reqs.check_ant()
+ .then(function() {
+ return spawn('ant', args, {stdio: 'inherit'});
+ })
+ .then(function () {
+ shell.rm('-rf', path.join(self.root, 'out'));
+
+ ['debug', 'release'].forEach(function(config) {
+ var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
+ if(isAutoGenerated(propertiesFilePath)){
+ shell.rm('-f', propertiesFilePath);
+ }
+ });
+ });
+};
+
+module.exports = AntBuilder;
+
+function hasCustomRules(projectRoot) {
+ return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
+}
+
+function isAutoGenerated(file) {
+ return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
+}
http://git-wip-us.apache.org/repos/asf/cordova-lib/blob/f0e19e8c/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/GenericBuilder.js
----------------------------------------------------------------------
diff --git a/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/GenericBuilder.js b/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/GenericBuilder.js
new file mode 100644
index 0000000..362da43
--- /dev/null
+++ b/cordova-lib/spec-plugman/projects/android/cordova/lib/builders/GenericBuilder.js
@@ -0,0 +1,147 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+var Q = require('q');
+var fs = require('fs');
+var path = require('path');
+var shell = require('shelljs');
+var events = require('cordova-common').events;
+var CordovaError = require('cordova-common').CordovaError;
+
+function GenericBuilder (projectDir) {
+ this.root = projectDir || path.resolve(__dirname, '../../..');
+ this.binDirs = {
+ ant: path.join(this.root, hasCustomRules(this.root) ? 'ant-build' : 'bin'),
+ gradle: path.join(this.root, 'build', 'outputs', 'apk')
+ };
+}
+
+function hasCustomRules(projectRoot) {
+ return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
+}
+
+GenericBuilder.prototype.prepEnv = function() {
+ return Q();
+};
+
+GenericBuilder.prototype.build = function() {
+ events.emit('log', 'Skipping build...');
+ return Q(null);
+};
+
+GenericBuilder.prototype.clean = function() {
+ return Q();
+};
+
+GenericBuilder.prototype.findOutputApks = function(build_type, arch) {
+ var self = this;
+ return Object.keys(this.binDirs)
+ .reduce(function (result, builderName) {
+ var binDir = self.binDirs[builderName];
+ return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch));
+ }, [])
+ .sort(apkSorter);
+};
+
+GenericBuilder.prototype.readProjectProperties = function () {
+ function findAllUniq(data, r) {
+ var s = {};
+ var m;
+ while ((m = r.exec(data))) {
+ s[m[1]] = 1;
+ }
+ return Object.keys(s);
+ }
+
+ var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
+ return {
+ libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
+ gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
+ systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
+ };
+};
+
+GenericBuilder.prototype.extractRealProjectNameFromManifest = function () {
+ var manifestPath = path.join(this.root, 'AndroidManifest.xml');
+ var manifestData = fs.readFileSync(manifestPath, 'utf8');
+ var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
+ if (!m) {
+ throw new CordovaError('Could not find package name in ' + manifestPath);
+ }
+
+ var packageName=m[1];
+ var lastDotIndex = packageName.lastIndexOf('.');
+ return packageName.substring(lastDotIndex + 1);
+};
+
+module.exports = GenericBuilder;
+
+function apkSorter(fileA, fileB) {
+ // De-prioritize unsigned builds
+ var unsignedRE = /-unsigned/;
+ if (unsignedRE.exec(fileA)) {
+ return 1;
+ } else if (unsignedRE.exec(fileB)) {
+ return -1;
+ }
+
+ var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime;
+ return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
+}
+
+function findOutputApksHelper(dir, build_type, arch) {
+ var shellSilent = shell.config.silent;
+ shell.config.silent = true;
+
+ var ret = shell.ls(path.join(dir, '*.apk'))
+ .filter(function(candidate) {
+ var apkName = path.basename(candidate);
+ // Need to choose between release and debug .apk.
+ if (build_type === 'debug') {
+ return /-debug/.exec(apkName) && !/-unaligned|-unsigned/.exec(apkName);
+ }
+ if (build_type === 'release') {
+ return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
+ }
+ return true;
+ })
+ .sort(apkSorter);
+
+ shellSilent = shellSilent;
+
+ if (ret.length === 0) {
+ return ret;
+ }
+ // Assume arch-specific build if newest apk has -x86 or -arm.
+ var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0]));
+ // And show only arch-specific ones (or non-arch-specific)
+ ret = ret.filter(function(p) {
+ /*jshint -W018 */
+ return !!/-x86|-arm/.exec(path.basename(p)) == archSpecific;
+ /*jshint +W018 */
+ });
+
+ if (archSpecific && ret.length > 1 && arch) {
+ ret = ret.filter(function(p) {
+ return path.basename(p).indexOf('-' + arch) != -1;
+ });
+ }
+
+ return ret;
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@cordova.apache.org
For additional commands, e-mail: commits-help@cordova.apache.org