Compare commits

..

100 Commits

Author SHA1 Message Date
Joe Bowser c0c3b769f2 A git conflict slipped into the repo, fixing 2017-11-29 11:38:14 -08:00
Joe Bowser fae39dd2e5 Merge branch 'master' into 6.4.x
Merging all non-StudioProjectCompat work into the 6.4.x branch for
possible 6.x, or 6.4.x work in the future.
2017-11-28 10:39:54 -08:00
Joe Bowser 3ad1ed7dbc Merge pull request #418 from dpogue/splash-compress
CB-13610: Compress the default app assets
2017-11-28 10:35:04 -08:00
Joe Bowser ae823e6c4e Merge pull request #385 from dreifachstein/master
CB-12835: add a Context getter in CordovaInterface
2017-11-28 10:34:19 -08:00
Darryl Pogue 9056e5a2dc CB-13610: Compress the default app assets 2017-11-27 22:46:02 -08:00
Joe Bowser a972d1ef62 Merge pull request #401 from fabulant/CB-8976
CB-8976: Added the `cdvVersionCodeForceAbiDigit` property
2017-11-27 14:02:20 -08:00
Joe Bowser 6f58d4c474 Merge pull request #352 from Icenium/include-armeabi-dir
CB-12291: (android) Add x86_64, arm64 and armeabi architecture flavors
2017-11-27 11:35:47 -08:00
Joe Bowser 6404780186 Merge pull request #417 from DavidStrausz/master
CB-13580: (android) fix build for multiple apks (different product flavors)
2017-11-16 10:13:50 -08:00
David Strauß 5d99e50c4a CB-13580: (android) fix lint errors 2017-11-16 01:54:04 +01:00
David Strauß aaeb630eb1 CB-13580: fix build for multiple apks (different product flavors) 2017-11-16 01:27:20 +01:00
Joe Bowser 3760616639 Merge pull request #416 from infil00p/bintray_fix
CB-13558: Upgrading the gradle so we can upload the AAR
2017-11-15 10:42:00 -08:00
Joe Bowser 026dce563b CB-13558: Upgrading the gradle so we can upload the AAR 2017-11-09 11:14:47 -08:00
Joe Bowser 83601dca2f Update JS snapshot to version 6.5.0-dev (via coho) 2017-11-06 11:44:23 -08:00
Joe Bowser 7a27ee4f69 Set VERSION to 6.4.0 (via coho) 2017-11-06 11:44:20 -08:00
Joe Bowser 05aeaf1bd2 Set VERSION to 6.5.0-dev (via coho) 2017-11-06 11:44:20 -08:00
Joe Bowser cc13413007 Update JS snapshot to version 6.4.0 (via coho) 2017-11-06 11:44:19 -08:00
Joe Bowser b138867b78 CB-13528 Updated RELEASENOTES and Version for release 6.4.0 2017-11-06 11:43:47 -08:00
Joe Bowser a1195cefd5 Merge pull request #415 from infil00p/CB-13530
CB-13530: Fix the utility method for finding the built APK for generic APKs
2017-11-03 16:50:32 -07:00
Joe Bowser b83c3b3684 CB-13530: Removing debug console.logs 2017-11-02 14:45:51 -07:00
Joe Bowser 5502ddaf0d CB-13530: This fixes the basic APK installation 2017-11-02 14:42:39 -07:00
Joe Bowser 39e6765e64 Merge pull request #413 from infil00p/StudioThreeFix
CB-13289: This fixes the Cordova-Android build on cordova-android 6.x
2017-11-01 10:26:53 -07:00
Joe Bowser 47e20da631 CB-13289: Updating Travis and appveyor 2017-10-31 10:48:19 -07:00
Audrey bb7b47b063 Merge pull request #414 from audreyso/CB-13501
CB-13501 : update appveyor to support node 8
2017-10-30 16:11:50 -07:00
Joe Bowser a2618dcde5 CB-13289: eslint fix 2017-10-30 13:17:18 -07:00
Joe Bowser 9fdb126715 CB-13289: Fixing build problems with Studio Three, but keeping Windows Gradle fix for now, will be deprecated 2017-10-30 10:39:59 -07:00
Audrey So b2a81c09ec :CB-13501 : update appveyor node versions to support node 8 2017-10-30 10:01:50 -07:00
Jan Piotrowski 04fa5d3feb CB-13499: Remove duplicate "setting" in error strings 2017-10-26 22:28:38 +02:00
Joe Bowser d73108cc13 CB-13289: Fix test to work with new Google Android Gradle DSL 2017-10-25 11:38:07 -07:00
Joe Bowser 93efe71080 Merge pull request #411 from Keyclic/master
CB-12802: (android) Fix build.gradle to sign when building with multiple APK is enable.
2017-10-16 11:23:29 -07:00
Joe Bowser 697c8f129c Merge pull request #410 from filmaj/emu-fixes
CB-13404, CB-13406: `best_image` function fixes when choosing emulator images to deploy to
2017-10-16 10:37:30 -07:00
Joe Bowser c12f7fef76 Close #379 2017-10-13 11:08:01 -07:00
Kevin cde238de94 Include missing values for task.name when 'cdvBuildMultipleApks' option is true, 'task.name' can have 'validateSigningArmv7Release' or 'validateSigningX86Release' values too. 2017-10-09 09:17:40 +02:00
filmaj ec83d481fa CB-13406: Fixed AVD API level comparison when choosing sub-par API level match. Added tests for the best_image method. 2017-10-05 15:18:42 -05:00
filmaj 1f12fdbeea CB-13404: add android-versions to bundledDependencies. Ignore best emulator selection when parsed AVD information does not include API level in the target 2017-10-05 15:17:31 -05:00
Audrey 6fa16b615b Merge pull request #408 from audreyso/CB-12895-eslint
CB-12895 : eslint ignoring cordova.js
2017-09-28 08:47:50 -07:00
Audrey So e5c90badba CB-12895 : eslint ignoring cordova.js 2017-09-26 17:15:30 -07:00
Joe Bowser be6c6ba976 CB-12895: Temporarily disabling eslint since cordova-js does not have eslint yet. 2017-09-25 14:00:38 -07:00
Joe Bowser 7f3be98199 Update JS snapshot to version 6.4.0-dev (via coho) 2017-09-25 11:37:52 -07:00
Joe Bowser 0e498db735 Set VERSION to 6.4.0-dev (via coho) 2017-09-25 11:37:51 -07:00
Joe Bowser 7203b740fd CB-13323 Updated RELEASENOTES and Version for release 6.3.0 2017-09-25 11:35:59 -07:00
Joe Bowser 97aab900da CB-13323 Updated checked-in node_modules 2017-09-25 11:17:24 -07:00
Joe Bowser dddb2837dd CB-6936: Merge pull request #304 from uareurapid/master
CB-6936: fix crash when calling methods on a destroyed webview
2017-09-15 13:26:21 -07:00
filmaj 1637937664 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. 2017-09-14 11:26:18 -07:00
filmaj 03144eb160 Add a node and npm package.json script for running java unit tests. Include them in the top-level npm test script. Run java unit tests in travis. Small refactor in gradlebuilder to support building gradle wrapper more easily. Don't explicitly build gradlew on appveyor CI as now npm test will do it for you. 2017-09-14 09:57:37 -07:00
Joe Bowser 53210710ba Merge pull request #404 from mediathand/maven-repo-fix
Update maven repo to include most recent lib versions
2017-09-11 10:04:48 -07:00
Steve Gill e7a972df77 updated bundled node_modules 2017-09-05 11:04:12 -07:00
Gil Pedersen cb2f396e33 Update maven repo to include most recent lib versions 2017-08-29 17:27:02 +02:00
Martin Bektchiev 2940d05209 CB-12291: (android) Add x86_64, arm64 and armeabi architecture flavors 2017-08-16 09:35:33 +03:00
Joe Bowser 2377aa7ac2 Merge pull request #403 from infil00p/api26
CB-13177: Updating to API Level 26
2017-08-15 14:17:09 -07:00
Joe Bowser dce3b7ed6c Merge pull request #402 from macdonst/master
Revert CB-12015: initial-scale values less than 1.0 are ignored on Android
2017-08-15 13:22:22 -07:00
Simon MacDonald 5bda4df7fa Revert CB-12015: initial-scale values less than 1.0 are ignored on Android 2017-08-14 20:57:44 -04:00
Joe Bowser 1a8e36ccd3 CB-13177: Updating to API Level 26 2017-08-14 11:41:46 -07:00
Simon MacDonald 14816c7c81 Merge pull request #399 from macdonst/CB-12730
CB-12730: Compat - INTEGRATE
2017-08-11 10:38:06 -04:00
Fabian Eichinger 940439866e CB-8976: Added the cdvVersionCodeForceAbiDigit flag to the template build.gradle that appends 0 to the versionCode when cdvBuildMultipleApks is not set 2017-08-04 18:28:06 +02:00
Simon MacDonald d364f46baa CB-12730: Compat - INTEGRATE 2017-07-28 08:56:19 -04:00
Nikita Matrosov 2b53c98cf5 CB-12453: Remove unnecessary double quotes from .bat files which are the causes of crash if project path contains spaces
this closes #362
2017-07-28 14:23:53 +03:00
Nikita Matrosov 36d07d7a15 CB-13031: Fix bug with case-sensitivity of android-packageName
this closes #397
2017-07-28 14:05:53 +03:00
filmaj 458e479681 Trying AppVeyor-supplied workaround for current appveyor time out issues. See http://help.appveyor.com/discussions/problems/7159-builds-timing-out-after-an-hour 2017-07-27 14:33:16 -07:00
filmaj c3ce2f8a07 Closes #398 2017-07-24 10:11:21 -07:00
Joe Bowser 893356abcd CB-13034: Fixing eslint error 2017-07-18 14:13:53 -07:00
Darryl Pogue 22645d9158 [CB-10916] Support display name for Android 2017-07-14 17:37:15 -02:30
filmaj 76dd8613ca CB-12423: make explicit JDK 1.8 or greater is needed in the README. 2017-07-14 11:13:52 -05:00
filmaj 5917d4ef0b 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. 2017-07-11 12:54:15 -05:00
filmaj 90053eb9df 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.
2017-06-27 15:59:16 -05:00
Nikita Matrosov 540929c6a0 CB-9971: Suppressed unwanted java stderr output when running gradle wrapper
this closes #388
2017-06-26 21:17:58 +03:00
filmaj 3ff32092a3 CB-12954 🔪 remove jshint leftovers 2017-06-26 12:26:53 -05:00
Audrey So 55d7cf3865 CB-12895 : updated .eslintrc file in spec dir and set jasmine true and removed root is true 2017-06-23 08:44:08 -07:00
Audrey So ac4ac935f6 CB-12895 : added .eslintrc files to set up jasmine environment 2017-06-23 08:07:08 -07:00
Audrey So d83d49d83b CB-12895 : fixed eslint errors 2017-06-23 08:07:08 -07:00
Audrey So e36158a0da CB-12895 : added eslint and removed jshint 2017-06-23 08:07:07 -07:00
Jesse MacFadyen 5cc14b8031 CB-12605 In Windows get Android studio path from the registry
This closes #387
2017-06-22 10:55:39 -07:00
Xiaolei Yu 17906735df CB-12835: add a Context getter in CordovaInterface
A custom engine may live outside of the Activity's lifecycle and the
Activity instance may not always be available. This getter allows
Context accesses in all cases.
2017-06-11 17:51:19 +08:00
Audrey So 3a6e898b12 CB-12762 : pointed package.json repo items to github mirrors instead of apache repos site
This closes #383
2017-06-07 09:28:22 -07:00
filmaj 0cc3df3747 CB-12859: document how to run the native tests. add a README to the test/ project. 2017-06-06 14:37:57 -05:00
Joe Bowser 2bc842a2b3 This commit should exist on the Crosswalk Plugin, Close #357 2017-05-29 13:04:17 -07:00
Joe Bowser 1c6f640026 Commit already merged, Close #378 2017-05-29 13:02:35 -07:00
Joe Bowser 6daad829cc Close #283 2017-05-29 09:53:49 -07:00
Darryl Pogue 7d926822ed CB-8980: Ensure copied resource-files are cleaned
This closes #377
2017-05-25 16:11:20 -07:00
Audrey So d4dcbb13fc CB-12617 : removed node0.x support for platforms and added engineStrict
This closes #372
2017-05-25 14:09:55 -07:00
filmaj f396712f59 CB-12847: added bugs entry to package.json. 2017-05-24 00:54:03 +02:00
filmaj d97250f968 Update JS snapshot to version 6.3.0-dev (via coho) 2017-05-02 16:19:21 -07:00
filmaj e7e8e95242 Set VERSION to 6.3.0-dev (via coho) 2017-05-02 16:19:19 -07:00
filmaj d518a655a8 CB-12746: updated release notes for impending 6.2.3 release, since some of the reported changes did not make it into 6.2.2. 2017-05-02 16:04:20 -07:00
filmaj b6a5844027 CB-12746: decrement working dev version on master to 6.2.4-dev, to align with impending patch release. 2017-05-02 16:04:20 -07:00
filmaj 9d9abea157 Start of GradleBuilder.js specs - puts it on the code coverage radar. 2017-05-02 15:31:26 -07:00
Simon MacDonald ee1165ea33 CB-12015: initial-scale values less than 1.0 are ignored on Android
This closes #376
2017-05-01 11:20:25 -07:00
Joe Bowser 2704ee54cf This closes #374 2017-05-01 10:51:50 -07:00
Steve Gill ad01d28351 Set VERSION to 6.3.0-dev (via coho) 2017-04-24 22:05:43 -07:00
Steve Gill a215c1cf30 CB-12697 Updated RELEASENOTES and Version for release 6.2.2 2017-04-24 22:04:56 -07:00
Steve Gill cadea2f6c3 CB-12697 Updated checked-in node_modules 2017-04-24 21:56:28 -07:00
filmaj e13e15d3e9 CB-12640: better handling of unrecognized commands on windows. removed error checking in emulator image listing when shelling out, as we already defensively dont shell out if the program is not on the PATH / not recognized. added additional test for windows unrecognized command errors for target listing. fixed up spying in a test. 2017-04-10 12:12:46 -07:00
filmaj 6ef2f67ae8 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 2017-04-10 12:12:46 -07:00
filmaj 765c4ee9f6 CB-12640: support for android sdk tools 26.0.1. simplified target parsing by using avdmanager instead of sdkmanager. flipped target parsing logic so that it always tries to use avdmanager to retrieve targets first, then falls back to android command if avdmanager cannot be found (and errors with ENOENT). updated tests. 2017-04-10 12:12:46 -07:00
Steve Gill a4103d8dc8 updated version in build.gradle 2017-04-07 10:56:39 -07:00
Steve Gill 8e0f021cad Set VERSION to 6.3.0-dev (via coho) 2017-04-02 17:43:13 -05:00
Steve Gill 002ab85f76 CB-12627 Updated RELEASENOTES and Version for release 6.2.1 2017-04-02 17:40:35 -05:00
Steve Gill 4a0f69a3f0 CB-12621: reverted elementtree dep to 0.1.6 2017-04-02 17:11:17 -05:00
Steve Gill 8a2e96d995 Update JS snapshot to version 6.3.0-dev (via coho) 2017-03-28 15:23:50 -07:00
Steve Gill 13dbd2f5d4 Set VERSION to 6.3.0-dev (via coho) 2017-03-28 15:18:35 -07:00
PC Dreams (Paulo Cristo) bcf3f8611a fix crash when calling methods on a destroyed webview 2016-05-04 08:42:14 +01:00
177 changed files with 6295 additions and 2881 deletions
+1
View File
@@ -0,0 +1 @@
bin/templates/project/assets/www/cordova.js
+10
View File
@@ -0,0 +1,10 @@
root: true
extends: semistandard
rules:
indent:
- error
- 4
camelcase: off
padded-blocks: off
operator-linebreak: off
no-throw-literal: off
+19 -17
View File
@@ -1,11 +1,21 @@
.DS_Store .DS_Store
.gradle
.metadata
Thumbs.db
Desktop.ini
*.tmp
*.bak
*.swp
*.class
*.jar
default.properties default.properties
gen gen
assets/www/cordova.js assets/www/cordova.js
local.properties local.properties
proguard.cfg proguard.cfg
proguard.cfg
proguard-project.txt proguard-project.txt
example
/coverage
/framework/lib /framework/lib
/framework/build /framework/build
/framework/bin /framework/bin
@@ -15,30 +25,23 @@ proguard-project.txt
/framework/libs /framework/libs
/framework/javadoc-public /framework/javadoc-public
/framework/javadoc-private /framework/javadoc-private
/test/libs /test/.externalNativeBuild
example /test/build.gradle
/test/bin
/test/assets/www/.tmp*
/test/assets/www/cordova.js
/test/gradle /test/gradle
/test/gradlew /test/gradlew
/test/gradlew.bat /test/gradlew.bat
/test/assets/www/.tmp*
/test/assets/www/cordova.js
/test/bin
/test/build /test/build
.gradle /test/captures
/test/libs
tmp/** tmp/**
.metadata
tmp/**/* tmp/**/*
Thumbs.db
Desktop.ini
*.tmp
*.bak
*.swp
*.class
*.jar
!/spec/fixtures/org.test.plugins.dummyplugin/src/android/TestLib.jar !/spec/fixtures/org.test.plugins.dummyplugin/src/android/TestLib.jar
# IntelliJ IDEA files # IntelliJ IDEA files
**/.idea/**/*
*.iml *.iml
.idea
npm-debug.log npm-debug.log
node_modules/jshint node_modules/jshint
node_modules/promise-matchers node_modules/promise-matchers
@@ -130,4 +133,3 @@ node_modules/wordwrap/
node_modules/yargs/ node_modules/yargs/
node_modules/jasmine-core/ node_modules/jasmine-core/
node_modules/fs.realpath/ node_modules/fs.realpath/
/coverage
-3
View File
@@ -1,3 +0,0 @@
bin/node_modules/*
bin/templates/project/*
spec/fixtures/*
-10
View File
@@ -1,10 +0,0 @@
{
"node": true
, "bitwise": true
, "undef": true
, "trailing": true
, "quotmark": true
, "indent": 4
, "unused": "vars"
, "latedef": "nofunc"
}
+13 -7
View File
@@ -2,21 +2,27 @@ language: android
sudo: false sudo: false
jdk: jdk:
- oraclejdk8 - oraclejdk8
env:
global:
- ANDROID_TOOLS=${ANDROID_HOME}/tools
before_install: before_install:
- nvm install 6 - 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 - node --version
- gradle --version - gradle --version
install: - 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
- npm install
- npm install -g codecov
- echo y | android update sdk -u --filter android-22,android-23,android-24,android-25
android: android:
components: components:
- tools - tools
- tools install:
- npm install
- npm install -g codecov
script: script:
- npm run jshint - npm test
- npm run cover - npm run cover
- npm run test-build
after_script: after_script:
- codecov - codecov
+7 -1
View File
@@ -36,7 +36,7 @@ at the core, applications written with web technology: HTML, CSS and JavaScript.
## Requires ## Requires
- Java JDK 1.6 or greater - Java JDK 1.8 or greater
- Android SDK [http://developer.android.com](http://developer.android.com) - Android SDK [http://developer.android.com](http://developer.android.com)
@@ -62,3 +62,9 @@ These commands live in a generated Cordova Android project. Any interactions wit
1. Create a project 1. Create a project
2. Import it via "Non-Android Studio 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!
+28
View File
@@ -20,6 +20,34 @@
--> -->
## Release Notes for Cordova (Android) ## ## 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) ### 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) 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) 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`
+1 -1
View File
@@ -1 +1 @@
6.2.3 6.4.1-dev
+24 -6
View File
@@ -1,20 +1,38 @@
image:
- Previous Visual Studio 2015
environment: environment:
ANDROID_HOME: "C:\\android"
matrix: matrix:
- nodejs_version: "0.10"
- nodejs_version: "0.12"
- nodejs_version: "4" - nodejs_version: "4"
- nodejs_version: "6" - 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: install:
# - cinst android-sdk - choco install gradle -version 3.4.1
# - echo y | android update sdk -u --filter android-22,android-23 - 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
- ps: Install-Product node $env:nodejs_version - ps: Install-Product node $env:nodejs_version
- npm install - 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 build: off
test_script: test_script:
- node --version - node --version
- npm --version - npm --version
- npm run test - npm test
# - npm run test-build
+1 -1
View File
@@ -18,7 +18,7 @@
@ECHO OFF @ECHO OFF
SET script_path="%~dp0android_sdk_version" SET script_path="%~dp0android_sdk_version"
IF EXIST %script_path% ( IF EXIST %script_path% (
node "%script_path%" %* node %script_path% %*
) ELSE ( ) ELSE (
ECHO. ECHO.
ECHO ERROR: Could not find 'android_sdk_version' script in 'bin' folder, aborting...>&2 ECHO ERROR: Could not find 'android_sdk_version' script in 'bin' folder, aborting...>&2
+1 -1
View File
@@ -18,7 +18,7 @@
@ECHO OFF @ECHO OFF
SET script_path="%~dp0check_reqs" SET script_path="%~dp0check_reqs"
IF EXIST %script_path% ( IF EXIST %script_path% (
node "%script_path%" %* node %script_path% %*
) ELSE ( ) ELSE (
ECHO. ECHO.
ECHO ERROR: Could not find 'check_reqs' script in 'bin' folder, aborting...>&2 ECHO ERROR: Could not find 'check_reqs' script in 'bin' folder, aborting...>&2
+112 -105
View File
@@ -19,30 +19,42 @@
under the License. under the License.
*/ */
var shell = require('shelljs'), var shell = require('shelljs');
Q = require('q'), var Q = require('q');
path = require('path'), var path = require('path');
fs = require('fs'), var fs = require('fs');
check_reqs = require('./../templates/cordova/lib/check_reqs'), var check_reqs = require('./../templates/cordova/lib/check_reqs');
ROOT = path.join(__dirname, '..', '..'); var ROOT = path.join(__dirname, '..', '..');
var MIN_SDK_VERSION = 16; var MIN_SDK_VERSION = 16;
var CordovaError = require('cordova-common').CordovaError; var CordovaError = require('cordova-common').CordovaError;
var AndroidManifest = require('../templates/cordova/lib/AndroidManifest'); var AndroidManifest = require('../templates/cordova/lib/AndroidManifest');
function setShellFatal(value, func) { // 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) {
var oldVal = shell.config.fatal; var oldVal = shell.config.fatal;
shell.config.fatal = value; shell.config.fatal = value;
func(); func();
shell.config.fatal = oldVal; shell.config.fatal = oldVal;
} }
function getFrameworkDir(projectPath, shared) { function getFrameworkDir (projectPath, shared) {
return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib'); return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
} }
function copyJsAndLibrary(projectPath, shared, projectName) { function copyJsAndLibrary (projectPath, shared, projectName) {
var nestedCordovaLibPath = getFrameworkDir(projectPath, false); var nestedCordovaLibPath = getFrameworkDir(projectPath, false);
var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js'); var srcCordovaJsPath = path.join(ROOT, 'bin', 'templates', 'project', 'assets', 'www', 'cordova.js');
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js')); shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js'));
@@ -57,8 +69,8 @@ function copyJsAndLibrary(projectPath, shared, projectName) {
shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www')); shell.cp('-rf', path.join(ROOT, 'cordova-js-src'), path.join(projectPath, 'platform_www'));
// Don't fail if there are no old jars. // Don't fail if there are no old jars.
setShellFatal(false, function() { exports.setShellFatal(false, function () {
shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function(oldJar) { shell.ls(path.join(projectPath, 'libs', 'cordova-*.jar')).forEach(function (oldJar) {
console.log('Deleting ' + oldJar); console.log('Deleting ' + oldJar);
shell.rm('-f', oldJar); shell.rm('-f', oldJar);
}); });
@@ -90,7 +102,7 @@ function copyJsAndLibrary(projectPath, shared, projectName) {
} }
} }
function extractSubProjectPaths(data) { function extractSubProjectPaths (data) {
var ret = {}; var ret = {};
var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg; var r = /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg;
var m; var m;
@@ -100,7 +112,7 @@ function extractSubProjectPaths(data) {
return Object.keys(ret); return Object.keys(ret);
} }
function writeProjectProperties(projectPath, target_api) { function writeProjectProperties (projectPath, target_api) {
var dstPath = path.join(projectPath, 'project.properties'); var dstPath = path.join(projectPath, 'project.properties');
var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties'); var templatePath = path.join(ROOT, 'bin', 'templates', 'project', 'project.properties');
var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath; var srcPath = fs.existsSync(dstPath) ? dstPath : templatePath;
@@ -108,11 +120,10 @@ function writeProjectProperties(projectPath, target_api) {
var data = fs.readFileSync(srcPath, 'utf8'); var data = fs.readFileSync(srcPath, 'utf8');
data = data.replace(/^target=.*/m, 'target=' + target_api); data = data.replace(/^target=.*/m, 'target=' + target_api);
var subProjects = extractSubProjectPaths(data); var subProjects = extractSubProjectPaths(data);
subProjects = subProjects.filter(function(p) { subProjects = subProjects.filter(function (p) {
return !(/^CordovaLib$/m.exec(p) || return !(/^CordovaLib$/m.exec(p) ||
/[\\\/]cordova-android[\\\/]framework$/m.exec(p) || /[\\/]cordova-android[\\/]framework$/m.exec(p) ||
/^(\.\.[\\\/])+framework$/m.exec(p) /^(\.\.[\\/])+framework$/m.exec(p));
);
}); });
subProjects.unshift('CordovaLib'); subProjects.unshift('CordovaLib');
data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, ''); data = data.replace(/^\s*android\.library\.reference\.\d+=.*\n/mg, '');
@@ -120,24 +131,24 @@ function writeProjectProperties(projectPath, target_api) {
data += '\n'; data += '\n';
} }
for (var i = 0; i < subProjects.length; ++i) { for (var i = 0; i < subProjects.length; ++i) {
data += 'android.library.reference.' + (i+1) + '=' + subProjects[i] + '\n'; data += 'android.library.reference.' + (i + 1) + '=' + subProjects[i] + '\n';
} }
fs.writeFileSync(dstPath, data); fs.writeFileSync(dstPath, data);
} }
function prepBuildFiles(projectPath) { function prepBuildFiles (projectPath) {
var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders')); var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders'));
buildModule.getBuilder('gradle').prepBuildFiles(); buildModule.getBuilder('gradle').prepBuildFiles();
} }
function copyBuildRules(projectPath) { function copyBuildRules (projectPath) {
var srcDir = path.join(ROOT, 'bin', 'templates', 'project'); var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath); shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath); shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath);
} }
function copyScripts(projectPath) { function copyScripts (projectPath) {
var bin = path.join(ROOT, 'bin'); var bin = path.join(ROOT, 'bin');
var srcScriptsDir = path.join(bin, 'templates', 'cordova'); var srcScriptsDir = path.join(bin, 'templates', 'cordova');
var destScriptsDir = path.join(projectPath, 'cordova'); var destScriptsDir = path.join(projectPath, 'cordova');
@@ -164,17 +175,18 @@ function copyScripts(projectPath) {
* Returns a promise, fulfilled if the package name is acceptable; rejected * Returns a promise, fulfilled if the package name is acceptable; rejected
* otherwise. * otherwise.
*/ */
function validatePackageName(package_name) { function validatePackageName (package_name) {
//Make the package conform to Java package types // Make the package conform to Java package types
//http://developer.android.com/guide/topics/manifest/manifest-element.html#package // http://developer.android.com/guide/topics/manifest/manifest-element.html#package
//Enforce underscore limitation // Enforce underscore limitation
var msg = 'Error validating package name. '; var msg = 'Error validating package name. ';
if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) { if (!/^[a-zA-Z][a-zA-Z0-9_]+(\.[a-zA-Z][a-zA-Z0-9_]*)+$/.test(package_name)) {
return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name')); return Q.reject(new CordovaError(msg + 'Package name must look like: com.company.Name'));
} }
//Class is a reserved word // Class is a reserved word
if(/\b[Cc]lass\b/.test(package_name)) { if (/\b[Cc]lass\b/.test(package_name)) {
return Q.reject(new CordovaError(msg + '"class" is a reserved word')); return Q.reject(new CordovaError(msg + '"class" is a reserved word'));
} }
@@ -186,19 +198,19 @@ function validatePackageName(package_name) {
* Returns a promise, fulfilled if the project name is acceptable; rejected * Returns a promise, fulfilled if the project name is acceptable; rejected
* otherwise. * otherwise.
*/ */
function validateProjectName(project_name) { function validateProjectName (project_name) {
var msg = 'Error validating project name. '; var msg = 'Error validating project name. ';
//Make sure there's something there // Make sure there's something there
if (project_name === '') { if (project_name === '') {
return Q.reject(new CordovaError(msg + 'Project name cannot be empty')); return Q.reject(new CordovaError(msg + 'Project name cannot be empty'));
} }
//Enforce stupid name error // Enforce stupid name error
if (project_name === 'CordovaActivity') { if (project_name === 'CordovaActivity') {
return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity')); return Q.reject(new CordovaError(msg + 'Project name cannot be CordovaActivity'));
} }
//Classes in Java don't begin with numbers // Classes in Java don't begin with numbers
if (/^[0-9]/.test(project_name)) { if (/^[0-9]/.test(project_name)) {
return Q.reject(new CordovaError(msg + 'Project name must not begin with a number')); return Q.reject(new CordovaError(msg + 'Project name must not begin with a number'));
} }
@@ -224,83 +236,83 @@ function validateProjectName(project_name) {
* *
* @return {Promise<String>} Directory where application has been created * @return {Promise<String>} Directory where application has been created
*/ */
exports.create = function(project_path, config, options, events) { exports.create = function (project_path, config, options, events) {
options = options || {}; options = options || {};
// Set default values for path, package and name // Set default values for path, package and name
project_path = path.relative(process.cwd(), (project_path || 'CordovaExample')); project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
// Check if project already exists // Check if project already exists
if(fs.existsSync(project_path)) { if (fs.existsSync(project_path)) {
return Q.reject(new CordovaError('Project already exists! Delete and recreate')); return Q.reject(new CordovaError('Project already exists! Delete and recreate'));
} }
var package_name = config.packageName() || 'my.cordova.project'; var package_name = config.android_packageName() || config.packageName() || 'my.cordova.project';
var project_name = config.name() ? var project_name = config.name() ?
config.name().replace(/[^\w.]/g,'_') : 'CordovaExample'; config.name().replace(/[^\w.]/g, '_') : 'CordovaExample';
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity'; var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
var target_api = check_reqs.get_target(); var target_api = check_reqs.get_target();
//Make the package conform to Java package types // Make the package conform to Java package types
return validatePackageName(package_name) return exports.validatePackageName(package_name)
.then(function() { .then(function () {
validateProjectName(project_name); exports.validateProjectName(project_name);
}).then(function() { }).then(function () {
// Log the given values for the project // Log the given values for the project
events.emit('log', 'Creating Cordova project for the Android platform:'); events.emit('log', 'Creating Cordova project for the Android platform:');
events.emit('log', '\tPath: ' + project_path); events.emit('log', '\tPath: ' + project_path);
events.emit('log', '\tPackage: ' + package_name); events.emit('log', '\tPackage: ' + package_name);
events.emit('log', '\tName: ' + project_name); events.emit('log', '\tName: ' + project_name);
events.emit('log', '\tActivity: ' + safe_activity_name); events.emit('log', '\tActivity: ' + safe_activity_name);
events.emit('log', '\tAndroid target: ' + target_api); events.emit('log', '\tAndroid target: ' + target_api);
events.emit('verbose', 'Copying android template project to ' + project_path); events.emit('verbose', 'Copying android template project to ' + project_path);
setShellFatal(true, function() { exports.setShellFatal(true, function () {
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project'); var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
// copy project template // copy project template
shell.cp('-r', path.join(project_template_dir, 'assets'), project_path); shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
shell.cp('-r', path.join(project_template_dir, 'res'), project_path); shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore')); shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
// Manually create directories that would be empty within the template (since git doesn't track directories). // Manually create directories that would be empty within the template (since git doesn't track directories).
shell.mkdir(path.join(project_path, 'libs')); shell.mkdir(path.join(project_path, 'libs'));
// copy cordova.js, cordova.jar // copy cordova.js, cordova.jar
copyJsAndLibrary(project_path, options.link, safe_activity_name); exports.copyJsAndLibrary(project_path, options.link, safe_activity_name);
// interpolate the activity name and package // interpolate the activity name and package
var packagePath = package_name.replace(/\./g, path.sep); var packagePath = package_name.replace(/\./g, path.sep);
var activity_dir = path.join(project_path, 'src', packagePath); var activity_dir = path.join(project_path, 'src', packagePath);
var activity_path = path.join(activity_dir, safe_activity_name + '.java'); var activity_path = path.join(activity_dir, safe_activity_name + '.java');
shell.mkdir('-p', activity_dir); shell.mkdir('-p', activity_dir);
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path); shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path); shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml')); shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
shell.sed('-i', /__ID__/, package_name, activity_path); shell.sed('-i', /__ID__/, package_name, activity_path);
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml')); var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
manifest.setPackageId(package_name) manifest.setPackageId(package_name)
.setTargetSdkVersion(target_api.split('-')[1]) .setTargetSdkVersion(target_api.split('-')[1])
.getActivity().setName(safe_activity_name); .getActivity().setName(safe_activity_name);
var manifest_path = path.join(project_path, 'AndroidManifest.xml'); var manifest_path = path.join(project_path, 'AndroidManifest.xml');
manifest.write(manifest_path); manifest.write(manifest_path);
copyScripts(project_path); exports.copyScripts(project_path);
copyBuildRules(project_path); exports.copyBuildRules(project_path);
}); });
// Link it to local android install. // Link it to local android install.
writeProjectProperties(project_path, target_api); exports.writeProjectProperties(project_path, target_api);
prepBuildFiles(project_path); exports.prepBuildFiles(project_path);
events.emit('log', generateDoneMessage('create', options.link)); events.emit('log', generateDoneMessage('create', options.link));
}).thenResolve(project_path); }).thenResolve(project_path);
}; };
function generateDoneMessage(type, link) { function generateDoneMessage (type, link) {
var pkg = require('../../package'); var pkg = require('../../package');
var msg = 'Android project ' + (type == 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version; var msg = 'Android project ' + (type === 'update' ? 'updated ' : 'created ') + 'with ' + pkg.name + '@' + pkg.version;
if (link) { if (link) {
msg += ' and has a linked CordovaLib'; msg += ' and has a linked CordovaLib';
} }
@@ -308,34 +320,29 @@ function generateDoneMessage(type, link) {
} }
// Returns a promise. // Returns a promise.
exports.update = function(projectPath, options, events) { exports.update = function (projectPath, options, events) {
options = options || {}; options = options || {};
return Q() return Q()
.then(function() { .then(function () {
var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml')); var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) { if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml'); events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
manifest.setMinSdkVersion(MIN_SDK_VERSION); manifest.setMinSdkVersion(MIN_SDK_VERSION);
} }
manifest.setDebuggable(false).write(); manifest.setDebuggable(false).write();
var projectName = manifest.getActivity().getName(); var projectName = manifest.getActivity().getName();
var target_api = check_reqs.get_target(); var target_api = check_reqs.get_target();
copyJsAndLibrary(projectPath, options.link, projectName); exports.copyJsAndLibrary(projectPath, options.link, projectName);
copyScripts(projectPath); exports.copyScripts(projectPath);
copyBuildRules(projectPath); exports.copyBuildRules(projectPath);
writeProjectProperties(projectPath, target_api); exports.writeProjectProperties(projectPath, target_api);
prepBuildFiles(projectPath); exports.prepBuildFiles(projectPath);
events.emit('log', generateDoneMessage('update', options.link)); events.emit('log', generateDoneMessage('update', options.link));
}).thenResolve(projectPath); }).thenResolve(projectPath);
}; };
// For testing
exports.validatePackageName = validatePackageName;
exports.validateProjectName = validateProjectName;
-10
View File
@@ -1,10 +0,0 @@
{
"node": true
, "bitwise": true
, "undef": true
, "trailing": true
, "quotmark": true
, "indent": 4
, "unused": "vars"
, "latedef": "nofunc"
}
+55 -74
View File
@@ -29,8 +29,7 @@ var selfEvents = require('cordova-common').events;
var PLATFORM = 'android'; var PLATFORM = 'android';
function setupEvents (externalEventEmitter) {
function setupEvents(externalEventEmitter) {
if (externalEventEmitter) { if (externalEventEmitter) {
// This will make the platform internal events visible outside // This will make the platform internal events visible outside
selfEvents.forwardEventsTo(externalEventEmitter); selfEvents.forwardEventsTo(externalEventEmitter);
@@ -43,7 +42,6 @@ function setupEvents(externalEventEmitter) {
return selfEvents; return selfEvents;
} }
/** /**
* Class, that acts as abstraction over particular platform. Encapsulates the * Class, that acts as abstraction over particular platform. Encapsulates the
* platform's properties and methods. * platform's properties and methods.
@@ -55,7 +53,7 @@ function setupEvents(externalEventEmitter) {
* *
* * platform: String that defines a platform name. * * platform: String that defines a platform name.
*/ */
function Api(platform, platformRootDir, events) { function Api (platform, platformRootDir, events) {
this.platform = PLATFORM; this.platform = PLATFORM;
this.root = path.resolve(__dirname, '..'); this.root = path.resolve(__dirname, '..');
@@ -79,14 +77,14 @@ function Api(platform, platformRootDir, events) {
}; };
// XXX Override some locations for Android Studio projects // XXX Override some locations for Android Studio projects
if(AndroidStudio.isAndroidStudioProject(self.root) === true) { if (AndroidStudio.isAndroidStudioProject(self.root) === true) {
selfEvents.emit('log', 'Android Studio project detected'); selfEvents.emit('log', 'Android Studio project detected');
this.android_studio = true; this.android_studio = true;
this.locations.configXml = path.join(self.root, 'app/src/main/res/xml/config.xml'); 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.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.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml');
this.locations.www = path.join(self.root, 'app/src/main/assets/www'); this.locations.www = path.join(self.root, 'app/src/main/assets/www');
this.locations.res = path.join(self.root, 'app/src/main/res'); this.locations.res = path.join(self.root, 'app/src/main/res');
} }
} }
@@ -112,16 +110,13 @@ Api.createPlatform = function (destination, config, options, events) {
events = setupEvents(events); events = setupEvents(events);
var result; var result;
try { try {
result = require('../../lib/create') result = require('../../lib/create').create(destination, config, options, events).then(function (destination) {
.create(destination, config, options, events)
.then(function (destination) {
var PlatformApi = require(path.resolve(destination, 'cordova/Api')); var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
return new PlatformApi(PLATFORM, destination, events); return new PlatformApi(PLATFORM, destination, events);
}); });
} } catch (e) {
catch (e) { events.emit('error', 'createPlatform is not callable from the android project API.');
events.emit('error','createPlatform is not callable from the android project API.'); throw (e);
throw(e);
} }
return result; return result;
}; };
@@ -146,16 +141,13 @@ Api.updatePlatform = function (destination, options, events) {
events = setupEvents(events); events = setupEvents(events);
var result; var result;
try { try {
result = require('../../lib/create') result = require('../../lib/create').update(destination, options, events).then(function (destination) {
.update(destination, options, events)
.then(function (destination) {
var PlatformApi = require(path.resolve(destination, 'cordova/Api')); var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
return new PlatformApi('android', destination, events); return new PlatformApi('android', destination, events);
}); });
} } catch (e) {
catch (e) { events.emit('error', 'updatePlatform is not callable from the android project API, you will need to do this manually.');
events.emit('error','updatePlatform is not callable from the android project API, you will need to do this manually.'); throw (e);
throw(e);
} }
return result; return result;
}; };
@@ -226,40 +218,36 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
installOptions.variables.PACKAGE_NAME = project.getPackageName(); installOptions.variables.PACKAGE_NAME = project.getPackageName();
} }
if(this.android_studio === true) { if (this.android_studio === true) {
installOptions.android_studio = true; installOptions.android_studio = true;
} }
return Q() return Q().then(function () {
.then(function () { // CB-11964: Do a clean when installing the plugin code to get around
//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
//the Gradle bug introduced by the Android Gradle Plugin Version 2.2 // TODO: Delete when the next version of Android Gradle plugin comes out
//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 // Since clean doesn't just clean the build, it also wipes out www, we need
// to pass additional options. // to pass additional options.
// Do some basic argument parsing // Do some basic argument parsing
var opts = {}; var opts = {};
// Skip cleaning prepared files when not invoking via cordova CLI. // Skip cleaning prepared files when not invoking via cordova CLI.
opts.noPrepare = true; opts.noPrepare = true;
if(!AndroidStudio.isAndroidStudioProject(self.root) && !project.isClean()) { if (!AndroidStudio.isAndroidStudioProject(self.root) && !project.isClean()) {
return self.clean(opts); return self.clean(opts);
} }
}) }).then(function () {
.then(function () { return PluginManager.get(self.platform, self.locations, project).addPlugin(plugin, installOptions);
return PluginManager.get(self.platform, self.locations, project) }).then(function () {
.addPlugin(plugin, installOptions); if (plugin.getFrameworks(this.platform).length === 0) return;
})
.then(function () {
if (plugin.getFrameworks(this.platform).length === 0) return;
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>'); selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles(); require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
}.bind(this)) }.bind(this))
// CB-11022 Return truthy value to prevent running prepare after // CB-11022 Return truthy value to prevent running prepare after
.thenResolve(true); .thenResolve(true);
}; };
@@ -279,9 +267,9 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
Api.prototype.removePlugin = function (plugin, uninstallOptions) { Api.prototype.removePlugin = function (plugin, uninstallOptions) {
var project = AndroidProject.getProjectFile(this.root); var project = AndroidProject.getProjectFile(this.root);
if(uninstallOptions && uninstallOptions.usePlatformWww === true && this.android_studio === true) { if (uninstallOptions && uninstallOptions.usePlatformWww === true && this.android_studio === true) {
uninstallOptions.usePlatformWww = false; uninstallOptions.usePlatformWww = false;
uninstallOptions.android_studio = true; uninstallOptions.android_studio = true;
} }
return PluginManager.get(this.platform, this.locations, project) return PluginManager.get(this.platform, this.locations, project)
@@ -343,11 +331,9 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) {
*/ */
Api.prototype.build = function (buildOptions) { Api.prototype.build = function (buildOptions) {
var self = this; var self = this;
return require('./lib/check_reqs').run() return require('./lib/check_reqs').run().then(function () {
.then(function () {
return require('./lib/build').run.call(self, buildOptions); return require('./lib/build').run.call(self, buildOptions);
}) }).then(function (buildResults) {
.then(function (buildResults) {
// Cast build result to array of build artifacts // Cast build result to array of build artifacts
return buildResults.apkPaths.map(function (apkPath) { return buildResults.apkPaths.map(function (apkPath) {
return { return {
@@ -372,10 +358,9 @@ Api.prototype.build = function (buildOptions) {
* @return {Promise} A promise either fulfilled if package was built and ran * @return {Promise} A promise either fulfilled if package was built and ran
* successfully, or rejected with CordovaError. * successfully, or rejected with CordovaError.
*/ */
Api.prototype.run = function(runOptions) { Api.prototype.run = function (runOptions) {
var self = this; var self = this;
return require('./lib/check_reqs').run() return require('./lib/check_reqs').run().then(function () {
.then(function () {
return require('./lib/run').run.call(self, runOptions); return require('./lib/run').run.call(self, runOptions);
}); });
}; };
@@ -387,19 +372,15 @@ Api.prototype.run = function(runOptions) {
* @return {Promise} Return a promise either fulfilled, or rejected with * @return {Promise} Return a promise either fulfilled, or rejected with
* CordovaError. * CordovaError.
*/ */
Api.prototype.clean = function(cleanOptions) { Api.prototype.clean = function (cleanOptions) {
var self = this; var self = this;
return require('./lib/check_reqs').run() return require('./lib/check_reqs').run().then(function () {
.then(function () { return require('./lib/build').runClean.call(self, cleanOptions);
return require('./lib/build').runClean.call(self, cleanOptions); }).then(function () {
}) return require('./lib/prepare').clean.call(self, cleanOptions);
.then(function () { });
return require('./lib/prepare').clean.call(self, cleanOptions);
});
}; };
/** /**
* Performs a requirements check for current platform. Each platform defines its * Performs a requirements check for current platform. Each platform defines its
* own set of requirements, which should be resolved before platform can be * own set of requirements, which should be resolved before platform can be
@@ -408,7 +389,7 @@ Api.prototype.clean = function(cleanOptions) {
* @return {Promise<Requirement[]>} Promise, resolved with set of Requirement * @return {Promise<Requirement[]>} Promise, resolved with set of Requirement
* objects for current platform. * objects for current platform.
*/ */
Api.prototype.requirements = function() { Api.prototype.requirements = function () {
return require('./lib/check_reqs').check_all(); return require('./lib/check_reqs').check_all();
}; };
+6 -10
View File
@@ -25,11 +25,11 @@ var CordovaError = require('cordova-common').CordovaError;
var Adb = {}; var Adb = {};
function isDevice(line) { function isDevice (line) {
return line.match(/\w+\tdevice/) && !line.match(/emulator/); return line.match(/\w+\tdevice/) && !line.match(/emulator/);
} }
function isEmulator(line) { function isEmulator (line) {
return line.match(/device/) && line.match(/emulator/); return line.match(/device/) && line.match(/emulator/);
} }
@@ -44,8 +44,7 @@ function isEmulator(line) {
* devices/emulators * devices/emulators
*/ */
Adb.devices = function (opts) { Adb.devices = function (opts) {
return spawn('adb', ['devices'], {cwd: os.tmpdir()}) return spawn('adb', ['devices'], {cwd: os.tmpdir()}).then(function (output) {
.then(function(output) {
return output.split('\n').filter(function (line) { return output.split('\n').filter(function (line) {
// Filter out either real devices or emulators, depending on options // Filter out either real devices or emulators, depending on options
return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line); return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
@@ -59,8 +58,7 @@ Adb.install = function (target, packagePath, opts) {
events.emit('verbose', 'Installing apk ' + packagePath + ' on target ' + target + '...'); events.emit('verbose', 'Installing apk ' + packagePath + ' on target ' + target + '...');
var args = ['-s', target, 'install']; var args = ['-s', target, 'install'];
if (opts && opts.replace) args.push('-r'); if (opts && opts.replace) args.push('-r');
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()}) return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()}).then(function (output) {
.then(function(output) {
// 'adb install' seems to always returns no error, even if installation fails // 'adb install' seems to always returns no error, even if installation fails
// so we catching output to detect installation failure // so we catching output to detect installation failure
if (output.match(/Failure/)) { if (output.match(/Failure/)) {
@@ -86,8 +84,7 @@ Adb.shell = function (target, shellCommand) {
events.emit('verbose', 'Running adb shell command "' + shellCommand + '" on target ' + target + '...'); events.emit('verbose', 'Running adb shell command "' + shellCommand + '" on target ' + target + '...');
var args = ['-s', target, 'shell']; var args = ['-s', target, 'shell'];
shellCommand = shellCommand.split(/\s+/); shellCommand = shellCommand.split(/\s+/);
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()}) return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()}).catch(function (output) {
.catch(function (output) {
return Q.reject(new CordovaError('Failed to execute shell command "' + return Q.reject(new CordovaError('Failed to execute shell command "' +
shellCommand + '"" on device: ' + output)); shellCommand + '"" on device: ' + output));
}); });
@@ -95,8 +92,7 @@ Adb.shell = function (target, shellCommand) {
Adb.start = function (target, activityName) { Adb.start = function (target, activityName) {
events.emit('verbose', 'Starting application "' + activityName + '" on target ' + target + '...'); events.emit('verbose', 'Starting application "' + activityName + '" on target ' + target + '...');
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName) return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName).catch(function (output) {
.catch(function (output) {
return Q.reject(new CordovaError('Failed to start application "' + return Q.reject(new CordovaError('Failed to start application "' +
activityName + '"" on device: ' + output)); activityName + '"" on device: ' + output));
}); });
+19 -20
View File
@@ -19,12 +19,12 @@
var fs = require('fs'); var fs = require('fs');
var et = require('elementtree'); var et = require('elementtree');
var xml= require('cordova-common').xmlHelpers; var xml = require('cordova-common').xmlHelpers;
var DEFAULT_ORIENTATION = 'default'; var DEFAULT_ORIENTATION = 'default';
/** Wraps an AndroidManifest file */ /** Wraps an AndroidManifest file */
function AndroidManifest(path) { function AndroidManifest (path) {
this.path = path; this.path = path;
this.doc = xml.parseElementtreeSync(path); this.doc = xml.parseElementtreeSync(path);
if (this.doc.getroot().tag !== 'manifest') { if (this.doc.getroot().tag !== 'manifest') {
@@ -32,38 +32,38 @@ function AndroidManifest(path) {
} }
} }
AndroidManifest.prototype.getVersionName = function() { AndroidManifest.prototype.getVersionName = function () {
return this.doc.getroot().attrib['android:versionName']; return this.doc.getroot().attrib['android:versionName'];
}; };
AndroidManifest.prototype.setVersionName = function(versionName) { AndroidManifest.prototype.setVersionName = function (versionName) {
this.doc.getroot().attrib['android:versionName'] = versionName; this.doc.getroot().attrib['android:versionName'] = versionName;
return this; return this;
}; };
AndroidManifest.prototype.getVersionCode = function() { AndroidManifest.prototype.getVersionCode = function () {
return this.doc.getroot().attrib['android:versionCode']; return this.doc.getroot().attrib['android:versionCode'];
}; };
AndroidManifest.prototype.setVersionCode = function(versionCode) { AndroidManifest.prototype.setVersionCode = function (versionCode) {
this.doc.getroot().attrib['android:versionCode'] = versionCode; this.doc.getroot().attrib['android:versionCode'] = versionCode;
return this; return this;
}; };
AndroidManifest.prototype.getPackageId = function() { AndroidManifest.prototype.getPackageId = function () {
/*jshint -W069 */ /* jshint -W069 */
return this.doc.getroot().attrib['package']; return this.doc.getroot().attrib['package'];
/*jshint +W069 */ /* jshint +W069 */
}; };
AndroidManifest.prototype.setPackageId = function(pkgId) { AndroidManifest.prototype.setPackageId = function (pkgId) {
/*jshint -W069 */ /* jshint -W069 */
this.doc.getroot().attrib['package'] = pkgId; this.doc.getroot().attrib['package'] = pkgId;
/*jshint +W069 */ /* jshint +W069 */
return this; return this;
}; };
AndroidManifest.prototype.getActivity = function() { AndroidManifest.prototype.getActivity = function () {
var activity = this.doc.getroot().find('./application/activity'); var activity = this.doc.getroot().find('./application/activity');
return { return {
getName: function () { getName: function () {
@@ -102,17 +102,16 @@ AndroidManifest.prototype.getActivity = function() {
}; };
}; };
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion'] ['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion'].forEach(function (sdkPrefName) {
.forEach(function(sdkPrefName) {
// Copy variable reference to avoid closure issues // Copy variable reference to avoid closure issues
var prefName = sdkPrefName; var prefName = sdkPrefName;
AndroidManifest.prototype['get' + capitalize(prefName)] = function() { AndroidManifest.prototype['get' + capitalize(prefName)] = function () {
var usesSdk = this.doc.getroot().find('./uses-sdk'); var usesSdk = this.doc.getroot().find('./uses-sdk');
return usesSdk && usesSdk.attrib['android:' + prefName]; return usesSdk && usesSdk.attrib['android:' + prefName];
}; };
AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) { AndroidManifest.prototype['set' + capitalize(prefName)] = function (prefValue) {
var usesSdk = this.doc.getroot().find('./uses-sdk'); var usesSdk = this.doc.getroot().find('./uses-sdk');
if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
@@ -128,11 +127,11 @@ AndroidManifest.prototype.getActivity = function() {
}; };
}); });
AndroidManifest.prototype.getDebuggable = function() { AndroidManifest.prototype.getDebuggable = function () {
return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true'; return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
}; };
AndroidManifest.prototype.setDebuggable = function(value) { AndroidManifest.prototype.setDebuggable = function (value) {
var application = this.doc.getroot().find('./application'); var application = this.doc.getroot().find('./application');
if (value) { if (value) {
application.attrib['android:debuggable'] = 'true'; application.attrib['android:debuggable'] = 'true';
@@ -150,7 +149,7 @@ AndroidManifest.prototype.setDebuggable = function(value) {
* @param {String} [destPath] File to write manifest to. If omitted, * @param {String} [destPath] File to write manifest to. If omitted,
* manifest will be written to file it has been read from. * manifest will be written to file it has been read from.
*/ */
AndroidManifest.prototype.write = function(destPath) { AndroidManifest.prototype.write = function (destPath) {
fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8'); fs.writeFileSync(destPath || this.path, this.doc.write({indent: 4}), 'utf-8');
}; };
+20 -21
View File
@@ -26,16 +26,15 @@ var pluginHandlers = require('./pluginHandlers');
var projectFileCache = {}; var projectFileCache = {};
function addToPropertyList(projectProperties, key, value) { function addToPropertyList (projectProperties, key, value) {
var i = 1; var i = 1;
while (projectProperties.get(key + '.' + i)) while (projectProperties.get(key + '.' + i)) { i++; }
i++;
projectProperties.set(key + '.' + i, value); projectProperties.set(key + '.' + i, value);
projectProperties.dirty = true; projectProperties.dirty = true;
} }
function removeFromPropertyList(projectProperties, key, value) { function removeFromPropertyList (projectProperties, key, value) {
var i = 1; var i = 1;
var currentValue; var currentValue;
while ((currentValue = projectProperties.get(key + '.' + i))) { while ((currentValue = projectProperties.get(key + '.' + i))) {
@@ -54,18 +53,18 @@ function removeFromPropertyList(projectProperties, key, value) {
function getRelativeLibraryPath (parentDir, subDir) { function getRelativeLibraryPath (parentDir, subDir) {
var libraryPath = path.relative(parentDir, subDir); var libraryPath = path.relative(parentDir, subDir);
return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath; return (path.sep === '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
} }
function AndroidProject(projectDir) { function AndroidProject (projectDir) {
this._propertiesEditors = {}; this._propertiesEditors = {};
this._subProjectDirs = {}; this._subProjectDirs = {};
this._dirty = false; this._dirty = false;
this.projectDir = projectDir; this.projectDir = projectDir;
this.platformWww = path.join(this.projectDir, 'platform_www'); this.platformWww = path.join(this.projectDir, 'platform_www');
this.www = path.join(this.projectDir, 'assets/www'); this.www = path.join(this.projectDir, 'assets/www');
if(AndroidStudio.isAndroidStudioProject(projectDir) === true) { if (AndroidStudio.isAndroidStudioProject(projectDir) === true) {
this.www = path.join(this.projectDir, 'app/src/main/assets/www'); this.www = path.join(this.projectDir, 'app/src/main/assets/www');
} }
} }
@@ -92,15 +91,15 @@ AndroidProject.purgeCache = function (projectDir) {
* *
* @return {String} The name of the package * @return {String} The name of the package
*/ */
AndroidProject.prototype.getPackageName = function() { AndroidProject.prototype.getPackageName = function () {
var manifestPath = path.join(this.projectDir, 'AndroidManifest.xml'); var manifestPath = path.join(this.projectDir, 'AndroidManifest.xml');
if(AndroidStudio.isAndroidStudioProject(this.projectDir) === true) { if (AndroidStudio.isAndroidStudioProject(this.projectDir) === true) {
manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml'); manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml');
} }
return new AndroidManifest(manifestPath).getPackageId(); 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. // All custom subprojects are prefixed with the last portion of the package id.
// This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name. // This is to avoid collisions when opening multiple projects in Eclipse that have subprojects with the same name.
var packageName = this.getPackageName(); var packageName = this.getPackageName();
@@ -110,7 +109,7 @@ AndroidProject.prototype.getCustomSubprojectRelativeDir = function(plugin_id, sr
return subRelativeDir; return subRelativeDir;
}; };
AndroidProject.prototype.addSubProject = function(parentDir, subDir) { AndroidProject.prototype.addSubProject = function (parentDir, subDir) {
var parentProjectFile = path.resolve(parentDir, 'project.properties'); var parentProjectFile = path.resolve(parentDir, 'project.properties');
var subProjectFile = path.resolve(subDir, 'project.properties'); var subProjectFile = path.resolve(subDir, 'project.properties');
var parentProperties = this._getPropertiesFile(parentProjectFile); var parentProperties = this._getPropertiesFile(parentProjectFile);
@@ -126,7 +125,7 @@ AndroidProject.prototype.addSubProject = function(parentDir, subDir) {
this._dirty = true; this._dirty = true;
}; };
AndroidProject.prototype.removeSubProject = function(parentDir, subDir) { AndroidProject.prototype.removeSubProject = function (parentDir, subDir) {
var parentProjectFile = path.resolve(parentDir, 'project.properties'); var parentProjectFile = path.resolve(parentDir, 'project.properties');
var parentProperties = this._getPropertiesFile(parentProjectFile); var parentProperties = this._getPropertiesFile(parentProjectFile);
removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir)); removeFromPropertyList(parentProperties, 'android.library.reference', getRelativeLibraryPath(parentDir, subDir));
@@ -134,35 +133,35 @@ AndroidProject.prototype.removeSubProject = function(parentDir, subDir) {
this._dirty = true; this._dirty = true;
}; };
AndroidProject.prototype.addGradleReference = function(parentDir, subDir) { AndroidProject.prototype.addGradleReference = function (parentDir, subDir) {
var parentProjectFile = path.resolve(parentDir, 'project.properties'); var parentProjectFile = path.resolve(parentDir, 'project.properties');
var parentProperties = this._getPropertiesFile(parentProjectFile); var parentProperties = this._getPropertiesFile(parentProjectFile);
addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir)); addToPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
this._dirty = true; this._dirty = true;
}; };
AndroidProject.prototype.removeGradleReference = function(parentDir, subDir) { AndroidProject.prototype.removeGradleReference = function (parentDir, subDir) {
var parentProjectFile = path.resolve(parentDir, 'project.properties'); var parentProjectFile = path.resolve(parentDir, 'project.properties');
var parentProperties = this._getPropertiesFile(parentProjectFile); var parentProperties = this._getPropertiesFile(parentProjectFile);
removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir)); removeFromPropertyList(parentProperties, 'cordova.gradle.include', getRelativeLibraryPath(parentDir, subDir));
this._dirty = true; this._dirty = true;
}; };
AndroidProject.prototype.addSystemLibrary = function(parentDir, value) { AndroidProject.prototype.addSystemLibrary = function (parentDir, value) {
var parentProjectFile = path.resolve(parentDir, 'project.properties'); var parentProjectFile = path.resolve(parentDir, 'project.properties');
var parentProperties = this._getPropertiesFile(parentProjectFile); var parentProperties = this._getPropertiesFile(parentProjectFile);
addToPropertyList(parentProperties, 'cordova.system.library', value); addToPropertyList(parentProperties, 'cordova.system.library', value);
this._dirty = true; this._dirty = true;
}; };
AndroidProject.prototype.removeSystemLibrary = function(parentDir, value) { AndroidProject.prototype.removeSystemLibrary = function (parentDir, value) {
var parentProjectFile = path.resolve(parentDir, 'project.properties'); var parentProjectFile = path.resolve(parentDir, 'project.properties');
var parentProperties = this._getPropertiesFile(parentProjectFile); var parentProperties = this._getPropertiesFile(parentProjectFile);
removeFromPropertyList(parentProperties, 'cordova.system.library', value); removeFromPropertyList(parentProperties, 'cordova.system.library', value);
this._dirty = true; this._dirty = true;
}; };
AndroidProject.prototype.write = function() { AndroidProject.prototype.write = function () {
if (!this._dirty) { if (!this._dirty) {
return; return;
} }
@@ -201,9 +200,9 @@ AndroidProject.prototype.getUninstaller = function (type) {
* This checks if an Android project is clean or has old build artifacts * 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'); 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)); return !(fs.existsSync(build_path));
}; };
+8 -8
View File
@@ -4,13 +4,13 @@
* @param {String} root Root folder of the project * @param {String} root Root folder of the project
*/ */
/*jshint esnext: false */ /* jshint esnext: false */
var path = require('path'); var path = require('path');
var fs = require('fs'); var fs = require('fs');
var CordovaError = require('cordova-common').CordovaError; 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 eclipseFiles = ['AndroidManifest.xml', 'libs', 'res', 'project.properties', 'platform_www'];
var androidStudioFiles = ['app', 'gradle', 'app/src/main/res']; var androidStudioFiles = ['app', 'gradle', 'app/src/main/res'];
@@ -18,21 +18,21 @@ module.exports.isAndroidStudioProject = function isAndroidStudioProject(root) {
var isEclipse = false; var isEclipse = false;
var isAS = true; var isAS = true;
if(!fs.existsSync(root)) { if (!fs.existsSync(root)) {
throw new CordovaError('AndroidStudio.js:inAndroidStudioProject root does not exist: ' + root); throw new CordovaError('AndroidStudio.js:inAndroidStudioProject root does not exist: ' + root);
} }
// if any of the following exists, then we are not an ASProj // if any of the following exists, then we are not an ASProj
eclipseFiles.forEach(function(file) { eclipseFiles.forEach(function (file) {
if(fs.existsSync(path.join(root, file))) { if (fs.existsSync(path.join(root, file))) {
isEclipse = true; isEclipse = true;
} }
}); });
// if it is NOT an eclipse project, check that all required files exist // if it is NOT an eclipse project, check that all required files exist
if(!isEclipse) { if (!isEclipse) {
androidStudioFiles.forEach(function(file){ androidStudioFiles.forEach(function (file) {
if(!fs.existsSync(path.join(root, file))) { if (!fs.existsSync(path.join(root, file))) {
console.log('missing file :: ' + file); console.log('missing file :: ' + file);
isAS = false; isAS = false;
} }
+16 -21
View File
@@ -17,8 +17,8 @@
under the License. under the License.
*/ */
var Q = require('q'), var Q = require('q');
superspawn = require('cordova-common').superspawn; var superspawn = require('cordova-common').superspawn;
var suffix_number_regex = /(\d+)$/; var suffix_number_regex = /(\d+)$/;
// Used for sorting Android targets, example strings to sort: // Used for sorting Android targets, example strings to sort:
@@ -29,7 +29,7 @@ var suffix_number_regex = /(\d+)$/;
// The idea is to sort based on largest "suffix" number - meaning the bigger // 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 // the number at the end, the more recent the target, the closer to the
// start of the array. // start of the array.
function sort_by_largest_numerical_suffix(a, b) { function sort_by_largest_numerical_suffix (a, b) {
var suffix_a = a.match(suffix_number_regex); var suffix_a = a.match(suffix_number_regex);
var suffix_b = b.match(suffix_number_regex); var suffix_b = b.match(suffix_number_regex);
if (suffix_a && suffix_b) { if (suffix_a && suffix_b) {
@@ -43,9 +43,8 @@ function sort_by_largest_numerical_suffix(a, b) {
} }
} }
module.exports.print_newest_available_sdk_target = function() { module.exports.print_newest_available_sdk_target = function () {
return module.exports.list_targets() return module.exports.list_targets().then(function (targets) {
.then(function(targets) {
targets.sort(sort_by_largest_numerical_suffix); targets.sort(sort_by_largest_numerical_suffix);
console.log(targets[0]); console.log(targets[0]);
}); });
@@ -66,38 +65,34 @@ module.exports.version_string_to_api_level = {
'7.1.1': 25 '7.1.1': 25
}; };
function parse_targets(output) { function parse_targets (output) {
var target_out = output.split('\n'); var target_out = output.split('\n');
var targets = []; var targets = [];
for (var i = target_out.length - 1; i >= 0; i--) { for (var i = target_out.length - 1; i >= 0; i--) {
if(target_out[i].match(/id:/)) { // if "id:" is in the line... if (target_out[i].match(/id:/)) { // if "id:" is in the line...
targets.push(target_out[i].match(/"(.+)"/)[1]); //.. match whatever is in quotes. targets.push(target_out[i].match(/"(.+)"/)[1]); // .. match whatever is in quotes.
} }
} }
return targets; return targets;
} }
module.exports.list_targets_with_android = function() { module.exports.list_targets_with_android = function () {
return superspawn.spawn('android', ['list', 'target']) return superspawn.spawn('android', ['list', 'target']).then(parse_targets);
.then(parse_targets);
}; };
module.exports.list_targets_with_avdmanager = function() { module.exports.list_targets_with_avdmanager = function () {
return superspawn.spawn('avdmanager', ['list', 'target']) return superspawn.spawn('avdmanager', ['list', 'target']).then(parse_targets);
.then(parse_targets);
}; };
module.exports.list_targets = function() { module.exports.list_targets = function () {
return module.exports.list_targets_with_avdmanager() return module.exports.list_targets_with_avdmanager().catch(function (err) {
.catch(function(err) {
// If there's an error, like avdmanager could not be found, we can try // 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 // as a last resort, to run `android`, in case this is a super old
// SDK installation. // SDK installation.
if (err && (err.code == 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) { if (err && (err.code === 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) {
return module.exports.list_targets_with_android(); return module.exports.list_targets_with_android();
} else throw err; } else throw err;
}) }).then(function (targets) {
.then(function(targets) {
if (targets.length === 0) { if (targets.length === 0) {
return Q.reject(new Error('No android targets (SDKs) installed!')); return Q.reject(new Error('No android targets (SDKs) installed!'));
} }
+38 -53
View File
@@ -19,10 +19,10 @@
under the License. under the License.
*/ */
var Q = require('q'), var Q = require('q');
path = require('path'), var path = require('path');
fs = require('fs'), var fs = require('fs');
nopt = require('nopt'); var nopt = require('nopt');
var Adb = require('./Adb'); var Adb = require('./Adb');
@@ -31,7 +31,7 @@ var events = require('cordova-common').events;
var spawn = require('cordova-common').superspawn.spawn; var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError; var CordovaError = require('cordova-common').CordovaError;
function parseOpts(options, resolvedTarget, projectRoot) { function parseOpts (options, resolvedTarget, projectRoot) {
options = options || {}; options = options || {};
options.argv = nopt({ options.argv = nopt({
gradle: Boolean, gradle: Boolean,
@@ -55,16 +55,13 @@ function parseOpts(options, resolvedTarget, projectRoot) {
extraArgs: [] extraArgs: []
}; };
if (options.argv.ant || options.argv.gradle) if (options.argv.ant || options.argv.gradle) { ret.buildMethod = options.argv.ant ? 'ant' : 'gradle'; }
ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
if (options.nobuild) ret.buildMethod = 'none'; if (options.nobuild) ret.buildMethod = 'none';
if (options.argv.versionCode) if (options.argv.versionCode) { ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode); }
ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode);
if (options.argv.minSdkVersion) if (options.argv.minSdkVersion) { ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion); }
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion);
if (options.argv.gradleArg) { if (options.argv.gradleArg) {
ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg); ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
@@ -72,12 +69,10 @@ function parseOpts(options, resolvedTarget, projectRoot) {
var packageArgs = {}; var packageArgs = {};
if (options.argv.keystore) if (options.argv.keystore) { packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore)); }
packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore));
['alias','storePassword','password','keystoreType'].forEach(function (flagName) { ['alias', 'storePassword', 'password', 'keystoreType'].forEach(function (flagName) {
if (options.argv[flagName]) if (options.argv[flagName]) { packageArgs[flagName] = options.argv[flagName]; }
packageArgs[flagName] = options.argv[flagName];
}); });
var buildConfig = options.buildConfig; var buildConfig = options.buildConfig;
@@ -88,20 +83,20 @@ function parseOpts(options, resolvedTarget, projectRoot) {
if (!fs.existsSync(buildConfig)) { if (!fs.existsSync(buildConfig)) {
throw new Error('Specified build config file does not exist: ' + buildConfig); throw new Error('Specified build config file does not exist: ' + buildConfig);
} }
events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig)); events.emit('log', 'Reading build config file: ' + path.resolve(buildConfig));
var buildjson = fs.readFileSync(buildConfig, 'utf8'); var buildjson = fs.readFileSync(buildConfig, 'utf8');
var config = JSON.parse(buildjson.replace(/^\ufeff/, '')); // Remove BOM var config = JSON.parse(buildjson.replace(/^\ufeff/, '')); // Remove BOM
if (config.android && config.android[ret.buildType]) { if (config.android && config.android[ret.buildType]) {
var androidInfo = config.android[ret.buildType]; var androidInfo = config.android[ret.buildType];
if(androidInfo.keystore && !packageArgs.keystore) { if (androidInfo.keystore && !packageArgs.keystore) {
if(androidInfo.keystore.substr(0,1) === '~') { if (androidInfo.keystore.substr(0, 1) === '~') {
androidInfo.keystore = process.env.HOME + androidInfo.keystore.substr(1); androidInfo.keystore = process.env.HOME + androidInfo.keystore.substr(1);
} }
packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore); packageArgs.keystore = path.resolve(path.dirname(buildConfig), androidInfo.keystore);
events.emit('log', 'Reading the keystore from: ' + packageArgs.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]; packageArgs[key] = packageArgs[key] || androidInfo[key];
}); });
} }
@@ -112,8 +107,8 @@ function parseOpts(options, resolvedTarget, projectRoot) {
packageArgs.password, packageArgs.keystoreType); packageArgs.password, packageArgs.keystoreType);
} }
if(!ret.packageInfo) { if (!ret.packageInfo) {
if(Object.keys(packageArgs).length > 0) { if (Object.keys(packageArgs).length > 0) {
events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.'); events.emit('warn', '\'keystore\' and \'alias\' need to be specified to generate a signed archive.');
} }
} }
@@ -125,11 +120,10 @@ function parseOpts(options, resolvedTarget, projectRoot) {
* Builds the project with the specifed options * Builds the project with the specifed options
* Returns a promise. * Returns a promise.
*/ */
module.exports.runClean = function(options) { module.exports.runClean = function (options) {
var opts = parseOpts(options, null, this.root); var opts = parseOpts(options, null, this.root);
var builder = builders.getBuilder(opts.buildMethod); var builder = builders.getBuilder(opts.buildMethod);
return builder.prepEnv(opts) return builder.prepEnv(opts).then(function () {
.then(function() {
return builder.clean(opts); return builder.clean(opts);
}); });
}; };
@@ -146,17 +140,15 @@ module.exports.runClean = function(options) {
* @return {Promise<Object>} Promise, resolved with built packages * @return {Promise<Object>} Promise, resolved with built packages
* information. * information.
*/ */
module.exports.run = function(options, optResolvedTarget) { module.exports.run = function (options, optResolvedTarget) {
var opts = parseOpts(options, optResolvedTarget, this.root); var opts = parseOpts(options, optResolvedTarget, this.root);
var builder = builders.getBuilder(opts.buildMethod); var builder = builders.getBuilder(opts.buildMethod);
return builder.prepEnv(opts) return builder.prepEnv(opts).then(function () {
.then(function() {
if (opts.prepEnv) { if (opts.prepEnv) {
events.emit('verbose', 'Build file successfully prepared.'); events.emit('verbose', 'Build file successfully prepared.');
return; return;
} }
return builder.build(opts) return builder.build(opts).then(function () {
.then(function() {
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch); var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t')); events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
return { return {
@@ -172,38 +164,31 @@ module.exports.run = function(options, optResolvedTarget) {
* Detects the architecture of a device/emulator * Detects the architecture of a device/emulator
* Returns "arm" or "x86". * Returns "arm" or "x86".
*/ */
module.exports.detectArchitecture = function(target) { module.exports.detectArchitecture = function (target) {
function helper() { function helper () {
return Adb.shell(target, 'cat /proc/cpuinfo') return Adb.shell(target, 'cat /proc/cpuinfo').then(function (output) {
.then(function(output) {
return /intel/i.exec(output) ? 'x86' : 'arm'; return /intel/i.exec(output) ? 'x86' : 'arm';
}); });
} }
// It sometimes happens (at least on OS X), that this command will hang forever. // It sometimes happens (at least on OS X), that this command will hang forever.
// To fix it, either unplug & replug device, or restart adb server. // To fix it, either unplug & replug device, or restart adb server.
return helper() return helper().timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.')).then(null, function (err) {
.timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))
.then(null, function(err) {
if (/timed out/.exec('' + err)) { if (/timed out/.exec('' + err)) {
// adb kill-server doesn't seem to do the trick. // adb kill-server doesn't seem to do the trick.
// Could probably find a x-platform version of killall, but I'm not actually // Could probably find a x-platform version of killall, but I'm not actually
// sure that this scenario even happens on non-OSX machines. // sure that this scenario even happens on non-OSX machines.
events.emit('verbose', 'adb timed out while detecting device/emulator architecture. Killing adb and trying again.'); events.emit('verbose', 'adb timed out while detecting device/emulator architecture. Killing adb and trying again.');
return spawn('killall', ['adb']) return spawn('killall', ['adb']).then(function () {
.then(function() { return helper().then(null, function () {
return helper()
.then(null, function() {
// The double kill is sadly often necessary, at least on mac. // The double kill is sadly often necessary, at least on mac.
events.emit('warn', 'adb timed out a second time while detecting device/emulator architecture. Killing adb and trying again.'); events.emit('warn', 'adb timed out a second time while detecting device/emulator architecture. Killing adb and trying again.');
return spawn('killall', ['adb']) return spawn('killall', ['adb']).then(function () {
.then(function() { return helper().then(null, 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.')); 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. // For non-killall OS's.
return Q.reject(err); return Q.reject(err);
}); });
@@ -212,10 +197,10 @@ module.exports.detectArchitecture = function(target) {
}); });
}; };
module.exports.findBestApkForArchitecture = function(buildResults, arch) { module.exports.findBestApkForArchitecture = function (buildResults, arch) {
var paths = buildResults.apkPaths.filter(function(p) { var paths = buildResults.apkPaths.filter(function (p) {
var apkName = path.basename(p); var apkName = path.basename(p);
if (buildResults.buildType == 'debug') { if (buildResults.buildType === 'debug') {
return /-debug/.exec(apkName); return /-debug/.exec(apkName);
} }
return !/-debug/.exec(apkName); return !/-debug/.exec(apkName);
@@ -235,7 +220,7 @@ module.exports.findBestApkForArchitecture = function(buildResults, arch) {
throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType); throw new Error('Could not find apk architecture: ' + arch + ' build-type: ' + buildResults.buildType);
}; };
function PackageInfo(keystore, alias, storePassword, password, keystoreType) { function PackageInfo (keystore, alias, storePassword, password, keystoreType) {
this.keystore = { this.keystore = {
'name': 'key.store', 'name': 'key.store',
'value': keystore 'value': keystore
@@ -265,10 +250,10 @@ function PackageInfo(keystore, alias, storePassword, password, keystoreType) {
} }
PackageInfo.prototype = { PackageInfo.prototype = {
toProperties: function() { toProperties: function () {
var self = this; var self = this;
var result = ''; var result = '';
Object.keys(self).forEach(function(key) { Object.keys(self).forEach(function (key) {
result += self[key].name; result += self[key].name;
result += '='; result += '=';
result += self[key].value.replace(/\\/g, '\\\\'); result += self[key].value.replace(/\\/g, '\\\\');
@@ -278,7 +263,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('Usage: ' + path.relative(process.cwd(), path.join('../build')) + ' [flags] [Signed APK flags]');
console.log('Flags:'); console.log('Flags:');
console.log(' \'--debug\': will build project in debug mode (default)'); console.log(' \'--debug\': will build project in debug mode (default)');
+21 -24
View File
@@ -16,6 +16,7 @@
specific language governing permissions and limitations specific language governing permissions and limitations
under the License. under the License.
*/ */
/* eslint no-unused-vars: 0 */
var Q = require('q'); var Q = require('q');
var fs = require('fs'); var fs = require('fs');
@@ -42,30 +43,29 @@ function AntBuilder (projectRoot) {
util.inherits(AntBuilder, GenericBuilder); util.inherits(AntBuilder, GenericBuilder);
AntBuilder.prototype.getArgs = function(cmd, opts) { AntBuilder.prototype.getArgs = function (cmd, opts) {
var args = [cmd, '-f', path.join(this.root, 'build.xml')]; var args = [cmd, '-f', path.join(this.root, 'build.xml')];
// custom_rules.xml is required for incremental builds. // custom_rules.xml is required for incremental builds.
if (hasCustomRules(this.root)) { if (hasCustomRules(this.root)) {
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen'); args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
} }
if(opts.packageInfo) { if (opts.packageInfo) {
args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES)); args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
} }
return args; return args;
}; };
AntBuilder.prototype.prepEnv = function(opts) { AntBuilder.prototype.prepEnv = function (opts) {
var self = this; var self = this;
return check_reqs.check_ant() return check_reqs.check_ant().then(function () {
.then(function() {
// Copy in build.xml on each build so that: // Copy in build.xml on each build so that:
// A) we don't require the Android SDK at project creation time, and // A) we don't require the Android SDK at project creation time, and
// B) we always use the SDK's latest version of it. // B) we always use the SDK's latest version of it.
/*jshint -W069 */ /* jshint -W069 */
var sdkDir = process.env['ANDROID_HOME']; var sdkDir = process.env['ANDROID_HOME'];
/*jshint +W069 */ /* jshint +W069 */
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8'); var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
function writeBuildXml(projectPath) { function writeBuildXml (projectPath) {
var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest()); var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData); fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) { if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
@@ -86,7 +86,7 @@ AntBuilder.prototype.prepEnv = function(opts) {
var propertiesFilePath = path.join(self.root, propertiesFile); var propertiesFilePath = path.join(self.root, propertiesFile);
if (opts.packageInfo) { if (opts.packageInfo) {
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties()); fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
} else if(isAutoGenerated(propertiesFilePath)) { } else if (isAutoGenerated(propertiesFilePath)) {
shell.rm('-f', propertiesFilePath); shell.rm('-f', propertiesFilePath);
} }
}); });
@@ -96,7 +96,7 @@ AntBuilder.prototype.prepEnv = function(opts) {
* Builds the project with ant. * Builds the project with ant.
* Returns a promise. * Returns a promise.
*/ */
AntBuilder.prototype.build = function(opts) { AntBuilder.prototype.build = function (opts) {
// Without our custom_rules.xml, we need to clean before building. // Without our custom_rules.xml, we need to clean before building.
var ret = Q(); var ret = Q();
if (!hasCustomRules(this.root)) { if (!hasCustomRules(this.root)) {
@@ -104,11 +104,10 @@ AntBuilder.prototype.build = function(opts) {
ret = this.clean(opts); ret = this.clean(opts);
} }
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts); var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);
return check_reqs.check_ant() return check_reqs.check_ant().then(function () {
.then(function() {
return spawn('ant', args, {stdio: 'pipe'}); return spawn('ant', args, {stdio: 'pipe'});
}).progress(function (stdio){ }).progress(function (stdio) {
if (stdio.stderr) { if (stdio.stderr) {
process.stderr.write(stdio.stderr); process.stderr.write(stdio.stderr);
} else { } else {
@@ -116,7 +115,7 @@ AntBuilder.prototype.build = function(opts) {
} }
}).catch(function (error) { }).catch(function (error) {
if (error.toString().indexOf('Unable to resolve project target') >= 0) { 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 // If due to some odd reason - check_android_target succeeds
// we should still fail here. // we should still fail here.
return Q.reject(error); return Q.reject(error);
@@ -126,19 +125,17 @@ AntBuilder.prototype.build = function(opts) {
}); });
}; };
AntBuilder.prototype.clean = function(opts) { AntBuilder.prototype.clean = function (opts) {
var args = this.getArgs('clean', opts); var args = this.getArgs('clean', opts);
var self = this; var self = this;
return check_reqs.check_ant() return check_reqs.check_ant().then(function () {
.then(function() {
return spawn('ant', args, {stdio: 'inherit'}); return spawn('ant', args, {stdio: 'inherit'});
}) }).then(function () {
.then(function () {
shell.rm('-rf', path.join(self.root, 'out')); shell.rm('-rf', path.join(self.root, 'out'));
['debug', 'release'].forEach(function(config) { ['debug', 'release'].forEach(function (config) {
var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES); var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
if(isAutoGenerated(propertiesFilePath)){ if (isAutoGenerated(propertiesFilePath)) {
shell.rm('-f', propertiesFilePath); shell.rm('-f', propertiesFilePath);
} }
}); });
@@ -147,10 +144,10 @@ AntBuilder.prototype.clean = function(opts) {
module.exports = AntBuilder; module.exports = AntBuilder;
function hasCustomRules(projectRoot) { function hasCustomRules (projectRoot) {
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml')); return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
} }
function isAutoGenerated(file) { function isAutoGenerated (file) {
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0; return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
} }
+37 -24
View File
@@ -16,6 +16,8 @@
specific language governing permissions and limitations specific language governing permissions and limitations
under the License. under the License.
*/ */
/* eslint no-self-assign: 0 */
/* eslint no-unused-vars: 0 */
var Q = require('q'); var Q = require('q');
var fs = require('fs'); var fs = require('fs');
@@ -32,35 +34,33 @@ function GenericBuilder (projectDir) {
}; };
} }
function hasCustomRules(projectRoot) { function hasCustomRules (projectRoot) {
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml')); return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
} }
GenericBuilder.prototype.prepEnv = function() { GenericBuilder.prototype.prepEnv = function () {
return Q(); return Q();
}; };
GenericBuilder.prototype.build = function() { GenericBuilder.prototype.build = function () {
events.emit('log', 'Skipping build...'); events.emit('log', 'Skipping build...');
return Q(null); return Q(null);
}; };
GenericBuilder.prototype.clean = function() { GenericBuilder.prototype.clean = function () {
return Q(); return Q();
}; };
GenericBuilder.prototype.findOutputApks = function(build_type, arch) { GenericBuilder.prototype.findOutputApks = function (build_type, arch) {
var self = this; var self = this;
return Object.keys(this.binDirs) return Object.keys(this.binDirs).reduce(function (result, builderName) {
.reduce(function (result, builderName) {
var binDir = self.binDirs[builderName]; var binDir = self.binDirs[builderName];
return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch)); return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch));
}, []) }, []).sort(apkSorter);
.sort(apkSorter);
}; };
GenericBuilder.prototype.readProjectProperties = function () { GenericBuilder.prototype.readProjectProperties = function () {
function findAllUniq(data, r) { function findAllUniq (data, r) {
var s = {}; var s = {};
var m; var m;
while ((m = r.exec(data))) { while ((m = r.exec(data))) {
@@ -85,14 +85,22 @@ GenericBuilder.prototype.extractRealProjectNameFromManifest = function () {
throw new CordovaError('Could not find package name in ' + manifestPath); throw new CordovaError('Could not find package name in ' + manifestPath);
} }
var packageName=m[1]; var packageName = m[1];
var lastDotIndex = packageName.lastIndexOf('.'); var lastDotIndex = packageName.lastIndexOf('.');
return packageName.substring(lastDotIndex + 1); return packageName.substring(lastDotIndex + 1);
}; };
module.exports = GenericBuilder; module.exports = GenericBuilder;
function apkSorter(fileA, fileB) { 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;
}
// De-prioritize unsigned builds // De-prioritize unsigned builds
var unsignedRE = /-unsigned/; var unsignedRE = /-unsigned/;
if (unsignedRE.exec(fileA)) { if (unsignedRE.exec(fileA)) {
@@ -101,16 +109,22 @@ function apkSorter(fileA, fileB) {
return -1; return -1;
} }
var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime; var timeDiff = fs.statSync(fileB).mtime - fs.statSync(fileA).mtime;
return timeDiff === 0 ? fileA.length - fileB.length : timeDiff; 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; var shellSilent = shell.config.silent;
shell.config.silent = true; shell.config.silent = true;
var ret = shell.ls(path.join(dir, '*.apk')) // list directory recursively
.filter(function(candidate) { 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 apkName = path.basename(candidate); var apkName = path.basename(candidate);
// Need to choose between release and debug .apk. // Need to choose between release and debug .apk.
if (build_type === 'debug') { if (build_type === 'debug') {
@@ -120,8 +134,7 @@ function findOutputApksHelper(dir, build_type, arch) {
return /-release/.exec(apkName) && !/-unaligned/.exec(apkName); return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
} }
return true; return true;
}) }).sort(apkSorter);
.sort(apkSorter);
shellSilent = shellSilent; shellSilent = shellSilent;
@@ -131,15 +144,15 @@ function findOutputApksHelper(dir, build_type, arch) {
// Assume arch-specific build if newest apk has -x86 or -arm. // Assume arch-specific build if newest apk has -x86 or -arm.
var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0])); var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0]));
// And show only arch-specific ones (or non-arch-specific) // And show only arch-specific ones (or non-arch-specific)
ret = ret.filter(function(p) { ret = ret.filter(function (p) {
/*jshint -W018 */ /* jshint -W018 */
return !!/-x86|-arm/.exec(path.basename(p)) == archSpecific; return !!/-x86|-arm/.exec(path.basename(p)) === archSpecific;
/*jshint +W018 */ /* jshint +W018 */
}); });
if (archSpecific && ret.length > 1 && arch) { if (archSpecific && ret.length > 1 && arch) {
ret = ret.filter(function(p) { ret = ret.filter(function (p) {
return path.basename(p).indexOf('-' + arch) != -1; return path.basename(p).indexOf('-' + arch) !== -1;
}); });
} }
+91 -91
View File
@@ -22,7 +22,7 @@ var fs = require('fs');
var util = require('util'); var util = require('util');
var path = require('path'); var path = require('path');
var shell = require('shelljs'); var shell = require('shelljs');
var spawn = require('cordova-common').superspawn.spawn; var superspawn = require('cordova-common').superspawn;
var CordovaError = require('cordova-common').CordovaError; var CordovaError = require('cordova-common').CordovaError;
var check_reqs = require('../check_reqs'); var check_reqs = require('../check_reqs');
@@ -37,15 +37,15 @@ var TEMPLATE =
function GradleBuilder (projectRoot) { function GradleBuilder (projectRoot) {
GenericBuilder.call(this, projectRoot); GenericBuilder.call(this, projectRoot);
this.binDirs = {gradle: this.binDirs.gradle}; this.binDirs = { gradle: this.binDirs.gradle };
} }
util.inherits(GradleBuilder, GenericBuilder); util.inherits(GradleBuilder, GenericBuilder);
GradleBuilder.prototype.getArgs = function(cmd, opts) { GradleBuilder.prototype.getArgs = function (cmd, opts) {
if (cmd == 'release') { if (cmd === 'release') {
cmd = 'cdvBuildRelease'; cmd = 'cdvBuildRelease';
} else if (cmd == 'debug') { } else if (cmd === 'debug') {
cmd = 'cdvBuildDebug'; cmd = 'cdvBuildDebug';
} }
var args = [cmd, '-b', path.join(this.root, 'build.gradle')]; var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
@@ -69,46 +69,47 @@ GradleBuilder.prototype.getArgs = function(cmd, opts) {
* This returns a promise * This returns a promise
*/ */
GradleBuilder.prototype.runGradleWrapper = function(gradle_cmd) { GradleBuilder.prototype.runGradleWrapper = function (gradle_cmd, gradle_file) {
var gradlePath = path.join(this.root, 'gradlew'); var gradlePath = path.join(this.root, 'gradlew');
var wrapperGradle = path.join(this.root, 'wrapper.gradle'); gradle_file = path.join(this.root, (gradle_file || 'wrapper.gradle'));
if(fs.existsSync(gradlePath)) { if (fs.existsSync(gradlePath)) {
//Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows // Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
} else { } else {
return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'}); 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. // Makes the project buildable, minus the gradle wrapper.
GradleBuilder.prototype.prepBuildFiles = function() { GradleBuilder.prototype.prepBuildFiles = function () {
// Update the version of build.gradle in each dependent library. // Update the version of build.gradle in each dependent library.
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle'); var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
var propertiesObj = this.readProjectProperties(); var propertiesObj = this.readProjectProperties();
var subProjects = propertiesObj.libs; var subProjects = propertiesObj.libs;
var checkAndCopy = function(subProject, root) { var checkAndCopy = function (subProject, root) {
var subProjectGradle = path.join(root, subProject, 'build.gradle'); var subProjectGradle = path.join(root, subProject, 'build.gradle');
// This is the future-proof way of checking if a file exists // This is the future-proof way of checking if a file exists
// This must be synchronous to satisfy a Travis test // This must be synchronous to satisfy a Travis test
try { try {
fs.accessSync(subProjectGradle, fs.F_OK); fs.accessSync(subProjectGradle, fs.F_OK);
} catch (e) { } catch (e) {
shell.cp('-f', pluginBuildGradle, subProjectGradle); shell.cp('-f', pluginBuildGradle, subProjectGradle);
} }
}; };
for (var i = 0; i < subProjects.length; ++i) { for (var i = 0; i < subProjects.length; ++i) {
if (subProjects[i] !== 'CordovaLib') { if (subProjects[i] !== 'CordovaLib') {
checkAndCopy(subProjects[i], this.root); checkAndCopy(subProjects[i], this.root);
} }
} }
var name = this.extractRealProjectNameFromManifest(); var name = this.extractRealProjectNameFromManifest();
//Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149 // Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
var settingsGradlePaths = subProjects.map(function(p){ var settingsGradlePaths = subProjects.map(function (p) {
var realDir=p.replace(/[/\\]/g, ':'); var realDir = p.replace(/[/\\]/g, ':');
var libName=realDir.replace(name+'-',''); var libName = realDir.replace(name + '-', '');
var str='include ":'+libName+'"\n'; var str = 'include ":' + libName + '"\n';
if(realDir.indexOf(name+'-')!==-1) if (realDir.indexOf(name + '-') !== -1) { str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n'; }
str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
return str; return str;
}); });
@@ -120,22 +121,19 @@ GradleBuilder.prototype.prepBuildFiles = function() {
var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8'); var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
var depsList = ''; var depsList = '';
var root = this.root; var root = this.root;
var insertExclude = function(p) { var insertExclude = function (p) {
var gradlePath = path.join(root, p, 'build.gradle'); var gradlePath = path.join(root, p, 'build.gradle');
var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8'); var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
if(projectGradleFile.indexOf('CordovaLib') != -1) { if (projectGradleFile.indexOf('CordovaLib') !== -1) {
depsList += '{\n exclude module:("CordovaLib")\n }\n'; depsList += '{\n exclude module:("CordovaLib")\n }\n';
} } else {
else { depsList += '\n';
depsList +='\n'; }
}
}; };
subProjects.forEach(function(p) { subProjects.forEach(function (p) {
console.log('Subproject Path: ' + p); console.log('Subproject Path: ' + p);
var libName=p.replace(/[/\\]/g, ':').replace(name+'-',''); var libName = p.replace(/[/\\]/g, ':').replace(name + '-', '');
depsList += ' debugCompile(project(path: "' + libName + '", configuration: "debug"))'; depsList += ' implementation(project(path: "' + libName + '"))';
insertExclude(p);
depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))';
insertExclude(p); insertExclude(p);
}); });
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390 // For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
@@ -143,7 +141,7 @@ GradleBuilder.prototype.prepBuildFiles = function() {
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'], [/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
[/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+'] [/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
]; ];
propertiesObj.systemLibs.forEach(function(p) { propertiesObj.systemLibs.forEach(function (p) {
var mavenRef; var mavenRef;
// It's already in gradle form if it has two ':'s // It's already in gradle form if it has two ':'s
if (/:.*:/.exec(p)) { if (/:.*:/.exec(p)) {
@@ -164,21 +162,20 @@ GradleBuilder.prototype.prepBuildFiles = function() {
}); });
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2'); buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
var includeList = ''; var includeList = '';
propertiesObj.gradleIncludes.forEach(function(includePath) { propertiesObj.gradleIncludes.forEach(function (includePath) {
includeList += 'apply from: "' + includePath + '"\n'; includeList += 'apply from: "' + includePath + '"\n';
}); });
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2'); buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle); fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
}; };
GradleBuilder.prototype.prepEnv = function(opts) { GradleBuilder.prototype.prepEnv = function (opts) {
var self = this; var self = this;
return check_reqs.check_gradle() return check_reqs.check_gradle().then(function (gradlePath) {
.then(function(gradlePath) {
return self.runGradleWrapper(gradlePath); return self.runGradleWrapper(gradlePath);
}).then(function() { }).then(function () {
return self.prepBuildFiles(); return self.prepBuildFiles();
}).then(function() { }).then(function () {
// We now copy the gradle out of the framework // We now copy the gradle out of the framework
// This is a dirty patch to get the build working // This is a dirty patch to get the build working
/* /*
@@ -198,12 +195,12 @@ GradleBuilder.prototype.prepEnv = function(opts) {
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with. // If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
// For some reason, using ^ and $ don't work. This does the job, though. // For some reason, using ^ and $ don't work. This does the job, though.
var distributionUrlRegex = /distributionUrl.*zip/; var distributionUrlRegex = /distributionUrl.*zip/;
/*jshint -W069 */ /* jshint -W069 */
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-3.3-all.zip'; var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-4.1-all.zip';
/*jshint +W069 */ /* jshint +W069 */
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties'); var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
shell.chmod('u+w', gradleWrapperPropertiesPath); shell.chmod('u+w', gradleWrapperPropertiesPath);
shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath); shell.sed('-i', distributionUrlRegex, 'distributionUrl=' + distributionUrl, gradleWrapperPropertiesPath);
var propertiesFile = opts.buildType + SIGNING_PROPERTIES; var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
var propertiesFilePath = path.join(self.root, propertiesFile); var propertiesFilePath = path.join(self.root, propertiesFile);
@@ -219,53 +216,37 @@ GradleBuilder.prototype.prepEnv = function(opts) {
* Builds the project with gradle. * Builds the project with gradle.
* Returns a promise. * Returns a promise.
*/ */
GradleBuilder.prototype.build = function(opts) { GradleBuilder.prototype.build = function (opts) {
var wrapper = path.join(this.root, 'gradlew'); var wrapper = path.join(this.root, 'gradlew');
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts); var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);
return spawn(wrapper, args, {stdio: 'pipe'}) return superspawn.spawn(wrapper, args, { stdio: 'pipe' })
.progress(function (stdio){ .progress(function (stdio) {
if (stdio.stderr) { suppressJavaOptionsInfo(stdio);
/* }).catch(function (error) {
* Workaround for the issue with Java printing some unwanted information to if (error.toString().indexOf('failed to find target with hash string') >= 0) {
* stderr instead of stdout. return check_reqs.check_android_target(error).then(function () {
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being // If due to some odd reason - check_android_target succeeds
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for // we should still fail here.
* explanation. return Q.reject(error);
*/ });
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
if (suppressThisLine) {
return;
} }
process.stderr.write(stdio.stderr); return Q.reject(error);
} 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 builder = this;
var wrapper = path.join(this.root, 'gradlew'); var wrapper = path.join(this.root, 'gradlew');
var args = builder.getArgs('clean', opts); var args = builder.getArgs('clean', opts);
return Q().then(function() { return Q().then(function () {
return spawn(wrapper, args, {stdio: 'inherit'}); return superspawn.spawn(wrapper, args, { stdio: 'inherit' });
}) }).then(function () {
.then(function () {
shell.rm('-rf', path.join(builder.root, 'out')); shell.rm('-rf', path.join(builder.root, 'out'));
['debug', 'release'].forEach(function(config) { ['debug', 'release'].forEach(function (config) {
var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES); var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
if(isAutoGenerated(propertiesFilePath)){ if (isAutoGenerated(propertiesFilePath)) {
shell.rm('-f', propertiesFilePath); shell.rm('-f', propertiesFilePath);
} }
}); });
@@ -274,6 +255,25 @@ GradleBuilder.prototype.clean = function(opts) {
module.exports = GradleBuilder; module.exports = GradleBuilder;
function isAutoGenerated(file) { 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) {
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0; return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
} }
+1 -2
View File
@@ -35,8 +35,7 @@ var knownBuilders = {
* @return {Builder} A builder instance for specified build type. * @return {Builder} A builder instance for specified build type.
*/ */
module.exports.getBuilder = function (builderType, projectRoot) { module.exports.getBuilder = function (builderType, projectRoot) {
if (!knownBuilders[builderType]) if (!knownBuilders[builderType]) { throw new CordovaError('Builder ' + builderType + ' is not supported.'); }
throw new CordovaError('Builder ' + builderType + ' is not supported.');
try { try {
var Builder = require('./' + knownBuilders[builderType]); var Builder = require('./' + knownBuilders[builderType]);
+90 -90
View File
@@ -21,19 +21,19 @@
/* jshint sub:true */ /* jshint sub:true */
var shelljs = require('shelljs'), var shelljs = require('shelljs');
child_process = require('child_process'), var child_process = require('child_process');
Q = require('q'), var Q = require('q');
path = require('path'), var path = require('path');
fs = require('fs'), var fs = require('fs');
os = require('os'), var os = require('os');
REPO_ROOT = path.join(__dirname, '..', '..', '..', '..'), var REPO_ROOT = path.join(__dirname, '..', '..', '..', '..');
PROJECT_ROOT = path.join(__dirname, '..', '..'); var PROJECT_ROOT = path.join(__dirname, '..', '..');
var CordovaError = require('cordova-common').CordovaError; var CordovaError = require('cordova-common').CordovaError;
var superspawn = require('cordova-common').superspawn; var superspawn = require('cordova-common').superspawn;
var android_sdk = require('./android_sdk'); var android_sdk = require('./android_sdk');
function forgivingWhichSync(cmd) { function forgivingWhichSync (cmd) {
try { try {
return fs.realpathSync(shelljs.which(cmd)); return fs.realpathSync(shelljs.which(cmd));
} catch (e) { } catch (e) {
@@ -41,9 +41,9 @@ function forgivingWhichSync(cmd) {
} }
} }
function tryCommand(cmd, errMsg, catchStderr) { function tryCommand (cmd, errMsg, catchStderr) {
var d = Q.defer(); var d = Q.defer();
child_process.exec(cmd, function(err, stdout, stderr) { child_process.exec(cmd, function (err, stdout, stderr) {
if (err) d.reject(new CordovaError(errMsg)); if (err) d.reject(new CordovaError(errMsg));
// Sometimes it is necessary to return an stderr instead of stdout in case of success, since // Sometimes it is necessary to return an stderr instead of stdout in case of success, since
// some commands prints theirs output to stderr instead of stdout. 'javac' is the example // some commands prints theirs output to stderr instead of stdout. 'javac' is the example
@@ -52,18 +52,18 @@ function tryCommand(cmd, errMsg, catchStderr) {
return d.promise; return d.promise;
} }
module.exports.isWindows = function() { module.exports.isWindows = function () {
return (os.platform() == 'win32'); return (os.platform() === 'win32');
}; };
module.exports.isDarwin = function() { module.exports.isDarwin = function () {
return (os.platform() == 'darwin'); return (os.platform() === 'darwin');
}; };
// Get valid target from framework/project.properties if run from this repo // 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 // Otherwise get target from project.properties file within a generated cordova-android project
module.exports.get_target = function() { module.exports.get_target = function () {
function extractFromFile(filePath) { function extractFromFile (filePath) {
var target = shelljs.grep(/\btarget=/, filePath); var target = shelljs.grep(/\btarget=/, filePath);
if (!target) { if (!target) {
throw new Error('Could not find android target within: ' + filePath); throw new Error('Could not find android target within: ' + filePath);
@@ -83,77 +83,82 @@ module.exports.get_target = function() {
}; };
// Returns a promise. Called only by build and clean commands. // Returns a promise. Called only by build and clean commands.
module.exports.check_ant = function() { module.exports.check_ant = function () {
return superspawn.spawn('ant', ['-version']) return superspawn.spawn('ant', ['-version']).then(function (output) {
.then(function(output) {
// Parse Ant version from command output // Parse Ant version from command output
return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1]; return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
}).catch(function(err) { }).catch(function (err) {
throw new CordovaError('Failed to run `ant -version`. Make sure you have `ant` on your $PATH.'); if (err) {
throw new CordovaError('Failed to run `ant -version`. Make sure you have `ant` on your $PATH.');
}
}); });
}; };
module.exports.get_gradle_wrapper = function() { module.exports.get_gradle_wrapper = function () {
var androidStudioPath; var androidStudioPath;
var i = 0; var i = 0;
var foundStudio = false; var foundStudio = false;
var program_dir; var program_dir;
if (module.exports.isDarwin()) { // OK, This hack only works on Windows, not on Mac OS or Linux. We will be deleting this eventually!
program_dir = fs.readdirSync('/Applications'); if (module.exports.isWindows()) {
while (i < program_dir.length && !foundStudio) {
if (program_dir[i].startsWith('Android Studio')) { var result = child_process.spawnSync(path.join(__dirname, 'getASPath.bat'));
//TODO: Check for a specific Android Studio version, make sure it's not Canary // console.log('result.stdout =' + result.stdout.toString());
androidStudioPath = path.join('/Applications', program_dir[i], 'Contents', 'gradle'); // console.log('result.stderr =' + result.stderr.toString());
foundStudio = true;
} else { ++i; } if (result.stderr.toString().length > 0) {
} var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/';
} else if (module.exports.isWindows()) { if (fs.existsSync(androidPath)) {
var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/'; program_dir = fs.readdirSync(androidPath);
if (fs.existsSync(androidPath)) { while (i < program_dir.length && !foundStudio) {
program_dir = fs.readdirSync(androidPath); if (program_dir[i].startsWith('Android Studio')) {
while (i < program_dir.length && !foundStudio) { foundStudio = true;
if (program_dir[i].startsWith('Android Studio')) { androidStudioPath = path.join(process.env['ProgramFiles'], 'Android', program_dir[i], 'gradle');
foundStudio = true; } else { ++i; }
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)) { if (androidStudioPath !== null && fs.existsSync(androidStudioPath)) {
var dirs = fs.readdirSync(androidStudioPath); var dirs = fs.readdirSync(androidStudioPath);
if(dirs[0].split('-')[0] == 'gradle') { if (dirs[0].split('-')[0] === 'gradle') {
return path.join(androidStudioPath, dirs[0], 'bin', 'gradle'); return path.join(androidStudioPath, dirs[0], 'bin', 'gradle');
} }
} else { } else {
//OK, let's try to check for Gradle! // OK, let's try to check for Gradle!
return forgivingWhichSync('gradle'); return forgivingWhichSync('gradle');
} }
}; };
// Returns a promise. Called only by build and clean commands. // Returns a promise. Called only by build and clean commands.
module.exports.check_gradle = function() { module.exports.check_gradle = function () {
var sdkDir = process.env['ANDROID_HOME']; var sdkDir = process.env['ANDROID_HOME'];
var d = Q.defer(); 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' + return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.')); 'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
}
var gradlePath = module.exports.get_gradle_wrapper(); var gradlePath = module.exports.get_gradle_wrapper();
if (gradlePath.length !== 0) if (gradlePath.length !== 0) { d.resolve(gradlePath); } else {
d.resolve(gradlePath);
else
d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\n' + 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' + 'or on your system to install the gradle wrapper. Please include gradle \n' +
'in your path, or install Android Studio')); 'in your path, or install Android Studio'));
}
return d.promise; return d.promise;
}; };
// Returns a promise. // Returns a promise.
module.exports.check_java = function() { module.exports.check_java = function () {
var javacPath = forgivingWhichSync('javac'); var javacPath = forgivingWhichSync('javac');
var hasJavaHome = !!process.env['JAVA_HOME']; var hasJavaHome = !!process.env['JAVA_HOME'];
return Q().then(function() { return Q().then(function () {
if (hasJavaHome) { if (hasJavaHome) {
// Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh). // Windows java installer doesn't add javac to PATH, nor set JAVA_HOME (ugh).
if (!javacPath) { if (!javacPath) {
@@ -163,13 +168,14 @@ module.exports.check_java = function() {
if (javacPath) { if (javacPath) {
// OS X has a command for finding JAVA_HOME. // OS X has a command for finding JAVA_HOME.
var find_java = '/usr/libexec/java_home'; var find_java = '/usr/libexec/java_home';
var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.'; var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting it manually.';
if (fs.existsSync(find_java)) { if (fs.existsSync(find_java)) {
return superspawn.spawn(find_java) return superspawn.spawn(find_java).then(function (stdout) {
.then(function(stdout) {
process.env['JAVA_HOME'] = stdout.trim(); process.env['JAVA_HOME'] = stdout.trim();
}).catch(function(err) { }).catch(function (err) {
throw new CordovaError(default_java_error_msg); if (err) {
throw new CordovaError(default_java_error_msg);
}
}); });
} else { } else {
// See if we can derive it from javac's location. // See if we can derive it from javac's location.
@@ -200,7 +206,7 @@ module.exports.check_java = function() {
} }
} }
} }
}).then(function() { }).then(function () {
var msg = var msg =
'Failed to run "javac -version", make sure that you have a JDK installed.\n' + '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'; 'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
@@ -209,9 +215,8 @@ module.exports.check_java = function() {
} }
// We use tryCommand with catchStderr = true, because // We use tryCommand with catchStderr = true, because
// javac writes version info to stderr instead of stdout // javac writes version info to stderr instead of stdout
return tryCommand('javac -version', msg, true) return tryCommand('javac -version', msg, true).then(function (output) {
.then(function (output) { // Let's check for at least Java 8, and keep it future proof so we can support Java 10
//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); var match = /javac ((?:1\.)(?:[8-9]\.)(?:\d+))|((?:1\.)(?:[1-9]\d+\.)(?:\d+))/i.exec(output);
return match && match[1]; return match && match[1];
}); });
@@ -219,13 +224,13 @@ module.exports.check_java = function() {
}; };
// Returns a promise. // Returns a promise.
module.exports.check_android = function() { module.exports.check_android = function () {
return Q().then(function() { return Q().then(function () {
var androidCmdPath = forgivingWhichSync('android'); var androidCmdPath = forgivingWhichSync('android');
var adbInPath = forgivingWhichSync('adb'); var adbInPath = forgivingWhichSync('adb');
var avdmanagerInPath = forgivingWhichSync('avdmanager'); var avdmanagerInPath = forgivingWhichSync('avdmanager');
var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']); var hasAndroidHome = !!process.env['ANDROID_HOME'] && fs.existsSync(process.env['ANDROID_HOME']);
function maybeSetAndroidHome(value) { function maybeSetAndroidHome (value) {
if (!hasAndroidHome && fs.existsSync(value)) { if (!hasAndroidHome && fs.existsSync(value)) {
hasAndroidHome = true; hasAndroidHome = true;
process.env['ANDROID_HOME'] = value; process.env['ANDROID_HOME'] = value;
@@ -265,10 +270,10 @@ module.exports.check_android = function() {
if (androidCmdPath) { if (androidCmdPath) {
parentDir = path.dirname(androidCmdPath); parentDir = path.dirname(androidCmdPath);
grandParentDir = path.dirname(parentDir); grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) == 'tools' || fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) { if (path.basename(parentDir) === 'tools' || fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
maybeSetAndroidHome(grandParentDir); maybeSetAndroidHome(grandParentDir);
} else { } else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' + throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' + 'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools directory.'); 'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools directory.');
} }
@@ -276,10 +281,10 @@ module.exports.check_android = function() {
if (adbInPath) { if (adbInPath) {
parentDir = path.dirname(adbInPath); parentDir = path.dirname(adbInPath);
grandParentDir = path.dirname(parentDir); grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) == 'platform-tools') { if (path.basename(parentDir) === 'platform-tools') {
maybeSetAndroidHome(grandParentDir); maybeSetAndroidHome(grandParentDir);
} else { } else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' + throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
'Detected \'adb\' command at ' + parentDir + ' but no \'platform-tools\' directory found near.\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.'); 'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'platform-tools directory.');
} }
@@ -287,17 +292,17 @@ module.exports.check_android = function() {
if (avdmanagerInPath) { if (avdmanagerInPath) {
parentDir = path.dirname(avdmanagerInPath); parentDir = path.dirname(avdmanagerInPath);
grandParentDir = path.dirname(parentDir); grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) == 'bin' && path.basename(grandParentDir) == 'tools') { if (path.basename(parentDir) === 'bin' && path.basename(grandParentDir) === 'tools') {
maybeSetAndroidHome(path.dirname(grandParentDir)); maybeSetAndroidHome(path.dirname(grandParentDir));
} else { } else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' + throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
'Detected \'avdmanager\' command at ' + parentDir + ' but no \'tools' + path.sep + 'bin\' directory found near.\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.'); 'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools' + path.sep + 'bin directory.');
} }
} }
} }
if (!process.env['ANDROID_HOME']) { if (!process.env['ANDROID_HOME']) {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' + throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.'); 'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
} }
if (!fs.existsSync(process.env['ANDROID_HOME'])) { if (!fs.existsSync(process.env['ANDROID_HOME'])) {
@@ -330,20 +335,19 @@ module.exports.getAbsoluteAndroidCmd = function () {
return cmd.replace(/(\s)/g, '\\$1'); 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: // valid_target can look like:
// android-19 // android-19
// android-L // android-L
// Google Inc.:Google APIs:20 // Google Inc.:Google APIs:20
// Google Inc.:Glass Development Kit Preview:20 // Google Inc.:Glass Development Kit Preview:20
var desired_api_level = module.exports.get_target(); var desired_api_level = module.exports.get_target();
return android_sdk.list_targets() return android_sdk.list_targets().then(function (targets) {
.then(function(targets) {
if (targets.indexOf(desired_api_level) >= 0) { if (targets.indexOf(desired_api_level) >= 0) {
return targets; return targets;
} }
var androidCmd = module.exports.getAbsoluteAndroidCmd(); var androidCmd = module.exports.getAbsoluteAndroidCmd();
var msg = 'Please install Android target / API level: "' + desired_api_level + '".\n\n' + var msg = 'Please install Android target / API level: "' + desired_api_level + '".\n\n' +
'Hint: Open the SDK manager by running: ' + androidCmd + '\n' + 'Hint: Open the SDK manager by running: ' + androidCmd + '\n' +
'You will require:\n' + 'You will require:\n' +
'1. "SDK Platform" for API level ' + desired_api_level + '\n' + '1. "SDK Platform" for API level ' + desired_api_level + '\n' +
@@ -357,23 +361,21 @@ module.exports.check_android_target = function(originalError) {
}; };
// Returns a promise. // Returns a promise.
module.exports.run = function() { module.exports.run = function () {
return Q.all([this.check_java(), this.check_android()]) return Q.all([this.check_java(), this.check_android()]).then(function (values) {
.then(function(values) { console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']); console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
if (!values[0]) { if (!values[0]) {
throw new CordovaError('Requirements check failed for JDK 1.8 or greater'); 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'); throw new CordovaError('Requirements check failed for Android SDK');
} }
}); });
}; };
/** /**
* Object thar represents one of requirements for current platform. * Object thar represents one of requirements for current platform.
* @param {String} id The unique identifier for this requirements. * @param {String} id The unique identifier for this requirements.
@@ -387,7 +389,7 @@ var Requirement = function (id, name, version, installed) {
this.name = name; this.name = name;
this.installed = installed || false; this.installed = installed || false;
this.metadata = { this.metadata = {
version: version, version: version
}; };
}; };
@@ -397,7 +399,7 @@ var Requirement = function (id, name, version, installed) {
* *
* @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled. * @return Promise<Requirement[]> Array of requirements. Due to implementation, promise is always fulfilled.
*/ */
module.exports.check_all = function() { module.exports.check_all = function () {
var requirements = [ var requirements = [
new Requirement('java', 'Java JDK'), new Requirement('java', 'Java JDK'),
@@ -417,15 +419,13 @@ module.exports.check_all = function() {
return checkFns.reduce(function (promise, checkFn, idx) { return checkFns.reduce(function (promise, checkFn, idx) {
// Update each requirement with results // Update each requirement with results
var requirement = requirements[idx]; var requirement = requirements[idx];
return promise.then(checkFn) return promise.then(checkFn).then(function (version) {
.then(function (version) {
requirement.installed = true; requirement.installed = true;
requirement.metadata.version = version; requirement.metadata.version = version;
}, function (err) { }, function (err) {
requirement.metadata.reason = err instanceof Error ? err.message : err; requirement.metadata.reason = err instanceof Error ? err.message : err;
}); });
}, Q()) }, Q()).then(function () {
.then(function () {
// When chain is completed, return requirements array to upstream API // When chain is completed, return requirements array to upstream API
return requirements; return requirements;
}); });
+20 -28
View File
@@ -19,8 +19,8 @@
under the License. under the License.
*/ */
var Q = require('q'), var Q = require('q');
build = require('./build'); var build = require('./build');
var path = require('path'); var path = require('path');
var Adb = require('./Adb'); var Adb = require('./Adb');
var AndroidManifest = require('./AndroidManifest'); var AndroidManifest = require('./AndroidManifest');
@@ -32,18 +32,16 @@ var events = require('cordova-common').events;
* Returns a promise for the list of the device ID's found * Returns a promise for the list of the device ID's found
* @param lookHarder When true, try restarting adb if no devices are found. * @param lookHarder When true, try restarting adb if no devices are found.
*/ */
module.exports.list = function(lookHarder) { module.exports.list = function (lookHarder) {
return Adb.devices() return Adb.devices().then(function (list) {
.then(function(list) {
if (list.length === 0 && lookHarder) { if (list.length === 0 && lookHarder) {
// adb kill-server doesn't seem to do the trick. // adb kill-server doesn't seem to do the trick.
// Could probably find a x-platform version of killall, but I'm not actually // Could probably find a x-platform version of killall, but I'm not actually
// sure that this scenario even happens on non-OSX machines. // sure that this scenario even happens on non-OSX machines.
return spawn('killall', ['adb']) return spawn('killall', ['adb']).then(function () {
.then(function() {
events.emit('verbose', 'Restarting adb to see if more devices are detected.'); events.emit('verbose', 'Restarting adb to see if more devices are detected.');
return Adb.devices(); return Adb.devices();
}, function() { }, function () {
// For non-killall OS's. // For non-killall OS's.
return list; return list;
}); });
@@ -52,9 +50,8 @@ module.exports.list = function(lookHarder) {
}); });
}; };
module.exports.resolveTarget = function(target) { module.exports.resolveTarget = function (target) {
return this.list(true) return this.list(true).then(function (device_list) {
.then(function(device_list) {
if (!device_list || !device_list.length) { if (!device_list || !device_list.length) {
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.')); return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
} }
@@ -65,8 +62,7 @@ module.exports.resolveTarget = function(target) {
return Q.reject('ERROR: Unable to find target \'' + target + '\'.'); return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
} }
return build.detectArchitecture(target) return build.detectArchitecture(target).then(function (arch) {
.then(function(arch) {
return { target: target, arch: arch, isEmulator: false }; return { target: target, arch: arch, isEmulator: false };
}); });
}); });
@@ -77,13 +73,13 @@ module.exports.resolveTarget = function(target) {
* and launches it. * and launches it.
* Returns a promise. * Returns a promise.
*/ */
module.exports.install = function(target, buildResults) { module.exports.install = function (target, buildResults) {
return Q().then(function() { return Q().then(function () {
if (target && typeof target == 'object') { if (target && typeof target === 'object') {
return target; return target;
} }
return module.exports.resolveTarget(target); return module.exports.resolveTarget(target);
}).then(function(resolvedTarget) { }).then(function (resolvedTarget) {
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch); var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml')); var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
var pkgName = manifest.getPackageId(); var pkgName = manifest.getPackageId();
@@ -91,29 +87,25 @@ module.exports.install = function(target, buildResults) {
events.emit('log', 'Using apk: ' + apk_path); events.emit('log', 'Using apk: ' + apk_path);
events.emit('log', 'Package name: ' + pkgName); events.emit('log', 'Package name: ' + pkgName);
return Adb.install(resolvedTarget.target, apk_path, {replace: true}) return Adb.install(resolvedTarget.target, apk_path, {replace: true}).catch(function (error) {
.catch(function (error) {
// CB-9557 CB-10157 only uninstall and reinstall app if the one that // CB-9557 CB-10157 only uninstall and reinstall app if the one that
// is already installed on device was signed w/different certificate // is already installed on device was signed w/different certificate
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
throw error;
events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' + events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
'installed app already signed with different key'); 'installed app already signed with different key');
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed. // or the app doesn't installed at all, so no error catching needed.
return Adb.uninstall(resolvedTarget.target, pkgName) return Adb.uninstall(resolvedTarget.target, pkgName).then(function () {
.then(function() {
return Adb.install(resolvedTarget.target, apk_path, {replace: true}); return Adb.install(resolvedTarget.target, apk_path, {replace: true});
}); });
}) }).then(function () {
.then(function() { // unlock screen
//unlock screen
return Adb.shell(resolvedTarget.target, 'input keyevent 82'); return Adb.shell(resolvedTarget.target, 'input keyevent 82');
}).then(function() { }).then(function () {
return Adb.start(resolvedTarget.target, launchName); return Adb.start(resolvedTarget.target, launchName);
}).then(function() { }).then(function () {
events.emit('log', 'LAUNCH SUCCESS'); events.emit('log', 'LAUNCH SUCCESS');
}); });
}); });
+93 -99
View File
@@ -21,8 +21,9 @@
/* jshint sub:true */ /* jshint sub:true */
var retry = require('./retry'); var android_versions = require('android-versions');
var build = require('./build'); var retry = require('./retry');
var build = require('./build');
var path = require('path'); var path = require('path');
var Adb = require('./Adb'); var Adb = require('./Adb');
var AndroidManifest = require('./AndroidManifest'); var AndroidManifest = require('./AndroidManifest');
@@ -33,20 +34,20 @@ var shelljs = require('shelljs');
var android_sdk = require('./android_sdk'); var android_sdk = require('./android_sdk');
var check_reqs = require('./check_reqs'); var check_reqs = require('./check_reqs');
var Q = require('q'); var Q = require('q');
var os = require('os'); var os = require('os');
var fs = require('fs'); var fs = require('fs');
var child_process = require('child_process'); var child_process = require('child_process');
// constants // constants
var ONE_SECOND = 1000; // in milliseconds var ONE_SECOND = 1000; // in milliseconds
var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds var ONE_MINUTE = 60 * ONE_SECOND; // in milliseconds
var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds var INSTALL_COMMAND_TIMEOUT = 5 * ONE_MINUTE; // in milliseconds
var NUM_INSTALL_RETRIES = 3; var NUM_INSTALL_RETRIES = 3;
var CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds var CHECK_BOOTED_INTERVAL = 3 * ONE_SECOND; // in milliseconds
var EXEC_KILL_SIGNAL = 'SIGKILL'; var EXEC_KILL_SIGNAL = 'SIGKILL';
function forgivingWhichSync(cmd) { function forgivingWhichSync (cmd) {
try { try {
return fs.realpathSync(shelljs.which(cmd)); return fs.realpathSync(shelljs.which(cmd));
} catch (e) { } catch (e) {
@@ -55,8 +56,7 @@ function forgivingWhichSync(cmd) {
} }
module.exports.list_images_using_avdmanager = function () { module.exports.list_images_using_avdmanager = function () {
return superspawn.spawn('avdmanager', ['list', 'avd']) return superspawn.spawn('avdmanager', ['list', 'avd']).then(function (output) {
.then(function(output) {
var response = output.split('\n'); var response = output.split('\n');
var emulator_list = []; var emulator_list = [];
for (var i = 1; i < response.length; i++) { for (var i = 1; i < response.length; i++) {
@@ -108,16 +108,15 @@ module.exports.list_images_using_avdmanager = function () {
/* To just return a list of names use this /* To just return a list of names use this
if (response[i].match(/Name:\s/)) { if (response[i].match(/Name:\s/)) {
emulator_list.push(response[i].split('Name: ')[1].replace('\r', ''); emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
}*/ } */
} }
return emulator_list; return emulator_list;
}); });
}; };
module.exports.list_images_using_android = function() { module.exports.list_images_using_android = function () {
return superspawn.spawn('android', ['list', 'avd']) return superspawn.spawn('android', ['list', 'avd']).then(function (output) {
.then(function(output) {
var response = output.split('\n'); var response = output.split('\n');
var emulator_list = []; var emulator_list = [];
for (var i = 1; i < response.length; i++) { for (var i = 1; i < response.length; i++) {
@@ -152,7 +151,7 @@ module.exports.list_images_using_android = function() {
/* To just return a list of names use this /* To just return a list of names use this
if (response[i].match(/Name:\s/)) { if (response[i].match(/Name:\s/)) {
emulator_list.push(response[i].split('Name: ')[1].replace('\r', ''); emulator_list.push(response[i].split('Name: ')[1].replace('\r', '');
}*/ } */
} }
return emulator_list; return emulator_list;
@@ -170,16 +169,30 @@ module.exports.list_images_using_android = function() {
skin : <skin> skin : <skin>
} }
*/ */
module.exports.list_images = function() { module.exports.list_images = function () {
if (forgivingWhichSync('avdmanager')) { return Q.fcall(function () {
return module.exports.list_images_using_avdmanager(); if (forgivingWhichSync('avdmanager')) {
} else if (forgivingWhichSync('android')) { return module.exports.list_images_using_avdmanager();
return module.exports.list_images_using_android(); } else if (forgivingWhichSync('android')) {
} else { return module.exports.list_images_using_android();
return Q().then(function() { } else {
throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?'); 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;
}); });
} });
}; };
/** /**
@@ -187,20 +200,19 @@ module.exports.list_images = function() {
* or undefined if no avds exist. * or undefined if no avds exist.
* Returns a promise. * Returns a promise.
*/ */
module.exports.best_image = function() { module.exports.best_image = function () {
return this.list_images() return this.list_images().then(function (images) {
.then(function(images) {
// Just return undefined if there is no images // Just return undefined if there is no images
if (images.length === 0) return; if (images.length === 0) return;
var closest = 9999; var closest = 9999;
var best = images[0]; var best = images[0];
var project_target = check_reqs.get_target().replace('android-', ''); var project_target = parseInt(check_reqs.get_target().replace('android-', ''));
for (var i in images) { for (var i in images) {
var target = images[i].target; var target = images[i].target;
if(target) { if (target && target.indexOf('API level') > -1) {
var num = target.split('(API level ')[1].replace(')', ''); var num = parseInt(target.split('(API level ')[1].replace(')', ''));
if (num == project_target) { if (num === project_target) {
return images[i]; return images[i];
} else if (project_target - num < closest && project_target > num) { } else if (project_target - num < closest && project_target > num) {
closest = project_target - num; closest = project_target - num;
@@ -213,19 +225,18 @@ module.exports.best_image = function() {
}; };
// Returns a promise. // Returns a promise.
module.exports.list_started = function() { module.exports.list_started = function () {
return Adb.devices({emulators: true}); return Adb.devices({emulators: true});
}; };
// Returns a promise. // Returns a promise.
// TODO: we should remove this, there's a more robust method under android_sdk.js // TODO: we should remove this, there's a more robust method under android_sdk.js
module.exports.list_targets = function() { module.exports.list_targets = function () {
return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()}) return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()}).then(function (output) {
.then(function(output) {
var target_out = output.split('\n'); var target_out = output.split('\n');
var targets = []; var targets = [];
for (var i = target_out.length; i >= 0; i--) { for (var i = target_out.length; i >= 0; i--) {
if(target_out[i].match(/id:/)) { if (target_out[i].match(/id:/)) {
targets.push(targets[i].split(' ')[1]); targets.push(targets[i].split(' ')[1]);
} }
} }
@@ -240,9 +251,8 @@ module.exports.list_targets = function() {
module.exports.get_available_port = function () { module.exports.get_available_port = function () {
var self = this; var self = this;
return self.list_started() return self.list_started().then(function (emulators) {
.then(function (emulators) { for (var p = 5584; p >= 5554; p -= 2) {
for (var p = 5584; p >= 5554; p-=2) {
if (emulators.indexOf('emulator-' + p) === -1) { if (emulators.indexOf('emulator-' + p) === -1) {
events.emit('verbose', 'Found available port: ' + p); events.emit('verbose', 'Found available port: ' + p);
return p; return p;
@@ -262,14 +272,13 @@ module.exports.get_available_port = function () {
* *
* Returns a promise. * Returns a promise.
*/ */
module.exports.start = function(emulator_ID, boot_timeout) { module.exports.start = function (emulator_ID, boot_timeout) {
var self = this; var self = this;
return Q().then(function() { return Q().then(function () {
if (emulator_ID) return Q(emulator_ID); if (emulator_ID) return Q(emulator_ID);
return self.best_image() return self.best_image().then(function (best) {
.then(function(best) {
if (best && best.name) { if (best && best.name) {
events.emit('warn', 'No emulator specified, defaulting to ' + best.name); events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
return best.name; return best.name;
@@ -281,9 +290,8 @@ module.exports.start = function(emulator_ID, boot_timeout) {
'2. Create an AVD by running: ' + androidCmd + ' avd\n' + '2. Create an AVD by running: ' + androidCmd + ' avd\n' +
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n')); 'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
}); });
}).then(function(emulatorId) { }).then(function (emulatorId) {
return self.get_available_port() return self.get_available_port().then(function (port) {
.then(function (port) {
// Figure out the directory the emulator binary runs in, and set the cwd to that directory. // 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 // Workaround for https://code.google.com/p/android/issues/detail?id=235461
var emulator_dir = path.dirname(shelljs.which('emulator')); var emulator_dir = path.dirname(shelljs.which('emulator'));
@@ -297,20 +305,17 @@ module.exports.start = function(emulator_ID, boot_timeout) {
events.emit('log', 'Waiting for emulator to start...'); events.emit('log', 'Waiting for emulator to start...');
return self.wait_for_emulator(port); return self.wait_for_emulator(port);
}); });
}).then(function(emulatorId) { }).then(function (emulatorId) {
if (!emulatorId) if (!emulatorId) { return Q.reject(new CordovaError('Failed to start emulator')); }
return Q.reject(new CordovaError('Failed to start emulator'));
//wait for emulator to boot up // wait for emulator to boot up
process.stdout.write('Waiting for emulator to boot (this may take a while)...'); process.stdout.write('Waiting for emulator to boot (this may take a while)...');
return self.wait_for_boot(emulatorId, boot_timeout) return self.wait_for_boot(emulatorId, boot_timeout).then(function (success) {
.then(function(success) {
if (success) { if (success) {
events.emit('log','BOOT COMPLETE'); events.emit('log', 'BOOT COMPLETE');
//unlock screen // unlock screen
return Adb.shell(emulatorId, 'input keyevent 82') return Adb.shell(emulatorId, 'input keyevent 82').then(function () {
.then(function() { // return the new emulator id for the started emulators
//return the new emulator id for the started emulators
return emulatorId; return emulatorId;
}); });
} else { } else {
@@ -325,20 +330,19 @@ module.exports.start = function(emulator_ID, boot_timeout) {
* Waits for an emulator to boot on a given port. * Waits for an emulator to boot on a given port.
* Returns this emulator's ID in a promise. * 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; var self = this;
return Q().then(function() { return Q().then(function () {
var emulator_id = 'emulator-' + port; var emulator_id = 'emulator-' + port;
return Adb.shell(emulator_id, 'getprop dev.bootcomplete') return Adb.shell(emulator_id, 'getprop dev.bootcomplete').then(function (output) {
.then(function (output) {
if (output.indexOf('1') >= 0) { if (output.indexOf('1') >= 0) {
return emulator_id; return emulator_id;
} }
return self.wait_for_emulator(port); return self.wait_for_emulator(port);
}, function (error) { }, function (error) {
if (error && error.message && if ((error && error.message &&
(error.message.indexOf('not found') > -1) || (error.message.indexOf('not found') > -1)) ||
error.message.indexOf('device offline') > -1) { (error.message.indexOf('device offline') > -1)) {
// emulator not yet started, continue waiting // emulator not yet started, continue waiting
return self.wait_for_emulator(port); return self.wait_for_emulator(port);
} else { } else {
@@ -346,7 +350,7 @@ module.exports.wait_for_emulator = function(port) {
throw error; throw error;
} }
}); });
}); });
}; };
/* /*
@@ -354,10 +358,9 @@ module.exports.wait_for_emulator = function(port) {
* promise that resolves to a boolean indicating success. Not specifying a * promise that resolves to a boolean indicating success. Not specifying a
* time_remaining or passing a negative value will cause it to wait forever * 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; var self = this;
return Adb.shell(emulator_id, 'ps') return Adb.shell(emulator_id, 'ps').then(function (output) {
.then(function(output) {
if (output.match(/android\.process\.acore/)) { if (output.match(/android\.process\.acore/)) {
return true; return true;
} else if (time_remaining === 0) { } else if (time_remaining === 0) {
@@ -366,7 +369,7 @@ module.exports.wait_for_boot = function(emulator_id, time_remaining) {
process.stdout.write('.'); process.stdout.write('.');
// Check at regular intervals // 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; 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); return self.wait_for_boot(emulator_id, updated_time);
}); });
@@ -379,11 +382,10 @@ module.exports.wait_for_boot = function(emulator_id, time_remaining) {
* TODO : Enter the stdin input required to complete the creation of an avd. * TODO : Enter the stdin input required to complete the creation of an avd.
* Returns a promise. * Returns a promise.
*/ */
module.exports.create_image = function(name, target) { module.exports.create_image = function (name, target) {
console.log('Creating new avd named ' + name); console.log('Creating new avd named ' + name);
if (target) { if (target) {
return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target]) return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target]).then(null, function (error) {
.then(null, function(error) {
console.error('ERROR : Failed to create emulator image : '); console.error('ERROR : Failed to create emulator image : ');
console.error(' Do you have the latest android targets including ' + target + '?'); console.error(' Do you have the latest android targets including ' + target + '?');
console.error(error); console.error(error);
@@ -391,22 +393,20 @@ module.exports.create_image = function(name, target) {
} else { } else {
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.'); console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
// TODO: there's a more robust method for finding targets in android_sdk.js // 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]]) return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]]).then(function () {
.then(function() {
// TODO: This seems like another error case, even though it always happens. // TODO: This seems like another error case, even though it always happens.
console.error('ERROR : Unable to create an avd emulator, no targets found.'); console.error('ERROR : Unable to create an avd emulator, no targets found.');
console.error('Ensure you have targets available by running the "android" command'); console.error('Ensure you have targets available by running the "android" command');
return Q.reject(); return Q.reject();
}, function(error) { }, function (error) {
console.error('ERROR : Failed to create emulator image : '); console.error('ERROR : Failed to create emulator image : ');
console.error(error); console.error(error);
}); });
} }
}; };
module.exports.resolveTarget = function(target) { module.exports.resolveTarget = function (target) {
return this.list_started() return this.list_started().then(function (emulator_list) {
.then(function(emulator_list) {
if (emulator_list.length < 1) { if (emulator_list.length < 1) {
return Q.reject('No running Android emulators found, please start an emulator before deploying your project.'); return Q.reject('No running Android emulators found, please start an emulator before deploying your project.');
} }
@@ -417,9 +417,8 @@ module.exports.resolveTarget = function(target) {
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.'); return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
} }
return build.detectArchitecture(target) return build.detectArchitecture(target).then(function (arch) {
.then(function(arch) { return {target: target, arch: arch, isEmulator: true};
return {target:target, arch:arch, isEmulator:true};
}); });
}); });
}; };
@@ -430,7 +429,7 @@ module.exports.resolveTarget = function(target) {
* If no started emulators are found, error out. * If no started emulators are found, error out.
* Returns a promise. * Returns a promise.
*/ */
module.exports.install = function(givenTarget, buildResults) { module.exports.install = function (givenTarget, buildResults) {
var target; var target;
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml')); var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
@@ -438,7 +437,7 @@ module.exports.install = function(givenTarget, buildResults) {
// resolve the target emulator // resolve the target emulator
return Q().then(function () { return Q().then(function () {
if (givenTarget && typeof givenTarget == 'object') { if (givenTarget && typeof givenTarget === 'object') {
return givenTarget; return givenTarget;
} else { } else {
return module.exports.resolveTarget(givenTarget); return module.exports.resolveTarget(givenTarget);
@@ -452,13 +451,12 @@ module.exports.install = function(givenTarget, buildResults) {
}).then(function () { }).then(function () {
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed. // or the app doesn't installed at all, so no error catching needed.
return Q.when() return Q.when().then(function () {
.then(function() {
var apk_path = build.findBestApkForArchitecture(buildResults, target.arch); var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
var execOptions = { var execOptions = {
cwd: os.tmpdir(), cwd: os.tmpdir(),
timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds timeout: INSTALL_COMMAND_TIMEOUT, // in milliseconds
killSignal: EXEC_KILL_SIGNAL killSignal: EXEC_KILL_SIGNAL
}; };
@@ -469,12 +467,12 @@ module.exports.install = function(givenTarget, buildResults) {
// A special function to call adb install in specific environment w/ specific options. // 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 // Introduced as a part of fix for http://issues.apache.org/jira/browse/CB-9119
// to workaround sporadic emulator hangs // to workaround sporadic emulator hangs
function adbInstallWithOptions(target, apk, opts) { function adbInstallWithOptions (target, apk, opts) {
events.emit('verbose', 'Installing apk ' + apk + ' on ' + target + '...'); events.emit('verbose', 'Installing apk ' + apk + ' on ' + target + '...');
var command = 'adb -s ' + target + ' install -r "' + apk + '"'; var command = 'adb -s ' + target + ' install -r "' + apk + '"';
return Q.promise(function (resolve, reject) { return Q.promise(function (resolve, reject) {
child_process.exec(command, opts, function(err, stdout, stderr) { child_process.exec(command, opts, function (err, stdout, stderr) {
if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr)); if (err) reject(new CordovaError('Error executing "' + command + '": ' + stderr));
// adb does not return an error code even if installation fails. Instead it puts a specific // 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. // message to stdout, so we have to use RegExp matching to detect installation failure.
@@ -494,27 +492,23 @@ module.exports.install = function(givenTarget, buildResults) {
} }
function installPromise () { function installPromise () {
return adbInstallWithOptions(target.target, apk_path, execOptions) return adbInstallWithOptions(target.target, apk_path, execOptions).catch(function (error) {
.catch(function (error) {
// CB-9557 CB-10157 only uninstall and reinstall app if the one that // CB-9557 CB-10157 only uninstall and reinstall app if the one that
// is already installed on device was signed w/different certificate // is already installed on device was signed w/different certificate
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
throw error;
events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' + events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
'currently installed app was signed with different key'); 'currently installed app was signed with different key');
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app // This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed. // or the app doesn't installed at all, so no error catching needed.
return Adb.uninstall(target.target, pkgName) return Adb.uninstall(target.target, pkgName).then(function () {
.then(function() {
return adbInstallWithOptions(target.target, apk_path, execOptions); return adbInstallWithOptions(target.target, apk_path, execOptions);
}); });
}); });
} }
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise) return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise).then(function (output) {
.then(function (output) {
events.emit('log', 'INSTALL SUCCESS'); events.emit('log', 'INSTALL SUCCESS');
}); });
}); });
+3
View File
@@ -0,0 +1,3 @@
@ECHO OFF
for /f "tokens=2*" %%a in ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Android Studio" /v Path') do set "ASPath=%%~b"
ECHO %ASPath%
+1 -1
View File
@@ -18,7 +18,7 @@
@ECHO OFF @ECHO OFF
SET script_path="%~dp0install-device" SET script_path="%~dp0install-device"
IF EXIST %script_path% ( IF EXIST %script_path% (
node "%script_path%" %* node %script_path% %*
) ELSE ( ) ELSE (
ECHO. ECHO.
ECHO ERROR: Could not find 'install-device' script in 'cordova\lib' folder, aborting...>&2 ECHO ERROR: Could not find 'install-device' script in 'cordova\lib' folder, aborting...>&2
@@ -18,7 +18,7 @@
@ECHO OFF @ECHO OFF
SET script_path="%~dp0install-emulator" SET script_path="%~dp0install-emulator"
IF EXIST %script_path% ( IF EXIST %script_path% (
node "%script_path%" %* node %script_path% %*
) ELSE ( ) ELSE (
ECHO. ECHO.
ECHO ERROR: Could not find 'install-emulator' script in 'cordova\lib' folder, aborting...>&2 ECHO ERROR: Could not find 'install-emulator' script in 'cordova\lib' folder, aborting...>&2
+1 -1
View File
@@ -18,7 +18,7 @@
@ECHO OFF @ECHO OFF
SET script_path="%~dp0list-devices" SET script_path="%~dp0list-devices"
IF EXIST %script_path% ( IF EXIST %script_path% (
node "%script_path%" %* node %script_path% %*
) ELSE ( ) ELSE (
ECHO. ECHO.
ECHO ERROR: Could not find 'list-devices' script in 'cordova\lib' folder, aborting...>&2 ECHO ERROR: Could not find 'list-devices' script in 'cordova\lib' folder, aborting...>&2
@@ -18,7 +18,7 @@
@ECHO OFF @ECHO OFF
SET script_path="%~dp0list-emulator-images" SET script_path="%~dp0list-emulator-images"
IF EXIST %script_path% ( IF EXIST %script_path% (
node "%script_path%" %* node %script_path% %*
) ELSE ( ) ELSE (
ECHO. ECHO.
ECHO ERROR: Could not find 'list-emulator-images' script in 'cordova\lib' folder, aborting...>&2 ECHO ERROR: Could not find 'list-emulator-images' script in 'cordova\lib' folder, aborting...>&2
@@ -18,7 +18,7 @@
@ECHO OFF @ECHO OFF
SET script_path="%~dp0list-started-emulators" SET script_path="%~dp0list-started-emulators"
IF EXIST %script_path% ( IF EXIST %script_path% (
node "%script_path%" %* node %script_path% %*
) ELSE ( ) ELSE (
ECHO. ECHO.
ECHO ERROR: Could not find 'list-started-emulators' script in 'cordova\lib' folder, aborting...>&2 ECHO ERROR: Could not find 'list-started-emulators' script in 'cordova\lib' folder, aborting...>&2
+10 -10
View File
@@ -19,28 +19,28 @@
under the License. under the License.
*/ */
var path = require('path'), var path = require('path');
os = require('os'), var os = require('os');
Q = require('q'), var Q = require('q');
child_process = require('child_process'), var child_process = require('child_process');
ROOT = path.join(__dirname, '..', '..'); var ROOT = path.join(__dirname, '..', '..');
/* /*
* Starts running logcat in the shell. * Starts running logcat in the shell.
* Returns a promise. * Returns a promise.
*/ */
module.exports.run = function() { module.exports.run = function () {
var d = Q.defer(); var d = Q.defer();
var adb = child_process.spawn('adb', ['logcat'], {cwd: os.tmpdir()}); 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 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')); console.log(out.join('\n'));
}); });
adb.stderr.on('data', console.error); adb.stderr.on('data', console.error);
adb.on('close', function(code) { adb.on('close', function (code) {
if (code > 0) { if (code > 0) {
d.reject('Failed to run logcat command.'); d.reject('Failed to run logcat command.');
} else d.resolve(); } else d.resolve();
@@ -49,7 +49,7 @@ module.exports.run = function() {
return d.promise; 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('Usage: ' + path.relative(process.cwd(), path.join(ROOT, 'cordova', 'log')));
console.log('Gives the logcat output on the command line.'); console.log('Gives the logcat output on the command line.');
process.exit(0); process.exit(0);
@@ -20,8 +20,10 @@
buildscript { buildscript {
repositories { repositories {
mavenCentral()
jcenter() jcenter()
maven {
url "https://maven.google.com"
}
} }
// Switch the Android Gradle plugin version requirement depending on the // Switch the Android Gradle plugin version requirement depending on the
+39 -43
View File
@@ -26,15 +26,15 @@ var events = require('cordova-common').events;
var CordovaError = require('cordova-common').CordovaError; var CordovaError = require('cordova-common').CordovaError;
var handlers = { var handlers = {
'source-file':{ 'source-file': {
install:function(obj, plugin, project, options) { install: function (obj, plugin, project, options) {
if (!obj.src) throw new CordovaError(generateAttributeError('src', 'source-file', plugin.id)); 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)); if (!obj.targetDir) throw new CordovaError(generateAttributeError('target-dir', 'source-file', plugin.id));
var dest = path.join(obj.targetDir, path.basename(obj.src)); var dest = path.join(obj.targetDir, path.basename(obj.src));
if(options && options.android_studio === true) { if (options && options.android_studio === true) {
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src)); dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
} }
if (options && options.force) { if (options && options.force) {
@@ -43,42 +43,42 @@ var handlers = {
copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); copyNewFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
} }
}, },
uninstall:function(obj, plugin, project, options) { uninstall: function (obj, plugin, project, options) {
var dest = path.join(obj.targetDir, path.basename(obj.src)); var dest = path.join(obj.targetDir, path.basename(obj.src));
if(options && options.android_studio === true) { if (options && options.android_studio === true) {
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src)); dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
} }
deleteJava(project.projectDir, dest); deleteJava(project.projectDir, dest);
} }
}, },
'lib-file':{ 'lib-file': {
install:function(obj, plugin, project, options) { install: function (obj, plugin, project, options) {
var dest = path.join('libs', path.basename(obj.src)); var dest = path.join('libs', path.basename(obj.src));
if(options && options.android_studio === true) { if (options && options.android_studio === true) {
dest = path.join('app/libs', path.basename(obj.src)); dest = path.join('app/libs', path.basename(obj.src));
} }
copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link)); copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
}, },
uninstall:function(obj, plugin, project, options) { uninstall: function (obj, plugin, project, options) {
var dest = path.join('libs', path.basename(obj.src)); var dest = path.join('libs', path.basename(obj.src));
if(options && options.android_studio === true) { if (options && options.android_studio === true) {
dest = path.join('app/libs', path.basename(obj.src)); dest = path.join('app/libs', path.basename(obj.src));
} }
removeFile(project.projectDir, dest); removeFile(project.projectDir, dest);
} }
}, },
'resource-file':{ 'resource-file': {
install:function(obj, plugin, project, options) { install: function (obj, plugin, project, options) {
copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link)); copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link));
}, },
uninstall:function(obj, plugin, project, options) { uninstall: function (obj, plugin, project, options) {
removeFile(project.projectDir, path.normalize(obj.target)); removeFile(project.projectDir, path.normalize(obj.target));
} }
}, },
'framework': { 'framework': {
install:function(obj, plugin, project, options) { install: function (obj, plugin, project, options) {
var src = obj.src; var src = obj.src;
if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id)); if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
@@ -95,15 +95,15 @@ var handlers = {
subDir = src; subDir = src;
} }
if (obj.type == 'gradleReference') { if (obj.type === 'gradleReference') {
project.addGradleReference(parentDir, subDir); project.addGradleReference(parentDir, subDir);
} else if (obj.type == 'sys') { } else if (obj.type === 'sys') {
project.addSystemLibrary(parentDir, subDir); project.addSystemLibrary(parentDir, subDir);
} else { } else {
project.addSubProject(parentDir, subDir); project.addSubProject(parentDir, subDir);
} }
}, },
uninstall:function(obj, plugin, project, options) { uninstall: function (obj, plugin, project, options) {
var src = obj.src; var src = obj.src;
if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id)); if (!src) throw new CordovaError(generateAttributeError('src', 'framework', plugin.id));
@@ -125,17 +125,17 @@ var handlers = {
subDir = src; subDir = src;
} }
if (obj.type == 'gradleReference') { if (obj.type === 'gradleReference') {
project.removeGradleReference(parentDir, subDir); project.removeGradleReference(parentDir, subDir);
} else if (obj.type == 'sys') { } else if (obj.type === 'sys') {
project.removeSystemLibrary(parentDir, subDir); project.removeSystemLibrary(parentDir, subDir);
} else { } else {
project.removeSubProject(parentDir, subDir); project.removeSubProject(parentDir, subDir);
} }
} }
}, },
asset:{ asset: {
install:function(obj, plugin, project, options) { install: function (obj, plugin, project, options) {
if (!obj.src) { if (!obj.src) {
throw new CordovaError(generateAttributeError('src', 'asset', plugin.id)); throw new CordovaError(generateAttributeError('src', 'asset', plugin.id));
} }
@@ -149,7 +149,7 @@ var handlers = {
copyFile(plugin.dir, obj.src, project.platformWww, obj.target); 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; var target = obj.target || obj.src;
if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id)); if (!target) throw new CordovaError(generateAttributeError('target', 'asset', plugin.id));
@@ -167,7 +167,7 @@ var handlers = {
install: function (obj, plugin, project, options) { install: function (obj, plugin, project, options) {
// Copy the plugin's files into the www directory. // Copy the plugin's files into the www directory.
var moduleSource = path.resolve(plugin.dir, obj.src); var moduleSource = path.resolve(plugin.dir, obj.src);
var moduleName = plugin.id + '.' + (obj.name || path.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. // Read in the file, prepend the cordova.define, and write it back out.
var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM var scriptContent = fs.readFileSync(moduleSource, 'utf-8').replace(/^\ufeff/, ''); // Window BOM
@@ -206,7 +206,7 @@ module.exports.getInstaller = function (type) {
events.emit('verbose', '<' + type + '> is not supported for android plugins'); events.emit('verbose', '<' + type + '> is not supported for android plugins');
}; };
module.exports.getUninstaller = function(type) { module.exports.getUninstaller = function (type) {
if (handlers[type] && handlers[type].uninstall) { if (handlers[type] && handlers[type].uninstall) {
return handlers[type].uninstall; return handlers[type].uninstall;
} }
@@ -221,21 +221,19 @@ function copyFile (plugin_dir, src, project_dir, dest, link) {
// check that src path is inside plugin directory // check that src path is inside plugin directory
var real_path = fs.realpathSync(src); var real_path = fs.realpathSync(src);
var real_plugin_path = fs.realpathSync(plugin_dir); var real_plugin_path = fs.realpathSync(plugin_dir);
if (real_path.indexOf(real_plugin_path) !== 0) if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }
throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"');
dest = path.resolve(project_dir, dest); dest = path.resolve(project_dir, dest);
// check that dest path is located in project directory // check that dest path is located in project directory
if (dest.indexOf(project_dir) !== 0) if (dest.indexOf(project_dir) !== 0) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }
throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project');
shell.mkdir('-p', path.dirname(dest)); shell.mkdir('-p', path.dirname(dest));
if (link) { if (link) {
symlinkFileOrDirTree(src, dest); symlinkFileOrDirTree(src, dest);
} else if (fs.statSync(src).isDirectory()) { } else if (fs.statSync(src).isDirectory()) {
// XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq // XXX shelljs decides to create a directory when -R|-r is used which sucks. http://goo.gl/nbsjq
shell.cp('-Rf', src+'/*', dest); shell.cp('-Rf', src + '/*', dest);
} else { } else {
shell.cp('-f', src, dest); shell.cp('-f', src, dest);
} }
@@ -244,24 +242,22 @@ function copyFile (plugin_dir, src, project_dir, dest, link) {
// Same as copy file but throws error if target exists // Same as copy file but throws error if target exists
function copyNewFile (plugin_dir, src, project_dir, dest, link) { function copyNewFile (plugin_dir, src, project_dir, dest, link) {
var target_path = path.resolve(project_dir, dest); var target_path = path.resolve(project_dir, dest);
if (fs.existsSync(target_path)) if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); }
throw new CordovaError('"' + target_path + '" already exists!');
copyFile(plugin_dir, src, project_dir, dest, !!link); copyFile(plugin_dir, src, project_dir, dest, !!link);
} }
function symlinkFileOrDirTree(src, dest) { function symlinkFileOrDirTree (src, dest) {
if (fs.existsSync(dest)) { if (fs.existsSync(dest)) {
shell.rm('-Rf', dest); shell.rm('-Rf', dest);
} }
if (fs.statSync(src).isDirectory()) { if (fs.statSync(src).isDirectory()) {
shell.mkdir('-p', dest); 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)); symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
}); });
} } else {
else {
fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest); fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);
} }
} }
@@ -292,8 +288,8 @@ function removeFileAndParents (baseDir, destFile, stopper) {
// check if directory is empty // check if directory is empty
var curDir = path.dirname(file); var curDir = path.dirname(file);
while(curDir !== path.resolve(baseDir, stopper)) { while (curDir !== path.resolve(baseDir, stopper)) {
if(fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) { if (fs.existsSync(curDir) && fs.readdirSync(curDir).length === 0) {
fs.rmdirSync(curDir); fs.rmdirSync(curDir);
curDir = path.resolve(curDir, '..'); curDir = path.resolve(curDir, '..');
} else { } else {
@@ -303,6 +299,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; return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
} }
+55 -47
View File
@@ -16,6 +16,7 @@
specific language governing permissions and limitations specific language governing permissions and limitations
under the License. under the License.
*/ */
/* eslint no-useless-escape: 0 */
var Q = require('q'); var Q = require('q');
var fs = require('fs'); var fs = require('fs');
@@ -23,6 +24,7 @@ var path = require('path');
var shell = require('shelljs'); var shell = require('shelljs');
var events = require('cordova-common').events; var events = require('cordova-common').events;
var AndroidManifest = require('./AndroidManifest'); var AndroidManifest = require('./AndroidManifest');
var checkReqs = require('./check_reqs');
var xmlHelpers = require('cordova-common').xmlHelpers; var xmlHelpers = require('cordova-common').xmlHelpers;
var CordovaError = require('cordova-common').CordovaError; var CordovaError = require('cordova-common').CordovaError;
var ConfigParser = require('cordova-common').ConfigParser; var ConfigParser = require('cordova-common').ConfigParser;
@@ -40,17 +42,14 @@ module.exports.prepare = function (cordovaProject, options) {
this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations); this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
// Update own www dir with project's www assets and plugins' assets and js-files // Update own www dir with project's www assets and plugins' assets and js-files
return Q.when(updateWww(cordovaProject, this.locations)) return Q.when(updateWww(cordovaProject, this.locations)).then(function () {
.then(function () {
// update project according to config.xml changes. // update project according to config.xml changes.
return updateProjectAccordingTo(self._config, self.locations); return updateProjectAccordingTo(self._config, self.locations);
}) }).then(function () {
.then(function () {
updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res)); updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
updateSplashes(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)); updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root));
}) }).then(function () {
.then(function () {
events.emit('verbose', 'Prepared android project successfully'); events.emit('verbose', 'Prepared android project successfully');
}); });
}; };
@@ -91,7 +90,7 @@ module.exports.clean = function (options) {
* represents current project's configuration. When returned, the * represents current project's configuration. When returned, the
* configuration is already dumped to appropriate config.xml file. * configuration is already dumped to appropriate config.xml file.
*/ */
function updateConfigFilesFrom(sourceConfig, configMunger, locations) { function updateConfigFilesFrom (sourceConfig, configMunger, locations) {
events.emit('verbose', 'Generating platform-specific config.xml from defaults for android at ' + locations.configXml); 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 // First cleanup current config and merge project's one into own
@@ -106,7 +105,7 @@ function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
// Merge changes from app's config.xml into platform's one // Merge changes from app's config.xml into platform's one
var config = new ConfigParser(locations.configXml); var config = new ConfigParser(locations.configXml);
xmlHelpers.mergeXml(sourceConfig.doc.getroot(), xmlHelpers.mergeXml(sourceConfig.doc.getroot(),
config.doc.getroot(), 'android', /*clobber=*/true); config.doc.getroot(), 'android', /* clobber= */true);
config.write(); config.write();
return config; return config;
@@ -115,7 +114,7 @@ function updateConfigFilesFrom(sourceConfig, configMunger, locations) {
/** /**
* Logs all file operations via the verbose event stream, indented. * Logs all file operations via the verbose event stream, indented.
*/ */
function logFileOp(message) { function logFileOp (message) {
events.emit('verbose', ' ' + message); events.emit('verbose', ' ' + message);
} }
@@ -128,7 +127,7 @@ function logFileOp(message) {
* @param {Object} destinations An object that contains destination * @param {Object} destinations An object that contains destination
* paths for www files. * paths for www files.
*/ */
function updateWww(cordovaProject, destinations) { function updateWww (cordovaProject, destinations) {
var sourceDirs = [ var sourceDirs = [
path.relative(cordovaProject.root, cordovaProject.locations.www), path.relative(cordovaProject.root, cordovaProject.locations.www),
path.relative(cordovaProject.root, destinations.platformWww) path.relative(cordovaProject.root, destinations.platformWww)
@@ -151,7 +150,7 @@ function updateWww(cordovaProject, destinations) {
/** /**
* Cleans all files from the platform 'www' directory. * Cleans all files from the platform 'www' directory.
*/ */
function cleanWww(projectRoot, locations) { function cleanWww (projectRoot, locations) {
var targetDir = path.relative(projectRoot, locations.www); var targetDir = path.relative(projectRoot, locations.www);
events.emit('verbose', 'Cleaning ' + targetDir); events.emit('verbose', 'Cleaning ' + targetDir);
@@ -167,19 +166,26 @@ function cleanWww(projectRoot, locations) {
* be used to update project * be used to update project
* @param {Object} locations A map of locations for this platform * @param {Object} locations A map of locations for this platform
*/ */
function updateProjectAccordingTo(platformConfig, locations) { function updateProjectAccordingTo (platformConfig, locations) {
// Update app name by editing res/values/strings.xml // Update app name by editing res/values/strings.xml
var name = platformConfig.name();
var strings = xmlHelpers.parseElementtreeSync(locations.strings); var strings = xmlHelpers.parseElementtreeSync(locations.strings);
var name = platformConfig.name();
strings.find('string[@name="app_name"]').text = name.replace(/\'/g, '\\\''); 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'); fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings); events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
// Java packages cannot support dashes // Java packages cannot support dashes
var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_'); var androidPkgName = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
var manifest = new AndroidManifest(locations.manifest); var manifest = new AndroidManifest(locations.manifest);
var orig_pkg = manifest.getPackageId(); var manifestId = manifest.getPackageId();
manifest.getActivity() manifest.getActivity()
.setOrientation(platformConfig.getPreference('orientation')) .setOrientation(platformConfig.getPreference('orientation'))
@@ -187,36 +193,40 @@ function updateProjectAccordingTo(platformConfig, locations) {
manifest.setVersionName(platformConfig.version()) manifest.setVersionName(platformConfig.version())
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version())) .setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
.setPackageId(pkg) .setPackageId(androidPkgName)
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android')) .setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android')) .setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android')) .setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
.write(); .write();
var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java'); var javaPattern = path.join(locations.root, 'src', manifestId.replace(/\./g, '/'), '*.java');
var java_files = shell.ls(javaPattern).filter(function(f) { var java_files = shell.ls(javaPattern).filter(function (f) {
return shell.grep(/extends\s+CordovaActivity/g, f); return shell.grep(/extends\s+CordovaActivity/g, f);
}); });
if (java_files.length === 0) { if (java_files.length === 0) {
throw new CordovaError('No Java files found that extend CordovaActivity.'); 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]); 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', pkg.replace(/\./g, '/'), path.basename(java_files[0])); var destFile = path.join(locations.root, 'src', androidPkgName.replace(/\./g, '/'), path.basename(java_files[0]));
shell.mkdir('-p', path.dirname(destFile)); shell.mkdir('-p', path.dirname(destFile));
shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile); shell.sed(/package [\w\.]*;/, 'package ' + androidPkgName + ';', java_files[0]).to(destFile);
events.emit('verbose', 'Wrote out Android package name "' + pkg + '" to ' + destFile); events.emit('verbose', 'Wrote out Android package name "' + androidPkgName + '" to ' + destFile);
if (orig_pkg !== pkg) { var removeOrigPkg = checkReqs.isWindows() || checkReqs.isDarwin() ?
manifestId.toUpperCase() !== androidPkgName.toUpperCase() :
manifestId !== androidPkgName;
if (removeOrigPkg) {
// If package was name changed we need to remove old java with main activity // 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 // remove any empty directories
var currentDir = path.dirname(java_files[0]); var currentDir = path.dirname(java_files[0]);
var sourcesRoot = path.resolve(locations.root, 'src'); var sourcesRoot = path.resolve(locations.root, 'src');
while(currentDir !== sourcesRoot) { while (currentDir !== sourcesRoot) {
if(fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) { if (fs.existsSync(currentDir) && fs.readdirSync(currentDir).length === 0) {
fs.rmdirSync(currentDir); fs.rmdirSync(currentDir);
currentDir = path.resolve(currentDir, '..'); currentDir = path.resolve(currentDir, '..');
} else { } else {
@@ -229,7 +239,7 @@ function updateProjectAccordingTo(platformConfig, locations) {
// Consturct the default value for versionCode as // Consturct the default value for versionCode as
// PATCH + MINOR * 100 + MAJOR * 10000 // PATCH + MINOR * 100 + MAJOR * 10000
// see http://developer.android.com/tools/publishing/versioning.html // see http://developer.android.com/tools/publishing/versioning.html
function default_versionCode(version) { function default_versionCode (version) {
var nums = version.split('-')[0].split('.'); var nums = version.split('-')[0].split('.');
var versionCode = 0; var versionCode = 0;
if (+nums[0]) { if (+nums[0]) {
@@ -246,7 +256,7 @@ function default_versionCode(version) {
return versionCode; return versionCode;
} }
function getImageResourcePath(resourcesDir, type, density, name, sourceName) { function getImageResourcePath (resourcesDir, type, density, name, sourceName) {
if (/\.9\.png$/.test(sourceName)) { if (/\.9\.png$/.test(sourceName)) {
name = name.replace(/\.png$/, '.9.png'); name = name.replace(/\.png$/, '.9.png');
} }
@@ -254,7 +264,7 @@ function getImageResourcePath(resourcesDir, type, density, name, sourceName) {
return resourcePath; return resourcePath;
} }
function updateSplashes(cordovaProject, platformResourcesDir) { function updateSplashes (cordovaProject, platformResourcesDir) {
var resources = cordovaProject.projectConfig.getSplashScreens('android'); var resources = cordovaProject.projectConfig.getSplashScreens('android');
// if there are "splash" elements in config.xml // if there are "splash" elements in config.xml
@@ -270,7 +280,7 @@ function updateSplashes(cordovaProject, platformResourcesDir) {
if (!resource.density) { if (!resource.density) {
return; return;
} }
if (resource.density == 'mdpi') { if (resource.density === 'mdpi') {
hadMdpi = true; hadMdpi = true;
} }
var targetPath = getImageResourcePath( var targetPath = getImageResourcePath(
@@ -290,7 +300,7 @@ function updateSplashes(cordovaProject, platformResourcesDir) {
resourceMap, { rootDir: cordovaProject.root }, logFileOp); resourceMap, { rootDir: cordovaProject.root }, logFileOp);
} }
function cleanSplashes(projectRoot, projectConfig, platformResourcesDir) { function cleanSplashes (projectRoot, projectConfig, platformResourcesDir) {
var resources = projectConfig.getSplashScreens('android'); var resources = projectConfig.getSplashScreens('android');
if (resources.length > 0) { if (resources.length > 0) {
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'drawable', 'screen.png'); var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'drawable', 'screen.png');
@@ -302,7 +312,7 @@ function cleanSplashes(projectRoot, projectConfig, platformResourcesDir) {
} }
} }
function updateIcons(cordovaProject, platformResourcesDir) { function updateIcons (cordovaProject, platformResourcesDir) {
var icons = cordovaProject.projectConfig.getIcons('android'); var icons = cordovaProject.projectConfig.getIcons('android');
// if there are icon elements in config.xml // if there are icon elements in config.xml
@@ -326,7 +336,7 @@ function updateIcons(cordovaProject, platformResourcesDir) {
}; };
// find the best matching icon for a given density or size // find the best matching icon for a given density or size
// @output android_icons // @output android_icons
var parseIcon = function(icon, icon_size) { var parseIcon = function (icon, icon_size) {
// do I have a platform icon for that density already // do I have a platform icon for that density already
var density = icon.density || sizeToDensityMap[icon_size]; var density = icon.density || sizeToDensityMap[icon_size];
if (!density) { if (!density) {
@@ -341,7 +351,7 @@ function updateIcons(cordovaProject, platformResourcesDir) {
}; };
// iterate over all icon elements to find the default icon and call parseIcon // iterate over all icon elements to find the default icon and call parseIcon
for (var i=0; i<icons.length; i++) { for (var i = 0; i < icons.length; i++) {
var icon = icons[i]; var icon = icons[i];
var size = icon.width; var size = icon.width;
if (!size) { if (!size) {
@@ -378,7 +388,7 @@ function updateIcons(cordovaProject, platformResourcesDir) {
resourceMap, { rootDir: cordovaProject.root }, logFileOp); resourceMap, { rootDir: cordovaProject.root }, logFileOp);
} }
function cleanIcons(projectRoot, projectConfig, platformResourcesDir) { function cleanIcons (projectRoot, projectConfig, platformResourcesDir) {
var icons = projectConfig.getIcons('android'); var icons = projectConfig.getIcons('android');
if (icons.length > 0) { if (icons.length > 0) {
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'icon.png'); var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'icon.png');
@@ -393,18 +403,16 @@ function cleanIcons(projectRoot, projectConfig, platformResourcesDir) {
/** /**
* Gets a map containing resources of a specified name from all drawable folders in a directory. * 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 = {}; var pathMap = {};
shell.ls(path.join(rootDir, subDir, type + '-*')) shell.ls(path.join(rootDir, subDir, type + '-*')).forEach(function (drawableFolder) {
.forEach(function (drawableFolder) {
var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName); var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName);
pathMap[imagePath] = null; pathMap[imagePath] = null;
}); });
return pathMap; return pathMap;
} }
function updateFileResources (cordovaProject, platformDir) {
function updateFileResources(cordovaProject, platformDir) {
var files = cordovaProject.projectConfig.getFileResources('android'); var files = cordovaProject.projectConfig.getFileResources('android');
// if there are resource-file elements in config.xml // if there are resource-file elements in config.xml
@@ -414,7 +422,7 @@ function updateFileResources(cordovaProject, platformDir) {
} }
var resourceMap = {}; var resourceMap = {};
files.forEach(function(res) { files.forEach(function (res) {
var targetPath = path.join(platformDir, res.target); var targetPath = path.join(platformDir, res.target);
resourceMap[targetPath] = res.src; resourceMap[targetPath] = res.src;
}); });
@@ -424,20 +432,20 @@ function updateFileResources(cordovaProject, platformDir) {
resourceMap, { rootDir: cordovaProject.root }, logFileOp); resourceMap, { rootDir: cordovaProject.root }, logFileOp);
} }
function cleanFileResources (projectRoot, projectConfig, platformDir) {
function cleanFileResources(projectRoot, projectConfig, platformDir) { var files = projectConfig.getFileResources('android', true);
var files = projectConfig.getFileResources('android');
if (files.length > 0) { if (files.length > 0) {
events.emit('verbose', 'Cleaning resource files at ' + platformDir); events.emit('verbose', 'Cleaning resource files at ' + platformDir);
var resourceMap = {}; var resourceMap = {};
files.forEach(function(res) { files.forEach(function (res) {
var filePath = path.join(platformDir, res.target); var filePath = path.join(platformDir, res.target);
resourceMap[filePath] = null; resourceMap[filePath] = null;
}); });
FileUpdater.updatePaths( FileUpdater.updatePaths(
resourceMap, { rootDir: projectRoot, all: true}, logFileOp); resourceMap, {
rootDir: projectRoot, all: true}, logFileOp);
} }
} }
@@ -452,7 +460,7 @@ function cleanFileResources(projectRoot, projectConfig, platformDir) {
* default value, if there is no such preference. The default value is * default value, if there is no such preference. The default value is
* 'singleTop' * 'singleTop'
*/ */
function findAndroidLaunchModePreference(platformConfig) { function findAndroidLaunchModePreference (platformConfig) {
var launchMode = platformConfig.getPreference('AndroidLaunchMode'); var launchMode = platformConfig.getPreference('AndroidLaunchMode');
if (!launchMode) { if (!launchMode) {
// Return a default value // Return a default value
+2 -2
View File
@@ -45,12 +45,12 @@ module.exports.retryPromise = function (attemts_left, promiseFunction) {
return promiseFunction.apply(undefined, promiseFunctionArguments).then( return promiseFunction.apply(undefined, promiseFunctionArguments).then(
// on success pass results through // on success pass results through
function onFulfilled(value) { function onFulfilled (value) {
return value; return value;
}, },
// on rejection either retry, or throw the error // on rejection either retry, or throw the error
function onRejected(error) { function onRejected (error) {
attemts_left -= 1; attemts_left -= 1;
+24 -33
View File
@@ -21,14 +21,14 @@
/* jshint loopfunc:true */ /* jshint loopfunc:true */
var path = require('path'), var path = require('path');
build = require('./build'), var build = require('./build');
emulator = require('./emulator'), var emulator = require('./emulator');
device = require('./device'), var device = require('./device');
Q = require('q'), var Q = require('q');
events = require('cordova-common').events; var events = require('cordova-common').events;
function getInstallTarget(runOptions) { function getInstallTarget (runOptions) {
var install_target; var install_target;
if (runOptions.target) { if (runOptions.target) {
install_target = runOptions.target; install_target = runOptions.target;
@@ -51,17 +51,15 @@ function getInstallTarget(runOptions) {
* *
* @return {Promise} * @return {Promise}
*/ */
module.exports.run = function(runOptions) { module.exports.run = function (runOptions) {
var self = this; var self = this;
var install_target = getInstallTarget(runOptions); var install_target = getInstallTarget(runOptions);
return Q() return Q().then(function () {
.then(function() {
if (!install_target) { if (!install_target) {
// no target given, deploy to device if available, otherwise use the emulator. // no target given, deploy to device if available, otherwise use the emulator.
return device.list() return device.list().then(function (device_list) {
.then(function(device_list) {
if (device_list.length > 0) { if (device_list.length > 0) {
events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.'); events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.');
install_target = device_list[0]; install_target = device_list[0];
@@ -71,36 +69,31 @@ function getInstallTarget(runOptions) {
} }
}); });
} }
}).then(function() { }).then(function () {
if (install_target == '--device') { if (install_target === '--device') {
return device.resolveTarget(null); return device.resolveTarget(null);
} else if (install_target == '--emulator') { } else if (install_target === '--emulator') {
// Give preference to any already started emulators. Else, start one. // Give preference to any already started emulators. Else, start one.
return emulator.list_started() return emulator.list_started().then(function (started) {
.then(function(started) {
return started && started.length > 0 ? started[0] : emulator.start(); return started && started.length > 0 ? started[0] : emulator.start();
}).then(function(emulatorId) { }).then(function (emulatorId) {
return emulator.resolveTarget(emulatorId); return emulator.resolveTarget(emulatorId);
}); });
} }
// They specified a specific device/emulator ID. // They specified a specific device/emulator ID.
return device.list() return device.list().then(function (devices) {
.then(function(devices) {
if (devices.indexOf(install_target) > -1) { if (devices.indexOf(install_target) > -1) {
return device.resolveTarget(install_target); return device.resolveTarget(install_target);
} }
return emulator.list_started() return emulator.list_started().then(function (started_emulators) {
.then(function(started_emulators) {
if (started_emulators.indexOf(install_target) > -1) { if (started_emulators.indexOf(install_target) > -1) {
return emulator.resolveTarget(install_target); return emulator.resolveTarget(install_target);
} }
return emulator.list_images() return emulator.list_images().then(function (avds) {
.then(function(avds) {
// if target emulator isn't started, then start it. // if target emulator isn't started, then start it.
for (var avd in avds) { for (var avd in avds) {
if (avds[avd].name == install_target) { if (avds[avd].name === install_target) {
return emulator.start(install_target) return emulator.start(install_target).then(function (emulatorId) {
.then(function(emulatorId) {
return emulator.resolveTarget(emulatorId); return emulator.resolveTarget(emulatorId);
}); });
} }
@@ -109,16 +102,14 @@ function getInstallTarget(runOptions) {
}); });
}); });
}); });
}).then(function(resolvedTarget) { }).then(function (resolvedTarget) {
// Better just call self.build, but we're doing some processing of // Better just call self.build, but we're doing some processing of
// build results (according to platformApi spec) so they are in different // build results (according to platformApi spec) so they are in different
// format than emulator.install expects. // format than emulator.install expects.
// TODO: Update emulator/device.install to handle this change // TODO: Update emulator/device.install to handle this change
return build.run.call(self, runOptions, resolvedTarget) return build.run.call(self, runOptions, resolvedTarget).then(function (buildResults) {
.then(function(buildResults) {
if (resolvedTarget.isEmulator) { if (resolvedTarget.isEmulator) {
return emulator.wait_for_boot(resolvedTarget.target) return emulator.wait_for_boot(resolvedTarget.target).then(function () {
.then(function () {
return emulator.install(resolvedTarget, buildResults); return emulator.install(resolvedTarget, buildResults);
}); });
} }
@@ -127,7 +118,7 @@ function getInstallTarget(runOptions) {
}); });
}; };
module.exports.help = function() { module.exports.help = function () {
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]) + ' [options]'); console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]) + ' [options]');
console.log('Build options :'); console.log('Build options :');
console.log(' --debug : Builds project in debug mode'); console.log(' --debug : Builds project in debug mode');
+1 -1
View File
@@ -18,7 +18,7 @@
@ECHO OFF @ECHO OFF
SET script_path="%~dp0start-emulator" SET script_path="%~dp0start-emulator"
IF EXIST %script_path% ( IF EXIST %script_path% (
node "%script_path%" %* node %script_path% %*
) ELSE ( ) ELSE (
ECHO. ECHO.
ECHO ERROR: Could not find 'start-emulator' script in 'cordova\lib' folder, aborting...>&2 ECHO ERROR: Could not find 'start-emulator' script in 'cordova\lib' folder, aborting...>&2
+1 -1
View File
@@ -20,7 +20,7 @@
*/ */
// Coho updates this line: // Coho updates this line:
var VERSION = "6.2.3"; var VERSION = "6.4.1-dev";
module.exports.version = VERSION; module.exports.version = VERSION;
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -18,25 +18,25 @@
*/ */
var app = { var app = {
// Application Constructor // Application Constructor
initialize: function() { initialize: function () {
this.bindEvents(); this.bindEvents();
}, },
// Bind Event Listeners // Bind Event Listeners
// //
// Bind any events that are required on startup. Common events are: // Bind any events that are required on startup. Common events are:
// 'load', 'deviceready', 'offline', and 'online'. // 'load', 'deviceready', 'offline', and 'online'.
bindEvents: function() { bindEvents: function () {
document.addEventListener('deviceready', this.onDeviceReady, false); document.addEventListener('deviceready', this.onDeviceReady, false);
}, },
// deviceready Event Handler // deviceready Event Handler
// //
// The scope of 'this' is the event. In order to call the 'receivedEvent' // The scope of 'this' is the event. In order to call the 'receivedEvent'
// function, we must explicitly call 'app.receivedEvent(...);' // function, we must explicitly call 'app.receivedEvent(...);'
onDeviceReady: function() { onDeviceReady: function () {
app.receivedEvent('deviceready'); app.receivedEvent('deviceready');
}, },
// Update DOM on a Received Event // Update DOM on a Received Event
receivedEvent: function(id) { receivedEvent: function (id) {
var parentElement = document.getElementById(id); var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening'); var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received'); var receivedElement = parentElement.querySelector('.received');
@@ -48,4 +48,4 @@ var app = {
} }
}; };
app.initialize(); app.initialize();
+40 -10
View File
@@ -21,8 +21,10 @@ apply plugin: 'com.android.application'
buildscript { buildscript {
repositories { repositories {
mavenCentral()
jcenter() jcenter()
maven {
url "https://maven.google.com"
}
} }
// Switch the Android Gradle plugin version requirement depending on the // Switch the Android Gradle plugin version requirement depending on the
@@ -30,20 +32,22 @@ buildscript {
// http://tools.android.com/tech-docs/new-build-system/version-compatibility // http://tools.android.com/tech-docs/new-build-system/version-compatibility
// and https://issues.apache.org/jira/browse/CB-8143 // and https://issues.apache.org/jira/browse/CB-8143
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.2.3' classpath 'com.android.tools.build:gradle:3.0.0'
} }
} }
// Allow plugins to declare Maven dependencies via build-extras.gradle. // Allow plugins to declare Maven dependencies via build-extras.gradle.
allprojects { allprojects {
repositories { repositories {
mavenCentral();
jcenter() jcenter()
maven {
url "https://maven.google.com"
}
} }
} }
task wrapper(type: Wrapper) { task wrapper(type: Wrapper) {
gradleVersion = '2.14.1' gradleVersion = '4.1.0'
} }
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties. // Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
@@ -70,6 +74,10 @@ ext {
if (!project.hasProperty('cdvBuildMultipleApks')) { if (!project.hasProperty('cdvBuildMultipleApks')) {
cdvBuildMultipleApks = null 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. // .properties files to use for release signing.
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) { if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
cdvReleaseSigningPropertiesFile = null cdvReleaseSigningPropertiesFile = null
@@ -111,6 +119,7 @@ if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.propert
// Cast to appropriate types. // Cast to appropriate types.
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean(); ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
ext.cdvVersionCodeForceAbiDigit = cdvVersionCodeForceAbiDigit == null ? false : cdvVersionCodeForceAbiDigit.toBoolean();
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion) ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode) ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
@@ -138,6 +147,7 @@ task cdvPrintProps << {
println('cdvCompileSdkVersion=' + cdvCompileSdkVersion) println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion) println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
println('cdvVersionCode=' + cdvVersionCode) println('cdvVersionCode=' + cdvVersionCode)
println('cdvVersionCodeForceAbiDigit=' + cdvVersionCodeForceAbiDigit)
println('cdvMinSdkVersion=' + cdvMinSdkVersion) println('cdvMinSdkVersion=' + cdvMinSdkVersion)
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks) println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile) println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
@@ -180,25 +190,45 @@ android {
buildToolsVersion cdvBuildToolsVersion buildToolsVersion cdvBuildToolsVersion
if (Boolean.valueOf(cdvBuildMultipleApks)) { if (Boolean.valueOf(cdvBuildMultipleApks)) {
flavorDimensions "default"
productFlavors { productFlavors {
armeabi {
versionCode defaultConfig.versionCode*10 + 1
ndk {
abiFilters = ["armeabi"]
}
}
armv7 { armv7 {
versionCode defaultConfig.versionCode*10 + 2 versionCode defaultConfig.versionCode*10 + 2
ndk { ndk {
abiFilters "armeabi-v7a", "" abiFilters = ["armeabi-v7a"]
}
}
arm64 {
versionCode defaultConfig.versionCode*10 + 3
ndk {
abiFilters = ["arm64-v8a"]
} }
} }
x86 { x86 {
versionCode defaultConfig.versionCode*10 + 4 versionCode defaultConfig.versionCode*10 + 4
ndk { ndk {
abiFilters "x86", "" abiFilters = ["x86"]
} }
} }
all { x86_64 {
versionCode defaultConfig.versionCode*10 + 5
ndk { ndk {
abiFilters "all", "" abiFilters = ["x86_64"]
} }
} }
} }
} 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
}
} }
/* /*
@@ -245,7 +275,7 @@ android {
} }
dependencies { dependencies {
compile fileTree(dir: 'libs', include: '*.jar') implementation fileTree(dir: 'libs', include: '*.jar')
// SUB-PROJECT DEPENDENCIES START // SUB-PROJECT DEPENDENCIES START
// SUB-PROJECT DEPENDENCIES END // SUB-PROJECT DEPENDENCIES END
} }
@@ -264,7 +294,7 @@ def promptForReleaseKeyPassword() {
gradle.taskGraph.whenReady { taskGraph -> gradle.taskGraph.whenReady { taskGraph ->
taskGraph.getAllTasks().each() { task -> taskGraph.getAllTasks().each() { task ->
if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') { if (['validateReleaseSigning', 'validateSigningRelease', 'validateSigningArmv7Release', 'validateSigningX86Release'].contains(task.name)) {
promptForReleaseKeyPassword() promptForReleaseKeyPassword()
} }
} }
Binary file not shown.

Before

Width:  |  Height:  |  Size: 213 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 KiB

After

Width:  |  Height:  |  Size: 139 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 222 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 286 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 217 KiB

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 493 KiB

After

Width:  |  Height:  |  Size: 138 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 207 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

After

Width:  |  Height:  |  Size: 292 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 7.7 KiB

+7 -5
View File
@@ -24,12 +24,14 @@ ext {
buildscript { buildscript {
repositories { repositories {
mavenCentral()
jcenter() jcenter()
maven {
url "https://maven.google.com"
}
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:2.2.3' classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3' classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
} }
@@ -40,7 +42,7 @@ apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray' apply plugin: 'com.jfrog.bintray'
group = 'org.apache.cordova' group = 'org.apache.cordova'
version = '6.2.3' version = '6.4.1-dev'
android { android {
compileSdkVersion cdvCompileSdkVersion compileSdkVersion cdvCompileSdkVersion
@@ -127,9 +129,9 @@ bintray {
licenses = ['Apache-2.0'] licenses = ['Apache-2.0']
labels = ['android', 'cordova', 'phonegap'] labels = ['android', 'cordova', 'phonegap']
version { version {
name = '6.2.3' name = '6.4.1-dev'
released = new Date() released = new Date()
vcsTag = '6.2.3' vcsTag = '6.4.1-dev'
} }
} }
} }
+2 -2
View File
@@ -1,6 +1,6 @@
#Mon Dec 28 10:00:20 PST 2015 #Thu Nov 09 10:50:25 PST 2017
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
+1 -1
View File
@@ -10,7 +10,7 @@
# Indicates whether an apk should be generated for each density. # Indicates whether an apk should be generated for each density.
split.density=false split.density=false
# Project target. # Project target.
target=android-25 target=android-26
apk-configurations= apk-configurations=
renderscript.opt.level=O0 renderscript.opt.level=O0
android.library=true android.library=true
@@ -0,0 +1,70 @@
/*
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;
}
}
@@ -19,6 +19,7 @@
package org.apache.cordova; package org.apache.cordova;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CordovaPlugin;
@@ -51,10 +52,18 @@ public interface CordovaInterface {
/** /**
* Get the Android activity. * Get the Android activity.
* *
* If a custom engine lives outside of the Activity's lifecycle the return value may be null.
*
* @return the Activity * @return the Activity
*/ */
public abstract Activity getActivity(); public abstract Activity getActivity();
/**
* Get the Android context.
*
* @return the Context
*/
public Context getContext();
/** /**
* Called when a message is sent to plugin. * Called when a message is sent to plugin.
@@ -20,6 +20,7 @@
package org.apache.cordova; package org.apache.cordova;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.os.Build; import android.os.Build;
@@ -84,6 +85,11 @@ public class CordovaInterfaceImpl implements CordovaInterface {
return activity; return activity;
} }
@Override
public Context getContext() {
return activity;
}
@Override @Override
public Object onMessage(String id, Object data) { public Object onMessage(String id, Object data) {
if ("exit".equals(id)) { if ("exit".equals(id)) {
@@ -31,7 +31,7 @@ import android.webkit.WebChromeClient.CustomViewCallback;
* are not expected to implement it. * are not expected to implement it.
*/ */
public interface CordovaWebView { public interface CordovaWebView {
public static final String CORDOVA_VERSION = "6.2.3"; public static final String CORDOVA_VERSION = "6.4.1-dev";
void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences); void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences);
@@ -0,0 +1,87 @@
/*
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);
}
}
}
@@ -110,7 +110,11 @@ public class SystemWebViewEngine implements CordovaWebViewEngine {
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() { nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() {
@Override @Override
public void setNetworkAvailable(boolean value) { public void setNetworkAvailable(boolean value) {
webView.setNetworkAvailable(value); //sometimes this can be called after calling webview.destroy() on destroy()
//thus resulting in a NullPointerException
if(webView!=null) {
webView.setNetworkAvailable(value);
}
} }
@Override @Override
public void runOnUiThread(Runnable r) { public void runOnUiThread(Runnable r) {
@@ -210,11 +214,6 @@ public class SystemWebViewEngine implements CordovaWebViewEngine {
settings.setAppCachePath(databasePath); settings.setAppCachePath(databasePath);
settings.setAppCacheEnabled(true); settings.setAppCacheEnabled(true);
// Enable scaling
// Fix for CB-12015
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
// Fix for CB-1405 // Fix for CB-1405
// Google issue 4641 // Google issue 4641
String defaultUserAgent = settings.getUserAgentString(); String defaultUserAgent = settings.getUserAgentString();
+3 -3
View File
@@ -10,7 +10,7 @@
"spec": ">=1.0.0 <2.0.0", "spec": ">=1.0.0 <2.0.0",
"type": "range" "type": "range"
}, },
"/Users/steveng/repo/cordova/cordova-android/node_modules/nopt" "/Users/jbowser/cordova/cordova-android/node_modules/nopt"
] ]
], ],
"_from": "abbrev@>=1.0.0 <2.0.0", "_from": "abbrev@>=1.0.0 <2.0.0",
@@ -40,11 +40,11 @@
"_requiredBy": [ "_requiredBy": [
"/nopt" "/nopt"
], ],
"_resolved": "http://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz", "_resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.0.tgz",
"_shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f", "_shasum": "d0554c2256636e2f56e7c2e5ad183f859428d81f",
"_shrinkwrap": null, "_shrinkwrap": null,
"_spec": "abbrev@1", "_spec": "abbrev@1",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/nopt", "_where": "/Users/jbowser/cordova/cordova-android/node_modules/nopt",
"author": { "author": {
"name": "Isaac Z. Schlueter", "name": "Isaac Z. Schlueter",
"email": "i@izs.me" "email": "i@izs.me"
+8
View File
@@ -0,0 +1,8 @@
.git/
node_modules/
coverage/
build/
assets/
dist/
docs/
tests/
+28
View File
@@ -0,0 +1,28 @@
{
"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
}
+3
View File
@@ -0,0 +1,3 @@
language: node_js
node_js:
- "6.1.0"
+87
View File
@@ -0,0 +1,87 @@
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
+153
View File
@@ -0,0 +1,153 @@
/**
* 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)
}
}
+103
View File
@@ -0,0 +1,103 @@
{
"_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"
}
+3 -3
View File
@@ -10,7 +10,7 @@
"spec": ">=0.3.1 <0.4.0", "spec": ">=0.3.1 <0.4.0",
"type": "range" "type": "range"
}, },
"/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common" "/Users/jbowser/cordova/cordova-android/node_modules/cordova-common"
] ]
], ],
"_from": "ansi@>=0.3.1 <0.4.0", "_from": "ansi@>=0.3.1 <0.4.0",
@@ -36,11 +36,11 @@
"_requiredBy": [ "_requiredBy": [
"/cordova-common" "/cordova-common"
], ],
"_resolved": "http://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz", "_resolved": "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz",
"_shasum": "0c42d4fb17160d5a9af1e484bace1c66922c1b21", "_shasum": "0c42d4fb17160d5a9af1e484bace1c66922c1b21",
"_shrinkwrap": null, "_shrinkwrap": null,
"_spec": "ansi@^0.3.1", "_spec": "ansi@^0.3.1",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common", "_where": "/Users/jbowser/cordova/cordova-android/node_modules/cordova-common",
"author": { "author": {
"name": "Nathan Rajlich", "name": "Nathan Rajlich",
"email": "nathan@tootallnate.net", "email": "nathan@tootallnate.net",
+1
View File
@@ -1,3 +1,4 @@
'use strict';
module.exports = balanced; module.exports = balanced;
function balanced(a, b, str) { function balanced(a, b, str) {
if (a instanceof RegExp) a = maybeMatch(a, str); if (a instanceof RegExp) a = maybeMatch(a, str);
+23 -21
View File
@@ -2,49 +2,49 @@
"_args": [ "_args": [
[ [
{ {
"raw": "balanced-match@^0.4.1", "raw": "balanced-match@^1.0.0",
"scope": null, "scope": null,
"escapedName": "balanced-match", "escapedName": "balanced-match",
"name": "balanced-match", "name": "balanced-match",
"rawSpec": "^0.4.1", "rawSpec": "^1.0.0",
"spec": ">=0.4.1 <0.5.0", "spec": ">=1.0.0 <2.0.0",
"type": "range" "type": "range"
}, },
"/Users/steveng/repo/cordova/cordova-android/node_modules/brace-expansion" "/Users/jbowser/cordova/cordova-android/node_modules/brace-expansion"
] ]
], ],
"_from": "balanced-match@>=0.4.1 <0.5.0", "_from": "balanced-match@>=1.0.0 <2.0.0",
"_id": "balanced-match@0.4.2", "_id": "balanced-match@1.0.0",
"_inCache": true, "_inCache": true,
"_location": "/balanced-match", "_location": "/balanced-match",
"_nodeVersion": "4.4.7", "_nodeVersion": "7.8.0",
"_npmOperationalInternal": { "_npmOperationalInternal": {
"host": "packages-16-east.internal.npmjs.com", "host": "s3://npm-registry-packages",
"tmp": "tmp/balanced-match-0.4.2.tgz_1468834991581_0.6590619895141572" "tmp": "tmp/balanced-match-1.0.0.tgz_1497251909645_0.8755026108119637"
}, },
"_npmUser": { "_npmUser": {
"name": "juliangruber", "name": "juliangruber",
"email": "julian@juliangruber.com" "email": "julian@juliangruber.com"
}, },
"_npmVersion": "2.15.8", "_npmVersion": "4.2.0",
"_phantomChildren": {}, "_phantomChildren": {},
"_requested": { "_requested": {
"raw": "balanced-match@^0.4.1", "raw": "balanced-match@^1.0.0",
"scope": null, "scope": null,
"escapedName": "balanced-match", "escapedName": "balanced-match",
"name": "balanced-match", "name": "balanced-match",
"rawSpec": "^0.4.1", "rawSpec": "^1.0.0",
"spec": ">=0.4.1 <0.5.0", "spec": ">=1.0.0 <2.0.0",
"type": "range" "type": "range"
}, },
"_requiredBy": [ "_requiredBy": [
"/brace-expansion" "/brace-expansion"
], ],
"_resolved": "http://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz", "_resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"_shasum": "cb3f3e3c732dc0f01ee70b403f302e61d7709838", "_shasum": "89b4d199ab2bee49de164ea02b89ce462d71b767",
"_shrinkwrap": null, "_shrinkwrap": null,
"_spec": "balanced-match@^0.4.1", "_spec": "balanced-match@^1.0.0",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/brace-expansion", "_where": "/Users/jbowser/cordova/cordova-android/node_modules/brace-expansion",
"author": { "author": {
"name": "Julian Gruber", "name": "Julian Gruber",
"email": "mail@juliangruber.com", "email": "mail@juliangruber.com",
@@ -56,14 +56,15 @@
"dependencies": {}, "dependencies": {},
"description": "Match balanced character pairs, like \"{\" and \"}\"", "description": "Match balanced character pairs, like \"{\" and \"}\"",
"devDependencies": { "devDependencies": {
"matcha": "^0.7.0",
"tape": "^4.6.0" "tape": "^4.6.0"
}, },
"directories": {}, "directories": {},
"dist": { "dist": {
"shasum": "cb3f3e3c732dc0f01ee70b403f302e61d7709838", "shasum": "89b4d199ab2bee49de164ea02b89ce462d71b767",
"tarball": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz" "tarball": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz"
}, },
"gitHead": "57c2ea29d89a2844ae3bdcc637c6e2cbb73725e2", "gitHead": "d701a549a7653a874eebce7eca25d3577dc868ac",
"homepage": "https://github.com/juliangruber/balanced-match", "homepage": "https://github.com/juliangruber/balanced-match",
"keywords": [ "keywords": [
"match", "match",
@@ -88,6 +89,7 @@
"url": "git://github.com/juliangruber/balanced-match.git" "url": "git://github.com/juliangruber/balanced-match.git"
}, },
"scripts": { "scripts": {
"bench": "make bench",
"test": "make test" "test": "make test"
}, },
"testling": { "testling": {
@@ -106,5 +108,5 @@
"android-browser/4.2..latest" "android-browser/4.2..latest"
] ]
}, },
"version": "0.4.2" "version": "1.0.0"
} }
+3 -3
View File
@@ -10,7 +10,7 @@
"spec": "0.0.8", "spec": "0.0.8",
"type": "version" "type": "version"
}, },
"/Users/steveng/repo/cordova/cordova-android/node_modules/plist" "/Users/jbowser/cordova/cordova-android/node_modules/plist"
] ]
], ],
"_from": "base64-js@0.0.8", "_from": "base64-js@0.0.8",
@@ -36,11 +36,11 @@
"_requiredBy": [ "_requiredBy": [
"/plist" "/plist"
], ],
"_resolved": "http://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", "_resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
"_shasum": "1101e9544f4a76b1bc3b26d452ca96d7a35e7978", "_shasum": "1101e9544f4a76b1bc3b26d452ca96d7a35e7978",
"_shrinkwrap": null, "_shrinkwrap": null,
"_spec": "base64-js@0.0.8", "_spec": "base64-js@0.0.8",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/plist", "_where": "/Users/jbowser/cordova/cordova-android/node_modules/plist",
"author": { "author": {
"name": "T. Jameson Little", "name": "T. Jameson Little",
"email": "t.jameson.little@gmail.com" "email": "t.jameson.little@gmail.com"
+2364
View File
File diff suppressed because it is too large Load Diff
+21 -2
View File
@@ -1038,14 +1038,31 @@ var bigInt = (function (undefined) {
} }
var parseBase = function (text, base) { var parseBase = function (text, base) {
var length = text.length; 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 + ".");
}
}
}
if (2 <= base && base <= 36) { if (2 <= base && base <= 36) {
if (length <= LOG_MAX_INT / Math.log(base)) { 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)); return new SmallInteger(parseInt(text, base));
} }
} }
base = parseValue(base); base = parseValue(base);
var digits = []; var digits = [];
var i;
var isNegative = text[0] === "-"; var isNegative = text[0] === "-";
for (i = isNegative ? 1 : 0; i < text.length; i++) { for (i = isNegative ? 1 : 0; i < text.length; i++) {
var c = text[i].toLowerCase(), var c = text[i].toLowerCase(),
@@ -1126,11 +1143,13 @@ var bigInt = (function (undefined) {
var sign = this.sign ? "-" : ""; var sign = this.sign ? "-" : "";
return sign + str; return sign + str;
}; };
SmallInteger.prototype.toString = function (radix) { SmallInteger.prototype.toString = function (radix) {
if (radix === undefined) radix = 10; if (radix === undefined) radix = 10;
if (radix != 10) return toBase(this, radix); if (radix != 10) return toBase(this, radix);
return String(this.value); return String(this.value);
}; };
BigInteger.prototype.toJSON = SmallInteger.prototype.toJSON = function() { return this.toString(); }
BigInteger.prototype.valueOf = function () { BigInteger.prototype.valueOf = function () {
return +this.toString(); return +this.toString();
@@ -1227,7 +1246,7 @@ if (typeof module !== "undefined" && module.hasOwnProperty("exports")) {
} }
//amd check //amd check
if ( typeof define === "function" && define.amd ) { if ( typeof define === "function" && define.amd ) {
define( "big-integer", [], function() { define( "big-integer", [], function() {
return bigInt; return bigInt;
}); });
+1 -1
View File
File diff suppressed because one or more lines are too long
+2 -2
View File
@@ -211,7 +211,7 @@ Returns `true` if the number is prime, `false` otherwise.
#### `isProbablePrime([iterations])` #### `isProbablePrime([iterations])`
Returns `true` if the number is very likely to be positive, `false` otherwise. Returns `true` if the number is very likely to be prime, `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. 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). This uses the [Fermat primality test](https://en.wikipedia.org/wiki/Fermat_primality_test).
@@ -517,4 +517,4 @@ There are performance benchmarks that can be viewed from the `benchmarks/index.h
## License ## 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/).
-1
View File
@@ -24,7 +24,6 @@
"bower_components", "bower_components",
"test", "test",
"coverage", "coverage",
"spec",
"tests" "tests"
] ]
} }
+19 -14
View File
@@ -10,17 +10,17 @@
"spec": ">=1.6.7 <2.0.0", "spec": ">=1.6.7 <2.0.0",
"type": "range" "type": "range"
}, },
"/Users/steveng/repo/cordova/cordova-android/node_modules/bplist-parser" "/Users/jbowser/cordova/cordova-android/node_modules/bplist-parser"
] ]
], ],
"_from": "big-integer@>=1.6.7 <2.0.0", "_from": "big-integer@>=1.6.7 <2.0.0",
"_id": "big-integer@1.6.22", "_id": "big-integer@1.6.25",
"_inCache": true, "_inCache": true,
"_location": "/big-integer", "_location": "/big-integer",
"_nodeVersion": "6.9.4", "_nodeVersion": "6.10.3",
"_npmOperationalInternal": { "_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com", "host": "s3://npm-registry-packages",
"tmp": "tmp/big-integer-1.6.22.tgz_1493091323169_0.5048394540790468" "tmp": "tmp/big-integer-1.6.25.tgz_1504748727289_0.9231066561769694"
}, },
"_npmUser": { "_npmUser": {
"name": "peterolson", "name": "peterolson",
@@ -40,11 +40,11 @@
"_requiredBy": [ "_requiredBy": [
"/bplist-parser" "/bplist-parser"
], ],
"_resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.22.tgz", "_resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.25.tgz",
"_shasum": "487c95fce886022ea48ff5f19e388932df46dd2e", "_shasum": "1de45a9f57542ac20121c682f8d642220a34e823",
"_shrinkwrap": null, "_shrinkwrap": null,
"_spec": "big-integer@^1.6.7", "_spec": "big-integer@^1.6.7",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/bplist-parser", "_where": "/Users/jbowser/cordova/cordova-android/node_modules/bplist-parser",
"author": { "author": {
"name": "Peter Olson", "name": "Peter Olson",
"email": "peter.e.c.olson+npm@gmail.com" "email": "peter.e.c.olson+npm@gmail.com"
@@ -57,24 +57,28 @@
"dependencies": {}, "dependencies": {},
"description": "An arbitrary length integer library for Javascript", "description": "An arbitrary length integer library for Javascript",
"devDependencies": { "devDependencies": {
"@types/lodash": "^4.14.64",
"@types/node": "^7.0.22",
"coveralls": "^2.11.4", "coveralls": "^2.11.4",
"jasmine": "2.1.x", "jasmine": "2.1.x",
"jasmine-core": "^2.3.4", "jasmine-core": "^2.3.4",
"karma": "^0.13.3", "karma": "^0.13.3",
"karma-coverage": "^0.4.2", "karma-coverage": "^0.4.2",
"karma-jasmine": "^0.3.6", "karma-jasmine": "^0.3.6",
"karma-phantomjs-launcher": "~0.1", "karma-phantomjs-launcher": "^1.0.4",
"lodash": "^4.17.4",
"typescript": "^2.3.3",
"uglifyjs": "^2.4.10" "uglifyjs": "^2.4.10"
}, },
"directories": {}, "directories": {},
"dist": { "dist": {
"shasum": "487c95fce886022ea48ff5f19e388932df46dd2e", "shasum": "1de45a9f57542ac20121c682f8d642220a34e823",
"tarball": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.22.tgz" "tarball": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.25.tgz"
}, },
"engines": { "engines": {
"node": ">=0.6" "node": ">=0.6"
}, },
"gitHead": "40483b881b4380931e5af6f2f8a161b6caa71690", "gitHead": "a0c10d68aae8f5df56a67b3e3eb353b428abf170",
"homepage": "https://github.com/peterolson/BigInteger.js#readme", "homepage": "https://github.com/peterolson/BigInteger.js#readme",
"keywords": [ "keywords": [
"math", "math",
@@ -104,7 +108,8 @@
}, },
"scripts": { "scripts": {
"minify": "uglifyjs BigInteger.js -o BigInteger.min.js", "minify": "uglifyjs BigInteger.js -o BigInteger.min.js",
"test": "karma start my.conf.js" "test": "tsc && node_modules/.bin/karma start my.conf.js && node spec/tsDefinitions.js"
}, },
"version": "1.6.22" "typings": "./BigInteger.d.ts",
"version": "1.6.25"
} }
+25
View File
@@ -0,0 +1,25 @@
{
"compilerOptions": {
"module": "commonjs",
"lib": [
"es6"
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": false,
"baseUrl": "./",
"moduleResolution": "node",
"allowJs": true,
"typeRoots": [
"./"
],
"types": [
"node"
],
"forceConsistentCasingInFileNames": true
},
"files": [
"BigInteger.d.ts",
"spec/tsDefinitions.ts"
]
}
+3 -3
View File
@@ -10,7 +10,7 @@
"spec": ">=0.1.0 <0.2.0", "spec": ">=0.1.0 <0.2.0",
"type": "range" "type": "range"
}, },
"/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common" "/Users/jbowser/cordova/cordova-android/node_modules/cordova-common"
] ]
], ],
"_from": "bplist-parser@>=0.1.0 <0.2.0", "_from": "bplist-parser@>=0.1.0 <0.2.0",
@@ -36,11 +36,11 @@
"_requiredBy": [ "_requiredBy": [
"/cordova-common" "/cordova-common"
], ],
"_resolved": "http://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz", "_resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.1.1.tgz",
"_shasum": "d60d5dcc20cba6dc7e1f299b35d3e1f95dafbae6", "_shasum": "d60d5dcc20cba6dc7e1f299b35d3e1f95dafbae6",
"_shrinkwrap": null, "_shrinkwrap": null,
"_spec": "bplist-parser@^0.1.0", "_spec": "bplist-parser@^0.1.0",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/cordova-common", "_where": "/Users/jbowser/cordova/cordova-android/node_modules/cordova-common",
"author": { "author": {
"name": "Joe Ferner", "name": "Joe Ferner",
"email": "joe.ferner@nearinfinity.com" "email": "joe.ferner@nearinfinity.com"
+20 -20
View File
@@ -2,25 +2,25 @@
"_args": [ "_args": [
[ [
{ {
"raw": "brace-expansion@^1.0.0", "raw": "brace-expansion@^1.1.7",
"scope": null, "scope": null,
"escapedName": "brace-expansion", "escapedName": "brace-expansion",
"name": "brace-expansion", "name": "brace-expansion",
"rawSpec": "^1.0.0", "rawSpec": "^1.1.7",
"spec": ">=1.0.0 <2.0.0", "spec": ">=1.1.7 <2.0.0",
"type": "range" "type": "range"
}, },
"/Users/steveng/repo/cordova/cordova-android/node_modules/minimatch" "/Users/jbowser/cordova/cordova-android/node_modules/minimatch"
] ]
], ],
"_from": "brace-expansion@>=1.0.0 <2.0.0", "_from": "brace-expansion@>=1.1.7 <2.0.0",
"_id": "brace-expansion@1.1.7", "_id": "brace-expansion@1.1.8",
"_inCache": true, "_inCache": true,
"_location": "/brace-expansion", "_location": "/brace-expansion",
"_nodeVersion": "7.8.0", "_nodeVersion": "7.8.0",
"_npmOperationalInternal": { "_npmOperationalInternal": {
"host": "packages-12-west.internal.npmjs.com", "host": "s3://npm-registry-packages",
"tmp": "tmp/brace-expansion-1.1.7.tgz_1491552830231_0.7213963181711733" "tmp": "tmp/brace-expansion-1.1.8.tgz_1497251980593_0.6575565172825009"
}, },
"_npmUser": { "_npmUser": {
"name": "juliangruber", "name": "juliangruber",
@@ -29,22 +29,22 @@
"_npmVersion": "4.2.0", "_npmVersion": "4.2.0",
"_phantomChildren": {}, "_phantomChildren": {},
"_requested": { "_requested": {
"raw": "brace-expansion@^1.0.0", "raw": "brace-expansion@^1.1.7",
"scope": null, "scope": null,
"escapedName": "brace-expansion", "escapedName": "brace-expansion",
"name": "brace-expansion", "name": "brace-expansion",
"rawSpec": "^1.0.0", "rawSpec": "^1.1.7",
"spec": ">=1.0.0 <2.0.0", "spec": ">=1.1.7 <2.0.0",
"type": "range" "type": "range"
}, },
"_requiredBy": [ "_requiredBy": [
"/minimatch" "/minimatch"
], ],
"_resolved": "http://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz", "_resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
"_shasum": "3effc3c50e000531fb720eaff80f0ae8ef23cf59", "_shasum": "c07b211c7c952ec1f8efd51a77ef0d1d3990a292",
"_shrinkwrap": null, "_shrinkwrap": null,
"_spec": "brace-expansion@^1.0.0", "_spec": "brace-expansion@^1.1.7",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/minimatch", "_where": "/Users/jbowser/cordova/cordova-android/node_modules/minimatch",
"author": { "author": {
"name": "Julian Gruber", "name": "Julian Gruber",
"email": "mail@juliangruber.com", "email": "mail@juliangruber.com",
@@ -54,7 +54,7 @@
"url": "https://github.com/juliangruber/brace-expansion/issues" "url": "https://github.com/juliangruber/brace-expansion/issues"
}, },
"dependencies": { "dependencies": {
"balanced-match": "^0.4.1", "balanced-match": "^1.0.0",
"concat-map": "0.0.1" "concat-map": "0.0.1"
}, },
"description": "Brace expansion as known from sh/bash", "description": "Brace expansion as known from sh/bash",
@@ -64,10 +64,10 @@
}, },
"directories": {}, "directories": {},
"dist": { "dist": {
"shasum": "3effc3c50e000531fb720eaff80f0ae8ef23cf59", "shasum": "c07b211c7c952ec1f8efd51a77ef0d1d3990a292",
"tarball": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.7.tgz" "tarball": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz"
}, },
"gitHead": "892512024872ca7680554be90f6e8ce065053372", "gitHead": "8f59e68bd5c915a0d624e8e39354e1ccf672edf6",
"homepage": "https://github.com/juliangruber/brace-expansion", "homepage": "https://github.com/juliangruber/brace-expansion",
"keywords": [], "keywords": [],
"license": "MIT", "license": "MIT",
@@ -110,5 +110,5 @@
"android-browser/4.2..latest" "android-browser/4.2..latest"
] ]
}, },
"version": "1.1.7" "version": "1.1.8"
} }
+3 -3
View File
@@ -10,7 +10,7 @@
"spec": "0.0.1", "spec": "0.0.1",
"type": "version" "type": "version"
}, },
"/Users/steveng/repo/cordova/cordova-android/node_modules/brace-expansion" "/Users/jbowser/cordova/cordova-android/node_modules/brace-expansion"
] ]
], ],
"_from": "concat-map@0.0.1", "_from": "concat-map@0.0.1",
@@ -35,11 +35,11 @@
"_requiredBy": [ "_requiredBy": [
"/brace-expansion" "/brace-expansion"
], ],
"_resolved": "http://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "_resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"_shasum": "d8a96bd77fd68df7793a73036a3ba0d5405d477b", "_shasum": "d8a96bd77fd68df7793a73036a3ba0d5405d477b",
"_shrinkwrap": null, "_shrinkwrap": null,
"_spec": "concat-map@0.0.1", "_spec": "concat-map@0.0.1",
"_where": "/Users/steveng/repo/cordova/cordova-android/node_modules/brace-expansion", "_where": "/Users/jbowser/cordova/cordova-android/node_modules/brace-expansion",
"author": { "author": {
"name": "James Halliday", "name": "James Halliday",
"email": "mail@substack.net", "email": "mail@substack.net",
+1
View File
@@ -0,0 +1 @@
spec/fixtures/*
+11
View File
@@ -0,0 +1,11 @@
root: true
extends: semistandard
rules:
indent:
- error
- 4
camelcase: off
padded-blocks: off
operator-linebreak: off
no-throw-literal: off
-1
View File
@@ -1 +0,0 @@
spec/fixtures/*
+1
View File
@@ -1,3 +1,4 @@
fixtures fixtures
coverage coverage
jasmine.json jasmine.json
appveyor.yml
+15
View File
@@ -0,0 +1,15 @@
language: node_js
sudo: false
git:
depth: 10
node_js:
- "4"
- "6"
install:
- npm install
- npm install -g codecov
script:
- npm test
- npm run cover
after_script:
- codecov
+4
View File
@@ -19,6 +19,10 @@
# #
--> -->
[![Build status](https://ci.appveyor.com/api/projects/status/wxkmo0jalsr8gane?svg=true)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-common/branch/master)
[![Build Status](https://travis-ci.org/apache/cordova-common.svg?branch=master)](https://travis-ci.org/apache/cordova-common)
[![NPM](https://nodei.co/npm/cordova-common.png)](https://nodei.co/npm/cordova-common/)
# cordova-common # cordova-common
Expoeses shared functionality used by [cordova-lib](https://github.com/apache/cordova-lib/) and Cordova platforms. Expoeses shared functionality used by [cordova-lib](https://github.com/apache/cordova-lib/) and Cordova platforms.
## Exposed APIs ## Exposed APIs
+15
View File
@@ -20,6 +20,21 @@
--> -->
# Cordova-common Release Notes # Cordova-common Release Notes
### 2.1.0 (August 30, 2017)
* [CB-13145](https://issues.apache.org/jira/browse/CB-13145) added variable replacing to `framework` tag
* [CB-13211](https://issues.apache.org/jira/browse/CB-13211) Add `allows-arbitrary-loads-for-media` attribute parsing for `getAccesses`
* [CB-11968](https://issues.apache.org/jira/browse/CB-11968) Added support for `<config-file>` in `config.xml`
* [CB-12895](https://issues.apache.org/jira/browse/CB-12895) set up `eslint` and removed `jshint`
* [CB-12785](https://issues.apache.org/jira/browse/CB-12785) added `.gitignore`, `travis`, and `appveyor` support
* [CB-12250](https://issues.apache.org/jira/browse/CB-12250) & [CB-12409](https://issues.apache.org/jira/browse/CB-12409) *iOS*: Fix bug with escaping properties from `plist` file
* [CB-12762](https://issues.apache.org/jira/browse/CB-12762) updated `common`, `fetch`, and `serve` `pkgJson` to point `pkgJson` repo items to github mirrors
* [CB-12766](https://issues.apache.org/jira/browse/CB-12766) Consistently write `JSON` with 2 spaces indentation
### 2.0.3 (May 02, 2017)
* [CB-8978](https://issues.apache.org/jira/browse/CB-8978) Add option to get `resource-file` from `root`
* [CB-11908](https://issues.apache.org/jira/browse/CB-11908) Add tests for `edit-config` in `config.xml`
* [CB-12665](https://issues.apache.org/jira/browse/CB-12665) removed `enginestrict` since it is deprecated
### 2.0.2 (Apr 14, 2017) ### 2.0.2 (Apr 14, 2017)
* [CB-11233](https://issues.apache.org/jira/browse/CB-11233) - Support installing frameworks into 'Embedded Binaries' section of the Xcode project * [CB-11233](https://issues.apache.org/jira/browse/CB-11233) - Support installing frameworks into 'Embedded Binaries' section of the Xcode project
* [CB-10438](https://issues.apache.org/jira/browse/CB-10438) - Install correct dependency version. Removed shell.remove, added pkg.json to dependency tests 1-3, and updated install.js (.replace) to fix tests in uninstall.spec.js and update to workw with jasmine 2.0 * [CB-10438](https://issues.apache.org/jira/browse/CB-10438) - Install correct dependency version. Removed shell.remove, added pkg.json to dependency tests 1-3, and updated install.js (.replace) to fix tests in uninstall.spec.js and update to workw with jasmine 2.0

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