Compare commits

..

18 Commits
6.4.x ... 6.1.x

Author SHA1 Message Date
Steve Gill
37ee3cdf81 Set VERSION to 6.1.2 (via coho) 2017-01-26 16:30:31 -08:00
Steve Gill
22694606f9 Update JS snapshot to version 6.1.2 (via coho) 2017-01-26 16:30:31 -08:00
Steve Gill
9d217813f1 CB-12403 Updated RELEASENOTES and Version for release 6.1.2 2017-01-26 16:30:02 -08:00
Joe Bowser
07dce213a2 Change to https by default 2017-01-26 16:29:11 -08:00
audreyso
f114ac8c8c CB:12018 : added dev dependencies to gitignore
This closes #355
2017-01-26 16:27:39 -08:00
audreyso
05af619521 CB-12018 : updated tests to work with jasmine (promise matcher tests commented out for now) 2017-01-26 16:27:29 -08:00
Steve Gill
96457effbc Set VERSION to 6.1.1 (via coho) 2017-01-03 17:45:53 -08:00
Steve Gill
67e7980eba Update JS snapshot to version 6.1.1 (via coho) 2017-01-03 17:45:53 -08:00
Steve Gill
0efa6cd766 CB-12314 Updated RELEASENOTES and Version for release 6.1.1 2017-01-03 17:42:13 -08:00
daserge
a51fc4b25e CB-12159 Android: Keystore password prompt won't show up
This closes #351
2017-01-03 17:21:39 -08:00
Joe Bowser
071ddbf6eb Adding isClean to the spec, this really should have failed a few commits ago
This closes #349
2017-01-03 17:21:24 -08:00
Joe Bowser
a87eb7266f Need to pass lint 2017-01-03 17:21:05 -08:00
Joe Bowser
c2ddd2da7f CB-12169: Check for build directory before running a clean 2017-01-03 17:20:26 -08:00
Joe Bowser
e856613787 Updating the timeout due to known travis issues 2016-11-03 12:49:40 -07:00
Jesse MacFadyen
94e9bd5e26 Do not test for non-existent build folder
This closes #348
2016-11-03 12:49:30 -07:00
Jesse MacFadyen
011b57da54 Fixed AndroidStudio tests to actually run, removed app/src/main/assets/ as a requirement and added app/src/main/res instead, added placeholder for build/ folder, Removed dupe gitignore 2016-11-03 12:49:18 -07:00
Joe Bowser
7e54af75d8 Set VERSION to 6.1.0 (via coho) 2016-11-02 16:32:15 -07:00
Joe Bowser
d95df96881 Update JS snapshot to version 6.1.0 (via coho) 2016-11-02 16:32:15 -07:00
281 changed files with 5597 additions and 11154 deletions

View File

@@ -1 +0,0 @@
bin/templates/project/assets/www/cordova.js

View File

@@ -1,10 +0,0 @@
root: true
extends: semistandard
rules:
indent:
- error
- 4
camelcase: off
padded-blocks: off
operator-linebreak: off
no-throw-literal: off

36
.gitignore vendored
View File

@@ -1,21 +1,11 @@
.DS_Store
.gradle
.metadata
Thumbs.db
Desktop.ini
*.tmp
*.bak
*.swp
*.class
*.jar
default.properties
gen
assets/www/cordova.js
local.properties
proguard.cfg
proguard.cfg
proguard-project.txt
example
/coverage
/framework/lib
/framework/build
/framework/bin
@@ -25,23 +15,30 @@ example
/framework/libs
/framework/javadoc-public
/framework/javadoc-private
/test/.externalNativeBuild
/test/build.gradle
/test/libs
example
/test/bin
/test/assets/www/.tmp*
/test/assets/www/cordova.js
/test/gradle
/test/gradlew
/test/gradlew.bat
/test/assets/www/.tmp*
/test/assets/www/cordova.js
/test/bin
/test/build
/test/captures
/test/libs
.gradle
tmp/**
.metadata
tmp/**/*
Thumbs.db
Desktop.ini
*.tmp
*.bak
*.swp
*.class
*.jar
!/spec/fixtures/org.test.plugins.dummyplugin/src/android/TestLib.jar
# IntelliJ IDEA files
**/.idea/**/*
*.iml
.idea
npm-debug.log
node_modules/jshint
node_modules/promise-matchers
@@ -133,3 +130,4 @@ node_modules/wordwrap/
node_modules/yargs/
node_modules/jasmine-core/
node_modules/fs.realpath/
/coverage

3
.jshintignore Normal file
View File

@@ -0,0 +1,3 @@
bin/node_modules/*
bin/templates/project/*
spec/fixtures/*

10
.jshintrc Normal file
View File

@@ -0,0 +1,10 @@
{
"node": true
, "bitwise": true
, "undef": true
, "trailing": true
, "quotmark": true
, "indent": 4
, "unused": "vars"
, "latedef": "nofunc"
}

View File

@@ -5,4 +5,3 @@ proguard-project.txt
spec
appveyor.yml
framework/build
ic_launcher.png

View File

@@ -2,27 +2,20 @@ language: android
sudo: false
jdk:
- oraclejdk8
env:
global:
- ANDROID_TOOLS=${ANDROID_HOME}/tools
before_install:
- nvm install 6
# ensure at least gradle 3.3 is in place.
- wget http://services.gradle.org/distributions/gradle-3.3-bin.zip
- unzip gradle-3.3-bin.zip
- export GRADLE_HOME=$PWD/gradle-3.3
- export PATH=${GRADLE_HOME}/bin:${ANDROID_HOME}:${ANDROID_HOME}/emulator:${ANDROID_TOOLS}:${ANDROID_TOOLS}/bin:${ANDROID_HOME}/platform-tools:$PATH
- node --version
- gradle --version
- echo y | android --silent update sdk --no-ui --all --filter platform-tools,tools,build-tools-26.0.2,android-26,android-25,extra-google-m2repository,extra-android-m2repository
android:
components:
- tools
install:
- npm install
- npm install -g codecov
- echo y | android update sdk -u --filter android-22,android-23,android-24,android-25
android:
components:
- tools
- tools
script:
- npm test
- npm run jshint
- npm run cover
- npm run test-build
after_script:
- codecov

View File

@@ -36,7 +36,7 @@ at the core, applications written with web technology: HTML, CSS and JavaScript.
## Requires
- Java JDK 1.8 or greater
- Java JDK 1.6 or greater
- Android SDK [http://developer.android.com](http://developer.android.com)
@@ -62,9 +62,3 @@ These commands live in a generated Cordova Android project. Any interactions wit
1. Create a project
2. Import it via "Non-Android Studio Project"
## Running the Native Tests
The `test/` directory in this project contains an Android test project that can
be used to run different kinds of native tests. Check out the
[README contained therein](test/README.md) for more details!

View File

@@ -20,54 +20,6 @@
-->
## Release Notes for Cordova (Android) ##
### 6.4.0 (Nov 06, 2017)
* [CB-13289](https://issues.apache.org/jira/browse/CB-13289) Fixing build problems with Studio Three, but keeping **Windows** Gradle fix for now, will be deprecated
* [CB-13289](https://issues.apache.org/jira/browse/CB-13289) Fix test to work with new Google **Android** Gradle DSL
* :CB-13501 : update appveyor node versions to support node 8
* [CB-13499](https://issues.apache.org/jira/browse/CB-13499) Remove duplicate "setting" in error strings
* Include missing values for task.name when 'cdvBuildMultipleApks' option is true, 'task.name' can have 'validateSigningArmv7Release' or 'validateSigningX86Release' values too.
* [CB-13406](https://issues.apache.org/jira/browse/CB-13406) Fixed AVD API level comparison when choosing sub-par API level match. Added tests for the best_image method.
* [CB-13404](https://issues.apache.org/jira/browse/CB-13404) add **Android**-versions to bundledDependencies. Ignore best emulator selection when parsed AVD information does not include API level in the target
* [CB-12895](https://issues.apache.org/jira/browse/CB-12895) : eslint ignoring cordova.js
* [CB-12895](https://issues.apache.org/jira/browse/CB-12895) Temporarily disabling eslint since cordova-js does not have eslint yet.
### 6.3.0 (Sep 25, 2017)
* [CB-6936](https://issues.apache.org/jira/browse/CB-6936) fix crash when calling methods on a destroyed webview
* [CB-12981](https://issues.apache.org/jira/browse/CB-12981) handle SDK 26.0.2 slightly different AVD list output for **Android** 8+ AVDs. Would cause "cannot read property replace of undefined" errors when trying to deploy an **Android** 8 emulator.
* Updated maven repo to include most recent lib versions
* [CB-13177](https://issues.apache.org/jira/browse/CB-13177) Updating to API Level 26
* Revert [CB-12015](https://issues.apache.org/jira/browse/CB-12015) initial-scale values less than 1.0 are ignored on **Android**
* [CB-12730](https://issues.apache.org/jira/browse/CB-12730) The Cordova Compatibility Plugin is now integrated into cordova-android
* [CB-12453](https://issues.apache.org/jira/browse/CB-12453) Remove unnecessary double quotes from .bat files which are the causes of crash if project path contains spaces
* [CB-13031](https://issues.apache.org/jira/browse/CB-13031) Fix bug with case-sensitivity of **Android**-packageName
* [CB-10916](https://issues.apache.org/jira/browse/CB-10916) Support display name for **Android**
* [CB-12423](https://issues.apache.org/jira/browse/CB-12423) make explicit JDK 1.8 or greater is needed in the `README`, we require 1.8 for compilation, but do not have 1.8 Java features yet
* [CB-13006](https://issues.apache.org/jira/browse/CB-13006) removed create and update end-to-end tests, and instead added more unit test coverage. tweaked code coverage invocation so that we get coverage details on the create.js module. slight changes to the create.js module so that it is slightly easier to test.
* [CB-12950](https://issues.apache.org/jira/browse/CB-12950) lots of tweaks for end-to-end test runs, especially on CI: - rename npm tasks to reflect what they do (npm run unit-tests, npm run e2e-tests). main `npm test` runs linter, unit tests and e2e tests now. - locked jasmine down to ~2.6.0. - consolidate gitignores. - updated travis to run `npm test`. add **Android** sdk installation to appveyor ci run.align **Android** dpendencies across travis and appveyor. have appveyor install gradle. force gradle to version 3.4.1 in appveyor, as that seems to be the only version choco has. explicitly invoke sdkmanager to move license accepting process along.
* [CB-12605](https://issues.apache.org/jira/browse/CB-12605) In **Windows** get **Android** studio path from the registry
* [CB-12762](https://issues.apache.org/jira/browse/CB-12762) : pointed `package.json` repo items to github mirrors instead of apache repos site
* [CB-12617](https://issues.apache.org/jira/browse/CB-12617) : removed node0.x support for platforms and added engineStrict
### 6.2.3 (May 2, 2017)
* [CB-12640](https://issues.apache.org/jira/browse/CB-12640) better handling of unrecognized Android SDK commands on **Windows**.
* [CB-12640](https://issues.apache.org/jira/browse/CB-12640) flipped avd parsing logic so that it always tries to use avdmanager to retrieve avds first, then falls back to android command if avdmanager cannot be found (and errors with ENOENT). updated tests - and added explicit tests to ensure to shell out to singular forms of sub-commands when executing `android`
* [CB-12640](https://issues.apache.org/jira/browse/CB-12640) support for android sdk tools 26.0.1.
### 6.2.2 (Apr 24, 2017)
* [CB-12697](https://issues.apache.org/jira/browse/CB-12697) Updated checked-in `node_modules`
### 6.2.1 (Apr 02, 2017)
* [CB-12621](https://issues.apache.org/jira/browse/CB-12621) reverted elementtree dep to 0.1.6
### 6.2.0 (Mar 28, 2017)
* [CB-12614](https://issues.apache.org/jira/browse/CB-12614) Adding headers to tests
* [CB-8978](https://issues.apache.org/jira/browse/CB-8978) Prepare copy `resource-files` from `config.xml`
* [CB-12605](https://issues.apache.org/jira/browse/CB-12605) Fix a requirements check failure on **Windows**
* [CB-12595](https://issues.apache.org/jira/browse/CB-12595) This should find an **Android Studio** installation and use the sweet gradle center found inside
* [CB-12546](https://issues.apache.org/jira/browse/CB-12546) leverage `avdmanager` if `android` warns it is no longer useful, which happens in **Android SDK Tools 25.3.1**. Explicitly set the `CWD` of the spawned emulator process to workaround a recent google android sdk bug. Rename `android_sdk_version.js` to `android_sdk.js`, to better reflect its contents. Have `create.js` copy over the `android_sdk_version` batch file.
* [CB-12524](https://issues.apache.org/jira/browse/CB-12524) Fix for missing gradle template error. This now fetches the template from inside of the **Android Studio** directory, and falls back to a locally installed Gradle instance
* [CB-12465](https://issues.apache.org/jira/browse/CB-12465) Writing new JUnit Test Instrumentation to replace tests and retire problmatic tests
### 6.1.2 (Jan 26, 2017)
* **Security** Change to `https` by default
* [CB-12018](https://issues.apache.org/jira/browse/CB-12018): updated tests to work with jasmine (promise matcher tests commented out for now)

View File

@@ -1 +1 @@
6.4.1-dev
6.1.2

View File

@@ -1,38 +1,20 @@
image:
- Previous Visual Studio 2015
environment:
ANDROID_HOME: "C:\\android"
matrix:
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "4"
- nodejs_version: "6"
- nodejs_version: "8"
init:
- mkdir "%ANDROID_HOME%
- cd "%ANDROID_HOME%"
- appveyor DownloadFile "https://dl.google.com/android/repository/tools_r25.2.3-windows.zip"
- 7z x "tools_r25.2.3-windows.zip" > nul
- cd "C:\projects\cordova-android"
install:
- choco install gradle -version 3.4.1
- gradle -version
- echo y | "%ANDROID_HOME%\tools\android.bat" --silent update sdk --no-ui --all --filter platform-tools,tools,build-tools-26.0.2,android-26,android-25,extra-google-m2repository,extra-android-m2repository
# on windows we need to accept sublicenses for the new tooling, wee. 30 is an arbitrary number,
# but should be the maximum number of licenses we explicitly need to type "Y ENTER" for.
# also, the sdkmanager in all its glory leaks a bit of output to stderr, and powershell
# and appveyor interpret that as errors, and blows up. so, when piping in our "Y ENTER"
# responses, we invoke cmd so we can redirect stderr to stdout, and tell it to --update itself.
- ps: for($i=0;$i -lt 30;$i++) { $response += "y`n"}; $response | cmd /c 'C:\android\tools\bin\sdkmanager.bat 2>&1' --update
# - cinst android-sdk
# - echo y | android update sdk -u --filter android-22,android-23
- ps: Install-Product node $env:nodejs_version
- npm install
# below is a workaround on using gradle installed via choco on appveyor
- set path=C:\ProgramData\chocolatey\lib\gradle\tools\gradle-3.4.1\bin;%path%
build: off
test_script:
- node --version
- npm --version
- npm test
- npm run test
# - npm run test-build

View File

@@ -19,10 +19,10 @@
under the License.
*/
var android_sdk = require('./templates/cordova/lib/android_sdk');
var android_sdk_version = require('./lib/android_sdk_version');
android_sdk.print_newest_available_sdk_target().done(null, function(err) {
console.error(err);
android_sdk_version.run().done(null, function(err) {
console.log(err);
process.exit(2);
});

View File

@@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0android_sdk_version"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'android_sdk_version' script in 'bin' folder, aborting...>&2

View File

@@ -19,7 +19,7 @@
under the License.
*/
var check_reqs = require('./templates/cordova/lib/check_reqs');
var check_reqs = require('./lib/check_reqs');
check_reqs.run().done(
function success() {

View File

@@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0check_reqs"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'check_reqs' script in 'bin' folder, aborting...>&2

64
bin/lib/android_sdk_version.js Executable file
View File

@@ -0,0 +1,64 @@
#!/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 child_process = require('child_process'),
Q = require('q');
var get_highest_sdk = function(results){
var reg = /\d+/;
var apiLevels = [];
for(var i=0;i<results.length;i++){
apiLevels[i] = parseInt(results[i].match(reg)[0]);
}
apiLevels.sort(function(a,b){return b-a;});
console.log(apiLevels[0]);
};
var get_sdks = function() {
var d = Q.defer();
child_process.exec('android list targets', function(err, stdout, stderr) {
if (err) d.reject(stderr);
else d.resolve(stdout);
});
return d.promise.then(function(output) {
var reg = /android-\d+/gi;
var results = output.match(reg);
if(results.length===0){
return Q.reject(new Error('No android sdks installed.'));
}else{
get_highest_sdk(results);
}
return Q();
}, function(stderr) {
if (stderr.match(/command\snot\sfound/) || stderr.match(/'android' is not recognized/)) {
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'));
}
});
};
module.exports.run = function() {
return Q.all([get_sdks()]);
};

View File

@@ -21,19 +21,17 @@
/* jshint sub:true */
var shelljs = require('shelljs');
var child_process = require('child_process');
var Q = require('q');
var path = require('path');
var fs = require('fs');
var os = require('os');
var REPO_ROOT = path.join(__dirname, '..', '..', '..', '..');
var PROJECT_ROOT = path.join(__dirname, '..', '..');
var shelljs = require('shelljs'),
child_process = require('child_process'),
Q = require('q'),
path = require('path'),
fs = require('fs'),
ROOT = path.join(__dirname, '..', '..');
var CordovaError = require('cordova-common').CordovaError;
var superspawn = require('cordova-common').superspawn;
var android_sdk = require('./android_sdk');
function forgivingWhichSync (cmd) {
var isWindows = process.platform == 'win32';
function forgivingWhichSync(cmd) {
try {
return fs.realpathSync(shelljs.which(cmd));
} catch (e) {
@@ -41,9 +39,9 @@ function forgivingWhichSync (cmd) {
}
}
function tryCommand (cmd, errMsg, catchStderr) {
function tryCommand(cmd, errMsg, catchStderr) {
var d = Q.defer();
child_process.exec(cmd, function (err, stdout, stderr) {
child_process.exec(cmd, function(err, stdout, stderr) {
if (err) d.reject(new CordovaError(errMsg));
// Sometimes it is necessary to return an stderr instead of stdout in case of success, since
// some commands prints theirs output to stderr instead of stdout. 'javac' is the example
@@ -52,113 +50,54 @@ function tryCommand (cmd, errMsg, catchStderr) {
return d.promise;
}
module.exports.isWindows = function () {
return (os.platform() === 'win32');
};
module.exports.isDarwin = function () {
return (os.platform() === 'darwin');
};
// Get valid target from framework/project.properties if run from this repo
// Otherwise get target from project.properties file within a generated cordova-android project
module.exports.get_target = function () {
function extractFromFile (filePath) {
// Get valid target from framework/project.properties
module.exports.get_target = function() {
function extractFromFile(filePath) {
var target = shelljs.grep(/\btarget=/, filePath);
if (!target) {
throw new Error('Could not find android target within: ' + filePath);
}
return target.split('=')[1].trim();
}
var repo_file = path.join(REPO_ROOT, 'framework', 'project.properties');
if (fs.existsSync(repo_file)) {
return extractFromFile(repo_file);
if (fs.existsSync(path.join(ROOT, 'framework', 'project.properties'))) {
return extractFromFile(path.join(ROOT, 'framework', 'project.properties'));
}
var project_file = path.join(PROJECT_ROOT, 'project.properties');
if (fs.existsSync(project_file)) {
// if no target found, we're probably in a project and project.properties is in PROJECT_ROOT.
return extractFromFile(project_file);
if (fs.existsSync(path.join(ROOT, 'project.properties'))) {
// if no target found, we're probably in a project and project.properties is in ROOT.
return extractFromFile(path.join(ROOT, 'project.properties'));
}
throw new Error('Could not find android target in either ' + repo_file + ' nor ' + project_file);
throw new Error('Could not find android target. File missing: ' + path.join(ROOT, 'project.properties'));
};
// Returns a promise. Called only by build and clean commands.
module.exports.check_ant = function () {
return superspawn.spawn('ant', ['-version']).then(function (output) {
module.exports.check_ant = function() {
return tryCommand('ant -version', 'Failed to run "ant -version", make sure you have ant installed and added to your PATH.')
.then(function (output) {
// Parse Ant version from command output
return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
}).catch(function (err) {
if (err) {
throw new CordovaError('Failed to run `ant -version`. Make sure you have `ant` on your $PATH.');
}
});
};
module.exports.get_gradle_wrapper = function () {
var androidStudioPath;
var i = 0;
var foundStudio = false;
var program_dir;
// OK, This hack only works on Windows, not on Mac OS or Linux. We will be deleting this eventually!
if (module.exports.isWindows()) {
var result = child_process.spawnSync(path.join(__dirname, 'getASPath.bat'));
// console.log('result.stdout =' + result.stdout.toString());
// console.log('result.stderr =' + result.stderr.toString());
if (result.stderr.toString().length > 0) {
var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/';
if (fs.existsSync(androidPath)) {
program_dir = fs.readdirSync(androidPath);
while (i < program_dir.length && !foundStudio) {
if (program_dir[i].startsWith('Android Studio')) {
foundStudio = true;
androidStudioPath = path.join(process.env['ProgramFiles'], 'Android', program_dir[i], 'gradle');
} else { ++i; }
}
}
} else {
// console.log('got android studio path from registry');
// remove the (os independent) new line char at the end of stdout
// add gradle to match the above.
androidStudioPath = path.join(result.stdout.toString().split('\r\n')[0], 'gradle');
}
}
if (androidStudioPath !== null && fs.existsSync(androidStudioPath)) {
var dirs = fs.readdirSync(androidStudioPath);
if (dirs[0].split('-')[0] === 'gradle') {
return path.join(androidStudioPath, dirs[0], 'bin', 'gradle');
}
} else {
// OK, let's try to check for Gradle!
return forgivingWhichSync('gradle');
}
};
// Returns a promise. Called only by build and clean commands.
module.exports.check_gradle = function () {
module.exports.check_gradle = function() {
var sdkDir = process.env['ANDROID_HOME'];
var d = Q.defer();
if (!sdkDir) {
if (!sdkDir)
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
}
var gradlePath = module.exports.get_gradle_wrapper();
if (gradlePath.length !== 0) { d.resolve(gradlePath); } else {
d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\n' +
'or on your system to install the gradle wrapper. Please include gradle \n' +
'in your path, or install Android Studio'));
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
if (!fs.existsSync(wrapperDir)) {
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Might need to update your Android SDK.\n' +
'Looked here: ' + wrapperDir));
}
return d.promise;
return Q.when();
};
// Returns a promise.
module.exports.check_java = function () {
module.exports.check_java = function() {
var javacPath = forgivingWhichSync('javac');
var hasJavaHome = !!process.env['JAVA_HOME'];
return Q().then(function () {
return Q().then(function() {
if (hasJavaHome) {
// Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
if (!javacPath) {
@@ -166,16 +105,12 @@ module.exports.check_java = function () {
}
} else {
if (javacPath) {
var msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
// OS X has a command for finding JAVA_HOME.
var find_java = '/usr/libexec/java_home';
var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting it manually.';
if (fs.existsSync(find_java)) {
return superspawn.spawn(find_java).then(function (stdout) {
if (fs.existsSync('/usr/libexec/java_home')) {
return tryCommand('/usr/libexec/java_home', msg)
.then(function(stdout) {
process.env['JAVA_HOME'] = stdout.trim();
}).catch(function (err) {
if (err) {
throw new CordovaError(default_java_error_msg);
}
});
} else {
// See if we can derive it from javac's location.
@@ -184,10 +119,10 @@ module.exports.check_java = function () {
if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
process.env['JAVA_HOME'] = maybeJavaHome;
} else {
throw new CordovaError(default_java_error_msg);
throw new CordovaError(msg);
}
}
} else if (module.exports.isWindows()) {
} else if (isWindows) {
// Try to auto-detect java in the default install paths.
var oldSilent = shelljs.config.silent;
shelljs.config.silent = true;
@@ -206,40 +141,38 @@ module.exports.check_java = function () {
}
}
}
}).then(function () {
var msg =
'Failed to run "javac -version", make sure that you have a JDK installed.\n' +
'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
if (process.env['JAVA_HOME']) {
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
}
// We use tryCommand with catchStderr = true, because
// javac writes version info to stderr instead of stdout
return tryCommand('javac -version', msg, true).then(function (output) {
// Let's check for at least Java 8, and keep it future proof so we can support Java 10
var match = /javac ((?:1\.)(?:[8-9]\.)(?:\d+))|((?:1\.)(?:[1-9]\d+\.)(?:\d+))/i.exec(output);
return match && match[1];
}).then(function() {
var msg =
'Failed to run "javac -version", make sure that you have a JDK installed.\n' +
'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
if (process.env['JAVA_HOME']) {
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
}
// We use tryCommand with catchStderr = true, because
// javac writes version info to stderr instead of stdout
return tryCommand('javac -version', msg, true)
.then(function (output) {
//Let's check for at least Java 8, and keep it future proof so we can support Java 10
var match = /javac ((?:1\.)(?:[8-9]\.)(?:\d+))|((?:1\.)(?:[1-9]\d+\.)(?:\d+))/i.exec(output);
return match && match[1];
});
});
});
};
// Returns a promise.
module.exports.check_android = function () {
return Q().then(function () {
module.exports.check_android = function() {
return Q().then(function() {
var androidCmdPath = forgivingWhichSync('android');
var adbInPath = forgivingWhichSync('adb');
var avdmanagerInPath = forgivingWhichSync('avdmanager');
var adbInPath = !!forgivingWhichSync('adb');
var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);
function maybeSetAndroidHome (value) {
function maybeSetAndroidHome(value) {
if (!hasAndroidHome && fs.existsSync(value)) {
hasAndroidHome = true;
process.env['ANDROID_HOME'] = value;
}
}
// First ensure ANDROID_HOME is set
// If we have no hints (nothing in PATH), try a few default locations
if (!hasAndroidHome && !androidCmdPath && !adbInPath && !avdmanagerInPath) {
if (module.exports.isWindows()) {
if (!hasAndroidHome && !androidCmdPath) {
if (isWindows) {
// Android Studio 1.0 installer
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'sdk'));
@@ -249,7 +182,7 @@ module.exports.check_android = function () {
// Stand-alone installer
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'android-sdk'));
maybeSetAndroidHome(path.join(process.env['ProgramFiles'], 'Android', 'android-sdk'));
} else if (module.exports.isDarwin()) {
} else if (process.platform == 'darwin') {
// Android Studio 1.0 installer
maybeSetAndroidHome(path.join(process.env['HOME'], 'Library', 'Android', 'sdk'));
// Android Studio pre-1.0 installer
@@ -264,93 +197,67 @@ module.exports.check_android = function () {
maybeSetAndroidHome(path.join(process.env['HOME'], 'android-sdk'));
}
}
if (!hasAndroidHome) {
// If we dont have ANDROID_HOME, but we do have some tools on the PATH, try to infer from the tooling PATH.
var parentDir, grandParentDir;
if (androidCmdPath) {
parentDir = path.dirname(androidCmdPath);
grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) === 'tools' || fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
maybeSetAndroidHome(grandParentDir);
} else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools directory.');
}
}
if (adbInPath) {
parentDir = path.dirname(adbInPath);
grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) === 'platform-tools') {
maybeSetAndroidHome(grandParentDir);
} else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
'Detected \'adb\' command at ' + parentDir + ' but no \'platform-tools\' directory found near.\n' +
'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'platform-tools directory.');
}
}
if (avdmanagerInPath) {
parentDir = path.dirname(avdmanagerInPath);
grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) === 'bin' && path.basename(grandParentDir) === 'tools') {
maybeSetAndroidHome(path.dirname(grandParentDir));
} else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
'Detected \'avdmanager\' command at ' + parentDir + ' but no \'tools' + path.sep + 'bin\' directory found near.\n' +
'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools' + path.sep + 'bin directory.');
}
if (hasAndroidHome && !androidCmdPath) {
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
}
if (androidCmdPath && !hasAndroidHome) {
var parentDir = path.dirname(androidCmdPath);
var grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) == 'tools') {
process.env['ANDROID_HOME'] = path.dirname(parentDir);
hasAndroidHome = true;
} else if (fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
process.env['ANDROID_HOME'] = grandParentDir;
hasAndroidHome = true;
} else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
'Try reinstall Android SDK or update your PATH to include path to valid SDK directory.');
}
}
if (hasAndroidHome && !adbInPath) {
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
}
if (!process.env['ANDROID_HOME']) {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
}
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env['ANDROID_HOME'] +
'\nTry update it manually to point to valid SDK directory.');
}
// Next let's make sure relevant parts of the SDK tooling is in our PATH
if (hasAndroidHome && !androidCmdPath) {
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools');
}
if (hasAndroidHome && !adbInPath) {
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'platform-tools');
}
if (hasAndroidHome && !avdmanagerInPath) {
process.env['PATH'] += path.delimiter + path.join(process.env['ANDROID_HOME'], 'tools', 'bin');
}
return hasAndroidHome;
});
};
// TODO: is this actually needed?
module.exports.getAbsoluteAndroidCmd = function () {
var cmd = forgivingWhichSync('android');
if (cmd.length === 0) {
cmd = forgivingWhichSync('sdkmanager');
}
if (module.exports.isWindows()) {
if (process.platform === 'win32') {
return '"' + cmd + '"';
}
return cmd.replace(/(\s)/g, '\\$1');
};
module.exports.check_android_target = function (originalError) {
module.exports.check_android_target = function(originalError) {
// valid_target can look like:
// android-19
// android-L
// Google Inc.:Google APIs:20
// Google Inc.:Glass Development Kit Preview:20
var desired_api_level = module.exports.get_target();
return android_sdk.list_targets().then(function (targets) {
if (targets.indexOf(desired_api_level) >= 0) {
var valid_target = module.exports.get_target();
var msg = 'Android SDK not found. Make sure that it is installed. If it is not at the default location, set the ANDROID_HOME environment variable.';
return tryCommand('android list targets --compact', msg)
.then(function(output) {
var targets = output.split('\n');
if (targets.indexOf(valid_target) >= 0) {
return targets;
}
var androidCmd = module.exports.getAbsoluteAndroidCmd();
var msg = 'Please install Android target / API level: "' + desired_api_level + '".\n\n' +
var msg = 'Please install Android target: "' + valid_target + '".\n\n' +
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
'You will require:\n' +
'1. "SDK Platform" for API level ' + desired_api_level + '\n' +
'1. "SDK Platform" for ' + valid_target + '\n' +
'2. "Android SDK Platform-tools (latest)\n' +
'3. "Android SDK Build-tools" (latest)';
if (originalError) {
@@ -361,21 +268,24 @@ module.exports.check_android_target = function (originalError) {
};
// Returns a promise.
module.exports.run = function () {
return Q.all([this.check_java(), this.check_android()]).then(function (values) {
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
module.exports.run = function() {
return Q.all([this.check_java(), this.check_android()])
.then(function(values) {
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
if (!values[0]) {
if (!values[0]) {
throw new CordovaError('Requirements check failed for JDK 1.8 or greater');
}
}
if (!values[1]) {
if (!values[1]) {
throw new CordovaError('Requirements check failed for Android SDK');
}
});
}
});
};
/**
* Object thar represents one of requirements for current platform.
* @param {String} id The unique identifier for this requirements.
@@ -389,7 +299,7 @@ var Requirement = function (id, name, version, installed) {
this.name = name;
this.installed = installed || false;
this.metadata = {
version: version
version: version,
};
};
@@ -399,7 +309,7 @@ var Requirement = function (id, name, version, installed) {
*
* @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
*/
module.exports.check_all = function () {
module.exports.check_all = function() {
var requirements = [
new Requirement('java', 'Java JDK'),
@@ -419,13 +329,15 @@ module.exports.check_all = function () {
return checkFns.reduce(function (promise, checkFn, idx) {
// Update each requirement with results
var requirement = requirements[idx];
return promise.then(checkFn).then(function (version) {
return promise.then(checkFn)
.then(function (version) {
requirement.installed = true;
requirement.metadata.version = version;
}, function (err) {
requirement.metadata.reason = err instanceof Error ? err.message : err;
});
}, Q()).then(function () {
}, Q())
.then(function () {
// When chain is completed, return requirements array to upstream API
return requirements;
});

View File

@@ -19,42 +19,30 @@
under the License.
*/
var shell = require('shelljs');
var Q = require('q');
var path = require('path');
var fs = require('fs');
var check_reqs = require('./../templates/cordova/lib/check_reqs');
var ROOT = path.join(__dirname, '..', '..');
var shell = require('shelljs'),
Q = require('q'),
path = require('path'),
fs = require('fs'),
check_reqs = require('./check_reqs'),
ROOT = path.join(__dirname, '..', '..');
var MIN_SDK_VERSION = 16;
var CordovaError = require('cordova-common').CordovaError;
var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
// Export all helper functions, and make sure internally within this module, we
// reference these methods via the `exports` object - this helps with testing
// (since we can then mock and control behaviour of all of these functions)
exports.validatePackageName = validatePackageName;
exports.validateProjectName = validateProjectName;
exports.setShellFatal = setShellFatal;
exports.copyJsAndLibrary = copyJsAndLibrary;
exports.copyScripts = copyScripts;
exports.copyBuildRules = copyBuildRules;
exports.writeProjectProperties = writeProjectProperties;
exports.prepBuildFiles = prepBuildFiles;
function setShellFatal (value, func) {
function setShellFatal(value, func) {
var oldVal = shell.config.fatal;
shell.config.fatal = value;
func();
shell.config.fatal = oldVal;
}
function getFrameworkDir (projectPath, shared) {
function getFrameworkDir(projectPath, shared) {
return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
}
function copyJsAndLibrary (projectPath, shared, projectName) {
function copyJsAndLibrary(projectPath, shared, projectName) {
var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js');
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js'));
@@ -69,8 +57,8 @@ function copyJsAndLibrary (projectPath, shared, projectName) {
shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www'));
// Don't fail if there are no old jars.
exports.setShellFatal(false, function () {
shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function (oldJar) {
setShellFatal(false, function() {
shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) {
console.log('Deleting ' + oldJar);
shell.rm('-f', oldJar);
});
@@ -102,7 +90,7 @@ function copyJsAndLibrary (projectPath, shared, projectName) {
}
}
function extractSubProjectPaths (data) {
function extractSubProjectPaths(data) {
var ret = {};
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
var m;
@@ -112,7 +100,7 @@ function extractSubProjectPaths (data) {
return Object.keys(ret);
}
function writeProjectProperties (projectPath, target_api) {
function writeProjectProperties(projectPath, target_api) {
var dstPath = path.join(projectPath, 'project.properties');
var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
@@ -120,10 +108,11 @@ function writeProjectProperties (projectPath, target_api) {
var data = fs.readFileSync(srcPath, 'utf8');
data = data.replace(/^target=.*/m, 'target=' + target_api);
var subProjects = extractSubProjectPaths(data);
subProjects = subProjects.filter(function (p) {
subProjects = subProjects.filter(function(p) {
return !(/^CordovaLib$/m.exec(p) ||
/[\\/]cordova-android[\\/]framework$/m.exec(p) ||
/^(\.\.[\\/])+framework$/m.exec(p));
/[\\\/]cordova-android[\\\/]framework$/m.exec(p) ||
/^(\.\.[\\\/])+framework$/m.exec(p)
);
});
subProjects.unshift('CordovaLib');
data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
@@ -131,43 +120,34 @@ function writeProjectProperties (projectPath, target_api) {
data += '\n';
}
for (var i = 0; i < subProjects.length; ++i) {
data += 'android.library.reference.' + (i + 1) + '=' + subProjects[i] + '\n';
data += 'android.library.reference.' + (i+1) + '=' + subProjects[i] + '\n';
}
fs.writeFileSync(dstPath, data);
}
function prepBuildFiles (projectPath) {
function prepBuildFiles(projectPath) {
var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders'));
buildModule.getBuilder('gradle').prepBuildFiles();
}
function copyBuildRules (projectPath) {
function copyBuildRules(projectPath) {
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath);
}
function copyScripts (projectPath) {
var bin = path.join(ROOT, 'bin');
var srcScriptsDir = path.join(bin, 'templates', 'cordova');
function copyScripts(projectPath) {
var srcScriptsDir = path.join(ROOT, 'bin', 'templates', 'cordova');
var destScriptsDir = path.join(projectPath, 'cordova');
// Delete old scripts directory if this is an update.
shell.rm('-rf', destScriptsDir);
// Copy in the new ones.
shell.cp('-r', srcScriptsDir, projectPath);
shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
shell.cp(path.join(bin, 'check_reqs*'), destScriptsDir);
shell.cp(path.join(bin, 'android_sdk_version*'), destScriptsDir);
var check_reqs = path.join(destScriptsDir, 'check_reqs');
var android_sdk_version = path.join(destScriptsDir, 'android_sdk_version');
// TODO: the two files being edited on-the-fly here are shared between
// platform and project-level commands. the below `sed` is updating the
// `require` path for the two libraries. if there's a better way to share
// modules across both the repo and generated projects, we should make sure
// to remove/update this.
shell.sed('-i', /templates\/cordova\//, '', android_sdk_version);
shell.sed('-i', /templates\/cordova\//, '', check_reqs);
shell.cp(path.join(ROOT, 'bin', 'check_reqs*'), destScriptsDir);
shell.cp(path.join(ROOT, 'bin', 'lib', 'check_reqs.js'), path.join(projectPath, 'cordova', 'lib', 'check_reqs.js'));
shell.cp(path.join(ROOT, 'bin', 'android_sdk_version'), path.join(destScriptsDir, 'android_sdk_version'));
shell.cp(path.join(ROOT, 'bin', 'lib', 'android_sdk_version.js'), path.join(projectPath, 'cordova', 'lib', 'android_sdk_version.js'));
}
/**
@@ -175,18 +155,17 @@ function copyScripts (projectPath) {
* Returns a promise, fulfilled if the package name is acceptable; rejected
* otherwise.
*/
function validatePackageName (package_name) {
// Make the package conform to Java package types
// http://developer.android.com/guide/topics/manifest/manifest-element.html#package
// Enforce underscore limitation
function validatePackageName(package_name) {
//Make the package conform to Java package types
//http://developer.android.com/guide/topics/manifest/manifest-element.html#package
//Enforce underscore limitation
var msg = 'Error validating package name. ';
if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name'));
}
// Class is a reserved word
if (/\b[Cc]lass\b/.test(package_name)) {
//Class is a reserved word
if(/\b[Cc]lass\b/.test(package_name)) {
return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
}
@@ -198,19 +177,19 @@ function validatePackageName (package_name) {
* Returns a promise, fulfilled if the project name is acceptable; rejected
* otherwise.
*/
function validateProjectName (project_name) {
function validateProjectName(project_name) {
var msg = 'Error validating project name. ';
// Make sure there's something there
//Make sure there's something there
if (project_name === '') {
return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
}
// Enforce stupid name error
//Enforce stupid name error
if (project_name === 'CordovaActivity') {
return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
}
// Classes in Java don't begin with numbers
//Classes in Java don't begin with numbers
if (/^[0-9]/.test(project_name)) {
return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
}
@@ -236,83 +215,83 @@ function validateProjectName (project_name) {
*
* @return {Promise<String>} Directory where application has been created
*/
exports.create = function (project_path, config, options, events) {
exports.create = function(project_path, config, options, events) {
options = options || {};
// Set default values for path, package and name
project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
// Check if project already exists
if (fs.existsSync(project_path)) {
if(fs.existsSync(project_path)) {
return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
}
var package_name = config.android_packageName() || config.packageName() || 'my.cordova.project';
var package_name = config.packageName() || 'my.cordova.project';
var project_name = config.name() ?
config.name().replace(/[^\w.]/g, '_') : 'CordovaExample';
config.name().replace(/[^\w.]/g,'_') : 'CordovaExample';
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
var target_api = check_reqs.get_target();
var target_api = check_reqs.get_target();
// Make the package conform to Java package types
return exports.validatePackageName(package_name)
.then(function () {
exports.validateProjectName(project_name);
}).then(function () {
//Make the package conform to Java package types
return validatePackageName(package_name)
.then(function() {
validateProjectName(project_name);
}).then(function() {
// Log the given values for the project
events.emit('log', 'Creating Cordova project for the Android platform:');
events.emit('log', '\tPath: ' + project_path);
events.emit('log', '\tPackage: ' + package_name);
events.emit('log', '\tName: ' + project_name);
events.emit('log', '\tActivity: ' + safe_activity_name);
events.emit('log', '\tAndroid target: ' + target_api);
events.emit('log', 'Creating Cordova project for the Android platform:');
events.emit('log', '\tPath: ' + project_path);
events.emit('log', '\tPackage: ' + package_name);
events.emit('log', '\tName: ' + project_name);
events.emit('log', '\tActivity: ' + safe_activity_name);
events.emit('log', '\tAndroid target: ' + target_api);
events.emit('verbose', 'Copying android template project to ' + project_path);
events.emit('verbose', 'Copying android template project to ' + project_path);
exports.setShellFatal(true, function () {
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
// copy project template
shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
setShellFatal(true, function() {
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
// copy project template
shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
// Manually create directories that would be empty within the template (since git doesn't track directories).
shell.mkdir(path.join(project_path, 'libs'));
// Manually create directories that would be empty within the template (since git doesn't track directories).
shell.mkdir(path.join(project_path, 'libs'));
// copy cordova.js, cordova.jar
exports.copyJsAndLibrary(project_path, options.link, safe_activity_name);
// copy cordova.js, cordova.jar
copyJsAndLibrary(project_path, options.link, safe_activity_name);
// interpolate the activity name and package
var packagePath = package_name.replace(/\./g, path.sep);
var activity_dir = path.join(project_path, 'src', packagePath);
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
shell.mkdir('-p', activity_dir);
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
shell.sed('-i', /__ID__/, package_name, activity_path);
// interpolate the activity name and package
var packagePath = package_name.replace(/\./g, path.sep);
var activity_dir = path.join(project_path, 'src', packagePath);
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
shell.mkdir('-p', activity_dir);
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
shell.sed('-i', /__ID__/, package_name, activity_path);
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
manifest.setPackageId(package_name)
.setTargetSdkVersion(target_api.split('-')[1])
.getActivity().setName(safe_activity_name);
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
manifest.setPackageId(package_name)
.setTargetSdkVersion(target_api.split('-')[1])
.getActivity().setName(safe_activity_name);
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
manifest.write(manifest_path);
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
manifest.write(manifest_path);
exports.copyScripts(project_path);
exports.copyBuildRules(project_path);
});
// Link it to local android install.
exports.writeProjectProperties(project_path, target_api);
exports.prepBuildFiles(project_path);
events.emit('log', generateDoneMessage('create', options.link));
}).thenResolve(project_path);
copyScripts(project_path);
copyBuildRules(project_path);
});
// Link it to local android install.
writeProjectProperties(project_path, target_api);
prepBuildFiles(project_path);
events.emit('log', generateDoneMessage('create', options.link));
}).thenResolve(project_path);
};
function generateDoneMessage (type, link) {
function generateDoneMessage(type, link) {
var pkg = require('../../package');
var msg = 'Android project ' + (type === 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
var msg = 'Android project ' + (type == 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
if (link) {
msg += ' and has a linked CordovaLib';
}
@@ -320,29 +299,34 @@ function generateDoneMessage (type, link) {
}
// Returns a promise.
exports.update = function (projectPath, options, events) {
exports.update = function(projectPath, options, events) {
options = options || {};
return Q()
.then(function () {
.then(function() {
var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
manifest.setMinSdkVersion(MIN_SDK_VERSION);
}
if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
manifest.setMinSdkVersion(MIN_SDK_VERSION);
}
manifest.setDebuggable(false).write();
manifest.setDebuggable(false).write();
var projectName = manifest.getActivity().getName();
var target_api = check_reqs.get_target();
var projectName = manifest.getActivity().getName();
var target_api = check_reqs.get_target();
exports.copyJsAndLibrary(projectPath, options.link, projectName);
exports.copyScripts(projectPath);
exports.copyBuildRules(projectPath);
exports.writeProjectProperties(projectPath, target_api);
exports.prepBuildFiles(projectPath);
events.emit('log', generateDoneMessage('update', options.link));
}).thenResolve(projectPath);
copyJsAndLibrary(projectPath, options.link, projectName);
copyScripts(projectPath);
copyBuildRules(projectPath);
writeProjectProperties(projectPath, target_api);
prepBuildFiles(projectPath);
events.emit('log', generateDoneMessage('update', options.link));
}).thenResolve(projectPath);
};
// For testing
exports.validatePackageName = validatePackageName;
exports.validateProjectName = validateProjectName;

View File

@@ -0,0 +1,10 @@
{
"node": true
, "bitwise": true
, "undef": true
, "trailing": true
, "quotmark": true
, "indent": 4
, "unused": "vars"
, "latedef": "nofunc"
}

View File

@@ -29,7 +29,8 @@ var selfEvents = require('cordova-common').events;
var PLATFORM = 'android';
function setupEvents (externalEventEmitter) {
function setupEvents(externalEventEmitter) {
if (externalEventEmitter) {
// This will make the platform internal events visible outside
selfEvents.forwardEventsTo(externalEventEmitter);
@@ -42,6 +43,7 @@ function setupEvents (externalEventEmitter) {
return selfEvents;
}
/**
* Class, that acts as abstraction over particular platform. Encapsulates the
* platform's properties and methods.
@@ -53,7 +55,7 @@ function setupEvents (externalEventEmitter) {
*
* * platform: String that defines a platform name.
*/
function Api (platform, platformRootDir, events) {
function Api(platform, platformRootDir, events) {
this.platform = PLATFORM;
this.root = path.resolve(__dirname, '..');
@@ -77,14 +79,14 @@ function Api (platform, platformRootDir, events) {
};
// XXX Override some locations for Android Studio projects
if (AndroidStudio.isAndroidStudioProject(self.root) === true) {
selfEvents.emit('log', 'Android Studio project detected');
this.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');
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');
}
}
@@ -110,13 +112,16 @@ 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) {
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);
}
catch (e) {
events.emit('error','createPlatform is not callable from the android project API.');
throw(e);
}
return result;
};
@@ -141,13 +146,16 @@ Api.updatePlatform = function (destination, options, events) {
events = setupEvents(events);
var result;
try {
result = require('../../lib/create').update(destination, options, events).then(function (destination) {
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);
}
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;
};
@@ -218,36 +226,40 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
installOptions.variables.PACKAGE_NAME = project.getPackageName();
}
if (this.android_studio === true) {
installOptions.android_studio = true;
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
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.
// 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 = {};
// Do some basic argument parsing
var opts = {};
// Skip cleaning prepared files when not invoking via cordova CLI.
opts.noPrepare = true;
// 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;
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
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);
};
@@ -267,9 +279,9 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
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;
if(uninstallOptions && uninstallOptions.usePlatformWww === true && this.android_studio === true) {
uninstallOptions.usePlatformWww = false;
uninstallOptions.android_studio = true;
}
return PluginManager.get(this.platform, this.locations, project)
@@ -331,9 +343,11 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) {
*/
Api.prototype.build = function (buildOptions) {
var self = this;
return require('./lib/check_reqs').run().then(function () {
return require('./lib/check_reqs').run()
.then(function () {
return require('./lib/build').run.call(self, buildOptions);
}).then(function (buildResults) {
})
.then(function (buildResults) {
// Cast build result to array of build artifacts
return buildResults.apkPaths.map(function (apkPath) {
return {
@@ -358,9 +372,10 @@ Api.prototype.build = function (buildOptions) {
* @return {Promise} A promise either fulfilled if package was built and ran
* successfully, or rejected with CordovaError.
*/
Api.prototype.run = function (runOptions) {
Api.prototype.run = function(runOptions) {
var self = this;
return require('./lib/check_reqs').run().then(function () {
return require('./lib/check_reqs').run()
.then(function () {
return require('./lib/run').run.call(self, runOptions);
});
};
@@ -372,15 +387,19 @@ Api.prototype.run = function (runOptions) {
* @return {Promise} Return a promise either fulfilled, or rejected with
* CordovaError.
*/
Api.prototype.clean = function (cleanOptions) {
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);
});
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
@@ -389,7 +408,7 @@ Api.prototype.clean = function (cleanOptions) {
* @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
* objects for current platform.
*/
Api.prototype.requirements = function () {
Api.prototype.requirements = function() {
return require('./lib/check_reqs').check_all();
};

View File

@@ -25,11 +25,11 @@ var CordovaError = require('cordova-common').CordovaError;
var Adb = {};
function isDevice (line) {
function isDevice(line) {
return line.match(/\w+\tdevice/) && !line.match(/emulator/);
}
function isEmulator (line) {
function isEmulator(line) {
return line.match(/device/) && line.match(/emulator/);
}
@@ -44,7 +44,8 @@ function isEmulator (line) {
* devices/emulators
*/
Adb.devices = function (opts) {
return spawn('adb', ['devices'], {cwd: os.tmpdir()}).then(function (output) {
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);
@@ -58,7 +59,8 @@ 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) {
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/)) {
@@ -84,7 +86,8 @@ 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 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));
});
@@ -92,7 +95,8 @@ Adb.shell = function (target, shellCommand) {
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 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));
});

View File

@@ -19,12 +19,12 @@
var fs = require('fs');
var et = require('elementtree');
var xml = require('cordova-common').xmlHelpers;
var xml= require('cordova-common').xmlHelpers;
var DEFAULT_ORIENTATION = 'default';
/** Wraps an AndroidManifest file */
function AndroidManifest (path) {
function AndroidManifest(path) {
this.path = path;
this.doc = xml.parseElementtreeSync(path);
if (this.doc.getroot().tag !== 'manifest') {
@@ -32,38 +32,38 @@ function AndroidManifest (path) {
}
}
AndroidManifest.prototype.getVersionName = function () {
AndroidManifest.prototype.getVersionName = function() {
return this.doc.getroot().attrib['android:versionName'];
};
AndroidManifest.prototype.setVersionName = function (versionName) {
AndroidManifest.prototype.setVersionName = function(versionName) {
this.doc.getroot().attrib['android:versionName'] = versionName;
return this;
};
AndroidManifest.prototype.getVersionCode = function () {
AndroidManifest.prototype.getVersionCode = function() {
return this.doc.getroot().attrib['android:versionCode'];
};
AndroidManifest.prototype.setVersionCode = function (versionCode) {
AndroidManifest.prototype.setVersionCode = function(versionCode) {
this.doc.getroot().attrib['android:versionCode'] = versionCode;
return this;
};
AndroidManifest.prototype.getPackageId = function () {
/* jshint -W069 */
AndroidManifest.prototype.getPackageId = function() {
/*jshint -W069 */
return this.doc.getroot().attrib['package'];
/* jshint +W069 */
/*jshint +W069 */
};
AndroidManifest.prototype.setPackageId = function (pkgId) {
/* jshint -W069 */
AndroidManifest.prototype.setPackageId = function(pkgId) {
/*jshint -W069 */
this.doc.getroot().attrib['package'] = pkgId;
/* jshint +W069 */
/*jshint +W069 */
return this;
};
AndroidManifest.prototype.getActivity = function () {
AndroidManifest.prototype.getActivity = function() {
var activity = this.doc.getroot().find('./application/activity');
return {
getName: function () {
@@ -102,16 +102,17 @@ AndroidManifest.prototype.getActivity = function () {
};
};
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion'].forEach(function (sdkPrefName) {
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
.forEach(function(sdkPrefName) {
// Copy variable reference to avoid closure issues
var prefName = sdkPrefName;
AndroidManifest.prototype['get' + capitalize(prefName)] = function () {
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) {
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
@@ -127,11 +128,11 @@ AndroidManifest.prototype.getActivity = function () {
};
});
AndroidManifest.prototype.getDebuggable = function () {
AndroidManifest.prototype.getDebuggable = function() {
return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
};
AndroidManifest.prototype.setDebuggable = function (value) {
AndroidManifest.prototype.setDebuggable = function(value) {
var application = this.doc.getroot().find('./application');
if (value) {
application.attrib['android:debuggable'] = 'true';
@@ -149,7 +150,7 @@ AndroidManifest.prototype.setDebuggable = function (value) {
* @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) {
AndroidManifest.prototype.write = function(destPath) {
fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
};

View File

@@ -26,15 +26,16 @@ var pluginHandlers = require('./pluginHandlers');
var projectFileCache = {};
function addToPropertyList (projectProperties, key, value) {
function addToPropertyList(projectProperties, key, value) {
var i = 1;
while (projectProperties.get(key + '.' + i)) { i++; }
while (projectProperties.get(key + '.' + i))
i++;
projectProperties.set(key + '.' + i, value);
projectProperties.dirty = true;
}
function removeFromPropertyList (projectProperties, key, value) {
function removeFromPropertyList(projectProperties, key, value) {
var i = 1;
var currentValue;
while ((currentValue = projectProperties.get(key + '.' + i))) {
@@ -53,18 +54,18 @@ function removeFromPropertyList (projectProperties, key, value) {
function getRelativeLibraryPath (parentDir, subDir) {
var libraryPath = path.relative(parentDir, subDir);
return (path.sep === '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
}
function AndroidProject (projectDir) {
function AndroidProject(projectDir) {
this._propertiesEditors = {};
this._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');
if(AndroidStudio.isAndroidStudioProject(projectDir) === true) {
this.www = path.join(this.projectDir, 'app/src/main/assets/www');
}
}
@@ -91,15 +92,15 @@ AndroidProject.purgeCache = function (projectDir) {
*
* @return {String} The name of the package
*/
AndroidProject.prototype.getPackageName = function () {
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');
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) {
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();
@@ -109,7 +110,7 @@ AndroidProject.prototype.getCustomSubprojectRelativeDir = function (plugin_id, s
return subRelativeDir;
};
AndroidProject.prototype.addSubProject = function (parentDir, subDir) {
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);
@@ -125,7 +126,7 @@ AndroidProject.prototype.addSubProject = function (parentDir, subDir) {
this._dirty = true;
};
AndroidProject.prototype.removeSubProject = function (parentDir, subDir) {
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));
@@ -133,35 +134,35 @@ AndroidProject.prototype.removeSubProject = function (parentDir, subDir) {
this._dirty = true;
};
AndroidProject.prototype.addGradleReference = function (parentDir, subDir) {
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) {
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) {
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) {
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 () {
AndroidProject.prototype.write = function() {
if (!this._dirty) {
return;
}
@@ -200,9 +201,9 @@ AndroidProject.prototype.getUninstaller = function (type) {
* This checks if an Android project is clean or has old build artifacts
*/
AndroidProject.prototype.isClean = function () {
AndroidProject.prototype.isClean = function() {
var build_path = path.join(this.projectDir, 'build');
// If the build directory doesn't exist, it's clean
//If the build directory doesn't exist, it's clean
return !(fs.existsSync(build_path));
};

View File

@@ -4,13 +4,13 @@
* @param {String} root Root folder of the project
*/
/* jshint esnext: false */
/*jshint esnext: false */
var path = require('path');
var fs = require('fs');
var CordovaError = require('cordova-common').CordovaError;
module.exports.isAndroidStudioProject = function isAndroidStudioProject (root) {
module.exports.isAndroidStudioProject = function isAndroidStudioProject(root) {
var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res', 'project.properties', 'platform_www'];
var androidStudioFiles = ['app', 'gradle', 'app/src/main/res'];
@@ -18,21 +18,21 @@ module.exports.isAndroidStudioProject = function isAndroidStudioProject (root) {
var isEclipse = false;
var isAS = true;
if (!fs.existsSync(root)) {
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))) {
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))) {
if(!isEclipse) {
androidStudioFiles.forEach(function(file){
if(!fs.existsSync(path.join(root, file))) {
console.log('missing file :: ' + file);
isAS = false;
}

View File

@@ -1,101 +0,0 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
var Q = require('q');
var superspawn = require('cordova-common').superspawn;
var suffix_number_regex = /(\d+)$/;
// Used for sorting Android targets, example strings to sort:
// android-19
// android-L
// Google Inc.:Google APIs:20
// Google Inc.:Glass Development Kit Preview:20
// The idea is to sort based on largest "suffix" number - meaning the bigger
// the number at the end, the more recent the target, the closer to the
// start of the array.
function sort_by_largest_numerical_suffix (a, b) {
var suffix_a = a.match(suffix_number_regex);
var suffix_b = b.match(suffix_number_regex);
if (suffix_a && suffix_b) {
// If the two targets being compared have suffixes, return less than
// zero, or greater than zero, based on which suffix is larger.
return (parseInt(suffix_a[1]) > parseInt(suffix_b[1]) ? -1 : 1);
} else {
// If no suffix numbers were detected, leave the order as-is between
// elements a and b.
return 0;
}
}
module.exports.print_newest_available_sdk_target = function () {
return module.exports.list_targets().then(function (targets) {
targets.sort(sort_by_largest_numerical_suffix);
console.log(targets[0]);
});
};
module.exports.version_string_to_api_level = {
'4.0': 14,
'4.0.3': 15,
'4.1': 16,
'4.2': 17,
'4.3': 18,
'4.4': 19,
'4.4W': 20,
'5.0': 21,
'5.1': 22,
'6.0': 23,
'7.0': 24,
'7.1.1': 25
};
function parse_targets (output) {
var target_out = output.split('\n');
var targets = [];
for (var i = target_out.length - 1; i >= 0; i--) {
if (target_out[i].match(/id:/)) { // if "id:" is in the line...
targets.push(target_out[i].match(/"(.+)"/)[1]); // .. match whatever is in quotes.
}
}
return targets;
}
module.exports.list_targets_with_android = function () {
return superspawn.spawn('android', ['list', 'target']).then(parse_targets);
};
module.exports.list_targets_with_avdmanager = function () {
return superspawn.spawn('avdmanager', ['list', 'target']).then(parse_targets);
};
module.exports.list_targets = function () {
return module.exports.list_targets_with_avdmanager().catch(function (err) {
// If there's an error, like avdmanager could not be found, we can try
// as a last resort, to run `android`, in case this is a super old
// SDK installation.
if (err && (err.code === 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) {
return module.exports.list_targets_with_android();
} else throw err;
}).then(function (targets) {
if (targets.length === 0) {
return Q.reject(new Error('No android targets (SDKs) installed!'));
}
return targets;
});
};

View File

@@ -19,10 +19,10 @@
under the License.
*/
var Q = require('q');
var path = require('path');
var fs = require('fs');
var nopt = require('nopt');
var Q = require('q'),
path = require('path'),
fs = require('fs'),
nopt = require('nopt');
var Adb = require('./Adb');
@@ -31,7 +31,7 @@ var events = require('cordova-common').events;
var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError;
function parseOpts (options, resolvedTarget, projectRoot) {
function parseOpts(options, resolvedTarget, projectRoot) {
options = options || {};
options.argv = nopt({
gradle: Boolean,
@@ -55,13 +55,16 @@ function parseOpts (options, resolvedTarget, projectRoot) {
extraArgs: []
};
if (options.argv.ant || options.argv.gradle) { ret.buildMethod = options.argv.ant ? 'ant' : 'gradle'; }
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.versionCode)
ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode);
if (options.argv.minSdkVersion) { ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion); }
if (options.argv.minSdkVersion)
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion);
if (options.argv.gradleArg) {
ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
@@ -69,10 +72,12 @@ function parseOpts (options, resolvedTarget, projectRoot) {
var packageArgs = {};
if (options.argv.keystore) { packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore)); }
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]; }
['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
if (options.argv[flagName])
packageArgs[flagName] = options.argv[flagName];
});
var buildConfig = options.buildConfig;
@@ -83,20 +88,20 @@ function parseOpts (options, resolvedTarget, projectRoot) {
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));
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) === '~') {
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) {
['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){
packageArgs[key] = packageArgs[key] || androidInfo[key];
});
}
@@ -107,8 +112,8 @@ function parseOpts (options, resolvedTarget, projectRoot) {
packageArgs.password, packageArgs.keystoreType);
}
if (!ret.packageInfo) {
if (Object.keys(packageArgs).length > 0) {
if(!ret.packageInfo) {
if(Object.keys(packageArgs).length > 0) {
events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
}
}
@@ -120,10 +125,11 @@ function parseOpts (options, resolvedTarget, projectRoot) {
* Builds the project with the specifed options
* Returns a promise.
*/
module.exports.runClean = function (options) {
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.prepEnv(opts)
.then(function() {
return builder.clean(opts);
});
};
@@ -140,15 +146,17 @@ module.exports.runClean = function (options) {
* @return {Promise<Object>} Promise, resolved with built packages
* information.
*/
module.exports.run = function (options, optResolvedTarget) {
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 () {
return builder.prepEnv(opts)
.then(function() {
if (opts.prepEnv) {
events.emit('verbose', 'Build file successfully prepared.');
return;
}
return builder.build(opts).then(function () {
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 {
@@ -164,31 +172,38 @@ module.exports.run = function (options, optResolvedTarget) {
* 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) {
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) {
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 () {
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 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 () {
}, function() {
// For non-killall OS's.
return Q.reject(err);
});
@@ -197,10 +212,10 @@ module.exports.detectArchitecture = function (target) {
});
};
module.exports.findBestApkForArchitecture = function (buildResults, arch) {
var paths = buildResults.apkPaths.filter(function (p) {
module.exports.findBestApkForArchitecture = function(buildResults, arch) {
var paths = buildResults.apkPaths.filter(function(p) {
var apkName = path.basename(p);
if (buildResults.buildType === 'debug') {
if (buildResults.buildType == 'debug') {
return /-debug/.exec(apkName);
}
return !/-debug/.exec(apkName);
@@ -220,7 +235,7 @@ module.exports.findBestApkForArchitecture = function (buildResults, arch) {
throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
};
function PackageInfo (keystore, alias, storePassword, password, keystoreType) {
function PackageInfo(keystore, alias, storePassword, password, keystoreType) {
this.keystore = {
'name': 'key.store',
'value': keystore
@@ -250,10 +265,10 @@ function PackageInfo (keystore, alias, storePassword, password, keystoreType) {
}
PackageInfo.prototype = {
toProperties: function () {
toProperties: function() {
var self = this;
var result = '';
Object.keys(self).forEach(function (key) {
Object.keys(self).forEach(function(key) {
result += self[key].name;
result += '=';
result += self[key].value.replace(/\\/g, '\\\\');
@@ -263,7 +278,7 @@ PackageInfo.prototype = {
}
};
module.exports.help = function () {
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)');

View File

@@ -16,7 +16,6 @@
specific language governing permissions and limitations
under the License.
*/
/* eslint no-unused-vars: 0 */
var Q = require('q');
var fs = require('fs');
@@ -43,29 +42,30 @@ function AntBuilder (projectRoot) {
util.inherits(AntBuilder, GenericBuilder);
AntBuilder.prototype.getArgs = function (cmd, opts) {
AntBuilder.prototype.getArgs = function(cmd, opts) {
var args = [cmd, '-f', path.join(this.root, 'build.xml')];
// 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) {
if(opts.packageInfo) {
args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
}
return args;
};
AntBuilder.prototype.prepEnv = function (opts) {
AntBuilder.prototype.prepEnv = function(opts) {
var self = this;
return check_reqs.check_ant().then(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.
/* jshint -W069 */
/*jshint -W069 */
var sdkDir = process.env['ANDROID_HOME'];
/* jshint +W069 */
/*jshint +W069 */
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
function writeBuildXml (projectPath) {
function writeBuildXml(projectPath) {
var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
@@ -86,7 +86,7 @@ AntBuilder.prototype.prepEnv = function (opts) {
var propertiesFilePath = path.join(self.root, propertiesFile);
if (opts.packageInfo) {
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
} else if (isAutoGenerated(propertiesFilePath)) {
} else if(isAutoGenerated(propertiesFilePath)) {
shell.rm('-f', propertiesFilePath);
}
});
@@ -96,7 +96,7 @@ AntBuilder.prototype.prepEnv = function (opts) {
* Builds the project with ant.
* Returns a promise.
*/
AntBuilder.prototype.build = function (opts) {
AntBuilder.prototype.build = function(opts) {
// Without our custom_rules.xml, we need to clean before building.
var ret = Q();
if (!hasCustomRules(this.root)) {
@@ -104,10 +104,11 @@ AntBuilder.prototype.build = function (opts) {
ret = this.clean(opts);
}
var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);
return check_reqs.check_ant().then(function () {
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) {
}).progress(function (stdio){
if (stdio.stderr) {
process.stderr.write(stdio.stderr);
} else {
@@ -115,7 +116,7 @@ AntBuilder.prototype.build = function (opts) {
}
}).catch(function (error) {
if (error.toString().indexOf('Unable to resolve project target') >= 0) {
return check_reqs.check_android_target(error).then(function () {
return check_reqs.check_android_target(error).then(function() {
// If due to some odd reason - check_android_target succeeds
// we should still fail here.
return Q.reject(error);
@@ -125,17 +126,19 @@ AntBuilder.prototype.build = function (opts) {
});
};
AntBuilder.prototype.clean = function (opts) {
AntBuilder.prototype.clean = function(opts) {
var args = this.getArgs('clean', opts);
var self = this;
return check_reqs.check_ant().then(function () {
return check_reqs.check_ant()
.then(function() {
return spawn('ant', args, {stdio: 'inherit'});
}).then(function () {
})
.then(function () {
shell.rm('-rf', path.join(self.root, 'out'));
['debug', 'release'].forEach(function (config) {
['debug', 'release'].forEach(function(config) {
var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
if (isAutoGenerated(propertiesFilePath)) {
if(isAutoGenerated(propertiesFilePath)){
shell.rm('-f', propertiesFilePath);
}
});
@@ -144,10 +147,10 @@ AntBuilder.prototype.clean = function (opts) {
module.exports = AntBuilder;
function hasCustomRules (projectRoot) {
function hasCustomRules(projectRoot) {
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
}
function isAutoGenerated (file) {
function isAutoGenerated(file) {
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
}

View File

@@ -16,8 +16,6 @@
specific language governing permissions and limitations
under the License.
*/
/* eslint no-self-assign: 0 */
/* eslint no-unused-vars: 0 */
var Q = require('q');
var fs = require('fs');
@@ -34,33 +32,35 @@ function GenericBuilder (projectDir) {
};
}
function hasCustomRules (projectRoot) {
function hasCustomRules(projectRoot) {
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
}
GenericBuilder.prototype.prepEnv = function () {
GenericBuilder.prototype.prepEnv = function() {
return Q();
};
GenericBuilder.prototype.build = function () {
GenericBuilder.prototype.build = function() {
events.emit('log', 'Skipping build...');
return Q(null);
};
GenericBuilder.prototype.clean = function () {
GenericBuilder.prototype.clean = function() {
return Q();
};
GenericBuilder.prototype.findOutputApks = function (build_type, arch) {
GenericBuilder.prototype.findOutputApks = function(build_type, arch) {
var self = this;
return Object.keys(this.binDirs).reduce(function (result, builderName) {
return Object.keys(this.binDirs)
.reduce(function (result, builderName) {
var binDir = self.binDirs[builderName];
return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch));
}, []).sort(apkSorter);
}, [])
.sort(apkSorter);
};
GenericBuilder.prototype.readProjectProperties = function () {
function findAllUniq (data, r) {
function findAllUniq(data, r) {
var s = {};
var m;
while ((m = r.exec(data))) {
@@ -85,22 +85,14 @@ GenericBuilder.prototype.extractRealProjectNameFromManifest = function () {
throw new CordovaError('Could not find package name in ' + manifestPath);
}
var packageName = m[1];
var packageName=m[1];
var lastDotIndex = packageName.lastIndexOf('.');
return packageName.substring(lastDotIndex + 1);
};
module.exports = GenericBuilder;
function apkSorter (fileA, fileB) {
// De-prioritize arch specific builds
var archSpecificRE = /-x86|-arm/;
if (archSpecificRE.exec(fileA)) {
return 1;
} else if (archSpecificRE.exec(fileB)) {
return -1;
}
function apkSorter(fileA, fileB) {
// De-prioritize unsigned builds
var unsignedRE = /-unsigned/;
if (unsignedRE.exec(fileA)) {
@@ -109,22 +101,16 @@ function apkSorter (fileA, fileB) {
return -1;
}
var timeDiff = fs.statSync(fileB).mtime - fs.statSync(fileA).mtime;
var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime;
return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
}
function findOutputApksHelper (dir, build_type, arch) {
function findOutputApksHelper(dir, build_type, arch) {
var shellSilent = shell.config.silent;
shell.config.silent = true;
// list directory recursively
var ret = shell.ls('-R', dir).map(function (file) {
// ls does not include base directory
return path.join(dir, file);
}).filter(function (file) {
// find all APKs
return file.match(/\.apk?$/i);
}).filter(function (candidate) {
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') {
@@ -134,7 +120,8 @@ function findOutputApksHelper (dir, build_type, arch) {
return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
}
return true;
}).sort(apkSorter);
})
.sort(apkSorter);
shellSilent = shellSilent;
@@ -144,15 +131,15 @@ function findOutputApksHelper (dir, build_type, arch) {
// 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 */
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;
ret = ret.filter(function(p) {
return path.basename(p).indexOf('-' + arch) != -1;
});
}

View File

@@ -22,7 +22,7 @@ var fs = require('fs');
var util = require('util');
var path = require('path');
var shell = require('shelljs');
var superspawn = require('cordova-common').superspawn;
var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError;
var check_reqs = require('../check_reqs');
@@ -37,15 +37,15 @@ var TEMPLATE =
function GradleBuilder (projectRoot) {
GenericBuilder.call(this, projectRoot);
this.binDirs = { gradle: this.binDirs.gradle };
this.binDirs = {gradle: this.binDirs.gradle};
}
util.inherits(GradleBuilder, GenericBuilder);
GradleBuilder.prototype.getArgs = function (cmd, opts) {
if (cmd === 'release') {
GradleBuilder.prototype.getArgs = function(cmd, opts) {
if (cmd == 'release') {
cmd = 'cdvBuildRelease';
} else if (cmd === 'debug') {
} else if (cmd == 'debug') {
cmd = 'cdvBuildDebug';
}
var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
@@ -65,51 +65,35 @@ GradleBuilder.prototype.getArgs = function (cmd, opts) {
return args;
};
/*
* This returns a promise
*/
GradleBuilder.prototype.runGradleWrapper = function (gradle_cmd, gradle_file) {
var gradlePath = path.join(this.root, 'gradlew');
gradle_file = path.join(this.root, (gradle_file || 'wrapper.gradle'));
if (fs.existsSync(gradlePath)) {
// Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
} else {
return superspawn.spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', gradle_file], { stdio: 'pipe' })
.progress(function (stdio) {
suppressJavaOptionsInfo(stdio);
});
}
};
// Makes the project buildable, minus the gradle wrapper.
GradleBuilder.prototype.prepBuildFiles = function () {
GradleBuilder.prototype.prepBuildFiles = function() {
// Update the version of build.gradle in each dependent library.
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
var propertiesObj = this.readProjectProperties();
var subProjects = propertiesObj.libs;
var checkAndCopy = function (subProject, root) {
var subProjectGradle = path.join(root, subProject, 'build.gradle');
// This is the future-proof way of checking if a file exists
// This must be synchronous to satisfy a Travis test
try {
fs.accessSync(subProjectGradle, fs.F_OK);
} catch (e) {
shell.cp('-f', pluginBuildGradle, subProjectGradle);
}
var checkAndCopy = function(subProject, root) {
var subProjectGradle = path.join(root, subProject, 'build.gradle');
// This is the future-proof way of checking if a file exists
// This must be synchronous to satisfy a Travis test
try {
fs.accessSync(subProjectGradle, fs.F_OK);
} catch (e) {
shell.cp('-f', pluginBuildGradle, subProjectGradle);
}
};
for (var i = 0; i < subProjects.length; ++i) {
if (subProjects[i] !== 'CordovaLib') {
checkAndCopy(subProjects[i], this.root);
checkAndCopy(subProjects[i], this.root);
}
}
var name = this.extractRealProjectNameFromManifest();
// Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
var settingsGradlePaths = subProjects.map(function (p) {
var realDir = p.replace(/[/\\]/g, ':');
var libName = realDir.replace(name + '-', '');
var str = 'include ":' + libName + '"\n';
if (realDir.indexOf(name + '-') !== -1) { str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n'; }
//Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
var settingsGradlePaths = subProjects.map(function(p){
var realDir=p.replace(/[/\\]/g, ':');
var libName=realDir.replace(name+'-','');
var str='include ":'+libName+'"\n';
if(realDir.indexOf(name+'-')!==-1)
str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
return str;
});
@@ -121,19 +105,22 @@ GradleBuilder.prototype.prepBuildFiles = function () {
var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
var depsList = '';
var root = this.root;
var insertExclude = function (p) {
var gradlePath = path.join(root, p, 'build.gradle');
var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
if (projectGradleFile.indexOf('CordovaLib') !== -1) {
var insertExclude = function(p) {
var gradlePath = path.join(root, p, 'build.gradle');
var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
if(projectGradleFile.indexOf('CordovaLib') != -1) {
depsList += '{\n exclude module:("CordovaLib")\n }\n';
} else {
depsList += '\n';
}
}
else {
depsList +='\n';
}
};
subProjects.forEach(function (p) {
subProjects.forEach(function(p) {
console.log('Subproject Path: ' + p);
var libName = p.replace(/[/\\]/g, ':').replace(name + '-', '');
depsList += ' implementation(project(path: "' + libName + '"))';
var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
depsList += ' debugCompile(project(path: "' + libName + '", configuration: "debug"))';
insertExclude(p);
depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))';
insertExclude(p);
});
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
@@ -141,7 +128,7 @@ GradleBuilder.prototype.prepBuildFiles = function () {
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
[/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
];
propertiesObj.systemLibs.forEach(function (p) {
propertiesObj.systemLibs.forEach(function(p) {
var mavenRef;
// It's already in gradle form if it has two ':'s
if (/:.*:/.exec(p)) {
@@ -162,24 +149,27 @@ GradleBuilder.prototype.prepBuildFiles = function () {
});
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
var includeList = '';
propertiesObj.gradleIncludes.forEach(function (includePath) {
propertiesObj.gradleIncludes.forEach(function(includePath) {
includeList += 'apply from: "' + includePath + '"\n';
});
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
};
GradleBuilder.prototype.prepEnv = function (opts) {
GradleBuilder.prototype.prepEnv = function(opts) {
var self = this;
return check_reqs.check_gradle().then(function (gradlePath) {
return self.runGradleWrapper(gradlePath);
}).then(function () {
return check_reqs.check_gradle()
.then(function() {
return self.prepBuildFiles();
}).then(function () {
// We now copy the gradle out of the framework
// This is a dirty patch to get the build working
/*
var wrapperDir = path.join(self.root, 'CordovaLib');
}).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.
// check_reqs ensures that this is set.
/*jshint -W069 */
var sdkDir = process.env['ANDROID_HOME'];
/*jshint +W069 */
var wrapperDir = path.join(sdkDir, 'tools', 'templates', 'gradle', 'wrapper');
if (process.platform == 'win32') {
shell.rm('-f', path.join(self.root, 'gradlew.bat'));
shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
@@ -190,17 +180,17 @@ GradleBuilder.prototype.prepEnv = function (opts) {
shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
shell.mkdir('-p', path.join(self.root, 'gradle'));
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));
*/
// If the gradle distribution URL is set, make sure it points to version we want.
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
// For some reason, using ^ and $ don't work. This does the job, though.
var distributionUrlRegex = /distributionUrl.*zip/;
/* jshint -W069 */
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-4.1-all.zip';
/* jshint +W069 */
/*jshint -W069 */
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-2.14.1-all.zip';
/*jshint +W069 */
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
shell.chmod('u+w', gradleWrapperPropertiesPath);
shell.sed('-i', distributionUrlRegex, 'distributionUrl=' + distributionUrl, gradleWrapperPropertiesPath);
shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
var propertiesFilePath = path.join(self.root, propertiesFile);
@@ -216,37 +206,53 @@ GradleBuilder.prototype.prepEnv = function (opts) {
* Builds the project with gradle.
* Returns a promise.
*/
GradleBuilder.prototype.build = function (opts) {
GradleBuilder.prototype.build = function(opts) {
var wrapper = path.join(this.root, 'gradlew');
var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
return superspawn.spawn(wrapper, args, { stdio: 'pipe' })
.progress(function (stdio) {
suppressJavaOptionsInfo(stdio);
}).catch(function (error) {
if (error.toString().indexOf('failed to find target with hash string') >= 0) {
return check_reqs.check_android_target(error).then(function () {
// If due to some odd reason - check_android_target succeeds
// we should still fail here.
return Q.reject(error);
});
return spawn(wrapper, args, {stdio: 'pipe'})
.progress(function (stdio){
if (stdio.stderr) {
/*
* Workaround for the issue with Java printing some unwanted information to
* stderr instead of stdout.
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
* explanation.
*/
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
if (suppressThisLine) {
return;
}
return Q.reject(error);
});
process.stderr.write(stdio.stderr);
} else {
process.stdout.write(stdio.stdout);
}
}).catch(function (error) {
if (error.toString().indexOf('failed to find target with hash string') >= 0) {
return check_reqs.check_android_target(error).then(function() {
// If due to some odd reason - check_android_target succeeds
// we should still fail here.
return Q.reject(error);
});
}
return Q.reject(error);
});
};
GradleBuilder.prototype.clean = function (opts) {
GradleBuilder.prototype.clean = function(opts) {
var builder = this;
var wrapper = path.join(this.root, 'gradlew');
var args = builder.getArgs('clean', opts);
return Q().then(function () {
return superspawn.spawn(wrapper, args, { stdio: 'inherit' });
}).then(function () {
return Q().then(function() {
return spawn(wrapper, args, {stdio: 'inherit'});
})
.then(function () {
shell.rm('-rf', path.join(builder.root, 'out'));
['debug', 'release'].forEach(function (config) {
['debug', 'release'].forEach(function(config) {
var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
if (isAutoGenerated(propertiesFilePath)) {
if(isAutoGenerated(propertiesFilePath)){
shell.rm('-f', propertiesFilePath);
}
});
@@ -255,25 +261,6 @@ GradleBuilder.prototype.clean = function (opts) {
module.exports = GradleBuilder;
function suppressJavaOptionsInfo (stdio) {
if (stdio.stderr) {
/*
* Workaround for the issue with Java printing some unwanted information to
* stderr instead of stdout.
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
* explanation.
*/
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
if (suppressThisLine) {
return;
}
process.stderr.write(stdio.stderr);
} else {
process.stdout.write(stdio.stdout);
}
}
function isAutoGenerated (file) {
function isAutoGenerated(file) {
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
}

View File

@@ -35,7 +35,8 @@ var knownBuilders = {
* @return {Builder} A builder instance for specified build type.
*/
module.exports.getBuilder = function (builderType, projectRoot) {
if (!knownBuilders[builderType]) { throw new CordovaError('Builder ' + builderType + ' is not supported.'); }
if (!knownBuilders[builderType])
throw new CordovaError('Builder ' + builderType + ' is not supported.');
try {
var Builder = require('./' + knownBuilders[builderType]);

View File

@@ -19,8 +19,8 @@
under the License.
*/
var Q = require('q');
var build = require('./build');
var Q = require('q'),
build = require('./build');
var path = require('path');
var Adb = require('./Adb');
var AndroidManifest = require('./AndroidManifest');
@@ -32,16 +32,18 @@ var events = require('cordova-common').events;
* Returns a promise for the list of the device ID's found
* @param lookHarder When true, try restarting adb if no devices are found.
*/
module.exports.list = function (lookHarder) {
return Adb.devices().then(function (list) {
module.exports.list = function(lookHarder) {
return Adb.devices()
.then(function(list) {
if (list.length === 0 && lookHarder) {
// 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.
return spawn('killall', ['adb']).then(function () {
return spawn('killall', ['adb'])
.then(function() {
events.emit('verbose', 'Restarting adb to see if more devices are detected.');
return Adb.devices();
}, function () {
}, function() {
// For non-killall OS's.
return list;
});
@@ -50,8 +52,9 @@ module.exports.list = function (lookHarder) {
});
};
module.exports.resolveTarget = function (target) {
return this.list(true).then(function (device_list) {
module.exports.resolveTarget = function(target) {
return this.list(true)
.then(function(device_list) {
if (!device_list || !device_list.length) {
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
}
@@ -62,7 +65,8 @@ module.exports.resolveTarget = function (target) {
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
}
return build.detectArchitecture(target).then(function (arch) {
return build.detectArchitecture(target)
.then(function(arch) {
return { target: target, arch: arch, isEmulator: false };
});
});
@@ -73,13 +77,13 @@ module.exports.resolveTarget = function (target) {
* and launches it.
* Returns a promise.
*/
module.exports.install = function (target, buildResults) {
return Q().then(function () {
if (target && typeof target === 'object') {
module.exports.install = function(target, buildResults) {
return Q().then(function() {
if (target && typeof target == 'object') {
return target;
}
return module.exports.resolveTarget(target);
}).then(function (resolvedTarget) {
}).then(function(resolvedTarget) {
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
var pkgName = manifest.getPackageId();
@@ -87,25 +91,29 @@ module.exports.install = function (target, buildResults) {
events.emit('log', 'Using apk: ' + apk_path);
events.emit('log', 'Package name: ' + pkgName);
return Adb.install(resolvedTarget.target, apk_path, {replace: true}).catch(function (error) {
return Adb.install(resolvedTarget.target, apk_path, {replace: true})
.catch(function (error) {
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
// is already installed on device was signed w/different certificate
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
throw error;
events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
'installed app already signed with different key');
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed.
return Adb.uninstall(resolvedTarget.target, pkgName).then(function () {
return Adb.uninstall(resolvedTarget.target, pkgName)
.then(function() {
return Adb.install(resolvedTarget.target, apk_path, {replace: true});
});
}).then(function () {
// unlock screen
})
.then(function() {
//unlock screen
return Adb.shell(resolvedTarget.target, 'input keyevent 82');
}).then(function () {
}).then(function() {
return Adb.start(resolvedTarget.target, launchName);
}).then(function () {
}).then(function() {
events.emit('log', 'LAUNCH SUCCESS');
});
});

View File

@@ -21,102 +21,40 @@
/* jshint sub:true */
var android_versions = require('android-versions');
var retry = require('./retry');
var build = require('./build');
var retry = require('./retry');
var build = require('./build');
var path = require('path');
var Adb = require('./Adb');
var AndroidManifest = require('./AndroidManifest');
var events = require('cordova-common').events;
var superspawn = require('cordova-common').superspawn;
var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError;
var shelljs = require('shelljs');
var android_sdk = require('./android_sdk');
var check_reqs = require('./check_reqs');
var Q = require('q');
var os = require('os');
var fs = require('fs');
var Q = require('q');
var os = require('os');
var child_process = require('child_process');
// constants
var ONE_SECOND = 1000; // in milliseconds
var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
var ONE_SECOND = 1000; // in milliseconds
var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
var NUM_INSTALL_RETRIES = 3;
var CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds
var EXEC_KILL_SIGNAL = 'SIGKILL';
var NUM_INSTALL_RETRIES = 3;
var CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds
var EXEC_KILL_SIGNAL = 'SIGKILL';
function forgivingWhichSync (cmd) {
try {
return fs.realpathSync(shelljs.which(cmd));
} catch (e) {
return '';
}
}
module.exports.list_images_using_avdmanager = function () {
return superspawn.spawn('avdmanager', ['list', 'avd']).then(function (output) {
var response = output.split('\n');
var emulator_list = [];
for (var i = 1; i < response.length; i++) {
// To return more detailed information use img_obj
var img_obj = {};
if (response[i].match(/Name:\s/)) {
img_obj['name'] = response[i].split('Name: ')[1].replace('\r', '');
if (response[i + 1].match(/Device:\s/)) {
i++;
img_obj['device'] = response[i].split('Device: ')[1].replace('\r', '');
}
if (response[i + 1].match(/Path:\s/)) {
i++;
img_obj['path'] = response[i].split('Path: ')[1].replace('\r', '');
}
if (response[i + 1].match(/Target:\s/)) {
i++;
if (response[i + 1].match(/ABI:\s/)) {
img_obj['abi'] = response[i + 1].split('ABI: ')[1].replace('\r', '');
}
// This next conditional just aims to match the old output of `android list avd`
// We do so so that we don't have to change the logic when parsing for the
// best emulator target to spawn (see below in `best_image`)
// This allows us to transitionally support both `android` and `avdmanager` binaries,
// depending on what SDK version the user has
if (response[i + 1].match(/Based\son:\s/)) {
img_obj['target'] = response[i + 1].split('Based on:')[1];
if (img_obj['target'].match(/Tag\/ABI:\s/)) {
img_obj['target'] = img_obj['target'].split('Tag/ABI:')[0].replace('\r', '').trim();
if (img_obj['target'].indexOf('(') > -1) {
img_obj['target'] = img_obj['target'].substr(0, img_obj['target'].indexOf('(') - 1).trim();
}
}
var version_string = img_obj['target'].replace(/Android\s+/, '');
var api_level = android_sdk.version_string_to_api_level[version_string];
if (api_level) {
img_obj['target'] += ' (API level ' + api_level + ')';
}
}
}
if (response[i + 1].match(/Skin:\s/)) {
i++;
img_obj['skin'] = response[i].split('Skin: ')[1].replace('\r', '');
}
emulator_list.push(img_obj);
}
/* To just return a list of names use this
if (response[i].match(/Name:\s/)) {
emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
} */
}
return emulator_list;
});
};
module.exports.list_images_using_android = function () {
return superspawn.spawn('android', ['list', 'avd']).then(function (output) {
/**
* Returns a Promise for a list of emulator images in the form of objects
* {
name : <emulator_name>,
path : <path_to_emulator_image>,
target : <api_target>,
abi : <cpu>,
skin : <skin>
}
*/
module.exports.list_images = function() {
return spawn('android', ['list', 'avds'])
.then(function(output) {
var response = output.split('\n');
var emulator_list = [];
for (var i = 1; i < response.length; i++) {
@@ -151,68 +89,33 @@ module.exports.list_images_using_android = function () {
/* To just return a list of names use this
if (response[i].match(/Name:\s/)) {
emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
} */
}*/
}
return emulator_list;
});
};
/**
* Returns a Promise for a list of emulator images in the form of objects
* {
name : <emulator_name>,
device : <device>,
path : <path_to_emulator_image>,
target : <api_target>,
abi : <cpu>,
skin : <skin>
}
*/
module.exports.list_images = function () {
return Q.fcall(function () {
if (forgivingWhichSync('avdmanager')) {
return module.exports.list_images_using_avdmanager();
} else if (forgivingWhichSync('android')) {
return module.exports.list_images_using_android();
} else {
return Q().then(function () {
throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?');
});
}
}).then(function (avds) {
// In case we're missing the Android OS version string from the target description, add it.
return avds.map(function (avd) {
if (avd.target && avd.target.indexOf('Android API') > -1 && avd.target.indexOf('API level') < 0) {
var api_level = avd.target.match(/\d+/);
if (api_level) {
var level = android_versions.get(api_level);
avd.target = 'Android ' + level.semver + ' (API level ' + api_level + ')';
}
}
return avd;
});
});
};
/**
* Will return the closest avd to the projects target
* or undefined if no avds exist.
* Returns a promise.
*/
module.exports.best_image = function () {
return this.list_images().then(function (images) {
module.exports.best_image = function() {
return this.list_images()
.then(function(images) {
// Just return undefined if there is no images
if (images.length === 0) return;
var closest = 9999;
var best = images[0];
var project_target = parseInt(check_reqs.get_target().replace('android-', ''));
// Loading check_reqs at run-time to avoid test-time vs run-time directory structure difference issue
var project_target = require('./check_reqs').get_target().replace('android-', '');
for (var i in images) {
var target = images[i].target;
if (target && target.indexOf('API level') > -1) {
var num = parseInt(target.split('(API level ')[1].replace(')', ''));
if (num === project_target) {
if(target) {
var num = target.split('(API level ')[1].replace(')', '');
if (num == project_target) {
return images[i];
} else if (project_target - num < closest && project_target > num) {
closest = project_target - num;
@@ -225,18 +128,18 @@ module.exports.best_image = function () {
};
// Returns a promise.
module.exports.list_started = function () {
module.exports.list_started = function() {
return Adb.devices({emulators: true});
};
// Returns a promise.
// TODO: we should remove this, there's a more robust method under android_sdk.js
module.exports.list_targets = function () {
return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()}).then(function (output) {
module.exports.list_targets = function() {
return spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
.then(function(output) {
var target_out = output.split('\n');
var targets = [];
for (var i = target_out.length; i >= 0; i--) {
if (target_out[i].match(/id:/)) {
if(target_out[i].match(/id:/)) {
targets.push(targets[i].split(' ')[1]);
}
}
@@ -251,8 +154,9 @@ module.exports.list_targets = function () {
module.exports.get_available_port = function () {
var self = this;
return self.list_started().then(function (emulators) {
for (var p = 5584; p >= 5554; p -= 2) {
return self.list_started()
.then(function (emulators) {
for (var p = 5584; p >= 5554; p-=2) {
if (emulators.indexOf('emulator-' + p) === -1) {
events.emit('verbose', 'Found available port: ' + p);
return p;
@@ -272,50 +176,53 @@ module.exports.get_available_port = function () {
*
* Returns a promise.
*/
module.exports.start = function (emulator_ID, boot_timeout) {
module.exports.start = function(emulator_ID, boot_timeout) {
var self = this;
return Q().then(function () {
return Q().then(function() {
if (emulator_ID) return Q(emulator_ID);
return self.best_image().then(function (best) {
return self.best_image()
.then(function(best) {
if (best && best.name) {
events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
return best.name;
}
var androidCmd = check_reqs.getAbsoluteAndroidCmd();
// Loading check_reqs at run-time to avoid test-time vs run-time directory structure difference issue
var androidCmd = require('./check_reqs').getAbsoluteAndroidCmd();
return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
});
}).then(function (emulatorId) {
return self.get_available_port().then(function (port) {
// Figure out the directory the emulator binary runs in, and set the cwd to that directory.
// Workaround for https://code.google.com/p/android/issues/detail?id=235461
var emulator_dir = path.dirname(shelljs.which('emulator'));
}).then(function(emulatorId) {
return self.get_available_port()
.then(function (port) {
var args = ['-avd', emulatorId, '-port', port];
// Don't wait for it to finish, since the emulator will probably keep running for a long time.
child_process
.spawn('emulator', args, { stdio: 'inherit', detached: true, cwd: emulator_dir })
.spawn('emulator', args, { stdio: 'inherit', detached: true })
.unref();
// wait for emulator to start
events.emit('log', 'Waiting for emulator to start...');
return self.wait_for_emulator(port);
});
}).then(function (emulatorId) {
if (!emulatorId) { return Q.reject(new CordovaError('Failed to start emulator')); }
}).then(function(emulatorId) {
if (!emulatorId)
return Q.reject(new CordovaError('Failed to start emulator'));
// wait for emulator to boot up
//wait for emulator to boot up
process.stdout.write('Waiting for emulator to boot (this may take a while)...');
return self.wait_for_boot(emulatorId, boot_timeout).then(function (success) {
return self.wait_for_boot(emulatorId, boot_timeout)
.then(function(success) {
if (success) {
events.emit('log', 'BOOT COMPLETE');
// unlock screen
return Adb.shell(emulatorId, 'input keyevent 82').then(function () {
// return the new emulator id for the started emulators
events.emit('log','BOOT COMPLETE');
//unlock screen
return Adb.shell(emulatorId, 'input keyevent 82')
.then(function() {
//return the new emulator id for the started emulators
return emulatorId;
});
} else {
@@ -330,19 +237,20 @@ module.exports.start = function (emulator_ID, boot_timeout) {
* Waits for an emulator to boot on a given port.
* Returns this emulator's ID in a promise.
*/
module.exports.wait_for_emulator = function (port) {
module.exports.wait_for_emulator = function(port) {
var self = this;
return Q().then(function () {
return Q().then(function() {
var emulator_id = 'emulator-' + port;
return Adb.shell(emulator_id, 'getprop dev.bootcomplete').then(function (output) {
return Adb.shell(emulator_id, 'getprop dev.bootcomplete')
.then(function (output) {
if (output.indexOf('1') >= 0) {
return emulator_id;
}
return self.wait_for_emulator(port);
}, function (error) {
if ((error && error.message &&
(error.message.indexOf('not found') > -1)) ||
(error.message.indexOf('device offline') > -1)) {
if (error && error.message &&
(error.message.indexOf('not found') > -1) ||
error.message.indexOf('device offline') > -1) {
// emulator not yet started, continue waiting
return self.wait_for_emulator(port);
} else {
@@ -350,7 +258,7 @@ module.exports.wait_for_emulator = function (port) {
throw error;
}
});
});
});
};
/*
@@ -358,9 +266,10 @@ module.exports.wait_for_emulator = function (port) {
* promise that resolves to a boolean indicating success. Not specifying a
* time_remaining or passing a negative value will cause it to wait forever
*/
module.exports.wait_for_boot = function (emulator_id, time_remaining) {
module.exports.wait_for_boot = function(emulator_id, time_remaining) {
var self = this;
return Adb.shell(emulator_id, 'ps').then(function (output) {
return Adb.shell(emulator_id, 'ps')
.then(function(output) {
if (output.match(/android\.process\.acore/)) {
return true;
} else if (time_remaining === 0) {
@@ -369,7 +278,7 @@ module.exports.wait_for_boot = function (emulator_id, time_remaining) {
process.stdout.write('.');
// Check at regular intervals
return Q.delay(time_remaining < CHECK_BOOTED_INTERVAL ? time_remaining : CHECK_BOOTED_INTERVAL).then(function () {
return Q.delay(time_remaining < CHECK_BOOTED_INTERVAL ? time_remaining : CHECK_BOOTED_INTERVAL).then(function() {
var updated_time = time_remaining >= 0 ? Math.max(time_remaining - CHECK_BOOTED_INTERVAL, 0) : time_remaining;
return self.wait_for_boot(emulator_id, updated_time);
});
@@ -382,31 +291,33 @@ module.exports.wait_for_boot = function (emulator_id, time_remaining) {
* TODO : Enter the stdin input required to complete the creation of an avd.
* Returns a promise.
*/
module.exports.create_image = function (name, target) {
module.exports.create_image = function(name, target) {
console.log('Creating new avd named ' + name);
if (target) {
return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target]).then(null, function (error) {
return spawn('android', ['create', 'avd', '--name', name, '--target', target])
.then(null, function(error) {
console.error('ERROR : Failed to create emulator image : ');
console.error(' Do you have the latest android targets including ' + target + '?');
console.error(error);
});
} else {
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
// TODO: there's a more robust method for finding targets in android_sdk.js
return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]]).then(function () {
return spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
.then(function() {
// TODO: This seems like another error case, even though it always happens.
console.error('ERROR : Unable to create an avd emulator, no targets found.');
console.error('Ensure you have targets available by running the "android" command');
return Q.reject();
}, function (error) {
}, function(error) {
console.error('ERROR : Failed to create emulator image : ');
console.error(error);
});
}
};
module.exports.resolveTarget = function (target) {
return this.list_started().then(function (emulator_list) {
module.exports.resolveTarget = function(target) {
return this.list_started()
.then(function(emulator_list) {
if (emulator_list.length < 1) {
return Q.reject('No running Android emulators found, please start an emulator before deploying your project.');
}
@@ -417,8 +328,9 @@ module.exports.resolveTarget = function (target) {
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
}
return build.detectArchitecture(target).then(function (arch) {
return {target: target, arch: arch, isEmulator: true};
return build.detectArchitecture(target)
.then(function(arch) {
return {target:target, arch:arch, isEmulator:true};
});
});
};
@@ -429,7 +341,7 @@ module.exports.resolveTarget = function (target) {
* If no started emulators are found, error out.
* Returns a promise.
*/
module.exports.install = function (givenTarget, buildResults) {
module.exports.install = function(givenTarget, buildResults) {
var target;
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
@@ -437,7 +349,7 @@ module.exports.install = function (givenTarget, buildResults) {
// resolve the target emulator
return Q().then(function () {
if (givenTarget && typeof givenTarget === 'object') {
if (givenTarget && typeof givenTarget == 'object') {
return givenTarget;
} else {
return module.exports.resolveTarget(givenTarget);
@@ -451,12 +363,13 @@ module.exports.install = function (givenTarget, buildResults) {
}).then(function () {
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed.
return Q.when().then(function () {
return Q.when()
.then(function() {
var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
var execOptions = {
cwd: os.tmpdir(),
timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
killSignal: EXEC_KILL_SIGNAL
};
@@ -467,12 +380,12 @@ module.exports.install = function (givenTarget, buildResults) {
// A special function to call adb install in specific environment w/ specific options.
// Introduced as a part of fix for http://issues.apache.org/jira/browse/CB-9119
// to workaround sporadic emulator hangs
function adbInstallWithOptions (target, apk, opts) {
function adbInstallWithOptions(target, apk, opts) {
events.emit('verbose', 'Installing apk ' + apk + ' on ' + target + '...');
var command = 'adb -s ' + target + ' install -r "' + apk + '"';
return Q.promise(function (resolve, reject) {
child_process.exec(command, opts, function (err, stdout, stderr) {
child_process.exec(command, opts, function(err, stdout, stderr) {
if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
// adb does not return an error code even if installation fails. Instead it puts a specific
// message to stdout, so we have to use RegExp matching to detect installation failure.
@@ -492,23 +405,27 @@ module.exports.install = function (givenTarget, buildResults) {
}
function installPromise () {
return adbInstallWithOptions(target.target, apk_path, execOptions).catch(function (error) {
return adbInstallWithOptions(target.target, apk_path, execOptions)
.catch(function (error) {
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
// is already installed on device was signed w/different certificate
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
throw error;
events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
'currently installed app was signed with different key');
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed.
return Adb.uninstall(target.target, pkgName).then(function () {
return Adb.uninstall(target.target, pkgName)
.then(function() {
return adbInstallWithOptions(target.target, apk_path, execOptions);
});
});
}
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise).then(function (output) {
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise)
.then(function (output) {
events.emit('log', 'INSTALL SUCCESS');
});
});

View File

@@ -1,3 +0,0 @@
@ECHO OFF
for /f "tokens=2*" %%a in ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Android Studio" /v Path') do set "ASPath=%%~b"
ECHO %ASPath%

View File

@@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0install-device"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'install-device' script in 'cordova\lib' folder, aborting...>&2

View File

@@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0install-emulator"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'install-emulator' script in 'cordova\lib' folder, aborting...>&2

View File

@@ -22,7 +22,7 @@
var devices = require('./device');
// Usage support for when args are given
require('./check_reqs').check_android().then(function() {
require('../lib/check_reqs').check_android().then(function() {
devices.list().done(function(device_list) {
device_list && device_list.forEach(function(dev) {
console.log(dev);

View File

@@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0list-devices"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'list-devices' script in 'cordova\lib' folder, aborting...>&2

View File

@@ -22,7 +22,7 @@
var emulators = require('./emulator');
// Usage support for when args are given
require('./check_reqs').check_android().then(function() {
require('../lib/check_reqs').check_android().then(function() {
emulators.list_images().done(function(emulator_list) {
emulator_list && emulator_list.forEach(function(emu) {
console.log(emu.name);

View File

@@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0list-emulator-images"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'list-emulator-images' script in 'cordova\lib' folder, aborting...>&2

View File

@@ -22,7 +22,7 @@
var emulators = require('./emulator');
// Usage support for when args are given
require('./check_reqs').check_android().then(function() {
require('../lib/check_reqs').check_android().then(function() {
emulators.list_started().done(function(emulator_list) {
emulator_list && emulator_list.forEach(function(emu) {
console.log(emu);

View File

@@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0list-started-emulators"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'list-started-emulators' script in 'cordova\lib' folder, aborting...>&2

View File

@@ -19,28 +19,28 @@
under the License.
*/
var path = require('path');
var os = require('os');
var Q = require('q');
var child_process = require('child_process');
var ROOT = path.join(__dirname, '..', '..');
var path = require('path'),
os = require('os'),
Q = require('q'),
child_process = require('child_process'),
ROOT = path.join(__dirname, '..', '..');
/*
* Starts running logcat in the shell.
* Returns a promise.
*/
module.exports.run = function () {
module.exports.run = function() {
var d = Q.defer();
var adb = child_process.spawn('adb', ['logcat'], {cwd: os.tmpdir()});
adb.stdout.on('data', function (data) {
adb.stdout.on('data', function(data) {
var lines = data ? data.toString().split('\n') : [];
var out = lines.filter(function (x) { return x.indexOf('nativeGetEnabledTags') < 0; });
var out = lines.filter(function(x) { return x.indexOf('nativeGetEnabledTags') < 0; });
console.log(out.join('\n'));
});
adb.stderr.on('data', console.error);
adb.on('close', function (code) {
adb.on('close', function(code) {
if (code > 0) {
d.reject('Failed to run logcat command.');
} else d.resolve();
@@ -49,7 +49,7 @@ module.exports.run = function () {
return d.promise;
};
module.exports.help = function () {
module.exports.help = function() {
console.log('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));
console.log('Gives the logcat output on the command line.');
process.exit(0);

View File

@@ -20,10 +20,8 @@
buildscript {
repositories {
mavenCentral()
jcenter()
maven {
url "https://maven.google.com"
}
}
// Switch the Android Gradle plugin version requirement depending on the

View File

@@ -26,15 +26,15 @@ var events = require('cordova-common').events;
var CordovaError = require('cordova-common').CordovaError;
var handlers = {
'source-file': {
install: function (obj, plugin, project, options) {
'source-file':{
install:function(obj, plugin, project, options) {
if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id));
if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id));
var dest = path.join(obj.targetDir, path.basename(obj.src));
if (options && options.android_studio === true) {
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
if(options && options.android_studio === true) {
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
}
if (options && options.force) {
@@ -43,42 +43,42 @@ var handlers = {
copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
}
},
uninstall: function (obj, plugin, project, options) {
uninstall:function(obj, plugin, project, options) {
var dest = path.join(obj.targetDir, path.basename(obj.src));
if (options && options.android_studio === true) {
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
if(options && options.android_studio === true) {
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
}
deleteJava(project.projectDir, dest);
}
},
'lib-file': {
install: function (obj, plugin, project, options) {
'lib-file':{
install:function(obj, plugin, project, options) {
var dest = path.join('libs', path.basename(obj.src));
if (options && options.android_studio === true) {
dest = path.join('app/libs', path.basename(obj.src));
if(options && options.android_studio === true) {
dest = path.join('app/libs', path.basename(obj.src));
}
copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
},
uninstall: function (obj, plugin, project, options) {
uninstall:function(obj, plugin, project, options) {
var dest = path.join('libs', path.basename(obj.src));
if (options && options.android_studio === true) {
dest = path.join('app/libs', path.basename(obj.src));
if(options && options.android_studio === true) {
dest = path.join('app/libs', path.basename(obj.src));
}
removeFile(project.projectDir, dest);
}
},
'resource-file': {
install: function (obj, plugin, project, options) {
'resource-file':{
install:function(obj, plugin, project, options) {
copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link));
},
uninstall: function (obj, plugin, project, options) {
uninstall:function(obj, plugin, project, options) {
removeFile(project.projectDir, path.normalize(obj.target));
}
},
'framework': {
install: function (obj, plugin, project, options) {
install:function(obj, plugin, project, options) {
var src = obj.src;
if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
@@ -95,15 +95,15 @@ var handlers = {
subDir = src;
}
if (obj.type === 'gradleReference') {
if (obj.type == 'gradleReference') {
project.addGradleReference(parentDir, subDir);
} else if (obj.type === 'sys') {
} else if (obj.type == 'sys') {
project.addSystemLibrary(parentDir, subDir);
} else {
project.addSubProject(parentDir, subDir);
}
},
uninstall: function (obj, plugin, project, options) {
uninstall:function(obj, plugin, project, options) {
var src = obj.src;
if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
@@ -125,17 +125,17 @@ var handlers = {
subDir = src;
}
if (obj.type === 'gradleReference') {
if (obj.type == 'gradleReference') {
project.removeGradleReference(parentDir, subDir);
} else if (obj.type === 'sys') {
} else if (obj.type == 'sys') {
project.removeSystemLibrary(parentDir, subDir);
} else {
project.removeSubProject(parentDir, subDir);
}
}
},
asset: {
install: function (obj, plugin, project, options) {
asset:{
install:function(obj, plugin, project, options) {
if (!obj.src) {
throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
}
@@ -149,7 +149,7 @@ var handlers = {
copyFile(plugin.dir, obj.src, project.platformWww, obj.target);
}
},
uninstall: function (obj, plugin, project, options) {
uninstall:function(obj, plugin, project, options) {
var target = obj.target || obj.src;
if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
@@ -167,7 +167,7 @@ var handlers = {
install: function (obj, plugin, project, options) {
// Copy the plugin's files into the www directory.
var moduleSource = path.resolve(plugin.dir, obj.src);
var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname(obj.src)));
var moduleName = plugin.id + '.' + (obj.name || path.basename(obj.src, path.extname (obj.src)));
// Read in the file, prepend the cordova.define, and write it back out.
var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
@@ -206,7 +206,7 @@ module.exports.getInstaller = function (type) {
events.emit('verbose', '<' + type + '> is not supported for android plugins');
};
module.exports.getUninstaller = function (type) {
module.exports.getUninstaller = function(type) {
if (handlers[type] && handlers[type].uninstall) {
return handlers[type].uninstall;
}
@@ -221,19 +221,21 @@ function copyFile (plugin_dir, src, project_dir, dest, link) {
// check that src path is inside plugin directory
var real_path = fs.realpathSync(src);
var real_plugin_path = fs.realpathSync(plugin_dir);
if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }
if (real_path.indexOf(real_plugin_path) !== 0)
throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"');
dest = path.resolve(project_dir, dest);
// check that dest path is located in project directory
if (dest.indexOf(project_dir) !== 0) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }
if (dest.indexOf(project_dir) !== 0)
throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project');
shell.mkdir('-p', path.dirname(dest));
if (link) {
symlinkFileOrDirTree(src, dest);
} else if (fs.statSync(src).isDirectory()) {
// XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
shell.cp('-Rf', src + '/*', dest);
shell.cp('-Rf', src+'/*', dest);
} else {
shell.cp('-f', src, dest);
}
@@ -242,22 +244,24 @@ function copyFile (plugin_dir, src, project_dir, dest, link) {
// Same as copy file but throws error if target exists
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
var target_path = path.resolve(project_dir, dest);
if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); }
if (fs.existsSync(target_path))
throw new CordovaError('"' + target_path + '" already exists!');
copyFile(plugin_dir, src, project_dir, dest, !!link);
}
function symlinkFileOrDirTree (src, dest) {
function symlinkFileOrDirTree(src, dest) {
if (fs.existsSync(dest)) {
shell.rm('-Rf', dest);
}
if (fs.statSync(src).isDirectory()) {
shell.mkdir('-p', dest);
fs.readdirSync(src).forEach(function (entry) {
fs.readdirSync(src).forEach(function(entry) {
symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
});
} else {
}
else {
fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);
}
}
@@ -288,8 +292,8 @@ function removeFileAndParents (baseDir, destFile, stopper) {
// check if directory is empty
var curDir = path.dirname(file);
while (curDir !== path.resolve(baseDir, stopper)) {
if (fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
while(curDir !== path.resolve(baseDir, stopper)) {
if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
fs.rmdirSync(curDir);
curDir = path.resolve(curDir, '..');
} else {
@@ -299,6 +303,6 @@ function removeFileAndParents (baseDir, destFile, stopper) {
}
}
function generateAttributeError (attribute, element, id) {
function generateAttributeError(attribute, element, id) {
return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
}

View File

@@ -16,7 +16,6 @@
specific language governing permissions and limitations
under the License.
*/
/* eslint no-useless-escape: 0 */
var Q = require('q');
var fs = require('fs');
@@ -24,7 +23,6 @@ var path = require('path');
var shell = require('shelljs');
var events = require('cordova-common').events;
var AndroidManifest = require('./AndroidManifest');
var checkReqs = require('./check_reqs');
var xmlHelpers = require('cordova-common').xmlHelpers;
var CordovaError = require('cordova-common').CordovaError;
var ConfigParser = require('cordova-common').ConfigParser;
@@ -42,14 +40,16 @@ module.exports.prepare = function (cordovaProject, options) {
this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
// Update own www dir with project's www assets and plugins' assets and js-files
return Q.when(updateWww(cordovaProject, this.locations)).then(function () {
return Q.when(updateWww(cordovaProject, this.locations))
.then(function () {
// update project according to config.xml changes.
return updateProjectAccordingTo(self._config, self.locations);
}).then(function () {
})
.then(function () {
updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
updateSplashes(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root));
}).then(function () {
})
.then(function () {
events.emit('verbose', 'Prepared android project successfully');
});
};
@@ -72,7 +72,6 @@ module.exports.clean = function (options) {
cleanWww(projectRoot, self.locations);
cleanIcons(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));
cleanSplashes(projectRoot, projectConfig, path.relative(projectRoot, self.locations.res));
cleanFileResources(projectRoot, projectConfig, path.relative(projectRoot, self.locations.root));
});
};
@@ -90,7 +89,7 @@ module.exports.clean = function (options) {
* represents current project's configuration. When returned, the
* configuration is already dumped to appropriate config.xml file.
*/
function updateConfigFilesFrom (sourceConfig, configMunger, locations) {
function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
events.emit('verbose', 'Generating platform-specific config.xml from defaults for android at ' + locations.configXml);
// First cleanup current config and merge project's one into own
@@ -105,7 +104,7 @@ function updateConfigFilesFrom (sourceConfig, configMunger, locations) {
// Merge changes from app's config.xml into platform's one
var config = new ConfigParser(locations.configXml);
xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
config.doc.getroot(), 'android', /* clobber= */true);
config.doc.getroot(), 'android', /*clobber=*/true);
config.write();
return config;
@@ -114,7 +113,7 @@ function updateConfigFilesFrom (sourceConfig, configMunger, locations) {
/**
* Logs all file operations via the verbose event stream, indented.
*/
function logFileOp (message) {
function logFileOp(message) {
events.emit('verbose', ' ' + message);
}
@@ -127,7 +126,7 @@ function logFileOp (message) {
* @param {Object} destinations An object that contains destination
* paths for www files.
*/
function updateWww (cordovaProject, destinations) {
function updateWww(cordovaProject, destinations) {
var sourceDirs = [
path.relative(cordovaProject.root, cordovaProject.locations.www),
path.relative(cordovaProject.root, destinations.platformWww)
@@ -150,7 +149,7 @@ function updateWww (cordovaProject, destinations) {
/**
* Cleans all files from the platform 'www' directory.
*/
function cleanWww (projectRoot, locations) {
function cleanWww(projectRoot, locations) {
var targetDir = path.relative(projectRoot, locations.www);
events.emit('verbose', 'Cleaning ' + targetDir);
@@ -166,26 +165,19 @@ function cleanWww (projectRoot, locations) {
* be used to update project
* @param {Object} locations A map of locations for this platform
*/
function updateProjectAccordingTo (platformConfig, locations) {
function updateProjectAccordingTo(platformConfig, locations) {
// Update app name by editing res/values/strings.xml
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
var name = platformConfig.name();
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
strings.find('string[@name="app_name"]').text = name.replace(/\'/g, '\\\'');
var shortName = platformConfig.shortName && platformConfig.shortName();
if (shortName && shortName !== name) {
strings.find('string[@name="launcher_name"]').text = shortName.replace(/\'/g, '\\\'');
}
fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
// Java packages cannot support dashes
var androidPkgName = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
var manifest = new AndroidManifest(locations.manifest);
var manifestId = manifest.getPackageId();
var orig_pkg = manifest.getPackageId();
manifest.getActivity()
.setOrientation(platformConfig.getPreference('orientation'))
@@ -193,40 +185,36 @@ function updateProjectAccordingTo (platformConfig, locations) {
manifest.setVersionName(platformConfig.version())
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
.setPackageId(androidPkgName)
.setPackageId(pkg)
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
.write();
var javaPattern = path.join(locations.root, 'src', manifestId.replace(/\./g, '/'), '*.java');
var java_files = shell.ls(javaPattern).filter(function (f) {
var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
var java_files = shell.ls(javaPattern).filter(function(f) {
return shell.grep(/extends\s+CordovaActivity/g, f);
});
if (java_files.length === 0) {
throw new CordovaError('No Java files found that extend CordovaActivity.');
} else if (java_files.length > 1) {
} else if(java_files.length > 1) {
events.emit('log', 'Multiple candidate Java files that extend CordovaActivity found. Guessing at the first one, ' + java_files[0]);
}
var destFile = path.join(locations.root, 'src', androidPkgName.replace(/\./g, '/'), path.basename(java_files[0]));
var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
shell.mkdir('-p', path.dirname(destFile));
shell.sed(/package [\w\.]*;/, 'package ' + androidPkgName + ';', java_files[0]).to(destFile);
events.emit('verbose', 'Wrote out Android package name "' + androidPkgName + '" to ' + destFile);
shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
events.emit('verbose', 'Wrote out Android package name "' + pkg + '" to ' + destFile);
var removeOrigPkg = checkReqs.isWindows() || checkReqs.isDarwin() ?
manifestId.toUpperCase() !== androidPkgName.toUpperCase() :
manifestId !== androidPkgName;
if (removeOrigPkg) {
if (orig_pkg !== pkg) {
// If package was name changed we need to remove old java with main activity
shell.rm('-Rf', java_files[0]);
shell.rm('-Rf',java_files[0]);
// remove any empty directories
var currentDir = path.dirname(java_files[0]);
var sourcesRoot = path.resolve(locations.root, 'src');
while (currentDir !== sourcesRoot) {
if (fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) {
while(currentDir !== sourcesRoot) {
if(fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) {
fs.rmdirSync(currentDir);
currentDir = path.resolve(currentDir, '..');
} else {
@@ -239,7 +227,7 @@ function updateProjectAccordingTo (platformConfig, locations) {
// Consturct the default value for versionCode as
// PATCH + MINOR * 100 + MAJOR * 10000
// see http://developer.android.com/tools/publishing/versioning.html
function default_versionCode (version) {
function default_versionCode(version) {
var nums = version.split('-')[0].split('.');
var versionCode = 0;
if (+nums[0]) {
@@ -256,7 +244,7 @@ function default_versionCode (version) {
return versionCode;
}
function getImageResourcePath (resourcesDir, type, density, name, sourceName) {
function getImageResourcePath(resourcesDir, type, density, name, sourceName) {
if (/\.9\.png$/.test(sourceName)) {
name = name.replace(/\.png$/, '.9.png');
}
@@ -264,7 +252,7 @@ function getImageResourcePath (resourcesDir, type, density, name, sourceName) {
return resourcePath;
}
function updateSplashes (cordovaProject, platformResourcesDir) {
function updateSplashes(cordovaProject, platformResourcesDir) {
var resources = cordovaProject.projectConfig.getSplashScreens('android');
// if there are "splash" elements in config.xml
@@ -280,7 +268,7 @@ function updateSplashes (cordovaProject, platformResourcesDir) {
if (!resource.density) {
return;
}
if (resource.density === 'mdpi') {
if (resource.density == 'mdpi') {
hadMdpi = true;
}
var targetPath = getImageResourcePath(
@@ -300,7 +288,7 @@ function updateSplashes (cordovaProject, platformResourcesDir) {
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
}
function cleanSplashes (projectRoot, projectConfig, platformResourcesDir) {
function cleanSplashes(projectRoot, projectConfig, platformResourcesDir) {
var resources = projectConfig.getSplashScreens('android');
if (resources.length > 0) {
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'drawable', 'screen.png');
@@ -312,7 +300,7 @@ function cleanSplashes (projectRoot, projectConfig, platformResourcesDir) {
}
}
function updateIcons (cordovaProject, platformResourcesDir) {
function updateIcons(cordovaProject, platformResourcesDir) {
var icons = cordovaProject.projectConfig.getIcons('android');
// if there are icon elements in config.xml
@@ -336,7 +324,7 @@ function updateIcons (cordovaProject, platformResourcesDir) {
};
// find the best matching icon for a given density or size
// @output android_icons
var parseIcon = function (icon, icon_size) {
var parseIcon = function(icon, icon_size) {
// do I have a platform icon for that density already
var density = icon.density || sizeToDensityMap[icon_size];
if (!density) {
@@ -351,7 +339,7 @@ function updateIcons (cordovaProject, platformResourcesDir) {
};
// iterate over all icon elements to find the default icon and call parseIcon
for (var i = 0; i < icons.length; i++) {
for (var i=0; i<icons.length; i++) {
var icon = icons[i];
var size = icon.width;
if (!size) {
@@ -388,7 +376,7 @@ function updateIcons (cordovaProject, platformResourcesDir) {
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
}
function cleanIcons (projectRoot, projectConfig, platformResourcesDir) {
function cleanIcons(projectRoot, projectConfig, platformResourcesDir) {
var icons = projectConfig.getIcons('android');
if (icons.length > 0) {
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'icon.png');
@@ -403,52 +391,16 @@ function cleanIcons (projectRoot, projectConfig, platformResourcesDir) {
/**
* Gets a map containing resources of a specified name from all drawable folders in a directory.
*/
function mapImageResources (rootDir, subDir, type, resourceName) {
function mapImageResources(rootDir, subDir, type, resourceName) {
var pathMap = {};
shell.ls(path.join(rootDir, subDir, type + '-*')).forEach(function (drawableFolder) {
shell.ls(path.join(rootDir, subDir, type + '-*'))
.forEach(function (drawableFolder) {
var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName);
pathMap[imagePath] = null;
});
return pathMap;
}
function updateFileResources (cordovaProject, platformDir) {
var files = cordovaProject.projectConfig.getFileResources('android');
// if there are resource-file elements in config.xml
if (files.length === 0) {
events.emit('verbose', 'This app does not have additional resource files defined');
return;
}
var resourceMap = {};
files.forEach(function (res) {
var targetPath = path.join(platformDir, res.target);
resourceMap[targetPath] = res.src;
});
events.emit('verbose', 'Updating resource files at ' + platformDir);
FileUpdater.updatePaths(
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
}
function cleanFileResources (projectRoot, projectConfig, platformDir) {
var files = projectConfig.getFileResources('android', true);
if (files.length > 0) {
events.emit('verbose', 'Cleaning resource files at ' + platformDir);
var resourceMap = {};
files.forEach(function (res) {
var filePath = path.join(platformDir, res.target);
resourceMap[filePath] = null;
});
FileUpdater.updatePaths(
resourceMap, {
rootDir: projectRoot, all: true}, logFileOp);
}
}
/**
* Gets and validates 'AndroidLaunchMode' prepference from config.xml. Returns
* preference value and warns if it doesn't seems to be valid
@@ -460,7 +412,7 @@ function cleanFileResources (projectRoot, projectConfig, platformDir) {
* default value, if there is no such preference. The default value is
* 'singleTop'
*/
function findAndroidLaunchModePreference (platformConfig) {
function findAndroidLaunchModePreference(platformConfig) {
var launchMode = platformConfig.getPreference('AndroidLaunchMode');
if (!launchMode) {
// Return a default value

View File

@@ -45,12 +45,12 @@ module.exports.retryPromise = function (attemts_left, promiseFunction) {
return promiseFunction.apply(undefined, promiseFunctionArguments).then(
// on success pass results through
function onFulfilled (value) {
function onFulfilled(value) {
return value;
},
// on rejection either retry, or throw the error
function onRejected (error) {
function onRejected(error) {
attemts_left -= 1;

View File

@@ -21,14 +21,14 @@
/* jshint loopfunc:true */
var path = require('path');
var build = require('./build');
var emulator = require('./emulator');
var device = require('./device');
var Q = require('q');
var events = require('cordova-common').events;
var path = require('path'),
build = require('./build'),
emulator = require('./emulator'),
device = require('./device'),
Q = require('q'),
events = require('cordova-common').events;
function getInstallTarget (runOptions) {
function getInstallTarget(runOptions) {
var install_target;
if (runOptions.target) {
install_target = runOptions.target;
@@ -51,15 +51,17 @@ function getInstallTarget (runOptions) {
*
* @return {Promise}
*/
module.exports.run = function (runOptions) {
module.exports.run = function(runOptions) {
var self = this;
var install_target = getInstallTarget(runOptions);
return Q().then(function () {
return Q()
.then(function() {
if (!install_target) {
// no target given, deploy to device if available, otherwise use the emulator.
return device.list().then(function (device_list) {
return device.list()
.then(function(device_list) {
if (device_list.length > 0) {
events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.');
install_target = device_list[0];
@@ -69,31 +71,36 @@ module.exports.run = function (runOptions) {
}
});
}
}).then(function () {
if (install_target === '--device') {
}).then(function() {
if (install_target == '--device') {
return device.resolveTarget(null);
} else if (install_target === '--emulator') {
} else if (install_target == '--emulator') {
// Give preference to any already started emulators. Else, start one.
return emulator.list_started().then(function (started) {
return emulator.list_started()
.then(function(started) {
return started && started.length > 0 ? started[0] : emulator.start();
}).then(function (emulatorId) {
}).then(function(emulatorId) {
return emulator.resolveTarget(emulatorId);
});
}
// They specified a specific device/emulator ID.
return device.list().then(function (devices) {
return device.list()
.then(function(devices) {
if (devices.indexOf(install_target) > -1) {
return device.resolveTarget(install_target);
}
return emulator.list_started().then(function (started_emulators) {
return emulator.list_started()
.then(function(started_emulators) {
if (started_emulators.indexOf(install_target) > -1) {
return emulator.resolveTarget(install_target);
}
return emulator.list_images().then(function (avds) {
return emulator.list_images()
.then(function(avds) {
// if target emulator isn't started, then start it.
for (var avd in avds) {
if (avds[avd].name === install_target) {
return emulator.start(install_target).then(function (emulatorId) {
if (avds[avd].name == install_target) {
return emulator.start(install_target)
.then(function(emulatorId) {
return emulator.resolveTarget(emulatorId);
});
}
@@ -102,14 +109,16 @@ module.exports.run = function (runOptions) {
});
});
});
}).then(function (resolvedTarget) {
}).then(function(resolvedTarget) {
// Better just call self.build, but we're doing some processing of
// build results (according to platformApi spec) so they are in different
// format than emulator.install expects.
// TODO: Update emulator/device.install to handle this change
return build.run.call(self, runOptions, resolvedTarget).then(function (buildResults) {
return build.run.call(self, runOptions, resolvedTarget)
.then(function(buildResults) {
if (resolvedTarget.isEmulator) {
return emulator.wait_for_boot(resolvedTarget.target).then(function () {
return emulator.wait_for_boot(resolvedTarget.target)
.then(function () {
return emulator.install(resolvedTarget, buildResults);
});
}
@@ -118,7 +127,7 @@ module.exports.run = function (runOptions) {
});
};
module.exports.help = function () {
module.exports.help = function() {
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]) + ' [options]');
console.log('Build options :');
console.log(' --debug : Builds project in debug mode');

View File

@@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0start-emulator"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'start-emulator' script in 'cordova\lib' folder, aborting...>&2

View File

@@ -20,7 +20,7 @@
*/
// Coho updates this line:
var VERSION = "6.4.1-dev";
var VERSION = "6.1.2";
module.exports.version = VERSION;

File diff suppressed because it is too large Load Diff

View File

@@ -18,25 +18,25 @@
*/
var app = {
// Application Constructor
initialize: function () {
initialize: function() {
this.bindEvents();
},
// Bind Event Listeners
//
// Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function () {
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
// deviceready Event Handler
//
// The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function () {
onDeviceReady: function() {
app.receivedEvent('deviceready');
},
// Update DOM on a Received Event
receivedEvent: function (id) {
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
@@ -48,4 +48,4 @@ var app = {
}
};
app.initialize();
app.initialize();

View File

@@ -21,10 +21,8 @@ apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral()
jcenter()
maven {
url "https://maven.google.com"
}
}
// Switch the Android Gradle plugin version requirement depending on the
@@ -32,22 +30,20 @@ buildscript {
// 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:3.0.0'
classpath 'com.android.tools.build:gradle:2.2.1'
}
}
// Allow plugins to declare Maven dependencies via build-extras.gradle.
allprojects {
repositories {
mavenCentral();
jcenter()
maven {
url "https://maven.google.com"
}
}
}
task wrapper(type: Wrapper) {
gradleVersion = '4.1.0'
gradleVersion = '2.14.1'
}
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
@@ -74,10 +70,6 @@ ext {
if (!project.hasProperty('cdvBuildMultipleApks')) {
cdvBuildMultipleApks = null
}
// Whether to append a 0 "abi digit" to versionCode when only a single APK is build
if (!project.hasProperty('cdvVersionCodeForceAbiDigit')) {
cdvVersionCodeForceAbiDigit = null
}
// .properties files to use for release signing.
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
cdvReleaseSigningPropertiesFile = null
@@ -119,7 +111,6 @@ if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.propert
// Cast to appropriate types.
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
ext.cdvVersionCodeForceAbiDigit = cdvVersionCodeForceAbiDigit == null ? false : cdvVersionCodeForceAbiDigit.toBoolean();
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
@@ -147,7 +138,6 @@ task cdvPrintProps << {
println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
println('cdvVersionCode=' + cdvVersionCode)
println('cdvVersionCodeForceAbiDigit=' + cdvVersionCodeForceAbiDigit)
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
@@ -190,45 +180,25 @@ android {
buildToolsVersion cdvBuildToolsVersion
if (Boolean.valueOf(cdvBuildMultipleApks)) {
flavorDimensions "default"
productFlavors {
armeabi {
versionCode defaultConfig.versionCode*10 + 1
ndk {
abiFilters = ["armeabi"]
}
}
armv7 {
versionCode defaultConfig.versionCode*10 + 2
ndk {
abiFilters = ["armeabi-v7a"]
}
}
arm64 {
versionCode defaultConfig.versionCode*10 + 3
ndk {
abiFilters = ["arm64-v8a"]
abiFilters "armeabi-v7a", ""
}
}
x86 {
versionCode defaultConfig.versionCode*10 + 4
ndk {
abiFilters = ["x86"]
abiFilters "x86", ""
}
}
x86_64 {
versionCode defaultConfig.versionCode*10 + 5
all {
ndk {
abiFilters = ["x86_64"]
abiFilters "all", ""
}
}
}
} else if (Boolean.valueOf(cdvVersionCodeForceAbiDigit)) {
// This provides compatibility to the default logic for versionCode before cordova-android 5.2.0
defaultConfig {
versionCode defaultConfig.versionCode*10
}
}
/*
@@ -275,7 +245,7 @@ android {
}
dependencies {
implementation fileTree(dir: 'libs', include: '*.jar')
compile fileTree(dir: 'libs', include: '*.jar')
// SUB-PROJECT DEPENDENCIES START
// SUB-PROJECT DEPENDENCIES END
}
@@ -294,7 +264,7 @@ def promptForReleaseKeyPassword() {
gradle.taskGraph.whenReady { taskGraph ->
taskGraph.getAllTasks().each() { task ->
if (['validateReleaseSigning', 'validateSigningRelease', 'validateSigningArmv7Release', 'validateSigningX86Release'].contains(task.name)) {
if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') {
promptForReleaseKeyPassword()
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 213 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 478 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 493 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

View File

@@ -1 +0,0 @@
//This file is intentionally just a comment

View File

@@ -16,34 +16,28 @@
under the License.
*/
buildscript {
repositories {
mavenCentral()
jcenter();
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.1'
}
}
apply plugin: 'com.android.library'
ext {
apply from: 'cordova.gradle'
cdvCompileSdkVersion = privateHelpers.getProjectTarget()
cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
}
buildscript {
repositories {
jcenter()
maven {
url "https://maven.google.com"
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
}
}
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
group = 'org.apache.cordova'
version = '6.4.1-dev'
android {
compileSdkVersion cdvCompileSdkVersion
buildToolsVersion cdvBuildToolsVersion
@@ -65,73 +59,4 @@ android {
assets.srcDirs = ['assets']
}
}
packagingOptions {
exclude 'META-INF/LICENSE'
exclude 'META-INF/LICENSE.txt'
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
}
}
install {
repositories.mavenInstaller {
pom {
project {
packaging 'aar'
name 'Cordova'
url 'https://cordova.apache.org'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
developers {
developer {
id 'stevengill'
name 'Steve Gill'
}
}
scm {
connection 'https://git-wip-us.apache.org/repos/asf?p=cordova-android.git'
developerConnection 'https://git-wip-us.apache.org/repos/asf?p=cordova-android.git'
url 'https://git-wip-us.apache.org/repos/asf?p=cordova-android'
}
}
}
}
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
artifacts {
archives sourcesJar
}
bintray {
user = System.getenv('BINTRAY_USER')
key = System.getenv('BINTRAY_KEY')
configurations = ['archives']
pkg {
repo = 'maven'
name = 'cordova-android'
userOrg = 'cordova'
licenses = ['Apache-2.0']
vcsUrl = 'https://git-wip-us.apache.org/repos/asf?p=cordova-android.git'
websiteUrl = 'https://cordova.apache.org'
issueTrackerUrl = 'https://issues.apache.org/jira/browse/CB'
publicDownloadNumbers = true
licenses = ['Apache-2.0']
labels = ['android', 'cordova', 'phonegap']
version {
name = '6.4.1-dev'
released = new Date()
vcsTag = '6.4.1-dev'
}
}
}

View File

@@ -1,6 +0,0 @@
#Thu Nov 09 10:50:25 PST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip

View File

@@ -10,7 +10,7 @@
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=android-26
target=android-25
apk-configurations=
renderscript.opt.level=O0
android.library=true

View File

@@ -1,70 +0,0 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova;
/*
* This is a utility class that allows us to get the BuildConfig variable, which is required
* for the use of different providers. This is not guaranteed to work, and it's better for this
* to be set in the build step in config.xml
*
*/
import android.app.Activity;
import android.content.Context;
import java.lang.reflect.Field;
public class BuildHelper {
private static String TAG="BuildHelper";
/*
* This needs to be implemented if you wish to use the Camera Plugin or other plugins
* that read the Build Configuration.
*
* Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to
* StackOverflow. This is annoying as hell! However, this method does not work with
* ProGuard, and you should use the config.xml to define the application_id
*
*/
public static Object getBuildConfigValue(Context ctx, String key)
{
try
{
Class<?> clazz = Class.forName(ctx.getPackageName() + ".BuildConfig");
Field field = clazz.getField(key);
return field.get(null);
} catch (ClassNotFoundException e) {
LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?");
e.printStackTrace();
} catch (NoSuchFieldException e) {
LOG.d(TAG, key + " is not a valid field. Check your build.gradle");
} catch (IllegalAccessException e) {
LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace.");
e.printStackTrace();
}
return null;
}
}

View File

@@ -19,7 +19,6 @@
package org.apache.cordova;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import org.apache.cordova.CordovaPlugin;
@@ -52,18 +51,10 @@ public interface CordovaInterface {
/**
* Get the Android activity.
*
* If a custom engine lives outside of the Activity's lifecycle the return value may be null.
*
* @return the Activity
*/
public abstract Activity getActivity();
/**
* Get the Android context.
*
* @return the Context
*/
public Context getContext();
/**
* Called when a message is sent to plugin.

View File

@@ -20,7 +20,6 @@
package org.apache.cordova;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
@@ -85,11 +84,6 @@ public class CordovaInterfaceImpl implements CordovaInterface {
return activity;
}
@Override
public Context getContext() {
return activity;
}
@Override
public Object onMessage(String id, Object data) {
if ("exit".equals(id)) {

View File

@@ -31,7 +31,7 @@ import android.webkit.WebChromeClient.CustomViewCallback;
* are not expected to implement it.
*/
public interface CordovaWebView {
public static final String CORDOVA_VERSION = "6.4.1-dev";
public static final String CORDOVA_VERSION = "6.1.2";
void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences);

View File

@@ -488,34 +488,6 @@ public class NativeToJsMessageQueue {
encodeAsMessageHelper(sb, pluginResult);
}
void buildJsMessage(StringBuilder sb) {
switch (pluginResult.getMessageType()) {
case PluginResult.MESSAGE_TYPE_MULTIPART:
int size = pluginResult.getMultipartMessagesSize();
for (int i=0; i<size; i++) {
PluginResult subresult = pluginResult.getMultipartMessage(i);
JsMessage submessage = new JsMessage(subresult, jsPayloadOrCallbackId);
submessage.buildJsMessage(sb);
if (i < (size-1)) {
sb.append(",");
}
}
break;
case PluginResult.MESSAGE_TYPE_BINARYSTRING:
sb.append("atob('")
.append(pluginResult.getMessage())
.append("')");
break;
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
sb.append("cordova.require('cordova/base64').toArrayBuffer('")
.append(pluginResult.getMessage())
.append("')");
break;
default:
sb.append(pluginResult.getMessage());
}
}
void encodeAsJsMessage(StringBuilder sb) {
if (pluginResult == null) {
sb.append(jsPayloadOrCallbackId);
@@ -523,16 +495,29 @@ public class NativeToJsMessageQueue {
int status = pluginResult.getStatus();
boolean success = (status == PluginResult.Status.OK.ordinal()) || (status == PluginResult.Status.NO_RESULT.ordinal());
sb.append("cordova.callbackFromNative('")
.append(jsPayloadOrCallbackId)
.append("',")
.append(success)
.append(",")
.append(status)
.append(",[");
buildJsMessage(sb);
.append(jsPayloadOrCallbackId)
.append("',")
.append(success)
.append(",")
.append(status)
.append(",[");
switch (pluginResult.getMessageType()) {
case PluginResult.MESSAGE_TYPE_BINARYSTRING:
sb.append("atob('")
.append(pluginResult.getMessage())
.append("')");
break;
case PluginResult.MESSAGE_TYPE_ARRAYBUFFER:
sb.append("cordova.require('cordova/base64').toArrayBuffer('")
.append(pluginResult.getMessage())
.append("')");
break;
default:
sb.append(pluginResult.getMessage());
}
sb.append("],")
.append(pluginResult.getKeepCallback())
.append(");");
.append(pluginResult.getKeepCallback())
.append(");");
}
}
}

View File

@@ -1,87 +0,0 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova;
import java.util.Arrays;
import org.json.JSONException;
import android.content.pm.PackageManager;
/**
* This class provides reflective methods for permission requesting and checking so that plugins
* written for cordova-android 5.0.0+ can still compile with earlier cordova-android versions.
*/
public class PermissionHelper {
private static final String LOG_TAG = "CordovaPermissionHelper";
/**
* Requests a "dangerous" permission for the application at runtime. This is a helper method
* alternative to cordovaInterface.requestPermission() that does not require the project to be
* built with cordova-android 5.0.0+
*
* @param plugin The plugin the permission is being requested for
* @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult()
* along with the result of the permission request
* @param permission The permission to be requested
*/
public static void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {
PermissionHelper.requestPermissions(plugin, requestCode, new String[] {permission});
}
/**
* Requests "dangerous" permissions for the application at runtime. This is a helper method
* alternative to cordovaInterface.requestPermissions() that does not require the project to be
* built with cordova-android 5.0.0+
*
* @param plugin The plugin the permissions are being requested for
* @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult()
* along with the result of the permissions request
* @param permissions The permissions to be requested
*/
public static void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) {
plugin.cordova.requestPermissions(plugin, requestCode, permissions);
}
/**
* Checks at runtime to see if the application has been granted a permission. This is a helper
* method alternative to cordovaInterface.hasPermission() that does not require the project to
* be built with cordova-android 5.0.0+
*
* @param plugin The plugin the permission is being checked against
* @param permission The permission to be checked
*
* @return True if the permission has already been granted and false otherwise
*/
public static boolean hasPermission(CordovaPlugin plugin, String permission) {
return plugin.cordova.hasPermission(permission);
}
private static void deliverPermissionResult(CordovaPlugin plugin, int requestCode, String[] permissions) {
// Generate the request results
int[] requestResults = new int[permissions.length];
Arrays.fill(requestResults, PackageManager.PERMISSION_GRANTED);
try {
plugin.onRequestPermissionResult(requestCode, permissions, requestResults);
} catch (JSONException e) {
LOG.e(LOG_TAG, "JSONException when delivering permissions results", e);
}
}
}

View File

@@ -110,11 +110,7 @@ public class SystemWebViewEngine implements CordovaWebViewEngine {
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() {
@Override
public void setNetworkAvailable(boolean value) {
//sometimes this can be called after calling webview.destroy() on destroy()
//thus resulting in a NullPointerException
if(webView!=null) {
webView.setNetworkAvailable(value);
}
webView.setNetworkAvailable(value);
}
@Override
public void runOnUiThread(Runnable r) {

1
node_modules/abbrev/abbrev.js generated vendored
View File

@@ -1,3 +1,4 @@
module.exports = exports = abbrev.abbrev = abbrev
abbrev.monkeyPatch = monkeyPatch

35
node_modules/abbrev/package.json generated vendored
View File

@@ -10,23 +10,24 @@
"spec": ">=1.0.0 <2.0.0",
"type": "range"
},
"/Users/jbowser/cordova/cordova-android/node_modules/nopt"
"/Users/steveng/repo/cordova/cordova-android/node_modules/nopt"
]
],
"_from": "abbrev@>=1.0.0 <2.0.0",
"_id": "abbrev@1.1.0",
"_id": "abbrev@1.0.9",
"_inCache": true,
"_installable": true,
"_location": "/abbrev",
"_nodeVersion": "8.0.0-pre",
"_nodeVersion": "4.4.4",
"_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com",
"tmp": "tmp/abbrev-1.1.0.tgz_1487054000015_0.9229173036292195"
"host": "packages-16-east.internal.npmjs.com",
"tmp": "tmp/abbrev-1.0.9.tgz_1466016055839_0.7825860097073019"
},
"_npmUser": {
"name": "isaacs",
"email": "i@izs.me"
},
"_npmVersion": "4.3.0",
"_npmVersion": "3.9.1",
"_phantomChildren": {},
"_requested": {
"raw": "abbrev@1",
@@ -38,13 +39,14 @@
"type": "range"
},
"_requiredBy": [
"/istanbul",
"/nopt"
],
"_resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
"_shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f",
"_resolved": "http://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz",
"_shasum": "91b4792588a7738c25f35dd6f63752a2f8776135",
"_shrinkwrap": null,
"_spec": "abbrev@1",
"_where": "/Users/jbowser/cordova/cordova-android/node_modules/nopt",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/nopt",
"author": {
"name": "Isaac Z. Schlueter",
"email": "i@izs.me"
@@ -55,17 +57,17 @@
"dependencies": {},
"description": "Like ruby's abbrev module, but in js",
"devDependencies": {
"tap": "^10.1"
"tap": "^5.7.2"
},
"directories": {},
"dist": {
"shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f",
"tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz"
"shasum": "91b4792588a7738c25f35dd6f63752a2f8776135",
"tarball": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz"
},
"files": [
"abbrev.js"
],
"gitHead": "7136d4d95449dc44115d4f78b80ec907724f64e0",
"gitHead": "c386cd9dbb1d8d7581718c54d4ba944cc9298d6f",
"homepage": "https://github.com/isaacs/abbrev-js#readme",
"license": "ISC",
"main": "abbrev.js",
@@ -83,10 +85,7 @@
"url": "git+ssh://git@github.com/isaacs/abbrev-js.git"
},
"scripts": {
"postpublish": "git push origin --all; git push origin --tags",
"postversion": "npm publish",
"preversion": "npm test",
"test": "tap test.js --100"
"test": "tap test.js --cov"
},
"version": "1.1.0"
"version": "1.0.9"
}

View File

@@ -1,8 +0,0 @@
.git/
node_modules/
coverage/
build/
assets/
dist/
docs/
tests/

View File

@@ -1,28 +0,0 @@
{
"indent": 2,
"forin": true,
"noarg": true,
"bitwise": true,
"nonew": true,
"strict": true,
"browser": true,
"devel": true,
"node": false,
"jquery": false,
"esnext": false,
"moz": false,
"es3": false,
"asi": true,
"eqnull": true,
"debug": true,
"boss": true,
"evil": true,
"loopfunc": true,
"laxbreak": true,
"unused": true,
"undef": true
}

View File

@@ -1,3 +0,0 @@
language: node_js
node_js:
- "6.1.0"

View File

@@ -1,87 +0,0 @@
Android Versions
================
A node module to get Android versions by API level, NDK level, semantic version, or version name.
Versions are referenced from [source.android.com/source/build-numbers.html](https://source.android.com/source/build-numbers.html#platform-code-names-versions-api-levels-and-ndk-releases). The version for "Current Development Build" (`"CUR_DEVELOPMENT"`) is not included in the list of `VERSIONS`.
[![NPM version][npm-image]][npm-url]
[![build status][travis-image]][travis-url]
[npm-image]: https://img.shields.io/npm/v/android-versions.svg?style=flat-square
[npm-url]: https://npmjs.org/package/android-versions
[travis-image]: https://img.shields.io/travis/dvoiss/android-versions.svg?style=flat-square
[travis-url]: https://travis-ci.org/dvoiss/android-versions
## Install
```bash
# NPM
npm install android-versions --save
# YARN
yarn add android-versions
```
## Usage
View the tests for more advanced usage.
```javascript
const android = require('android-versions')
```
#### Get by API level:
```javascript
console.log(android.get(23))
=> { api: 23, ndk: 8, semver: "6.0", name: "Marshmallow", versionCode: "M" }
```
#### Get by version:
```javascript
console.log(android.get("2.3.3"))
=> { api: 10, ndk: 5, semver: "2.3.3", name: "Gingerbread", versionCode: "GINGERBREAD_MR1" }
```
#### Get all by predicate:
```
android.getAll((version) => {
return version.ndk > 5 && version.api < 15
}).map((version) => version.versionCode)
=> [ "HONEYCOMB_MR1", "HONEYCOMB_MR2", "ICE_CREAM_SANDWICH" ]
```
#### Access a specific version with all info:
```
android.LOLLIPOP
=> { api: 21, ndk: 8, semver: "5.0", name: "Lollipop", versionCode: "LOLLIPOP" }
```
#### Access the complete reference of Android versions with all info:
```javascript
android.VERSIONS
=> {
BASE: { api: 1, ndk: 0, semver: "1.0", name: "(no code name)", versionCode: "BASE" },
...
N: { api: 24, ndk: 8, semver: "7.0", name: "Nougat", versionCode: "N" }
...
}
```
## Test
```bash
npm run test
```
## License
MIT

View File

@@ -1,153 +0,0 @@
/**
* Copyright (c) 2016, David Voiss <davidvoiss@gmail.com>
*
* Permission to use, copy, modify, and/or distribute this software for any purpose
* with or without fee is hereby granted, provided that the above copyright notice
* and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* THIS SOFTWARE.
*/
/* jshint node: true */
"use strict";
/**
* A module to get Android versions by API level, NDK level, semantic version, or version name.
*
* Versions are referenced from here:
* {@link https://source.android.com/source/build-numbers.html#platform-code-names-versions-api-levels-and-ndk-releases}
* {@link https://github.com/android/platform_frameworks_base/blob/master/core/java/android/os/Build.java}
*
* The version for "Current Development Build" ("CUR_DEVELOPMENT") is not included.
*
* @module android-versions
*/
var VERSIONS = {
BASE: { api: 1, ndk: 0, semver: "1.0", name: "(no code name)", versionCode: "BASE" },
BASE_1_1: { api: 2, ndk: 0, semver: "1.1", name: "(no code name)", versionCode: "BASE_1_1" },
CUPCAKE: { api: 3, ndk: 1, semver: "1.5", name: "Cupcake", versionCode: "CUPCAKE" },
DONUT: { api: 4, ndk: 2, semver: "1.6", name: "Donut", versionCode: "DONUT" },
ECLAIR: { api: 5, ndk: 2, semver: "2.0", name: "Eclair", versionCode: "ECLAIR" },
ECLAIR_0_1: { api: 6, ndk: 2, semver: "2.0.1", name: "Eclair", versionCode: "ECLAIR_0_1" },
ECLAIR_MR1: { api: 7, ndk: 3, semver: "2.1", name: "Eclair", versionCode: "ECLAIR_MR1" },
FROYO: { api: 8, ndk: 4, semver: "2.2", name: "Froyo", versionCode: "FROYO" },
GINGERBREAD: { api: 9, ndk: 5, semver: "2.3", name: "Gingerbread", versionCode: "GINGERBREAD" },
GINGERBREAD_MR1: { api: 10, ndk: 5, semver: "2.3.3", name: "Gingerbread", versionCode: "GINGERBREAD_MR1" },
HONEYCOMB: { api: 11, ndk: 5, semver: "3.0", name: "Honeycomb", versionCode: "HONEYCOMB" },
HONEYCOMB_MR1: { api: 12, ndk: 6, semver: "3.1", name: "Honeycomb", versionCode: "HONEYCOMB_MR1" },
HONEYCOMB_MR2: { api: 13, ndk: 6, semver: "3.2", name: "Honeycomb", versionCode: "HONEYCOMB_MR2" },
ICE_CREAM_SANDWICH: { api: 14, ndk: 7, semver: "4.0", name: "Ice Cream Sandwich", versionCode: "ICE_CREAM_SANDWICH" },
ICE_CREAM_SANDWICH_MR1: { api: 15, ndk: 8, semver: "4.0.3", name: "Ice Cream Sandwich", versionCode: "ICE_CREAM_SANDWICH_MR1" },
JELLY_BEAN: { api: 16, ndk: 8, semver: "4.1", name: "Jellybean", versionCode: "JELLY_BEAN" },
JELLY_BEAN_MR1: { api: 17, ndk: 8, semver: "4.2", name: "Jellybean", versionCode: "JELLY_BEAN_MR1" },
JELLY_BEAN_MR2: { api: 18, ndk: 8, semver: "4.3", name: "Jellybean", versionCode: "JELLY_BEAN_MR2" },
KITKAT: { api: 19, ndk: 8, semver: "4.4", name: "KitKat", versionCode: "KITKAT" },
KITKAT_WATCH: { api: 20, ndk: 8, semver: "4.4", name: "KitKat Watch", versionCode: "KITKAT_WATCH" },
LOLLIPOP: { api: 21, ndk: 8, semver: "5.0", name: "Lollipop", versionCode: "LOLLIPOP" },
LOLLIPOP_MR1: { api: 22, ndk: 8, semver: "5.1", name: "Lollipop", versionCode: "LOLLIPOP_MR1" },
M: { api: 23, ndk: 8, semver: "6.0", name: "Marshmallow", versionCode: "M" },
N: { api: 24, ndk: 8, semver: "7.0", name: "Nougat", versionCode: "N" },
N_MR1: { api: 25, ndk: 8, semver: "7.1", name: "Nougat", versionCode: "N_MR1" },
O: { api: 26, ndk: 8, semver: "8.0.0", name: "Oreo", versionCode: "O" }
}
// This altSemVer accomodates the variations of semantic versions in the table above.
// For instance, Oreo is 8.0.0 while N is 7.0, searching for "8.0" or "8.0.0" will
// return Oreo, or searching for "7.0" or "7.0.0" will return N. "2.2.0" will return Froyo.
function getAlternateSemVer(semver) {
if (semver.match(/\d+.\d+.0/)) {
return semver.replace(/.\d+$/, '')
} else if (semver.match(/^\d+.\d+$/)) {
return semver + '.0'
} else {
return semver
}
}
// The default predicate compares against API level, semver, name, or code.
function getFromDefaultPredicate(arg) {
// Coerce arg to string for comparisons below.
arg = arg.toString()
return getFromPredicate(function(version) {
// Check API level before all else.
if (arg === version.api.toString()) {
return true
}
// Compare semver and alternate semver (see above).
var altSemVer = getAlternateSemVer(arg)
if (version.semver === arg || version.semver === altSemVer) {
return true
}
// Compare version name and code.
return arg === version.name || arg === version.versionCode
})
}
// The function to allow passing a predicate.
function getFromPredicate(predicate) {
if (predicate === null) {
return null
}
return Object.keys(VERSIONS).filter(function(version) {
return predicate(VERSIONS[version])
}).map(function(key) { return VERSIONS[key] })
}
/**
* The Android version codes available as keys for easier look-up.
*/
Object.keys(VERSIONS).forEach(function(name) {
exports[name] = VERSIONS[name]
})
/**
* The complete reference of Android versions for easier look-up.
*/
exports.VERSIONS = VERSIONS
/**
* Retrieve a single Android version.
*
* @param {object | Function} arg - The value or predicate to use to retrieve values.
*
* @return {object} An object representing the version found or null if none found.
*/
exports.get = function(arg) {
var result = exports.getAll(arg)
if (result === null || result.length === 0) {
return null
}
return result[0]
}
/**
* Retrieve all Android versions that meet the criteria of the argument.
*
* @param {object | Function} arg - The value or predicate to use to retrieve values.
*
* @return {object} An object representing the version found or null if none found.
*/
exports.getAll = function(arg) {
if (arg === null) {
return null
}
if (typeof arg === "function") {
return getFromPredicate(arg)
} else {
return getFromDefaultPredicate(arg)
}
}

View File

@@ -1,103 +0,0 @@
{
"_args": [
[
{
"raw": "android-versions@^1.2.0",
"scope": null,
"escapedName": "android-versions",
"name": "android-versions",
"rawSpec": "^1.2.0",
"spec": ">=1.2.0 <2.0.0",
"type": "range"
},
"/Users/jbowser/cordova/cordova-android"
]
],
"_from": "android-versions@>=1.2.0 <2.0.0",
"_id": "android-versions@1.2.1",
"_inCache": true,
"_location": "/android-versions",
"_nodeVersion": "8.0.0",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/android-versions-1.2.1.tgz_1505373302036_0.5689644906669855"
},
"_npmUser": {
"name": "dvoiss",
"email": "davidvoiss@gmail.com"
},
"_npmVersion": "5.4.0",
"_phantomChildren": {},
"_requested": {
"raw": "android-versions@^1.2.0",
"scope": null,
"escapedName": "android-versions",
"name": "android-versions",
"rawSpec": "^1.2.0",
"spec": ">=1.2.0 <2.0.0",
"type": "range"
},
"_requiredBy": [
"/"
],
"_resolved": "https://registry.npmjs.org/android-versions/-/android-versions-1.2.1.tgz",
"_shasum": "3f50baf693e73a512c3c5403542291cead900063",
"_shrinkwrap": null,
"_spec": "android-versions@^1.2.0",
"_where": "/Users/jbowser/cordova/cordova-android",
"author": {
"name": "dvoiss"
},
"bugs": {
"url": "https://github.com/dvoiss/android-versions/issues"
},
"dependencies": {},
"description": "Get the name, API level, version level, NDK level, or version code from any version of Android.",
"devDependencies": {
"jsdoc": "^3.4.0",
"jshint": "^2.9.2",
"tape": "^4.6.0"
},
"directories": {},
"dist": {
"integrity": "sha512-k6zlrtWbJ3tx1ZsyyJ0Bo3r6cqPA3JUnFGv7pnIaLr1XVxSi2Tcem2lg3kBebFp27v/A40tZqdlouPyakpyKrw==",
"shasum": "3f50baf693e73a512c3c5403542291cead900063",
"tarball": "https://registry.npmjs.org/android-versions/-/android-versions-1.2.1.tgz"
},
"gitHead": "7e2def6e70634a4ebcaaa639a4c4955ae2a566e7",
"homepage": "https://github.com/dvoiss/android-versions#readme",
"keywords": [
"android",
"version",
"versions",
"ndk",
"nougat",
"marshmallow",
"api",
"level"
],
"license": "MIT",
"main": "index.js",
"maintainers": [
{
"name": "dvoiss",
"email": "davidvoiss@gmail.com"
}
],
"name": "android-versions",
"optionalDependencies": {},
"pre-commit": [
"jshint"
],
"readme": "ERROR: No README data found!",
"repository": {
"type": "git",
"url": "git+https://github.com/dvoiss/android-versions.git"
},
"scripts": {
"docs": "jsdoc index.js -d ./docs/ -R README.md --debug",
"jshint": "jshint .",
"test": "tape tests/**/*.js"
},
"version": "1.2.1"
}

7
node_modules/ansi/package.json generated vendored
View File

@@ -10,12 +10,13 @@
"spec": ">=0.3.1 <0.4.0",
"type": "range"
},
"/Users/jbowser/cordova/cordova-android/node_modules/cordova-common"
"/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common"
]
],
"_from": "ansi@>=0.3.1 <0.4.0",
"_id": "ansi@0.3.1",
"_inCache": true,
"_installable": true,
"_location": "/ansi",
"_nodeVersion": "5.3.0",
"_npmUser": {
@@ -36,11 +37,11 @@
"_requiredBy": [
"/cordova-common"
],
"_resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz",
"_resolved": "http://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz",
"_shasum": "0c42d4fb17160d5a9af1e484bace1c66922c1b21",
"_shrinkwrap": null,
"_spec": "ansi@^0.3.1",
"_where": "/Users/jbowser/cordova/cordova-android/node_modules/cordova-common",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common",
"author": {
"name": "Nathan Rajlich",
"email": "nathan@tootallnate.net",

View File

@@ -1,4 +1,3 @@
'use strict';
module.exports = balanced;
function balanced(a, b, str) {
if (a instanceof RegExp) a = maybeMatch(a, str);

View File

@@ -2,49 +2,50 @@
"_args": [
[
{
"raw": "balanced-match@^1.0.0",
"raw": "balanced-match@^0.4.1",
"scope": null,
"escapedName": "balanced-match",
"name": "balanced-match",
"rawSpec": "^1.0.0",
"spec": ">=1.0.0 <2.0.0",
"rawSpec": "^0.4.1",
"spec": ">=0.4.1 <0.5.0",
"type": "range"
},
"/Users/jbowser/cordova/cordova-android/node_modules/brace-expansion"
"/Users/steveng/repo/cordova/cordova-android/node_modules/brace-expansion"
]
],
"_from": "balanced-match@>=1.0.0 <2.0.0",
"_id": "balanced-match@1.0.0",
"_from": "balanced-match@>=0.4.1 <0.5.0",
"_id": "balanced-match@0.4.2",
"_inCache": true,
"_installable": true,
"_location": "/balanced-match",
"_nodeVersion": "7.8.0",
"_nodeVersion": "4.4.7",
"_npmOperationalInternal": {
"host": "s3://npm-registry-packages",
"tmp": "tmp/balanced-match-1.0.0.tgz_1497251909645_0.8755026108119637"
"host": "packages-16-east.internal.npmjs.com",
"tmp": "tmp/balanced-match-0.4.2.tgz_1468834991581_0.6590619895141572"
},
"_npmUser": {
"name": "juliangruber",
"email": "julian@juliangruber.com"
},
"_npmVersion": "4.2.0",
"_npmVersion": "2.15.8",
"_phantomChildren": {},
"_requested": {
"raw": "balanced-match@^1.0.0",
"raw": "balanced-match@^0.4.1",
"scope": null,
"escapedName": "balanced-match",
"name": "balanced-match",
"rawSpec": "^1.0.0",
"spec": ">=1.0.0 <2.0.0",
"rawSpec": "^0.4.1",
"spec": ">=0.4.1 <0.5.0",
"type": "range"
},
"_requiredBy": [
"/brace-expansion"
],
"_resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"_shasum": "89b4d199ab2bee49de164ea02b89ce462d71b767",
"_resolved": "http://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
"_shasum": "cb3f3e3c732dc0f01ee70b403f302e61d7709838",
"_shrinkwrap": null,
"_spec": "balanced-match@^1.0.0",
"_where": "/Users/jbowser/cordova/cordova-android/node_modules/brace-expansion",
"_spec": "balanced-match@^0.4.1",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/brace-expansion",
"author": {
"name": "Julian Gruber",
"email": "mail@juliangruber.com",
@@ -56,15 +57,14 @@
"dependencies": {},
"description": "Match balanced character pairs, like \"{\" and \"}\"",
"devDependencies": {
"matcha": "^0.7.0",
"tape": "^4.6.0"
},
"directories": {},
"dist": {
"shasum": "89b4d199ab2bee49de164ea02b89ce462d71b767",
"tarball": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz"
"shasum": "cb3f3e3c732dc0f01ee70b403f302e61d7709838",
"tarball": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz"
},
"gitHead": "d701a549a7653a874eebce7eca25d3577dc868ac",
"gitHead": "57c2ea29d89a2844ae3bdcc637c6e2cbb73725e2",
"homepage": "https://github.com/juliangruber/balanced-match",
"keywords": [
"match",
@@ -89,7 +89,6 @@
"url": "git://github.com/juliangruber/balanced-match.git"
},
"scripts": {
"bench": "make bench",
"test": "make test"
},
"testling": {
@@ -108,5 +107,5 @@
"android-browser/4.2..latest"
]
},
"version": "1.0.0"
"version": "0.4.2"
}

View File

@@ -10,12 +10,13 @@
"spec": "0.0.8",
"type": "version"
},
"/Users/jbowser/cordova/cordova-android/node_modules/plist"
"/Users/steveng/repo/cordova/cordova-android/node_modules/plist"
]
],
"_from": "base64-js@0.0.8",
"_id": "base64-js@0.0.8",
"_inCache": true,
"_installable": true,
"_location": "/base64-js",
"_nodeVersion": "0.10.35",
"_npmUser": {
@@ -36,11 +37,11 @@
"_requiredBy": [
"/plist"
],
"_resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
"_resolved": "http://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
"_shasum": "1101e9544f4a76b1bc3b26d452ca96d7a35e7978",
"_shrinkwrap": null,
"_spec": "base64-js@0.0.8",
"_where": "/Users/jbowser/cordova/cordova-android/node_modules/plist",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/plist",
"author": {
"name": "T. Jameson Little",
"email": "t.jameson.little@gmail.com"

17
node_modules/big-integer/.npmignore generated vendored Normal file
View File

@@ -0,0 +1,17 @@
/.travis.yml
/.npmignore
/.gitignore
/spec
/benchmark
/big-integer*.tgz
/my.conf.js
/node_modules
/*.csproj*
/*.sh
/*.suo
/bin
/coverage
/*.bat
/obj
/Properties
/Web.*

File diff suppressed because it is too large Load Diff

View File

@@ -118,7 +118,7 @@ var bigInt = (function (undefined) {
}
BigInteger.prototype.add = function (v) {
var n = parseValue(v);
var value, n = parseValue(v);
if (this.sign !== n.sign) {
return this.subtract(n.negate());
}
@@ -177,7 +177,7 @@ var bigInt = (function (undefined) {
}
function subtractAny(a, b, sign) {
var value;
var value, isSmall;
if (compareAbs(a, b) >= 0) {
value = subtract(a,b);
} else {
@@ -326,7 +326,7 @@ var bigInt = (function (undefined) {
}
BigInteger.prototype.multiply = function (v) {
var n = parseValue(v),
var value, n = parseValue(v),
a = this.value, b = n.value,
sign = this.sign !== n.sign,
abs;
@@ -467,7 +467,6 @@ var bigInt = (function (undefined) {
guess, xlen, highx, highy, check;
while (a_l) {
part.unshift(a[--a_l]);
trim(part);
if (compareAbs(part, b) < 0) {
result.push(0);
continue;
@@ -826,24 +825,19 @@ var bigInt = (function (undefined) {
BigInteger.prototype.modInv = function (n) {
var t = bigInt.zero, newT = bigInt.one, r = parseValue(n), newR = this.abs(), q, lastT, lastR;
while (!newR.equals(bigInt.zero)) {
q = r.divide(newR);
lastT = t;
lastR = r;
t = newT;
r = newR;
newT = lastT.subtract(q.multiply(newT));
newR = lastR.subtract(q.multiply(newR));
q = r.divide(newR);
lastT = t;
lastR = r;
t = newT;
r = newR;
newT = lastT.subtract(q.multiply(newT));
newR = lastR.subtract(q.multiply(newR));
}
if (!r.equals(1)) throw new Error(this.toString() + " and " + n.toString() + " are not co-prime");
if (t.compare(0) === -1) {
t = t.add(n);
}
if (this.isNegative()) {
return t.negate();
t = t.add(n);
}
return t;
};
}
SmallInteger.prototype.modInv = BigInteger.prototype.modInv;
BigInteger.prototype.next = function () {
@@ -982,7 +976,7 @@ var bigInt = (function (undefined) {
b = parseValue(b);
return a.greater(b) ? a : b;
}
function min(a, b) {
function min(a,b) {
a = parseValue(a);
b = parseValue(b);
return a.lesser(b) ? a : b;
@@ -1037,32 +1031,16 @@ var bigInt = (function (undefined) {
return low.add(typeof result === "number" ? new SmallInteger(result) : new BigInteger(result, false));
}
var parseBase = function (text, base) {
var length = text.length;
var i;
var absBase = Math.abs(base);
for(var i = 0; i < length; i++) {
var c = text[i].toLowerCase();
if(c === "-") continue;
if(/[a-z0-9]/.test(c)) {
if(/[0-9]/.test(c) && +c >= absBase) {
if(c === "1" && absBase === 1) continue;
throw new Error(c + " is not a valid digit in base " + base + ".");
} else if(c.charCodeAt(0) - 87 >= absBase) {
throw new Error(c + " is not a valid digit in base " + base + ".");
}
}
}
var val = Integer[0], pow = Integer[1],
length = text.length;
if (2 <= base && base <= 36) {
if (length <= LOG_MAX_INT / Math.log(base)) {
var result = parseInt(text, base);
if(isNaN(result)) {
throw new Error(c + " is not a valid digit in base " + base + ".");
}
return new SmallInteger(parseInt(text, base));
}
}
base = parseValue(base);
var digits = [];
var i;
var isNegative = text[0] === "-";
for (i = isNegative ? 1 : 0; i < text.length; i++) {
var c = text[i].toLowerCase(),
@@ -1076,17 +1054,13 @@ var bigInt = (function (undefined) {
}
else throw new Error(c + " is not a valid character");
}
return parseBaseFromArray(digits, base, isNegative);
};
function parseBaseFromArray(digits, base, isNegative) {
var val = Integer[0], pow = Integer[1], i;
for (i = digits.length - 1; i >= 0; i--) {
digits.reverse();
for (i = 0; i < digits.length; i++) {
val = val.add(digits[i].times(pow));
pow = pow.times(base);
}
return isNegative ? val.negate() : val;
}
};
function stringify(digit) {
var v = digit.value;
@@ -1143,13 +1117,11 @@ var bigInt = (function (undefined) {
var sign = this.sign ? "-" : "";
return sign + str;
};
SmallInteger.prototype.toString = function (radix) {
if (radix === undefined) radix = 10;
if (radix != 10) return toBase(this, radix);
return String(this.value);
};
BigInteger.prototype.toJSON = SmallInteger.prototype.toJSON = function() { return this.toString(); }
BigInteger.prototype.valueOf = function () {
return +this.toString();
@@ -1232,11 +1204,6 @@ var bigInt = (function (undefined) {
Integer.lcm = lcm;
Integer.isInstance = function (x) { return x instanceof BigInteger || x instanceof SmallInteger; };
Integer.randBetween = randBetween;
Integer.fromArray = function (digits, base, isNegative) {
return parseBaseFromArray(digits.map(parseValue), parseValue(base || 10), isNegative);
};
return Integer;
})();
@@ -1244,10 +1211,3 @@ var bigInt = (function (undefined) {
if (typeof module !== "undefined" && module.hasOwnProperty("exports")) {
module.exports = bigInt;
}
//amd check
if ( typeof define === "function" && define.amd ) {
define( "big-integer", [], function() {
return bigInt;
});
}

File diff suppressed because one or more lines are too long

24
node_modules/big-integer/LICENSE generated vendored
View File

@@ -1,24 +0,0 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <http://unlicense.org>

11
node_modules/big-integer/README.md generated vendored
View File

@@ -211,7 +211,7 @@ Returns `true` if the number is prime, `false` otherwise.
#### `isProbablePrime([iterations])`
Returns `true` if the number is very likely to be prime, `false` otherwise.
Returns `true` if the number is very likely to be positive, `false` otherwise.
Argument is optional and determines the amount of iterations of the test (default: `5`). The more iterations, the lower chance of getting a false positive.
This uses the [Fermat primality test](https://en.wikipedia.org/wiki/Fermat_primality_test).
@@ -421,13 +421,6 @@ Performs the bitwise XOR operation. The operands are treated as if they were rep
### Static Methods
#### `fromArray(digits, base = 10, isNegative?)`
Constructs a bigInt from an array of digits in base `base`. The optional `isNegative` flag will make the number negative.
- `bigInt.fromArray([1, 2, 3, 4, 5], 10)` => `12345`
- `bigInt.fromArray([1, 0, 0], 2, true)` => `-4`
#### `gcd(a, b)`
Finds the greatest common denominator of `a` and `b`.
@@ -517,4 +510,4 @@ There are performance benchmarks that can be viewed from the `benchmarks/index.h
## License
This project is public domain. For more details, read about the [Unlicense](http://unlicense.org/).
This project is public domain. For more details, read about the [Unlicense](http://unlicense.org/).

View File

@@ -24,6 +24,7 @@
"bower_components",
"test",
"coverage",
"spec",
"tests"
]
}

Some files were not shown because too many files have changed in this diff Show More