Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 4d55fdb3e5 | |||
| b175d611bd |
@@ -1,2 +0,0 @@
|
|||||||
bin/templates/project/assets/www/cordova.js
|
|
||||||
test/app
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
root: true
|
|
||||||
extends: semistandard
|
|
||||||
rules:
|
|
||||||
indent:
|
|
||||||
- error
|
|
||||||
- 4
|
|
||||||
camelcase: off
|
|
||||||
padded-blocks: off
|
|
||||||
operator-linebreak: off
|
|
||||||
no-throw-literal: off
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
<!--
|
|
||||||
Please have a look at the issue templates you get when you click "New issue" in the GitHub UI.
|
|
||||||
We very much prefer issues created by using one of these templates.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Issue Type
|
|
||||||
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->
|
|
||||||
|
|
||||||
- [ ] Bug Report
|
|
||||||
- [ ] Feature Request
|
|
||||||
- [ ] Support Question
|
|
||||||
|
|
||||||
## Description
|
|
||||||
|
|
||||||
## Information
|
|
||||||
<!-- Include all relevant information that might help understand and reproduce the problem -->
|
|
||||||
|
|
||||||
### Command or Code
|
|
||||||
<!-- What command or code is needed to reproduce the problem? -->
|
|
||||||
|
|
||||||
### Environment, Platform, Device
|
|
||||||
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Version information
|
|
||||||
<!--
|
|
||||||
What are relevant versions you are using?
|
|
||||||
For example:
|
|
||||||
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins
|
|
||||||
Other Frameworks: Ionic Framework and CLI version
|
|
||||||
Operating System, Android Studio, Xcode etc.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
<!-- Please check the boxes by putting an `x` in the `[ ]` like so: `[x]` -->
|
|
||||||
|
|
||||||
- [ ] I searched for already existing GitHub issues about this
|
|
||||||
- [ ] I updated all Cordova tooling to their most recent version
|
|
||||||
- [ ] I included all the necessary information above
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
---
|
|
||||||
name: 🐛 Bug Report
|
|
||||||
about: If something isn't working as expected.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Bug Report
|
|
||||||
|
|
||||||
## Problem
|
|
||||||
|
|
||||||
### What is expected to happen?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What does actually happen?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Information
|
|
||||||
<!-- Include all relevant information that might help understand and reproduce the problem -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Command or Code
|
|
||||||
<!-- What command or code is needed to reproduce the problem? -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Environment, Platform, Device
|
|
||||||
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Version information
|
|
||||||
<!--
|
|
||||||
What are relevant versions you are using?
|
|
||||||
For example:
|
|
||||||
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins
|
|
||||||
Other Frameworks: Ionic Framework and CLI version
|
|
||||||
Operating System, Android Studio, Xcode etc.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Checklist
|
|
||||||
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->
|
|
||||||
|
|
||||||
- [ ] I searched for existing GitHub issues
|
|
||||||
- [ ] I updated all Cordova tooling to most recent version
|
|
||||||
- [ ] I included all the necessary information above
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
---
|
|
||||||
name: 🚀 Feature Request
|
|
||||||
about: A suggestion for a new functionality
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Feature Request
|
|
||||||
|
|
||||||
## Motivation Behind Feature
|
|
||||||
<!-- Why should this feature be implemented? What problem does it solve? -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Feature Description
|
|
||||||
<!--
|
|
||||||
Describe your feature request in detail
|
|
||||||
Please provide any code examples or screenshots of what this feature would look like
|
|
||||||
Are there any drawbacks? Will this break anything for existing users?
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Alternatives or Workarounds
|
|
||||||
<!--
|
|
||||||
Describe alternatives or workarounds you are currently using
|
|
||||||
Are there ways to do this with existing functionality?
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
---
|
|
||||||
name: 💬 Support Question
|
|
||||||
about: If you have a question, please check out our Slack or StackOverflow!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
<!------------^ Click "Preview" for a nicer view! -->
|
|
||||||
|
|
||||||
Apache Cordova uses GitHub Issues as a feature request and bug tracker _only_.
|
|
||||||
For usage and support questions, please check out the resources below. Thanks!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
You can get answers to your usage and support questions about **Apache Cordova** on:
|
|
||||||
|
|
||||||
* Slack Community Chat: https://cordova.slack.com (you can sign-up at http://slack.cordova.io/)
|
|
||||||
* StackOverflow: https://stackoverflow.com/questions/tagged/cordova using the tag `cordova`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
If you are using a tool that uses Cordova internally, like e.g. Ionic, check their support channels:
|
|
||||||
|
|
||||||
* **Ionic Framework**
|
|
||||||
* [Ionic Community Forum](https://forum.ionicframework.com/)
|
|
||||||
* [Ionic Worldwide Slack](https://ionicworldwide.herokuapp.com/)
|
|
||||||
* **PhoneGap**
|
|
||||||
* [PhoneGap Developer Community](https://forums.adobe.com/community/phonegap)
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
<!--
|
<!--
|
||||||
Please make sure the checklist boxes are all checked before submitting the PR. The checklist is intended as a quick reference, for complete details please see our Contributor Guidelines:
|
Please make sure the checklist boxes are all checked before submitting the PR. The checklist
|
||||||
|
is intended as a quick reference, for complete details please see our Contributor Guidelines:
|
||||||
|
|
||||||
http://cordova.apache.org/contribute/contribute_guidelines.html
|
http://cordova.apache.org/contribute/contribute_guidelines.html
|
||||||
|
|
||||||
@@ -9,27 +10,13 @@ Thanks!
|
|||||||
### Platforms affected
|
### Platforms affected
|
||||||
|
|
||||||
|
|
||||||
|
### What does this PR do?
|
||||||
### Motivation and Context
|
|
||||||
<!-- Why is this change required? What problem does it solve? -->
|
|
||||||
<!-- If it fixes an open issue, please link to the issue here. -->
|
|
||||||
|
|
||||||
|
|
||||||
|
### What testing has been done on this change?
|
||||||
### Description
|
|
||||||
<!-- Describe your changes in detail -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
<!-- Please describe in detail how you tested your changes. -->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Checklist
|
### Checklist
|
||||||
|
- [ ] [Reported an issue](http://cordova.apache.org/contribute/issues.html) in the JIRA database
|
||||||
- [ ] I've run the tests to see all new and existing tests pass
|
- [ ] Commit message follows the format: "CB-3232: (android) Fix bug with resolving file paths", where CB-xxxx is the JIRA ID & "android" is the platform affected.
|
||||||
- [ ] I added automated test coverage as appropriate for this change
|
- [ ] Added automated test coverage as appropriate for this change.
|
||||||
- [ ] Commit is prefixed with `(platform)` if this change only applies to one platform (e.g. `(android)`)
|
|
||||||
- [ ] If this Pull Request resolves an issue, I linked to the issue in the text above (and used the correct [keyword to close issues using keywords](https://help.github.com/articles/closing-issues-using-keywords/))
|
|
||||||
- [ ] I've updated the documentation if necessary
|
|
||||||
|
|||||||
@@ -1,21 +1,11 @@
|
|||||||
.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
|
||||||
@@ -25,24 +15,119 @@ example
|
|||||||
/framework/libs
|
/framework/libs
|
||||||
/framework/javadoc-public
|
/framework/javadoc-public
|
||||||
/framework/javadoc-private
|
/framework/javadoc-private
|
||||||
/test/.externalNativeBuild
|
/test/libs
|
||||||
|
example
|
||||||
|
/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
|
||||||
/test/captures
|
.gradle
|
||||||
/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/
|
node_modules/jshint
|
||||||
coverage/
|
node_modules/promise-matchers
|
||||||
.nyc_output/
|
node_modules/jasmine
|
||||||
package-lock.json
|
node_modules/rewire
|
||||||
|
node_modules/istanbul
|
||||||
|
node_modules/.bin/cake
|
||||||
|
node_modules/.bin/coffee
|
||||||
|
node_modules/.bin/escodegen
|
||||||
|
node_modules/.bin/esgenerate
|
||||||
|
node_modules/.bin/esparse
|
||||||
|
node_modules/.bin/esvalidate
|
||||||
|
node_modules/.bin/handlebars
|
||||||
|
node_modules/.bin/istanbul
|
||||||
|
node_modules/.bin/jasmine
|
||||||
|
node_modules/.bin/js-yaml
|
||||||
|
node_modules/.bin/jshint
|
||||||
|
node_modules/.bin/mkdirp
|
||||||
|
node_modules/.bin/r.js
|
||||||
|
node_modules/.bin/r_js
|
||||||
|
node_modules/.bin/strip-json-comments
|
||||||
|
node_modules/.bin/uglifyjs
|
||||||
|
node_modules/.bin/which
|
||||||
|
node_modules/align-text/
|
||||||
|
node_modules/amdefine/
|
||||||
|
node_modules/argparse/
|
||||||
|
node_modules/async/
|
||||||
|
node_modules/camelcase/
|
||||||
|
node_modules/center-align/
|
||||||
|
node_modules/cli/
|
||||||
|
node_modules/cliui/
|
||||||
|
node_modules/coffee-script/
|
||||||
|
node_modules/console-browserify/
|
||||||
|
node_modules/core-util-is/
|
||||||
|
node_modules/date-now/
|
||||||
|
node_modules/decamelize/
|
||||||
|
node_modules/deep-is/
|
||||||
|
node_modules/dom-serializer/
|
||||||
|
node_modules/domelementtype/
|
||||||
|
node_modules/domhandler/
|
||||||
|
node_modules/domutils/
|
||||||
|
node_modules/entities/
|
||||||
|
node_modules/escodegen/
|
||||||
|
node_modules/esprima/
|
||||||
|
node_modules/estraverse/
|
||||||
|
node_modules/esutils/
|
||||||
|
node_modules/exit/
|
||||||
|
node_modules/fast-levenshtein/
|
||||||
|
node_modules/fileset/
|
||||||
|
node_modules/gaze/
|
||||||
|
node_modules/growl/
|
||||||
|
node_modules/handlebars/
|
||||||
|
node_modules/has-flag/
|
||||||
|
node_modules/htmlparser2/
|
||||||
|
node_modules/is-buffer/
|
||||||
|
node_modules/isarray/
|
||||||
|
node_modules/isexe/
|
||||||
|
node_modules/jasmine-growl-reporter/
|
||||||
|
node_modules/jasmine-reporters/
|
||||||
|
node_modules/js-yaml/
|
||||||
|
node_modules/kind-of/
|
||||||
|
node_modules/lazy-cache/
|
||||||
|
node_modules/levn/
|
||||||
|
node_modules/longest/
|
||||||
|
node_modules/lru-cache/
|
||||||
|
node_modules/minimist/
|
||||||
|
node_modules/mkdirp/
|
||||||
|
node_modules/optimist/
|
||||||
|
node_modules/optionator/
|
||||||
|
node_modules/prelude-ls/
|
||||||
|
node_modules/readable-stream/
|
||||||
|
node_modules/repeat-string/
|
||||||
|
node_modules/requirejs/
|
||||||
|
node_modules/resolve/
|
||||||
|
node_modules/right-align/
|
||||||
|
node_modules/sigmund/
|
||||||
|
node_modules/source-map/
|
||||||
|
node_modules/sprintf-js/
|
||||||
|
node_modules/string_decoder/
|
||||||
|
node_modules/strip-json-comments/
|
||||||
|
node_modules/supports-color/
|
||||||
|
node_modules/type-check/
|
||||||
|
node_modules/uglify-js/
|
||||||
|
node_modules/uglify-to-browserify/
|
||||||
|
node_modules/walkdir/
|
||||||
|
node_modules/which/
|
||||||
|
node_modules/window-size/
|
||||||
|
node_modules/wordwrap/
|
||||||
|
node_modules/yargs/
|
||||||
|
node_modules/jasmine-core/
|
||||||
|
node_modules/fs.realpath/
|
||||||
|
/coverage
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
bin/node_modules/*
|
||||||
|
bin/templates/project/*
|
||||||
|
spec/fixtures/*
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"node": true
|
||||||
|
, "bitwise": true
|
||||||
|
, "undef": true
|
||||||
|
, "trailing": true
|
||||||
|
, "quotmark": true
|
||||||
|
, "indent": 4
|
||||||
|
, "unused": "vars"
|
||||||
|
, "latedef": "nofunc"
|
||||||
|
}
|
||||||
@@ -6,4 +6,3 @@ spec
|
|||||||
appveyor.yml
|
appveyor.yml
|
||||||
framework/build
|
framework/build
|
||||||
ic_launcher.png
|
ic_launcher.png
|
||||||
build
|
|
||||||
|
|||||||
@@ -1,48 +1,22 @@
|
|||||||
sudo: false
|
|
||||||
|
|
||||||
# NOTE: dist is added here to ensure that Travis CI works consistently
|
|
||||||
# on Node.js 12. It is desired to remove it once this issue is resolved
|
|
||||||
# or otherwise goes away.
|
|
||||||
dist: trusty
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- ANDROID_API_LEVEL=28
|
|
||||||
- ANDROID_BUILD_TOOLS_VERSION=28.0.3
|
|
||||||
- TERM=dumb # Keep gradle from crapping all over the log
|
|
||||||
matrix:
|
|
||||||
- nodejs_version=6
|
|
||||||
- nodejs_version=8
|
|
||||||
- nodejs_version=10
|
|
||||||
- nodejs_version=12
|
|
||||||
|
|
||||||
language: android
|
language: android
|
||||||
|
sudo: false
|
||||||
jdk:
|
jdk:
|
||||||
- oraclejdk8
|
- oraclejdk8
|
||||||
|
|
||||||
android:
|
|
||||||
components:
|
|
||||||
- tools
|
|
||||||
- build-tools-$ANDROID_BUILD_TOOLS_VERSION
|
|
||||||
- android-$ANDROID_API_LEVEL
|
|
||||||
licenses:
|
|
||||||
- 'android-sdk-preview-license-.+'
|
|
||||||
- 'android-sdk-license-.+'
|
|
||||||
- 'google-gdk-license-.+'
|
|
||||||
|
|
||||||
before_install:
|
before_install:
|
||||||
- nvm install $nodejs_version
|
- nvm install 6
|
||||||
- node --version
|
- node --version
|
||||||
- npm --version
|
- gradle --version
|
||||||
- gradle --version
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- npm install
|
- npm install
|
||||||
- npm install -g codecov
|
- npm install -g codecov
|
||||||
|
- echo y | android update sdk -u --filter android-22,android-23,android-24,android-25
|
||||||
|
android:
|
||||||
|
components:
|
||||||
|
- tools
|
||||||
|
- tools
|
||||||
script:
|
script:
|
||||||
- npm test
|
- npm run jshint
|
||||||
- npm run cover
|
- npm run cover
|
||||||
|
- npm run test-build
|
||||||
after_script:
|
after_script:
|
||||||
- codecov
|
- codecov
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ For instructions on this, start with the
|
|||||||
[contribution overview](http://cordova.apache.org/contribute/).
|
[contribution overview](http://cordova.apache.org/contribute/).
|
||||||
|
|
||||||
The details are explained there, but the important items are:
|
The details are explained there, but the important items are:
|
||||||
|
- Sign and submit an Apache ICLA (Contributor License Agreement).
|
||||||
- Have a Jira issue open that corresponds to your contribution.
|
- Have a Jira issue open that corresponds to your contribution.
|
||||||
- Run the tests so your patch doesn't break existing functionality.
|
- Run the tests so your patch doesn't break existing functionality.
|
||||||
|
|
||||||
|
|||||||
@@ -31,9 +31,12 @@ at the core, applications written with web technology: HTML, CSS and JavaScript.
|
|||||||
|
|
||||||
[Apache Cordova](https://cordova.apache.org) is a project of The Apache Software Foundation (ASF).
|
[Apache Cordova](https://cordova.apache.org) is a project of The Apache Software Foundation (ASF).
|
||||||
|
|
||||||
|
:warning: Report issues on the [Apache Cordova issue tracker](https://issues.apache.org/jira/issues/?jql=project%20%3D%20CB%20AND%20status%20in%20%28Open%2C%20%22In%20Progress%22%2C%20Reopened%29%20AND%20resolution%20%3D%20Unresolved%20AND%20component%20%3D%20%22Android%22%20ORDER%20BY%20priority%20DESC%2C%20summary%20ASC%2C%20updatedDate%20DESC)
|
||||||
|
|
||||||
|
|
||||||
## Requires
|
## Requires
|
||||||
|
|
||||||
- Java JDK 1.8 or greater
|
- Java JDK 1.6 or greater
|
||||||
- Android SDK [http://developer.android.com](http://developer.android.com)
|
- Android SDK [http://developer.android.com](http://developer.android.com)
|
||||||
|
|
||||||
|
|
||||||
@@ -59,9 +62,3 @@ 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!
|
|
||||||
|
|||||||
@@ -20,160 +20,6 @@
|
|||||||
-->
|
-->
|
||||||
## Release Notes for Cordova (Android) ##
|
## Release Notes for Cordova (Android) ##
|
||||||
|
|
||||||
### 8.1.0 (Sep 11, 2019)
|
|
||||||
|
|
||||||
* [GH-827](https://github.com/apache/cordova-android/pull/827) chore: bump dependencies for release 8.1.0
|
|
||||||
* [GH-651](https://github.com/apache/cordova-android/pull/651) feat: added multiple selection for filepicker
|
|
||||||
* [GH-672](https://github.com/apache/cordova-android/pull/672) chore: compress files in /res with tinypng.com
|
|
||||||
* [GH-815](https://github.com/apache/cordova-android/pull/815) fix: `clean` command
|
|
||||||
* [GH-750](https://github.com/apache/cordova-android/pull/750) Don't request focus explicitly if not needed
|
|
||||||
* [GH-800](https://github.com/apache/cordova-android/pull/800) [GH-799](https://github.com/apache/cordova-android/pull/799) (android) Stop webview from restarting when activity resizes
|
|
||||||
* [GH-764](https://github.com/apache/cordova-android/pull/764) feat: Build app bundles (.aab files)
|
|
||||||
* [GH-788](https://github.com/apache/cordova-android/pull/788) Simplify `apkSorter` using `compare-func` package
|
|
||||||
* [GH-787](https://github.com/apache/cordova-android/pull/787) Simplify and fix promise handling in specs
|
|
||||||
* [GH-784](https://github.com/apache/cordova-android/pull/784) Properly handle promise in create script
|
|
||||||
* [GH-783](https://github.com/apache/cordova-android/pull/783) Do not clobber process properties with test mocks
|
|
||||||
* [GH-782](https://github.com/apache/cordova-android/pull/782) Do not clobber `console.log` to spy on it
|
|
||||||
* [GH-724](https://github.com/apache/cordova-android/pull/724) Add Node.js 12 to CI Services
|
|
||||||
* [GH-777](https://github.com/apache/cordova-android/pull/777) ci(travis): set `dist: trusty` in `.travis.yml`
|
|
||||||
* [GH-779](https://github.com/apache/cordova-android/pull/779) Consistent order from `ProjectBuilder.apkSorter`
|
|
||||||
* [GH-778](https://github.com/apache/cordova-android/pull/778) test: use verbose spec reporter
|
|
||||||
* [GH-774](https://github.com/apache/cordova-android/pull/774) `rewire` workaround for NodeJS 12
|
|
||||||
* [GH-772](https://github.com/apache/cordova-android/pull/772) `nyc@14` update in devDependencies
|
|
||||||
* [GH-765](https://github.com/apache/cordova-android/pull/765) ci(travis): Fix **Android** SDK
|
|
||||||
* [GH-713](https://github.com/apache/cordova-android/pull/713) Do not explicitly require modules from project directory
|
|
||||||
* [GH-676](https://github.com/apache/cordova-android/pull/676) Added allprojects repositories for Framework Release Builds
|
|
||||||
* [GH-699](https://github.com/apache/cordova-android/pull/699) Improve Gradle Build Arguments
|
|
||||||
* [GH-710](https://github.com/apache/cordova-android/pull/710) Fix deprecation warning in `SystemCookieManager`
|
|
||||||
* [GH-691](https://github.com/apache/cordova-android/pull/691) [GH-690](https://github.com/apache/cordova-android/pull/690): Run `prepare` with the correct `ConfigParser`
|
|
||||||
* [GH-673](https://github.com/apache/cordova-android/pull/673) Updated `Android_HOME` Test to Follow [GH-656](https://github.com/apache/cordova-android/pull/656) Change
|
|
||||||
|
|
||||||
### 8.0.0 (Feb 13, 2019)
|
|
||||||
* [GH-669](https://github.com/apache/cordova-android/pull/669) Added Missing License Headers
|
|
||||||
* [GH-655](https://github.com/apache/cordova-android/pull/655) Use custom Gradle properties to read minSdkVersion value from `config.xml`
|
|
||||||
* [GH-656](https://github.com/apache/cordova-android/pull/656) Quick fix to support **Android**_SDK_ROOT
|
|
||||||
* [GH-632](https://github.com/apache/cordova-android/pull/632) Ignore more Gradle build artifacts in **Android** project
|
|
||||||
* [GH-642](https://github.com/apache/cordova-android/pull/642) **Android** tools 3.3 & **Gradle** 4.10.3 update
|
|
||||||
* [GH-654](https://github.com/apache/cordova-android/pull/654) Quick updates to top-level `project.properties`
|
|
||||||
* [GH-635](https://github.com/apache/cordova-android/pull/635) Ignore **Android** Studio `.idea` files in project
|
|
||||||
* [GH-624](https://github.com/apache/cordova-android/pull/624) Add missing log to Java version check
|
|
||||||
* [GH-630](https://github.com/apache/cordova-android/pull/630) Update `emulator.js` to fix issue [GH-608](https://github.com/apache/cordova-android/pull/608)
|
|
||||||
* [GH-626](https://github.com/apache/cordova-android/pull/626) Added `package-lock.json` to `.gitignore`
|
|
||||||
* [GH-620](https://github.com/apache/cordova-android/pull/620) Fix requirements error messages for JDK 8
|
|
||||||
* [GH-619](https://github.com/apache/cordova-android/pull/619) javac error message fixes in requirements check
|
|
||||||
* [GH-612](https://github.com/apache/cordova-android/pull/612) Android Platform Release Preparation (Cordova 9)
|
|
||||||
* [GH-607](https://github.com/apache/cordova-android/pull/607) Copy `node_modules` if the directory exists
|
|
||||||
* [GH-582](https://github.com/apache/cordova-android/pull/582) Improve Test `README`
|
|
||||||
* [GH-589](https://github.com/apache/cordova-android/pull/589) Rewrite install dir resolution for legacy plugins
|
|
||||||
* [GH-572](https://github.com/apache/cordova-android/pull/572) Resolve issue with plugin `target-dir="app*"` subdirs
|
|
||||||
* [GH-567](https://github.com/apache/cordova-android/pull/567) Output current package name if package name can't be validated
|
|
||||||
* [GH-507](https://github.com/apache/cordova-android/pull/507) Gradle Updates
|
|
||||||
* [GH-559](https://github.com/apache/cordova-android/pull/559) Eslint ignore version file
|
|
||||||
* [GH-550](https://github.com/apache/cordova-android/pull/550) Fix for old plugins with non-Java sources
|
|
||||||
* [GH-558](https://github.com/apache/cordova-android/pull/558) Update `cordova.js` from `cordova-js@4.2.3`
|
|
||||||
* [GH-553](https://github.com/apache/cordova-android/pull/553) Check for `build-extras.gradle` in the app-parent directory
|
|
||||||
* [GH-551](https://github.com/apache/cordova-android/pull/551) Add missing cast for `cdvMinSdkVersion`
|
|
||||||
* [GH-539](https://github.com/apache/cordova-android/pull/539) Fix destination path fallback
|
|
||||||
* [GH-544](https://github.com/apache/cordova-android/pull/544) Remove obsolete check for JellyBean
|
|
||||||
* [GH-465](https://github.com/apache/cordova-android/pull/465) Removes Gradle property in-line command arguments for `gradle.properties`
|
|
||||||
* [GH-523](https://github.com/apache/cordova-android/pull/523) Always put the Google repo above jcenter
|
|
||||||
* [GH-486](https://github.com/apache/cordova-android/pull/486) Change deprecated "compile" to "implementation"
|
|
||||||
* [GH-495](https://github.com/apache/cordova-android/pull/495) Incorrect default sdk version issue fix
|
|
||||||
* [GH-493](https://github.com/apache/cordova-android/pull/493) Remove bundled dependencies
|
|
||||||
* [GH-490](https://github.com/apache/cordova-android/pull/490) Fixes build & run related bugs from builder refactor
|
|
||||||
* [GH-464](https://github.com/apache/cordova-android/pull/464) Unit tests for **Android**_sdk and **Android**Project
|
|
||||||
* [GH-448](https://github.com/apache/cordova-android/pull/448) [CB-13685](https://issues.apache.org/jira/browse/CB-13685) Adaptive Icon Support
|
|
||||||
* [GH-487](https://github.com/apache/cordova-android/pull/487) Do not attempt an activity intent AND a url load into the webview, return from the internal webview load.
|
|
||||||
* [GH-461](https://github.com/apache/cordova-android/pull/461) Remove old builders code
|
|
||||||
* [GH-463](https://github.com/apache/cordova-android/pull/463) Emulator: Add unit tests and remove Q
|
|
||||||
* [GH-462](https://github.com/apache/cordova-android/pull/462) Device: Add unit tests and remove Q
|
|
||||||
* [GH-457](https://github.com/apache/cordova-android/pull/457) Emulator: handle "device still connecting" error
|
|
||||||
* [GH-445](https://github.com/apache/cordova-android/pull/445) Run and retryPromise improvements and tests
|
|
||||||
* [GH-453](https://github.com/apache/cordova-android/pull/453) Lint JS files w/out extension too
|
|
||||||
* [GH-452](https://github.com/apache/cordova-android/pull/452) Emit log event instead of logging directly
|
|
||||||
* [GH-449](https://github.com/apache/cordova-android/pull/449) Increase old plugin compatibility
|
|
||||||
* [GH-442](https://github.com/apache/cordova-android/pull/442) Fixes and cleanup for Java tests and CI
|
|
||||||
* [GH-446](https://github.com/apache/cordova-android/pull/446) [CB-14101](https://issues.apache.org/jira/browse/CB-14101) Fix Java version check for Java >= 9
|
|
||||||
* [CB-14127](https://issues.apache.org/jira/browse/CB-14127) Move google maven repo ahead of jcenter
|
|
||||||
* [CB-14038](https://issues.apache.org/jira/browse/CB-14038) Fix false positive detecting project type
|
|
||||||
* [CB-14008](https://issues.apache.org/jira/browse/CB-14008) Updating Gradle Libraries to work with **Android** Studio 3.1.0
|
|
||||||
* [CB-13975](https://issues.apache.org/jira/browse/CB-13975) Fix to fire pause event when cdvStartInBackground=true
|
|
||||||
* [CB-13830](https://issues.apache.org/jira/browse/CB-13830) Add handlers for plugins that use non-Java source files, such as Camera
|
|
||||||
* [CB-13923](https://issues.apache.org/jira/browse/CB-13923) Fix -1 length for compressed files
|
|
||||||
|
|
||||||
### 7.1.0 (Feb 20, 2018)
|
|
||||||
* [CB-13879](https://issues.apache.org/jira/browse/CB-13879) updated gradle tools dependency to 3.0.1 for project template
|
|
||||||
* [CB-13831](https://issues.apache.org/jira/browse/CB-13831) Update `android-versions` to 1.3.0 to support SDK 27.
|
|
||||||
* [CB-13800](https://issues.apache.org/jira/browse/CB-13800) Drop pre-KitKat specific code
|
|
||||||
* [CB-13724](https://issues.apache.org/jira/browse/CB-13724) Updated the **Android** Tooling required for the latest version on both the test project, and the template
|
|
||||||
* [CB-13724](https://issues.apache.org/jira/browse/CB-13724) Bump Target SDK to API 27
|
|
||||||
* [CB-13646](https://issues.apache.org/jira/browse/CB-13646) Using the deprecated `NDK` by default breaks the build. Crosswalk users need to specify the Gradle parameters to keep it working.
|
|
||||||
* [CB-12218](https://issues.apache.org/jira/browse/CB-12218) Fix consistency of null result message
|
|
||||||
* [CB-13571](https://issues.apache.org/jira/browse/CB-13571) Prevent crash with unrecognized **Android** version
|
|
||||||
* [CB-13721](https://issues.apache.org/jira/browse/CB-13721) Fix build apps that use `cdvHelpers.getConfigPreference`
|
|
||||||
* [CB-13621](https://issues.apache.org/jira/browse/CB-13621) Wrote similar warning to [CB-12948](https://issues.apache.org/jira/browse/CB-12948) on **iOS**. We no longer support `cordova update` command.
|
|
||||||
|
|
||||||
### 7.0.0 (Nov 30, 2017)
|
|
||||||
* [CB-13612](https://issues.apache.org/jira/browse/CB-13612) Fix the remapper so that XML files copy over and the Camera works again.
|
|
||||||
* [CB-13741](https://issues.apache.org/jira/browse/CB-13741) Bump `package.json` so we can install plugins
|
|
||||||
* [CB-13610](https://issues.apache.org/jira/browse/CB-13610) Compress the default app assets
|
|
||||||
* [CB-12835](https://issues.apache.org/jira/browse/CB-12835) add a Context getter in CordovaInterface
|
|
||||||
* [CB-8976](https://issues.apache.org/jira/browse/CB-8976) Added the `cdvVersionCodeForceAbiDigit` flag to the template build.gradle that appends 0 to the versionCode when `cdvBuildMultipleApks` is not set
|
|
||||||
* [CB-12291](https://issues.apache.org/jira/browse/CB-12291) (android) Add x86_64, arm64 and armeabi architecture flavors
|
|
||||||
* [CB-13602](https://issues.apache.org/jira/browse/CB-13602) We were setting the path wrong, this is hacky but it works
|
|
||||||
* [CB-13601](https://issues.apache.org/jira/browse/CB-13601) Fixing the standalone run scripts to make sure this works without using the CLI
|
|
||||||
* [CB-13580](https://issues.apache.org/jira/browse/CB-13580) fix build for multiple apks (different product flavors)
|
|
||||||
* [CB-13558](https://issues.apache.org/jira/browse/CB-13558) Upgrading the gradle so we can upload the AAR
|
|
||||||
* [CB-13297](https://issues.apache.org/jira/browse/CB-13297) This just works once you bump the project structure. Java 1.8 compatibility baked-in
|
|
||||||
* [CB-11244](https://issues.apache.org/jira/browse/CB-11244) **Android** Studio 3 work, things have changed with how the platform is built
|
|
||||||
* [CB-11244](https://issues.apache.org/jira/browse/CB-11244) Found bug where the gradle subproject changes weren't actually getting written to the correct gradle file
|
|
||||||
* [CB-13470](https://issues.apache.org/jira/browse/CB-13470) Fix Clean so that it cleans the **Android** Studio structure
|
|
||||||
* [CB-11244](https://issues.apache.org/jira/browse/CB-11244) Adding specs for resource files inside an **Android** Studio Project
|
|
||||||
* [CB-11244](https://issues.apache.org/jira/browse/CB-11244) Added remapping for drawables
|
|
||||||
* [CB-11244](https://issues.apache.org/jira/browse/CB-11244) Found bug in Api.js where xml/strings.xml is used instead of values/strings.xml
|
|
||||||
* [CB-11244](https://issues.apache.org/jira/browse/CB-11244) Setup Api.js to support multiple builders based on project structure
|
|
||||||
* [CB-11244](https://issues.apache.org/jira/browse/CB-11244) Changing directory creation, will most likely hide this behind a flag for the next release of `cordova-android`, and then make it default in the next major pending feedback
|
|
||||||
* Adding the Studio Builder to build a project based on **Android** Studio, and deleting Ant, since Google does not support Ant Builds anymore. Sorry guys!
|
|
||||||
|
|
||||||
### 6.4.0 (Nov 06, 2017)
|
|
||||||
* [CB-13289](https://issues.apache.org/jira/browse/CB-13289) Fixing build problems with Studio Three, but keeping **Windows** Gradle fix for now, will be deprecated
|
|
||||||
* [CB-13289](https://issues.apache.org/jira/browse/CB-13289) Fix test to work with new Google **Android** Gradle DSL
|
|
||||||
* :CB-13501 : update appveyor node versions to support node 8
|
|
||||||
* [CB-13499](https://issues.apache.org/jira/browse/CB-13499) Remove duplicate "setting" in error strings
|
|
||||||
* Include missing values for task.name when 'cdvBuildMultipleApks' option is true, 'task.name' can have 'validateSigningArmv7Release' or 'validateSigningX86Release' values too.
|
|
||||||
* [CB-13406](https://issues.apache.org/jira/browse/CB-13406) Fixed AVD API level comparison when choosing sub-par API level match. Added tests for the best_image method.
|
|
||||||
* [CB-13404](https://issues.apache.org/jira/browse/CB-13404) add **Android**-versions to bundledDependencies. Ignore best emulator selection when parsed AVD information does not include API level in the target
|
|
||||||
* [CB-12895](https://issues.apache.org/jira/browse/CB-12895) : eslint ignoring cordova.js
|
|
||||||
* [CB-12895](https://issues.apache.org/jira/browse/CB-12895) Temporarily disabling eslint since cordova-js does not have eslint yet.
|
|
||||||
|
|
||||||
### 6.3.0 (Sep 25, 2017)
|
|
||||||
* [CB-6936](https://issues.apache.org/jira/browse/CB-6936) fix crash when calling methods on a destroyed webview
|
|
||||||
* [CB-12981](https://issues.apache.org/jira/browse/CB-12981) handle SDK 26.0.2 slightly different AVD list output for **Android** 8+ AVDs. Would cause "cannot read property replace of undefined" errors when trying to deploy an **Android** 8 emulator.
|
|
||||||
* Updated maven repo to include most recent lib versions
|
|
||||||
* [CB-13177](https://issues.apache.org/jira/browse/CB-13177) Updating to API Level 26
|
|
||||||
* Revert [CB-12015](https://issues.apache.org/jira/browse/CB-12015) initial-scale values less than 1.0 are ignored on **Android**
|
|
||||||
* [CB-12730](https://issues.apache.org/jira/browse/CB-12730) The Cordova Compatibility Plugin is now integrated into cordova-android
|
|
||||||
* [CB-12453](https://issues.apache.org/jira/browse/CB-12453) Remove unnecessary double quotes from .bat files which are the causes of crash if project path contains spaces
|
|
||||||
* [CB-13031](https://issues.apache.org/jira/browse/CB-13031) Fix bug with case-sensitivity of **Android**-packageName
|
|
||||||
* [CB-10916](https://issues.apache.org/jira/browse/CB-10916) Support display name for **Android**
|
|
||||||
* [CB-12423](https://issues.apache.org/jira/browse/CB-12423) make explicit JDK 1.8 or greater is needed in the `README`, we require 1.8 for compilation, but do not have 1.8 Java features yet
|
|
||||||
* [CB-13006](https://issues.apache.org/jira/browse/CB-13006) removed create and update end-to-end tests, and instead added more unit test coverage. tweaked code coverage invocation so that we get coverage details on the create.js module. slight changes to the create.js module so that it is slightly easier to test.
|
|
||||||
* [CB-12950](https://issues.apache.org/jira/browse/CB-12950) lots of tweaks for end-to-end test runs, especially on CI: - rename npm tasks to reflect what they do (npm run unit-tests, npm run e2e-tests). main `npm test` runs linter, unit tests and e2e tests now. - locked jasmine down to ~2.6.0. - consolidate gitignores. - updated travis to run `npm test`. add **Android** sdk installation to appveyor ci run.align **Android** dpendencies across travis and appveyor. have appveyor install gradle. force gradle to version 3.4.1 in appveyor, as that seems to be the only version choco has. explicitly invoke sdkmanager to move license accepting process along.
|
|
||||||
* [CB-12605](https://issues.apache.org/jira/browse/CB-12605) In **Windows** get **Android** studio path from the registry
|
|
||||||
* [CB-12762](https://issues.apache.org/jira/browse/CB-12762) : pointed `package.json` repo items to github mirrors instead of apache repos site
|
|
||||||
* [CB-12617](https://issues.apache.org/jira/browse/CB-12617) : removed node0.x support for platforms and added engineStrict
|
|
||||||
|
|
||||||
### 6.2.3 (May 2, 2017)
|
|
||||||
* [CB-12640](https://issues.apache.org/jira/browse/CB-12640) better handling of unrecognized Android SDK commands on **Windows**.
|
|
||||||
* [CB-12640](https://issues.apache.org/jira/browse/CB-12640) flipped avd parsing logic so that it always tries to use avdmanager to retrieve avds first, then falls back to android command if avdmanager cannot be found (and errors with ENOENT). updated tests - and added explicit tests to ensure to shell out to singular forms of sub-commands when executing `android`
|
|
||||||
* [CB-12640](https://issues.apache.org/jira/browse/CB-12640) support for android sdk tools 26.0.1.
|
|
||||||
|
|
||||||
### 6.2.2 (Apr 24, 2017)
|
|
||||||
* [CB-12697](https://issues.apache.org/jira/browse/CB-12697) Updated checked-in `node_modules`
|
|
||||||
|
|
||||||
### 6.2.1 (Apr 02, 2017)
|
|
||||||
* [CB-12621](https://issues.apache.org/jira/browse/CB-12621) reverted elementtree dep to 0.1.6
|
|
||||||
|
|
||||||
### 6.2.0 (Mar 28, 2017)
|
### 6.2.0 (Mar 28, 2017)
|
||||||
* [CB-12614](https://issues.apache.org/jira/browse/CB-12614) Adding headers to tests
|
* [CB-12614](https://issues.apache.org/jira/browse/CB-12614) Adding headers to tests
|
||||||
* [CB-8978](https://issues.apache.org/jira/browse/CB-8978) Prepare copy `resource-files` from `config.xml`
|
* [CB-8978](https://issues.apache.org/jira/browse/CB-8978) Prepare copy `resource-files` from `config.xml`
|
||||||
|
|||||||
@@ -1,37 +1,20 @@
|
|||||||
environment:
|
environment:
|
||||||
ANDROID_HOME: "C:\\android"
|
matrix:
|
||||||
|
- nodejs_version: "0.10"
|
||||||
# If the gradle daemon is used, the build hangs after generating the wrapper
|
- nodejs_version: "0.12"
|
||||||
GRADLE_OPTS: -Dorg.gradle.daemon=false
|
- nodejs_version: "4"
|
||||||
|
- nodejs_version: "6"
|
||||||
# URL for SDK Tools, Revision 26.1.1 (September 2017)
|
|
||||||
SDK_TOOLS_URL: https://dl.google.com/android/repository/sdk-tools-windows-4333796.zip
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
- nodejs_version: 6
|
|
||||||
- nodejs_version: 8
|
|
||||||
- nodejs_version: 10
|
|
||||||
- nodejs_version: 12
|
|
||||||
|
|
||||||
install:
|
install:
|
||||||
# Install Android SDK Tools
|
# - cinst android-sdk
|
||||||
- mkdir "%ANDROID_HOME%"
|
# - echo y | android update sdk -u --filter android-22,android-23
|
||||||
- appveyor DownloadFile "%SDK_TOOLS_URL%" -FileName "%TMP%/sdk-tools.zip"
|
- ps: Install-Product node $env:nodejs_version
|
||||||
- 7z x "%TMP%/sdk-tools.zip" -o"%ANDROID_HOME%" > nul
|
- npm install
|
||||||
- set PATH=%PATH%;"%ANDROID_HOME%\tools\bin"
|
|
||||||
|
|
||||||
- yes 2> nul | sdkmanager --licenses > nul
|
|
||||||
- sdkmanager "build-tools;28.0.3"
|
|
||||||
|
|
||||||
- choco install gradle --version 3.4.1
|
|
||||||
|
|
||||||
- ps: Install-Product node $env:nodejs_version
|
|
||||||
- npm install
|
|
||||||
|
|
||||||
build: off
|
build: off
|
||||||
|
|
||||||
test_script:
|
test_script:
|
||||||
- gradle --version
|
- node --version
|
||||||
- node --version
|
- npm --version
|
||||||
- npm --version
|
- npm run test
|
||||||
- npm test
|
# - npm run test-build
|
||||||
|
|||||||
@@ -21,7 +21,9 @@
|
|||||||
|
|
||||||
var android_sdk = require('./templates/cordova/lib/android_sdk');
|
var android_sdk = require('./templates/cordova/lib/android_sdk');
|
||||||
|
|
||||||
android_sdk.print_newest_available_sdk_target().done(null, function (err) {
|
android_sdk.print_newest_available_sdk_target().done(null, function(err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -22,10 +22,9 @@
|
|||||||
var check_reqs = require('./templates/cordova/lib/check_reqs');
|
var check_reqs = require('./templates/cordova/lib/check_reqs');
|
||||||
|
|
||||||
check_reqs.run().done(
|
check_reqs.run().done(
|
||||||
function success () {
|
function success() {
|
||||||
console.log('Looks like your environment fully supports cordova-android development!');
|
console.log('Looks like your environment fully supports cordova-android development!');
|
||||||
},
|
}, function fail(err) {
|
||||||
function fail (err) {
|
|
||||||
console.log(err);
|
console.log(err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ var ConfigParser = require('cordova-common').ConfigParser;
|
|||||||
var Api = require('./templates/cordova/Api');
|
var Api = require('./templates/cordova/Api');
|
||||||
|
|
||||||
var argv = require('nopt')({
|
var argv = require('nopt')({
|
||||||
'help': Boolean,
|
'help' : Boolean,
|
||||||
'cli': Boolean,
|
'cli' : Boolean,
|
||||||
'shared': Boolean,
|
'shared' : Boolean,
|
||||||
'link': Boolean,
|
'link' : Boolean,
|
||||||
'activity-name': [String, undefined]
|
'activity-name' : [String, undefined]
|
||||||
}, { 'd': '--verbose' });
|
}, { 'd' : '--verbose' });
|
||||||
|
|
||||||
if (argv.help || argv.argv.remain.length === 0) {
|
if (argv.help || argv.argv.remain.length === 0) {
|
||||||
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--activity-name <activity_name>] [--link]');
|
console.log('Usage: ' + path.relative(process.cwd(), path.join(__dirname, 'create')) + ' <path_to_new_project> <package_name> <project_name> [<template_path>] [--activity-name <activity_name>] [--link]');
|
||||||
|
|||||||
@@ -19,49 +19,33 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var shell = require('shelljs');
|
var shell = require('shelljs'),
|
||||||
var Q = require('q');
|
Q = require('q'),
|
||||||
var path = require('path');
|
path = require('path'),
|
||||||
var fs = require('fs');
|
fs = require('fs'),
|
||||||
var check_reqs = require('./../templates/cordova/lib/check_reqs');
|
check_reqs = require('./../templates/cordova/lib/check_reqs'),
|
||||||
var ROOT = path.join(__dirname, '..', '..');
|
ROOT = path.join(__dirname, '..', '..');
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
// Export all helper functions, and make sure internally within this module, we
|
function setShellFatal(value, func) {
|
||||||
// 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, isLegacy) {
|
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');
|
||||||
var app_path = path.join(projectPath, 'app', 'src', 'main');
|
shell.cp('-f', srcCordovaJsPath, path.join(projectPath, 'assets', 'www', 'cordova.js'));
|
||||||
|
|
||||||
if (isLegacy) {
|
|
||||||
app_path = projectPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
shell.cp('-f', srcCordovaJsPath, path.join(app_path, 'assets', 'www', 'cordova.js'));
|
|
||||||
|
|
||||||
// Copy the cordova.js file to platforms/<platform>/platform_www/
|
// Copy the cordova.js file to platforms/<platform>/platform_www/
|
||||||
// The www dir is nuked on each prepare so we keep cordova.js in platform_www
|
// The www dir is nuked on each prepare so we keep cordova.js in platform_www
|
||||||
@@ -73,8 +57,8 @@ function copyJsAndLibrary (projectPath, shared, projectName, isLegacy) {
|
|||||||
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.
|
||||||
exports.setShellFatal(false, function () {
|
setShellFatal(false, function() {
|
||||||
shell.ls(path.join(app_path, '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);
|
||||||
});
|
});
|
||||||
@@ -106,7 +90,7 @@ function copyJsAndLibrary (projectPath, shared, projectName, isLegacy) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -116,7 +100,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;
|
||||||
@@ -124,10 +108,11 @@ 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, '');
|
||||||
@@ -135,32 +120,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This makes no sense, what if you're building with a different build system?
|
function prepBuildFiles(projectPath) {
|
||||||
function prepBuildFiles (projectPath) {
|
var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders'));
|
||||||
var buildModule = require('../templates/cordova/lib/builders/builders');
|
buildModule.getBuilder('gradle').prepBuildFiles();
|
||||||
buildModule.getBuilder(projectPath).prepBuildFiles();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function copyBuildRules (projectPath, isLegacy) {
|
function copyBuildRules(projectPath) {
|
||||||
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
var srcDir = path.join(ROOT, 'bin', 'templates', 'project');
|
||||||
|
|
||||||
if (isLegacy) {
|
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
|
||||||
// The project's build.gradle is identical to the earlier build.gradle, so it should still work
|
shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath);
|
||||||
shell.cp('-f', path.join(srcDir, 'legacy', 'build.gradle'), projectPath);
|
|
||||||
shell.cp('-f', path.join(srcDir, 'wrapper.gradle'), projectPath);
|
|
||||||
} else {
|
|
||||||
shell.cp('-f', path.join(srcDir, 'build.gradle'), projectPath);
|
|
||||||
shell.cp('-f', path.join(srcDir, 'app', 'build.gradle'), path.join(projectPath, 'app'));
|
|
||||||
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');
|
||||||
@@ -168,10 +145,7 @@ function copyScripts (projectPath) {
|
|||||||
shell.rm('-rf', destScriptsDir);
|
shell.rm('-rf', destScriptsDir);
|
||||||
// Copy in the new ones.
|
// Copy in the new ones.
|
||||||
shell.cp('-r', srcScriptsDir, projectPath);
|
shell.cp('-r', srcScriptsDir, projectPath);
|
||||||
|
shell.cp('-r', path.join(ROOT, 'node_modules'), destScriptsDir);
|
||||||
let nodeModulesDir = path.join(ROOT, 'node_modules');
|
|
||||||
if (fs.existsSync(nodeModulesDir)) shell.cp('-r', nodeModulesDir, destScriptsDir);
|
|
||||||
|
|
||||||
shell.cp(path.join(bin, 'check_reqs*'), destScriptsDir);
|
shell.cp(path.join(bin, 'check_reqs*'), destScriptsDir);
|
||||||
shell.cp(path.join(bin, 'android_sdk_version*'), destScriptsDir);
|
shell.cp(path.join(bin, 'android_sdk_version*'), destScriptsDir);
|
||||||
var check_reqs = path.join(destScriptsDir, 'check_reqs');
|
var check_reqs = path.join(destScriptsDir, 'check_reqs');
|
||||||
@@ -190,18 +164,17 @@ 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 + 'Must look like: `com.company.Name`. Currently is: `' + package_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'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,19 +186,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'));
|
||||||
}
|
}
|
||||||
@@ -251,94 +224,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.android_packageName() || config.packageName() || 'my.cordova.project';
|
var package_name = config.packageName() || 'my.cordova.project';
|
||||||
var project_name = config.name() ?
|
var project_name = config.name() ?
|
||||||
config.name().replace(/[^\w.]/g, '_') : 'CordovaExample';
|
config.name().replace(/[^\w.]/g,'_') : 'CordovaExample';
|
||||||
|
|
||||||
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
|
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
|
||||||
var target_api = check_reqs.get_target();
|
var target_api = check_reqs.get_target();
|
||||||
|
|
||||||
// Make the package conform to Java package types
|
//Make the package conform to Java package types
|
||||||
return exports.validatePackageName(package_name)
|
return validatePackageName(package_name)
|
||||||
.then(function () {
|
.then(function() {
|
||||||
return exports.validateProjectName(project_name);
|
validateProjectName(project_name);
|
||||||
}).then(function () {
|
}).then(function() {
|
||||||
// Log the given values for the project
|
// Log the given values for the project
|
||||||
events.emit('log', 'Creating Cordova project for the Android platform:');
|
events.emit('log', 'Creating Cordova project for the Android platform:');
|
||||||
events.emit('log', '\tPath: ' + project_path);
|
events.emit('log', '\tPath: ' + project_path);
|
||||||
events.emit('log', '\tPackage: ' + package_name);
|
events.emit('log', '\tPackage: ' + package_name);
|
||||||
events.emit('log', '\tName: ' + project_name);
|
events.emit('log', '\tName: ' + project_name);
|
||||||
events.emit('log', '\tActivity: ' + safe_activity_name);
|
events.emit('log', '\tActivity: ' + safe_activity_name);
|
||||||
events.emit('log', '\tAndroid target: ' + target_api);
|
events.emit('log', '\tAndroid target: ' + target_api);
|
||||||
|
|
||||||
events.emit('verbose', 'Copying android template project to ' + project_path);
|
events.emit('verbose', 'Copying android template project to ' + project_path);
|
||||||
|
|
||||||
exports.setShellFatal(true, function () {
|
setShellFatal(true, function() {
|
||||||
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
|
var project_template_dir = options.customTemplate || path.join(ROOT, 'bin', 'templates', 'project');
|
||||||
var app_path = path.join(project_path, 'app', 'src', 'main');
|
// copy project template
|
||||||
|
shell.cp('-r', path.join(project_template_dir, 'assets'), project_path);
|
||||||
|
shell.cp('-r', path.join(project_template_dir, 'res'), project_path);
|
||||||
|
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
|
||||||
|
|
||||||
// copy project template
|
// Manually create directories that would be empty within the template (since git doesn't track directories).
|
||||||
shell.mkdir('-p', app_path);
|
shell.mkdir(path.join(project_path, 'libs'));
|
||||||
shell.cp('-r', path.join(project_template_dir, 'assets'), app_path);
|
|
||||||
shell.cp('-r', path.join(project_template_dir, 'res'), app_path);
|
|
||||||
shell.cp(path.join(project_template_dir, 'gitignore'), path.join(project_path, '.gitignore'));
|
|
||||||
|
|
||||||
// Manually create directories that would be empty within the template (since git doesn't track directories).
|
// copy cordova.js, cordova.jar
|
||||||
shell.mkdir(path.join(app_path, 'libs'));
|
copyJsAndLibrary(project_path, options.link, safe_activity_name);
|
||||||
|
|
||||||
// copy cordova.js, cordova.jar
|
// interpolate the activity name and package
|
||||||
exports.copyJsAndLibrary(project_path, options.link, safe_activity_name);
|
var packagePath = package_name.replace(/\./g, path.sep);
|
||||||
|
var activity_dir = path.join(project_path, 'src', packagePath);
|
||||||
|
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
|
||||||
|
shell.mkdir('-p', activity_dir);
|
||||||
|
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
|
||||||
|
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
|
||||||
|
shell.sed('-i', /__NAME__/, project_name, path.join(project_path, 'res', 'values', 'strings.xml'));
|
||||||
|
shell.sed('-i', /__ID__/, package_name, activity_path);
|
||||||
|
|
||||||
// Set up ther Android Studio paths
|
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
|
||||||
var java_path = path.join(app_path, 'java');
|
manifest.setPackageId(package_name)
|
||||||
var assets_path = path.join(app_path, 'assets');
|
.setTargetSdkVersion(target_api.split('-')[1])
|
||||||
var resource_path = path.join(app_path, 'res');
|
.getActivity().setName(safe_activity_name);
|
||||||
shell.mkdir('-p', java_path);
|
|
||||||
shell.mkdir('-p', assets_path);
|
|
||||||
shell.mkdir('-p', resource_path);
|
|
||||||
|
|
||||||
// interpolate the activity name and package
|
var manifest_path = path.join(project_path, 'AndroidManifest.xml');
|
||||||
var packagePath = package_name.replace(/\./g, path.sep);
|
manifest.write(manifest_path);
|
||||||
var activity_dir = path.join(java_path, packagePath);
|
|
||||||
var activity_path = path.join(activity_dir, safe_activity_name + '.java');
|
|
||||||
|
|
||||||
shell.mkdir('-p', activity_dir);
|
copyScripts(project_path);
|
||||||
shell.cp('-f', path.join(project_template_dir, 'Activity.java'), activity_path);
|
copyBuildRules(project_path);
|
||||||
shell.sed('-i', /__ACTIVITY__/, safe_activity_name, activity_path);
|
});
|
||||||
shell.sed('-i', /__NAME__/, project_name, path.join(app_path, 'res', 'values', 'strings.xml'));
|
// Link it to local android install.
|
||||||
shell.sed('-i', /__ID__/, package_name, activity_path);
|
writeProjectProperties(project_path, target_api);
|
||||||
|
prepBuildFiles(project_path);
|
||||||
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
|
events.emit('log', generateDoneMessage('create', options.link));
|
||||||
manifest.setPackageId(package_name)
|
}).thenResolve(project_path);
|
||||||
.getActivity().setName(safe_activity_name);
|
|
||||||
|
|
||||||
var manifest_path = path.join(app_path, 'AndroidManifest.xml');
|
|
||||||
manifest.write(manifest_path);
|
|
||||||
|
|
||||||
exports.copyScripts(project_path);
|
|
||||||
exports.copyBuildRules(project_path);
|
|
||||||
});
|
|
||||||
// Link it to local android install.
|
|
||||||
exports.writeProjectProperties(project_path, target_api);
|
|
||||||
exports.prepBuildFiles(project_path);
|
|
||||||
events.emit('log', generateDoneMessage('create', options.link));
|
|
||||||
}).thenResolve(project_path);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
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';
|
||||||
}
|
}
|
||||||
@@ -346,17 +308,34 @@ function generateDoneMessage (type, link) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Returns a promise.
|
// Returns a promise.
|
||||||
exports.update = function (projectPath, options, events) {
|
exports.update = function(projectPath, options, events) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
var errorString =
|
return Q()
|
||||||
'An in-place platform update is not supported. \n' +
|
.then(function() {
|
||||||
'The `platforms` folder is always treated as a build artifact in the CLI workflow.\n' +
|
|
||||||
'To update your platform, you have to remove, then add your android platform again.\n' +
|
|
||||||
'Make sure you save your plugins beforehand using `cordova plugin save`, and save \n' + 'a copy of the platform first if you had manual changes in it.\n' +
|
|
||||||
'\tcordova plugin save\n' +
|
|
||||||
'\tcordova platform rm android\n' +
|
|
||||||
'\tcordova platform add android\n'
|
|
||||||
;
|
|
||||||
|
|
||||||
return Q.reject(errorString);
|
var manifest = new AndroidManifest(path.join(projectPath, 'AndroidManifest.xml'));
|
||||||
|
|
||||||
|
if (Number(manifest.getMinSdkVersion()) < MIN_SDK_VERSION) {
|
||||||
|
events.emit('verbose', 'Updating minSdkVersion to ' + MIN_SDK_VERSION + ' in AndroidManifest.xml');
|
||||||
|
manifest.setMinSdkVersion(MIN_SDK_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
manifest.setDebuggable(false).write();
|
||||||
|
|
||||||
|
var projectName = manifest.getActivity().getName();
|
||||||
|
var target_api = check_reqs.get_target();
|
||||||
|
|
||||||
|
copyJsAndLibrary(projectPath, options.link, projectName);
|
||||||
|
copyScripts(projectPath);
|
||||||
|
copyBuildRules(projectPath);
|
||||||
|
writeProjectProperties(projectPath, target_api);
|
||||||
|
prepBuildFiles(projectPath);
|
||||||
|
events.emit('log', generateDoneMessage('update', options.link));
|
||||||
|
}).thenResolve(projectPath);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// For testing
|
||||||
|
exports.validatePackageName = validatePackageName;
|
||||||
|
exports.validateProjectName = validateProjectName;
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"node": true
|
||||||
|
, "bitwise": true
|
||||||
|
, "undef": true
|
||||||
|
, "trailing": true
|
||||||
|
, "quotmark": true
|
||||||
|
, "indent": 4
|
||||||
|
, "unused": "vars"
|
||||||
|
, "latedef": "nofunc"
|
||||||
|
}
|
||||||
@@ -21,15 +21,16 @@ var path = require('path');
|
|||||||
var Q = require('q');
|
var Q = require('q');
|
||||||
|
|
||||||
var AndroidProject = require('./lib/AndroidProject');
|
var AndroidProject = require('./lib/AndroidProject');
|
||||||
|
var AndroidStudio = require('./lib/AndroidStudio');
|
||||||
var PluginManager = require('cordova-common').PluginManager;
|
var PluginManager = require('cordova-common').PluginManager;
|
||||||
|
|
||||||
var CordovaLogger = require('cordova-common').CordovaLogger;
|
var CordovaLogger = require('cordova-common').CordovaLogger;
|
||||||
var selfEvents = require('cordova-common').events;
|
var selfEvents = require('cordova-common').events;
|
||||||
var ConfigParser = require('cordova-common').ConfigParser;
|
|
||||||
|
|
||||||
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);
|
||||||
@@ -42,6 +43,7 @@ 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.
|
||||||
@@ -53,27 +55,39 @@ 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, '..');
|
||||||
|
|
||||||
setupEvents(events);
|
setupEvents(events);
|
||||||
|
|
||||||
const appMain = path.join(this.root, 'app', 'src', 'main');
|
var self = this;
|
||||||
const appRes = path.join(appMain, 'res');
|
|
||||||
|
|
||||||
this.locations = {
|
this.locations = {
|
||||||
root: this.root,
|
root: self.root,
|
||||||
www: path.join(appMain, 'assets', 'www'),
|
www: path.join(self.root, 'assets/www'),
|
||||||
res: appRes,
|
res: path.join(self.root, 'res'),
|
||||||
platformWww: path.join(this.root, 'platform_www'),
|
platformWww: path.join(self.root, 'platform_www'),
|
||||||
configXml: path.join(appRes, 'xml', 'config.xml'),
|
configXml: path.join(self.root, 'res/xml/config.xml'),
|
||||||
defaultConfigXml: path.join(this.root, 'cordova', 'defaults.xml'),
|
defaultConfigXml: path.join(self.root, 'cordova/defaults.xml'),
|
||||||
strings: path.join(appRes, 'values', 'strings.xml'),
|
strings: path.join(self.root, 'res/values/strings.xml'),
|
||||||
manifest: path.join(appMain, 'AndroidManifest.xml'),
|
manifest: path.join(self.root, 'AndroidManifest.xml'),
|
||||||
build: path.join(this.root, 'build'),
|
build: path.join(self.root, 'build'),
|
||||||
javaSrc: path.join(appMain, 'java')
|
// NOTE: Due to platformApi spec we need to return relative paths here
|
||||||
|
cordovaJs: 'bin/templates/project/assets/www/cordova.js',
|
||||||
|
cordovaJsSrc: 'cordova-js-src'
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// XXX Override some locations for Android Studio projects
|
||||||
|
if(AndroidStudio.isAndroidStudioProject(self.root) === true) {
|
||||||
|
selfEvents.emit('log', 'Android Studio project detected');
|
||||||
|
this.android_studio = true;
|
||||||
|
this.locations.configXml = path.join(self.root, 'app/src/main/res/xml/config.xml');
|
||||||
|
this.locations.strings = path.join(self.root, 'app/src/main/res/xml/strings.xml');
|
||||||
|
this.locations.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml');
|
||||||
|
this.locations.www = path.join(self.root, 'app/src/main/assets/www');
|
||||||
|
this.locations.res = path.join(self.root, 'app/src/main/res');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -98,12 +112,16 @@ Api.createPlatform = function (destination, config, options, events) {
|
|||||||
events = setupEvents(events);
|
events = setupEvents(events);
|
||||||
var result;
|
var result;
|
||||||
try {
|
try {
|
||||||
result = require('../../lib/create').create(destination, config, options, events).then(function (destination) {
|
result = require('../../lib/create')
|
||||||
return new Api(PLATFORM, destination, events);
|
.create(destination, config, options, events)
|
||||||
|
.then(function (destination) {
|
||||||
|
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
||||||
|
return new PlatformApi(PLATFORM, destination, events);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
}
|
||||||
events.emit('error', 'createPlatform is not callable from the android project API.');
|
catch (e) {
|
||||||
throw (e);
|
events.emit('error','createPlatform is not callable from the android project API.');
|
||||||
|
throw(e);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@@ -128,12 +146,16 @@ Api.updatePlatform = function (destination, options, events) {
|
|||||||
events = setupEvents(events);
|
events = setupEvents(events);
|
||||||
var result;
|
var result;
|
||||||
try {
|
try {
|
||||||
result = require('../../lib/create').update(destination, options, events).then(function (destination) {
|
result = require('../../lib/create')
|
||||||
return new Api(PLATFORM, destination, events);
|
.update(destination, options, events)
|
||||||
|
.then(function (destination) {
|
||||||
|
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
|
||||||
|
return new PlatformApi('android', destination, events);
|
||||||
});
|
});
|
||||||
} catch (e) {
|
}
|
||||||
events.emit('error', 'updatePlatform is not callable from the android project API, you will need to do this manually.');
|
catch (e) {
|
||||||
throw (e);
|
events.emit('error','updatePlatform is not callable from the android project API, you will need to do this manually.');
|
||||||
|
throw(e);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@@ -170,8 +192,6 @@ Api.prototype.getPlatformInfo = function () {
|
|||||||
* CordovaError instance.
|
* CordovaError instance.
|
||||||
*/
|
*/
|
||||||
Api.prototype.prepare = function (cordovaProject, prepareOptions) {
|
Api.prototype.prepare = function (cordovaProject, prepareOptions) {
|
||||||
cordovaProject.projectConfig = new ConfigParser(cordovaProject.locations.rootConfigXml || cordovaProject.projectConfig.path);
|
|
||||||
|
|
||||||
return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);
|
return require('./lib/prepare').prepare.call(this, cordovaProject, prepareOptions);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -206,15 +226,40 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
|
|||||||
installOptions.variables.PACKAGE_NAME = project.getPackageName();
|
installOptions.variables.PACKAGE_NAME = project.getPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
return Q().then(function () {
|
if(this.android_studio === true) {
|
||||||
return PluginManager.get(self.platform, self.locations, project).addPlugin(plugin, installOptions);
|
installOptions.android_studio = true;
|
||||||
}).then(function () {
|
}
|
||||||
if (plugin.getFrameworks(this.platform).length === 0) return;
|
|
||||||
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
|
return Q()
|
||||||
// This should pick the correct builder, not just get gradle
|
.then(function () {
|
||||||
require('./lib/builders/builders').getBuilder().prepBuildFiles();
|
//CB-11964: Do a clean when installing the plugin code to get around
|
||||||
}.bind(this))
|
//the Gradle bug introduced by the Android Gradle Plugin Version 2.2
|
||||||
// CB-11022 Return truthy value to prevent running prepare after
|
//TODO: Delete when the next version of Android Gradle plugin comes out
|
||||||
|
|
||||||
|
// Since clean doesn't just clean the build, it also wipes out www, we need
|
||||||
|
// to pass additional options.
|
||||||
|
|
||||||
|
// Do some basic argument parsing
|
||||||
|
var opts = {};
|
||||||
|
|
||||||
|
// Skip cleaning prepared files when not invoking via cordova CLI.
|
||||||
|
opts.noPrepare = true;
|
||||||
|
|
||||||
|
if(!AndroidStudio.isAndroidStudioProject(self.root) && !project.isClean()) {
|
||||||
|
return self.clean(opts);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
return PluginManager.get(self.platform, self.locations, project)
|
||||||
|
.addPlugin(plugin, installOptions);
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
if (plugin.getFrameworks(this.platform).length === 0) return;
|
||||||
|
|
||||||
|
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
|
||||||
|
require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
|
||||||
|
}.bind(this))
|
||||||
|
// CB-11022 Return truthy value to prevent running prepare after
|
||||||
.thenResolve(true);
|
.thenResolve(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -234,8 +279,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) {
|
if(uninstallOptions && uninstallOptions.usePlatformWww === true && this.android_studio === true) {
|
||||||
uninstallOptions.usePlatformWww = false;
|
uninstallOptions.usePlatformWww = false;
|
||||||
|
uninstallOptions.android_studio = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return PluginManager.get(this.platform, this.locations, project)
|
return PluginManager.get(this.platform, this.locations, project)
|
||||||
@@ -244,7 +290,7 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) {
|
|||||||
if (plugin.getFrameworks(this.platform).length === 0) return;
|
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().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);
|
||||||
@@ -297,17 +343,18 @@ 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.paths.map(function (apkPath) {
|
return buildResults.apkPaths.map(function (apkPath) {
|
||||||
return {
|
return {
|
||||||
buildType: buildResults.buildType,
|
buildType: buildResults.buildType,
|
||||||
buildMethod: buildResults.buildMethod,
|
buildMethod: buildResults.buildMethod,
|
||||||
path: apkPath,
|
path: apkPath,
|
||||||
type: path.extname(apkPath).replace(/\./g, '')
|
type: 'apk'
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -325,9 +372,10 @@ 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().then(function () {
|
return require('./lib/check_reqs').run()
|
||||||
|
.then(function () {
|
||||||
return require('./lib/run').run.call(self, runOptions);
|
return require('./lib/run').run.call(self, runOptions);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -339,20 +387,19 @@ 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;
|
||||||
// This will lint, checking for null won't
|
return require('./lib/check_reqs').run()
|
||||||
if (typeof cleanOptions === 'undefined') {
|
.then(function () {
|
||||||
cleanOptions = {};
|
return require('./lib/build').runClean.call(self, cleanOptions);
|
||||||
}
|
})
|
||||||
|
.then(function () {
|
||||||
return require('./lib/check_reqs').run().then(function () {
|
return require('./lib/prepare').clean.call(self, cleanOptions);
|
||||||
return require('./lib/build').runClean.call(self, cleanOptions);
|
});
|
||||||
}).then(function () {
|
|
||||||
return require('./lib/prepare').clean.call(self, cleanOptions);
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs a requirements check for current platform. Each platform defines its
|
* 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
|
||||||
@@ -361,7 +408,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();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -19,25 +19,24 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var args = process.argv;
|
var args = process.argv;
|
||||||
var Api = require('./Api');
|
var Api = require('./Api');
|
||||||
var nopt = require('nopt');
|
var nopt = require('nopt');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
// Support basic help commands
|
// Support basic help commands
|
||||||
if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(args[2]) >= 0) {
|
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)
|
||||||
require('./lib/build').help();
|
require('./lib/build').help();
|
||||||
}
|
|
||||||
|
|
||||||
// Do some basic argument parsing
|
// Do some basic argument parsing
|
||||||
var buildOpts = nopt({
|
var buildOpts = nopt({
|
||||||
'verbose': Boolean,
|
'verbose' : Boolean,
|
||||||
'silent': Boolean,
|
'silent' : Boolean,
|
||||||
'debug': Boolean,
|
'debug' : Boolean,
|
||||||
'release': Boolean,
|
'release' : Boolean,
|
||||||
'nobuild': Boolean,
|
'nobuild': Boolean,
|
||||||
'buildConfig': path
|
'buildConfig' : path
|
||||||
}, { 'd': '--verbose' });
|
}, { 'd' : '--verbose' });
|
||||||
|
|
||||||
// Make buildOptions compatible with PlatformApi build method spec
|
// Make buildOptions compatible with PlatformApi build method spec
|
||||||
buildOpts.argv = buildOpts.argv.original;
|
buildOpts.argv = buildOpts.argv.original;
|
||||||
@@ -45,7 +44,7 @@ buildOpts.argv = buildOpts.argv.original;
|
|||||||
require('./loggingHelper').adjustLoggerLevel(buildOpts);
|
require('./loggingHelper').adjustLoggerLevel(buildOpts);
|
||||||
|
|
||||||
new Api().build(buildOpts)
|
new Api().build(buildOpts)
|
||||||
.catch(function (err) {
|
.catch(function(err) {
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,11 +20,11 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var Api = require('./Api');
|
var Api = require('./Api');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var nopt = require('nopt');
|
var nopt = require('nopt');
|
||||||
|
|
||||||
// Support basic help commands
|
// Support basic help commands
|
||||||
if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
|
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
|
||||||
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
|
console.log('Usage: ' + path.relative(process.cwd(), process.argv[1]));
|
||||||
console.log('Cleans the project directory.');
|
console.log('Cleans the project directory.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
@@ -32,9 +32,9 @@ if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >=
|
|||||||
|
|
||||||
// Do some basic argument parsing
|
// Do some basic argument parsing
|
||||||
var opts = nopt({
|
var opts = nopt({
|
||||||
'verbose': Boolean,
|
'verbose' : Boolean,
|
||||||
'silent': Boolean
|
'silent' : Boolean
|
||||||
}, { 'd': '--verbose' });
|
}, { 'd' : '--verbose' });
|
||||||
|
|
||||||
// Make buildOptions compatible with PlatformApi clean method spec
|
// Make buildOptions compatible with PlatformApi clean method spec
|
||||||
opts.argv = opts.argv.original;
|
opts.argv = opts.argv.original;
|
||||||
@@ -45,7 +45,7 @@ opts.noPrepare = true;
|
|||||||
require('./loggingHelper').adjustLoggerLevel(opts);
|
require('./loggingHelper').adjustLoggerLevel(opts);
|
||||||
|
|
||||||
new Api().clean(opts)
|
new Api().clean(opts)
|
||||||
.catch(function (err) {
|
.catch(function(err) {
|
||||||
console.error(err.stack);
|
console.error(err.stack);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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,7 +44,8 @@ function isEmulator (line) {
|
|||||||
* devices/emulators
|
* devices/emulators
|
||||||
*/
|
*/
|
||||||
Adb.devices = function (opts) {
|
Adb.devices = function (opts) {
|
||||||
return spawn('adb', ['devices'], { cwd: os.tmpdir() }).then(function (output) {
|
return spawn('adb', ['devices'], {cwd: os.tmpdir()})
|
||||||
|
.then(function(output) {
|
||||||
return output.split('\n').filter(function (line) {
|
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);
|
||||||
@@ -58,7 +59,8 @@ 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() }).then(function (output) {
|
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
|
||||||
|
.then(function(output) {
|
||||||
// 'adb install' seems to always returns no error, even if installation fails
|
// '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/)) {
|
||||||
@@ -77,14 +79,15 @@ Adb.install = function (target, packagePath, opts) {
|
|||||||
|
|
||||||
Adb.uninstall = function (target, packageId) {
|
Adb.uninstall = function (target, packageId) {
|
||||||
events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');
|
events.emit('verbose', 'Uninstalling package ' + packageId + ' from target ' + target + '...');
|
||||||
return spawn('adb', ['-s', target, 'uninstall', packageId], { cwd: os.tmpdir() });
|
return spawn('adb', ['-s', target, 'uninstall', packageId], {cwd: os.tmpdir()});
|
||||||
};
|
};
|
||||||
|
|
||||||
Adb.shell = function (target, shellCommand) {
|
Adb.shell = function (target, shellCommand) {
|
||||||
events.emit('verbose', 'Running 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() }).catch(function (output) {
|
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
|
||||||
|
.catch(function (output) {
|
||||||
return Q.reject(new CordovaError('Failed to execute shell command "' +
|
return Q.reject(new CordovaError('Failed to execute shell command "' +
|
||||||
shellCommand + '"" on device: ' + output));
|
shellCommand + '"" on device: ' + output));
|
||||||
});
|
});
|
||||||
@@ -92,7 +95,8 @@ 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).catch(function (output) {
|
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
|
||||||
|
.catch(function (output) {
|
||||||
return Q.reject(new CordovaError('Failed to start application "' +
|
return Q.reject(new CordovaError('Failed to start application "' +
|
||||||
activityName + '"" on device: ' + output));
|
activityName + '"" on device: ' + output));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -18,12 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var xml = require('cordova-common').xmlHelpers;
|
var et = require('elementtree');
|
||||||
|
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') {
|
||||||
@@ -31,34 +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 */
|
||||||
return this.doc.getroot().attrib['package'];
|
return this.doc.getroot().attrib['package'];
|
||||||
|
/*jshint +W069 */
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.setPackageId = function (pkgId) {
|
AndroidManifest.prototype.setPackageId = function(pkgId) {
|
||||||
|
/*jshint -W069 */
|
||||||
this.doc.getroot().attrib['package'] = pkgId;
|
this.doc.getroot().attrib['package'] = pkgId;
|
||||||
|
/*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 () {
|
||||||
@@ -97,11 +102,37 @@ AndroidManifest.prototype.getActivity = function () {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
AndroidManifest.prototype.getDebuggable = function () {
|
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
|
||||||
|
.forEach(function(sdkPrefName) {
|
||||||
|
// Copy variable reference to avoid closure issues
|
||||||
|
var prefName = sdkPrefName;
|
||||||
|
|
||||||
|
AndroidManifest.prototype['get' + capitalize(prefName)] = function() {
|
||||||
|
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
||||||
|
return usesSdk && usesSdk.attrib['android:' + prefName];
|
||||||
|
};
|
||||||
|
|
||||||
|
AndroidManifest.prototype['set' + capitalize(prefName)] = function(prefValue) {
|
||||||
|
var usesSdk = this.doc.getroot().find('./uses-sdk');
|
||||||
|
|
||||||
|
if (!usesSdk && prefValue) { // if there is no required uses-sdk element, we should create it first
|
||||||
|
usesSdk = new et.Element('uses-sdk');
|
||||||
|
this.doc.getroot().append(usesSdk);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prefValue) {
|
||||||
|
usesSdk.attrib['android:' + prefName] = prefValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
AndroidManifest.prototype.getDebuggable = function() {
|
||||||
return this.doc.getroot().find('./application').attrib['android:debuggable'] === 'true';
|
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';
|
||||||
@@ -119,8 +150,12 @@ 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');
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = AndroidManifest;
|
module.exports = AndroidManifest;
|
||||||
|
|
||||||
|
function capitalize (str) {
|
||||||
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,19 +21,21 @@ var fs = require('fs');
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
var properties_parser = require('properties-parser');
|
var properties_parser = require('properties-parser');
|
||||||
var AndroidManifest = require('./AndroidManifest');
|
var AndroidManifest = require('./AndroidManifest');
|
||||||
|
var AndroidStudio = require('./AndroidStudio');
|
||||||
var pluginHandlers = require('./pluginHandlers');
|
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)) { i++; }
|
while (projectProperties.get(key + '.' + 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))) {
|
||||||
@@ -52,16 +54,19 @@ 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, 'app/src/main/assets/www');
|
this.www = path.join(this.projectDir, 'assets/www');
|
||||||
|
if(AndroidStudio.isAndroidStudioProject(projectDir) === true) {
|
||||||
|
this.www = path.join(this.projectDir, 'app/src/main/assets/www');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
AndroidProject.getProjectFile = function (projectDir) {
|
AndroidProject.getProjectFile = function (projectDir) {
|
||||||
@@ -87,12 +92,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, 'app/src/main/AndroidManifest.xml');
|
var manifestPath = path.join(this.projectDir, 'AndroidManifest.xml');
|
||||||
|
if(AndroidStudio.isAndroidStudioProject(this.projectDir) === true) {
|
||||||
|
manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml');
|
||||||
|
}
|
||||||
return new AndroidManifest(manifestPath).getPackageId();
|
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();
|
||||||
@@ -102,7 +110,7 @@ AndroidProject.prototype.getCustomSubprojectRelativeDir = function (plugin_id, s
|
|||||||
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);
|
||||||
@@ -118,7 +126,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));
|
||||||
@@ -126,35 +134,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;
|
||||||
}
|
}
|
||||||
@@ -193,9 +201,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));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* This is a simple routine that checks if project is an Android Studio Project
|
||||||
|
*
|
||||||
|
* @param {String} root Root folder of the project
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*jshint esnext: false */
|
||||||
|
|
||||||
|
var path = require('path');
|
||||||
|
var fs = require('fs');
|
||||||
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
|
module.exports.isAndroidStudioProject = function isAndroidStudioProject(root) {
|
||||||
|
var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res', 'project.properties', 'platform_www'];
|
||||||
|
var androidStudioFiles = ['app', 'gradle', 'app/src/main/res'];
|
||||||
|
|
||||||
|
// assume it is an AS project and not an Eclipse project
|
||||||
|
var isEclipse = false;
|
||||||
|
var isAS = true;
|
||||||
|
|
||||||
|
if(!fs.existsSync(root)) {
|
||||||
|
throw new CordovaError('AndroidStudio.js:inAndroidStudioProject root does not exist: ' + root);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if any of the following exists, then we are not an ASProj
|
||||||
|
eclipseFiles.forEach(function(file) {
|
||||||
|
if(fs.existsSync(path.join(root, file))) {
|
||||||
|
isEclipse = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// if it is NOT an eclipse project, check that all required files exist
|
||||||
|
if(!isEclipse) {
|
||||||
|
androidStudioFiles.forEach(function(file){
|
||||||
|
if(!fs.existsSync(path.join(root, file))) {
|
||||||
|
console.log('missing file :: ' + file);
|
||||||
|
isAS = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return (!isEclipse && isAS);
|
||||||
|
};
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/**
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const PackageType = {
|
|
||||||
APK: 'apk',
|
|
||||||
BUNDLE: 'bundle'
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = PackageType;
|
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
@@ -17,7 +19,8 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var superspawn = require('cordova-common').superspawn;
|
var Q = require('q'),
|
||||||
|
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:
|
||||||
@@ -28,7 +31,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) {
|
||||||
@@ -42,8 +45,9 @@ 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().then(function (targets) {
|
return module.exports.list_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]);
|
||||||
});
|
});
|
||||||
@@ -61,40 +65,70 @@ module.exports.version_string_to_api_level = {
|
|||||||
'5.1': 22,
|
'5.1': 22,
|
||||||
'6.0': 23,
|
'6.0': 23,
|
||||||
'7.0': 24,
|
'7.0': 24,
|
||||||
'7.1.1': 25,
|
'7.1.1': 25
|
||||||
'8.0': 26
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function parse_targets (output) {
|
module.exports.list_targets_with_android = function() {
|
||||||
var target_out = output.split('\n');
|
return superspawn.spawn('android', ['list', 'targets'])
|
||||||
var targets = [];
|
.then(function(stdout) {
|
||||||
for (var i = target_out.length - 1; i >= 0; i--) {
|
var target_out = stdout.split('\n');
|
||||||
if (target_out[i].match(/id:/)) { // if "id:" is in the line...
|
var targets = [];
|
||||||
targets.push(target_out[i].match(/"(.+)"/)[1]); // .. match whatever is in quotes.
|
for (var i = target_out.length - 1; i >= 0; i--) {
|
||||||
}
|
if(target_out[i].match(/id:/)) {
|
||||||
}
|
targets.push(target_out[i].match(/"(.+)"/)[1]);
|
||||||
return targets;
|
}
|
||||||
}
|
}
|
||||||
|
return targets;
|
||||||
module.exports.list_targets_with_android = function () {
|
});
|
||||||
return superspawn.spawn('android', ['list', 'target']).then(parse_targets);
|
};
|
||||||
};
|
|
||||||
|
module.exports.list_targets_with_sdkmanager = function() {
|
||||||
module.exports.list_targets_with_avdmanager = function () {
|
return superspawn.spawn('sdkmanager', ['--list'])
|
||||||
return superspawn.spawn('avdmanager', ['list', 'target']).then(parse_targets);
|
.then(function(stdout) {
|
||||||
};
|
var parsing_installed_packages = false;
|
||||||
|
var lines = stdout.split('\n');
|
||||||
module.exports.list_targets = function () {
|
var targets = [];
|
||||||
return module.exports.list_targets_with_avdmanager().catch(function (err) {
|
for (var i = 0, l = lines.length; i < l; i++) {
|
||||||
// If there's an error, like avdmanager could not be found, we can try
|
var line = lines[i];
|
||||||
// as a last resort, to run `android`, in case this is a super old
|
if (line.match(/Installed packages/)) {
|
||||||
// SDK installation.
|
parsing_installed_packages = true;
|
||||||
if (err && (err.code === 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) {
|
} else if (line.match(/Available Packages/) || line.match(/Available Updates/)) {
|
||||||
return module.exports.list_targets_with_android();
|
// we are done working through installed packages, exit
|
||||||
} else throw err;
|
break;
|
||||||
}).then(function (targets) {
|
}
|
||||||
if (targets.length === 0) {
|
if (parsing_installed_packages) {
|
||||||
return Promise.reject(new Error('No android targets (SDKs) installed!'));
|
// Match stock android platform
|
||||||
|
if (line.match(/platforms;android-\d+/)) {
|
||||||
|
targets.push(line.match(/(android-\d+)/)[1]);
|
||||||
|
}
|
||||||
|
// Match Google APIs
|
||||||
|
if (line.match(/addon-google_apis-google-\d+/)) {
|
||||||
|
var description = lines[i + 1];
|
||||||
|
// munge description to match output from old android sdk tooling
|
||||||
|
var api_level = description.match(/Android (\d+)/); //[1];
|
||||||
|
if (api_level) {
|
||||||
|
targets.push('Google Inc.:Google APIs:' + api_level[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// TODO: match anything else?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return targets;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports.list_targets = function() {
|
||||||
|
return module.exports.list_targets_with_android()
|
||||||
|
.catch(function(err) {
|
||||||
|
// there's a chance `android` no longer works.
|
||||||
|
// lets see if `sdkmanager` is available and we can figure it out
|
||||||
|
var avail_regex = /"?android"? command is no longer available/;
|
||||||
|
if (err.code && ((err.stdout && err.stdout.match(avail_regex)) || (err.stderr && err.stderr.match(avail_regex)))) {
|
||||||
|
return module.exports.list_targets_with_sdkmanager();
|
||||||
|
} else throw err;
|
||||||
|
}).then(function(targets) {
|
||||||
|
if (targets.length === 0) {
|
||||||
|
return Q.reject(new Error('No android targets (SDKs) installed!'));
|
||||||
}
|
}
|
||||||
return targets;
|
return targets;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,10 +19,10 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var Q = require('q');
|
var Q = require('q'),
|
||||||
var path = require('path');
|
path = require('path'),
|
||||||
var fs = require('fs');
|
fs = require('fs'),
|
||||||
var nopt = require('nopt');
|
nopt = require('nopt');
|
||||||
|
|
||||||
var Adb = require('./Adb');
|
var Adb = require('./Adb');
|
||||||
|
|
||||||
@@ -30,72 +30,78 @@ var builders = require('./builders/builders');
|
|||||||
var events = require('cordova-common').events;
|
var events = require('cordova-common').events;
|
||||||
var spawn = require('cordova-common').superspawn.spawn;
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
var PackageType = require('./PackageType');
|
|
||||||
|
|
||||||
module.exports.parseBuildOptions = parseOpts;
|
function parseOpts(options, resolvedTarget, projectRoot) {
|
||||||
function parseOpts (options, resolvedTarget, projectRoot) {
|
|
||||||
options = options || {};
|
options = options || {};
|
||||||
options.argv = nopt({
|
options.argv = nopt({
|
||||||
|
gradle: Boolean,
|
||||||
|
ant: Boolean,
|
||||||
prepenv: Boolean,
|
prepenv: Boolean,
|
||||||
versionCode: String,
|
versionCode: String,
|
||||||
minSdkVersion: String,
|
minSdkVersion: String,
|
||||||
maxSdkVersion: String,
|
|
||||||
targetSdkVersion: String,
|
|
||||||
gradleArg: [String, Array],
|
gradleArg: [String, Array],
|
||||||
keystore: path,
|
keystore: path,
|
||||||
alias: String,
|
alias: String,
|
||||||
storePassword: String,
|
storePassword: String,
|
||||||
password: String,
|
password: String,
|
||||||
keystoreType: String,
|
keystoreType: String
|
||||||
packageType: String
|
|
||||||
}, {}, options.argv, 0);
|
}, {}, options.argv, 0);
|
||||||
|
|
||||||
// Android Studio Build method is the default
|
|
||||||
var ret = {
|
var ret = {
|
||||||
buildType: options.release ? 'release' : 'debug',
|
buildType: options.release ? 'release' : 'debug',
|
||||||
|
buildMethod: process.env.ANDROID_BUILD || 'gradle',
|
||||||
prepEnv: options.argv.prepenv,
|
prepEnv: options.argv.prepenv,
|
||||||
arch: resolvedTarget && resolvedTarget.arch,
|
arch: resolvedTarget && resolvedTarget.arch,
|
||||||
extraArgs: []
|
extraArgs: []
|
||||||
};
|
};
|
||||||
|
|
||||||
if (options.argv.versionCode) { ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode); }
|
if (options.argv.ant || options.argv.gradle)
|
||||||
if (options.argv.minSdkVersion) { ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion); }
|
ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
|
||||||
if (options.argv.maxSdkVersion) { ret.extraArgs.push('-PcdvMaxSdkVersion=' + options.argv.maxSdkVersion); }
|
|
||||||
if (options.argv.targetSdkVersion) { ret.extraArgs.push('-PcdvTargetSdkVersion=' + options.argv.targetSdkVersion); }
|
if (options.nobuild) ret.buildMethod = 'none';
|
||||||
|
|
||||||
|
if (options.argv.versionCode)
|
||||||
|
ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode);
|
||||||
|
|
||||||
|
if (options.argv.minSdkVersion)
|
||||||
|
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion);
|
||||||
|
|
||||||
if (options.argv.gradleArg) {
|
if (options.argv.gradleArg) {
|
||||||
ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
|
ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
var packageArgs = {};
|
var packageArgs = {};
|
||||||
|
|
||||||
if (options.argv.keystore) { packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore)); }
|
if (options.argv.keystore)
|
||||||
|
packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore));
|
||||||
|
|
||||||
['alias', 'storePassword', 'password', 'keystoreType', 'packageType'].forEach(function (flagName) {
|
['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
|
||||||
if (options.argv[flagName]) { packageArgs[flagName] = options.argv[flagName]; }
|
if (options.argv[flagName])
|
||||||
|
packageArgs[flagName] = options.argv[flagName];
|
||||||
});
|
});
|
||||||
|
|
||||||
var buildConfig = options.buildConfig;
|
var buildConfig = options.buildConfig;
|
||||||
|
|
||||||
// If some values are not specified as command line arguments - use build config to supplement them.
|
// If some values are not specified as command line arguments - use build config to supplement them.
|
||||||
// Command line arguments have precedence over build config.
|
// Command line arguemnts have precedence over build config.
|
||||||
if (buildConfig) {
|
if (buildConfig) {
|
||||||
if (!fs.existsSync(buildConfig)) {
|
if (!fs.existsSync(buildConfig)) {
|
||||||
throw new Error('Specified build config file does not exist: ' + buildConfig);
|
throw new Error('Specified build config file does not exist: ' + buildConfig);
|
||||||
}
|
}
|
||||||
events.emit('log', 'Reading build config file: ' + path.resolve(buildConfig));
|
events.emit('log', 'Reading build config file: '+ path.resolve(buildConfig));
|
||||||
var 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', 'packageType'].forEach(function (key) {
|
['alias', 'storePassword', 'password','keystoreType'].forEach(function (key){
|
||||||
packageArgs[key] = packageArgs[key] || androidInfo[key];
|
packageArgs[key] = packageArgs[key] || androidInfo[key];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -106,39 +112,12 @@ function parseOpts (options, resolvedTarget, projectRoot) {
|
|||||||
packageArgs.password, packageArgs.keystoreType);
|
packageArgs.password, packageArgs.keystoreType);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ret.packageInfo) {
|
if(!ret.packageInfo) {
|
||||||
// The following loop is to decide whether to print a warning about generating a signed archive
|
if(Object.keys(packageArgs).length > 0) {
|
||||||
// We only want to produce a warning if they are using a config property that is related to signing, but
|
|
||||||
// missing the required properties for signing. We don't want to produce a warning if they are simply
|
|
||||||
// using a build property that isn't related to signing, such as --packageType
|
|
||||||
let shouldWarn = false;
|
|
||||||
const signingKeys = ['keystore', 'alias', 'storePassword', 'password', 'keystoreType'];
|
|
||||||
|
|
||||||
for (let key in packageArgs) {
|
|
||||||
if (!shouldWarn && signingKeys.indexOf(key) > -1) {
|
|
||||||
// If we enter this condition, we have a key used for signing a build,
|
|
||||||
// but we are missing some required signing properties
|
|
||||||
shouldWarn = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (shouldWarn) {
|
|
||||||
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.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (packageArgs.packageType) {
|
|
||||||
const VALID_PACKAGE_TYPES = [PackageType.APK, PackageType.BUNDLE];
|
|
||||||
if (VALID_PACKAGE_TYPES.indexOf(packageArgs.packageType) === -1) {
|
|
||||||
events.emit('warn', '"' + packageArgs.packageType + '" is an invalid packageType. Valid values are: ' + VALID_PACKAGE_TYPES.join(', ') + '\nDefaulting packageType to ' + PackageType.APK);
|
|
||||||
ret.packageType = PackageType.APK;
|
|
||||||
} else {
|
|
||||||
ret.packageType = packageArgs.packageType;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ret.packageType = PackageType.APK;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,11 +125,11 @@ 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();
|
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);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -167,28 +146,23 @@ 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();
|
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).then(function () {
|
return builder.build(opts)
|
||||||
var paths;
|
.then(function() {
|
||||||
if (opts.packageType === PackageType.BUNDLE) {
|
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
|
||||||
paths = builder.findOutputBundles(opts.buildType);
|
events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
|
||||||
events.emit('log', 'Built the following bundle(s): \n\t' + paths.join('\n\t'));
|
|
||||||
} else {
|
|
||||||
paths = builder.findOutputApks(opts.buildType, opts.arch);
|
|
||||||
events.emit('log', 'Built the following apk(s): \n\t' + paths.join('\n\t'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
paths: paths,
|
apkPaths: apkPaths,
|
||||||
buildType: opts.buildType
|
buildType: opts.buildType,
|
||||||
|
buildMethod: opts.buildMethod
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -198,31 +172,38 @@ 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').then(function (output) {
|
return Adb.shell(target, 'cat /proc/cpuinfo')
|
||||||
|
.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().timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.')).then(null, function (err) {
|
return helper()
|
||||||
|
.timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))
|
||||||
|
.then(null, function(err) {
|
||||||
if (/timed out/.exec('' + err)) {
|
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']).then(function () {
|
return spawn('killall', ['adb'])
|
||||||
return helper().then(null, function () {
|
.then(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']).then(function () {
|
return spawn('killall', ['adb'])
|
||||||
return helper().then(null, function () {
|
.then(function() {
|
||||||
|
return helper()
|
||||||
|
.then(null, function() {
|
||||||
return Q.reject(new CordovaError('adb timed out a third time while detecting device/emulator architecture. Try unplugging & replugging the device.'));
|
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);
|
||||||
});
|
});
|
||||||
@@ -231,10 +212,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);
|
||||||
@@ -254,7 +235,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
|
||||||
@@ -284,10 +265,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, '\\\\');
|
||||||
@@ -297,19 +278,18 @@ 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)');
|
||||||
console.log(' \'--release\': will build project for release');
|
console.log(' \'--release\': will build project for release');
|
||||||
|
console.log(' \'--ant\': will build project with ant');
|
||||||
|
console.log(' \'--gradle\': will build project with gradle (default)');
|
||||||
console.log(' \'--nobuild\': will skip build process (useful when using run command)');
|
console.log(' \'--nobuild\': will skip build process (useful when using run command)');
|
||||||
console.log(' \'--prepenv\': don\'t build, but copy in build scripts where necessary');
|
console.log(' \'--prepenv\': don\'t build, but copy in build scripts where necessary');
|
||||||
console.log(' \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs.');
|
console.log(' \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
||||||
console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build.');
|
console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build. Useful for uploading multiple APKs. Requires --gradle.');
|
||||||
console.log(' \'--maxSdkVersion=#\': Override maxSdkVersion for this build. (Not Recommended)');
|
|
||||||
console.log(' \'--targetSdkVersion=#\': Override targetSdkVersion for this build.');
|
|
||||||
console.log(' \'--gradleArg=<gradle command line arg>\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');
|
console.log(' \'--gradleArg=<gradle command line arg>\': Extra args to pass to the gradle command. Use one flag per arg. Ex. --gradleArg=-PcdvBuildMultipleApks=true');
|
||||||
console.log(' \'--packageType=<apk|bundle>\': Builds an APK or a bundle');
|
|
||||||
console.log('');
|
console.log('');
|
||||||
console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
|
console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
|
||||||
console.log(' \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');
|
console.log(' \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');
|
||||||
|
|||||||
@@ -0,0 +1,156 @@
|
|||||||
|
/*
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Q = require('q');
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var util = require('util');
|
||||||
|
var shell = require('shelljs');
|
||||||
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
var check_reqs = require('../check_reqs');
|
||||||
|
|
||||||
|
var SIGNING_PROPERTIES = '-signing.properties';
|
||||||
|
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
||||||
|
var TEMPLATE =
|
||||||
|
'# This file is automatically generated.\n' +
|
||||||
|
'# Do not modify this file -- ' + MARKER + '\n';
|
||||||
|
|
||||||
|
var GenericBuilder = require('./GenericBuilder');
|
||||||
|
|
||||||
|
function AntBuilder (projectRoot) {
|
||||||
|
GenericBuilder.call(this, projectRoot);
|
||||||
|
|
||||||
|
this.binDirs = {ant: this.binDirs.ant};
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(AntBuilder, GenericBuilder);
|
||||||
|
|
||||||
|
AntBuilder.prototype.getArgs = function(cmd, opts) {
|
||||||
|
var args = [cmd, '-f', path.join(this.root, 'build.xml')];
|
||||||
|
// custom_rules.xml is required for incremental builds.
|
||||||
|
if (hasCustomRules(this.root)) {
|
||||||
|
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
|
||||||
|
}
|
||||||
|
if(opts.packageInfo) {
|
||||||
|
args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
|
||||||
|
}
|
||||||
|
return args;
|
||||||
|
};
|
||||||
|
|
||||||
|
AntBuilder.prototype.prepEnv = function(opts) {
|
||||||
|
var self = this;
|
||||||
|
return check_reqs.check_ant()
|
||||||
|
.then(function() {
|
||||||
|
// Copy in build.xml on each build so that:
|
||||||
|
// A) we don't require the Android SDK at project creation time, and
|
||||||
|
// B) we always use the SDK's latest version of it.
|
||||||
|
/*jshint -W069 */
|
||||||
|
var sdkDir = process.env['ANDROID_HOME'];
|
||||||
|
/*jshint +W069 */
|
||||||
|
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
|
||||||
|
function writeBuildXml(projectPath) {
|
||||||
|
var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
|
||||||
|
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
|
||||||
|
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
|
||||||
|
fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeBuildXml(self.root);
|
||||||
|
var propertiesObj = self.readProjectProperties();
|
||||||
|
var subProjects = propertiesObj.libs;
|
||||||
|
for (var i = 0; i < subProjects.length; ++i) {
|
||||||
|
writeBuildXml(path.join(self.root, subProjects[i]));
|
||||||
|
}
|
||||||
|
if (propertiesObj.systemLibs.length > 0) {
|
||||||
|
throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Use gradle instead.');
|
||||||
|
}
|
||||||
|
|
||||||
|
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
||||||
|
var propertiesFilePath = path.join(self.root, propertiesFile);
|
||||||
|
if (opts.packageInfo) {
|
||||||
|
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
||||||
|
} else if(isAutoGenerated(propertiesFilePath)) {
|
||||||
|
shell.rm('-f', propertiesFilePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Builds the project with ant.
|
||||||
|
* Returns a promise.
|
||||||
|
*/
|
||||||
|
AntBuilder.prototype.build = function(opts) {
|
||||||
|
// Without our custom_rules.xml, we need to clean before building.
|
||||||
|
var ret = Q();
|
||||||
|
if (!hasCustomRules(this.root)) {
|
||||||
|
// clean will call check_ant() for us.
|
||||||
|
ret = this.clean(opts);
|
||||||
|
}
|
||||||
|
|
||||||
|
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
|
||||||
|
return check_reqs.check_ant()
|
||||||
|
.then(function() {
|
||||||
|
return spawn('ant', args, {stdio: 'pipe'});
|
||||||
|
}).progress(function (stdio){
|
||||||
|
if (stdio.stderr) {
|
||||||
|
process.stderr.write(stdio.stderr);
|
||||||
|
} else {
|
||||||
|
process.stdout.write(stdio.stdout);
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (error.toString().indexOf('Unable to resolve project target') >= 0) {
|
||||||
|
return check_reqs.check_android_target(error).then(function() {
|
||||||
|
// If due to some odd reason - check_android_target succeeds
|
||||||
|
// we should still fail here.
|
||||||
|
return Q.reject(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Q.reject(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
AntBuilder.prototype.clean = function(opts) {
|
||||||
|
var args = this.getArgs('clean', opts);
|
||||||
|
var self = this;
|
||||||
|
return check_reqs.check_ant()
|
||||||
|
.then(function() {
|
||||||
|
return spawn('ant', args, {stdio: 'inherit'});
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
shell.rm('-rf', path.join(self.root, 'out'));
|
||||||
|
|
||||||
|
['debug', 'release'].forEach(function(config) {
|
||||||
|
var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
|
||||||
|
if(isAutoGenerated(propertiesFilePath)){
|
||||||
|
shell.rm('-f', propertiesFilePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = AntBuilder;
|
||||||
|
|
||||||
|
function hasCustomRules(projectRoot) {
|
||||||
|
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
|
||||||
|
}
|
||||||
|
|
||||||
|
function isAutoGenerated(file) {
|
||||||
|
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Q = require('q');
|
||||||
|
var fs = require('fs');
|
||||||
|
var path = require('path');
|
||||||
|
var shell = require('shelljs');
|
||||||
|
var events = require('cordova-common').events;
|
||||||
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
|
function GenericBuilder (projectDir) {
|
||||||
|
this.root = projectDir || path.resolve(__dirname, '../../..');
|
||||||
|
this.binDirs = {
|
||||||
|
ant: path.join(this.root, hasCustomRules(this.root) ? 'ant-build' : 'bin'),
|
||||||
|
gradle: path.join(this.root, 'build', 'outputs', 'apk')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasCustomRules(projectRoot) {
|
||||||
|
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
|
||||||
|
}
|
||||||
|
|
||||||
|
GenericBuilder.prototype.prepEnv = function() {
|
||||||
|
return Q();
|
||||||
|
};
|
||||||
|
|
||||||
|
GenericBuilder.prototype.build = function() {
|
||||||
|
events.emit('log', 'Skipping build...');
|
||||||
|
return Q(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
GenericBuilder.prototype.clean = function() {
|
||||||
|
return Q();
|
||||||
|
};
|
||||||
|
|
||||||
|
GenericBuilder.prototype.findOutputApks = function(build_type, arch) {
|
||||||
|
var self = this;
|
||||||
|
return Object.keys(this.binDirs)
|
||||||
|
.reduce(function (result, builderName) {
|
||||||
|
var binDir = self.binDirs[builderName];
|
||||||
|
return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch));
|
||||||
|
}, [])
|
||||||
|
.sort(apkSorter);
|
||||||
|
};
|
||||||
|
|
||||||
|
GenericBuilder.prototype.readProjectProperties = function () {
|
||||||
|
function findAllUniq(data, r) {
|
||||||
|
var s = {};
|
||||||
|
var m;
|
||||||
|
while ((m = r.exec(data))) {
|
||||||
|
s[m[1]] = 1;
|
||||||
|
}
|
||||||
|
return Object.keys(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
|
||||||
|
return {
|
||||||
|
libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
|
||||||
|
gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
|
||||||
|
systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
GenericBuilder.prototype.extractRealProjectNameFromManifest = function () {
|
||||||
|
var manifestPath = path.join(this.root, 'AndroidManifest.xml');
|
||||||
|
var manifestData = fs.readFileSync(manifestPath, 'utf8');
|
||||||
|
var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
|
||||||
|
if (!m) {
|
||||||
|
throw new CordovaError('Could not find package name in ' + manifestPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
var packageName=m[1];
|
||||||
|
var lastDotIndex = packageName.lastIndexOf('.');
|
||||||
|
return packageName.substring(lastDotIndex + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = GenericBuilder;
|
||||||
|
|
||||||
|
function apkSorter(fileA, fileB) {
|
||||||
|
// De-prioritize unsigned builds
|
||||||
|
var unsignedRE = /-unsigned/;
|
||||||
|
if (unsignedRE.exec(fileA)) {
|
||||||
|
return 1;
|
||||||
|
} else if (unsignedRE.exec(fileB)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime;
|
||||||
|
return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findOutputApksHelper(dir, build_type, arch) {
|
||||||
|
var shellSilent = shell.config.silent;
|
||||||
|
shell.config.silent = true;
|
||||||
|
|
||||||
|
var ret = shell.ls(path.join(dir, '*.apk'))
|
||||||
|
.filter(function(candidate) {
|
||||||
|
var apkName = path.basename(candidate);
|
||||||
|
// Need to choose between release and debug .apk.
|
||||||
|
if (build_type === 'debug') {
|
||||||
|
return /-debug/.exec(apkName) && !/-unaligned|-unsigned/.exec(apkName);
|
||||||
|
}
|
||||||
|
if (build_type === 'release') {
|
||||||
|
return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
})
|
||||||
|
.sort(apkSorter);
|
||||||
|
|
||||||
|
shellSilent = shellSilent;
|
||||||
|
|
||||||
|
if (ret.length === 0) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
// Assume arch-specific build if newest apk has -x86 or -arm.
|
||||||
|
var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0]));
|
||||||
|
// And show only arch-specific ones (or non-arch-specific)
|
||||||
|
ret = ret.filter(function(p) {
|
||||||
|
/*jshint -W018 */
|
||||||
|
return !!/-x86|-arm/.exec(path.basename(p)) == archSpecific;
|
||||||
|
/*jshint +W018 */
|
||||||
|
});
|
||||||
|
|
||||||
|
if (archSpecific && ret.length > 1 && arch) {
|
||||||
|
ret = ret.filter(function(p) {
|
||||||
|
return path.basename(p).indexOf('-' + arch) != -1;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
/*
|
||||||
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
|
or more contributor license agreements. See the NOTICE file
|
||||||
|
distributed with this work for additional information
|
||||||
|
regarding copyright ownership. The ASF licenses this file
|
||||||
|
to you under the Apache License, Version 2.0 (the
|
||||||
|
"License"); you may not use this file except in compliance
|
||||||
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing,
|
||||||
|
software distributed under the License is distributed on an
|
||||||
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
|
KIND, either express or implied. See the License for the
|
||||||
|
specific language governing permissions and limitations
|
||||||
|
under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
var Q = require('q');
|
||||||
|
var fs = require('fs');
|
||||||
|
var util = require('util');
|
||||||
|
var path = require('path');
|
||||||
|
var shell = require('shelljs');
|
||||||
|
var spawn = require('cordova-common').superspawn.spawn;
|
||||||
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
var check_reqs = require('../check_reqs');
|
||||||
|
|
||||||
|
var GenericBuilder = require('./GenericBuilder');
|
||||||
|
|
||||||
|
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
||||||
|
var SIGNING_PROPERTIES = '-signing.properties';
|
||||||
|
var TEMPLATE =
|
||||||
|
'# This file is automatically generated.\n' +
|
||||||
|
'# Do not modify this file -- ' + MARKER + '\n';
|
||||||
|
|
||||||
|
function GradleBuilder (projectRoot) {
|
||||||
|
GenericBuilder.call(this, projectRoot);
|
||||||
|
|
||||||
|
this.binDirs = {gradle: this.binDirs.gradle};
|
||||||
|
}
|
||||||
|
|
||||||
|
util.inherits(GradleBuilder, GenericBuilder);
|
||||||
|
|
||||||
|
GradleBuilder.prototype.getArgs = function(cmd, opts) {
|
||||||
|
if (cmd == 'release') {
|
||||||
|
cmd = 'cdvBuildRelease';
|
||||||
|
} else if (cmd == 'debug') {
|
||||||
|
cmd = 'cdvBuildDebug';
|
||||||
|
}
|
||||||
|
var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
|
||||||
|
if (opts.arch) {
|
||||||
|
args.push('-PcdvBuildArch=' + opts.arch);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 10 seconds -> 6 seconds
|
||||||
|
args.push('-Dorg.gradle.daemon=true');
|
||||||
|
// to allow dex in process
|
||||||
|
args.push('-Dorg.gradle.jvmargs=-Xmx2048m');
|
||||||
|
// allow NDK to be used - required by Gradle 1.5 plugin
|
||||||
|
args.push('-Pandroid.useDeprecatedNdk=true');
|
||||||
|
args.push.apply(args, opts.extraArgs);
|
||||||
|
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
|
||||||
|
// args.push('-Dorg.gradle.parallel=true');
|
||||||
|
return args;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This returns a promise
|
||||||
|
*/
|
||||||
|
|
||||||
|
GradleBuilder.prototype.runGradleWrapper = function(gradle_cmd) {
|
||||||
|
var gradlePath = path.join(this.root, 'gradlew');
|
||||||
|
var wrapperGradle = path.join(this.root, 'wrapper.gradle');
|
||||||
|
if(fs.existsSync(gradlePath)) {
|
||||||
|
//Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
|
||||||
|
} else {
|
||||||
|
return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Makes the project buildable, minus the gradle wrapper.
|
||||||
|
GradleBuilder.prototype.prepBuildFiles = function() {
|
||||||
|
// Update the version of build.gradle in each dependent library.
|
||||||
|
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
|
||||||
|
var propertiesObj = this.readProjectProperties();
|
||||||
|
var subProjects = propertiesObj.libs;
|
||||||
|
var checkAndCopy = function(subProject, root) {
|
||||||
|
var subProjectGradle = path.join(root, subProject, 'build.gradle');
|
||||||
|
// This is the future-proof way of checking if a file exists
|
||||||
|
// This must be synchronous to satisfy a Travis test
|
||||||
|
try {
|
||||||
|
fs.accessSync(subProjectGradle, fs.F_OK);
|
||||||
|
} catch (e) {
|
||||||
|
shell.cp('-f', pluginBuildGradle, subProjectGradle);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
for (var i = 0; i < subProjects.length; ++i) {
|
||||||
|
if (subProjects[i] !== 'CordovaLib') {
|
||||||
|
checkAndCopy(subProjects[i], this.root);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var name = this.extractRealProjectNameFromManifest();
|
||||||
|
//Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
|
||||||
|
var settingsGradlePaths = subProjects.map(function(p){
|
||||||
|
var realDir=p.replace(/[/\\]/g, ':');
|
||||||
|
var libName=realDir.replace(name+'-','');
|
||||||
|
var str='include ":'+libName+'"\n';
|
||||||
|
if(realDir.indexOf(name+'-')!==-1)
|
||||||
|
str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
|
||||||
|
return str;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Write the settings.gradle file.
|
||||||
|
fs.writeFileSync(path.join(this.root, 'settings.gradle'),
|
||||||
|
'// GENERATED FILE - DO NOT EDIT\n' +
|
||||||
|
'include ":"\n' + settingsGradlePaths.join(''));
|
||||||
|
// Update dependencies within build.gradle.
|
||||||
|
var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
|
||||||
|
var depsList = '';
|
||||||
|
var root = this.root;
|
||||||
|
var insertExclude = function(p) {
|
||||||
|
var gradlePath = path.join(root, p, 'build.gradle');
|
||||||
|
var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
|
||||||
|
if(projectGradleFile.indexOf('CordovaLib') != -1) {
|
||||||
|
depsList += '{\n exclude module:("CordovaLib")\n }\n';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
depsList +='\n';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
subProjects.forEach(function(p) {
|
||||||
|
console.log('Subproject Path: ' + p);
|
||||||
|
var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
|
||||||
|
depsList += ' debugCompile(project(path: "' + libName + '", configuration: "debug"))';
|
||||||
|
insertExclude(p);
|
||||||
|
depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))';
|
||||||
|
insertExclude(p);
|
||||||
|
});
|
||||||
|
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
|
||||||
|
var SYSTEM_LIBRARY_MAPPINGS = [
|
||||||
|
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
|
||||||
|
[/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
|
||||||
|
];
|
||||||
|
propertiesObj.systemLibs.forEach(function(p) {
|
||||||
|
var mavenRef;
|
||||||
|
// It's already in gradle form if it has two ':'s
|
||||||
|
if (/:.*:/.exec(p)) {
|
||||||
|
mavenRef = p;
|
||||||
|
} else {
|
||||||
|
for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
|
||||||
|
var pair = SYSTEM_LIBRARY_MAPPINGS[i];
|
||||||
|
if (pair[0].exec(p)) {
|
||||||
|
mavenRef = p.replace(pair[0], pair[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!mavenRef) {
|
||||||
|
throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
depsList += ' compile "' + mavenRef + '"\n';
|
||||||
|
});
|
||||||
|
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
|
||||||
|
var includeList = '';
|
||||||
|
propertiesObj.gradleIncludes.forEach(function(includePath) {
|
||||||
|
includeList += 'apply from: "' + includePath + '"\n';
|
||||||
|
});
|
||||||
|
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
|
||||||
|
fs.writeFileSync(path.join(this.root, 'build.gradle'), buildGradle);
|
||||||
|
};
|
||||||
|
|
||||||
|
GradleBuilder.prototype.prepEnv = function(opts) {
|
||||||
|
var self = this;
|
||||||
|
return check_reqs.check_gradle()
|
||||||
|
.then(function(gradlePath) {
|
||||||
|
return self.runGradleWrapper(gradlePath);
|
||||||
|
}).then(function() {
|
||||||
|
return self.prepBuildFiles();
|
||||||
|
}).then(function() {
|
||||||
|
// We now copy the gradle out of the framework
|
||||||
|
// This is a dirty patch to get the build working
|
||||||
|
/*
|
||||||
|
var wrapperDir = path.join(self.root, 'CordovaLib');
|
||||||
|
if (process.platform == 'win32') {
|
||||||
|
shell.rm('-f', path.join(self.root, 'gradlew.bat'));
|
||||||
|
shell.cp(path.join(wrapperDir, 'gradlew.bat'), self.root);
|
||||||
|
} else {
|
||||||
|
shell.rm('-f', path.join(self.root, 'gradlew'));
|
||||||
|
shell.cp(path.join(wrapperDir, 'gradlew'), self.root);
|
||||||
|
}
|
||||||
|
shell.rm('-rf', path.join(self.root, 'gradle', 'wrapper'));
|
||||||
|
shell.mkdir('-p', path.join(self.root, 'gradle'));
|
||||||
|
shell.cp('-r', path.join(wrapperDir, 'gradle', 'wrapper'), path.join(self.root, 'gradle'));
|
||||||
|
*/
|
||||||
|
// If the gradle distribution URL is set, make sure it points to version we want.
|
||||||
|
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
|
||||||
|
// For some reason, using ^ and $ don't work. This does the job, though.
|
||||||
|
var distributionUrlRegex = /distributionUrl.*zip/;
|
||||||
|
/*jshint -W069 */
|
||||||
|
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-3.3-all.zip';
|
||||||
|
/*jshint +W069 */
|
||||||
|
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
||||||
|
shell.chmod('u+w', gradleWrapperPropertiesPath);
|
||||||
|
shell.sed('-i', distributionUrlRegex, 'distributionUrl='+distributionUrl, gradleWrapperPropertiesPath);
|
||||||
|
|
||||||
|
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
||||||
|
var propertiesFilePath = path.join(self.root, propertiesFile);
|
||||||
|
if (opts.packageInfo) {
|
||||||
|
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
||||||
|
} else if (isAutoGenerated(propertiesFilePath)) {
|
||||||
|
shell.rm('-f', propertiesFilePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Builds the project with gradle.
|
||||||
|
* Returns a promise.
|
||||||
|
*/
|
||||||
|
GradleBuilder.prototype.build = function(opts) {
|
||||||
|
var wrapper = path.join(this.root, 'gradlew');
|
||||||
|
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
|
||||||
|
|
||||||
|
return spawn(wrapper, args, {stdio: 'pipe'})
|
||||||
|
.progress(function (stdio){
|
||||||
|
if (stdio.stderr) {
|
||||||
|
/*
|
||||||
|
* Workaround for the issue with Java printing some unwanted information to
|
||||||
|
* stderr instead of stdout.
|
||||||
|
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
|
||||||
|
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
|
||||||
|
* explanation.
|
||||||
|
*/
|
||||||
|
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
|
||||||
|
if (suppressThisLine) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
process.stderr.write(stdio.stderr);
|
||||||
|
} else {
|
||||||
|
process.stdout.write(stdio.stdout);
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (error.toString().indexOf('failed to find target with hash string') >= 0) {
|
||||||
|
return check_reqs.check_android_target(error).then(function() {
|
||||||
|
// If due to some odd reason - check_android_target succeeds
|
||||||
|
// we should still fail here.
|
||||||
|
return Q.reject(error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return Q.reject(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
GradleBuilder.prototype.clean = function(opts) {
|
||||||
|
var builder = this;
|
||||||
|
var wrapper = path.join(this.root, 'gradlew');
|
||||||
|
var args = builder.getArgs('clean', opts);
|
||||||
|
return Q().then(function() {
|
||||||
|
return spawn(wrapper, args, {stdio: 'inherit'});
|
||||||
|
})
|
||||||
|
.then(function () {
|
||||||
|
shell.rm('-rf', path.join(builder.root, 'out'));
|
||||||
|
|
||||||
|
['debug', 'release'].forEach(function(config) {
|
||||||
|
var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
|
||||||
|
if(isAutoGenerated(propertiesFilePath)){
|
||||||
|
shell.rm('-f', propertiesFilePath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = GradleBuilder;
|
||||||
|
|
||||||
|
function isAutoGenerated(file) {
|
||||||
|
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
||||||
|
}
|
||||||
@@ -1,412 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
/* eslint no-self-assign: 0 */
|
|
||||||
/* eslint no-unused-vars: 0 */
|
|
||||||
|
|
||||||
var Q = require('q');
|
|
||||||
var fs = require('fs');
|
|
||||||
var path = require('path');
|
|
||||||
var shell = require('shelljs');
|
|
||||||
var spawn = require('cordova-common').superspawn.spawn;
|
|
||||||
var events = require('cordova-common').events;
|
|
||||||
var CordovaError = require('cordova-common').CordovaError;
|
|
||||||
var check_reqs = require('../check_reqs');
|
|
||||||
var PackageType = require('../PackageType');
|
|
||||||
const compareFunc = require('compare-func');
|
|
||||||
|
|
||||||
const MARKER = 'YOUR CHANGES WILL BE ERASED!';
|
|
||||||
const SIGNING_PROPERTIES = '-signing.properties';
|
|
||||||
const TEMPLATE =
|
|
||||||
'# This file is automatically generated.\n' +
|
|
||||||
'# Do not modify this file -- ' + MARKER + '\n';
|
|
||||||
|
|
||||||
class ProjectBuilder {
|
|
||||||
constructor (rootDirectory) {
|
|
||||||
this.root = rootDirectory || path.resolve(__dirname, '../../..');
|
|
||||||
this.apkDir = path.join(this.root, 'app', 'build', 'outputs', 'apk');
|
|
||||||
this.aabDir = path.join(this.root, 'app', 'build', 'outputs', 'bundle');
|
|
||||||
}
|
|
||||||
|
|
||||||
getArgs (cmd, opts) {
|
|
||||||
let args;
|
|
||||||
let buildCmd = cmd;
|
|
||||||
if (opts.packageType === PackageType.BUNDLE) {
|
|
||||||
if (cmd === 'release') {
|
|
||||||
buildCmd = ':app:bundleRelease';
|
|
||||||
} else if (cmd === 'debug') {
|
|
||||||
buildCmd = ':app:bundleDebug';
|
|
||||||
}
|
|
||||||
|
|
||||||
args = [buildCmd, '-b', path.join(this.root, 'build.gradle')];
|
|
||||||
} else {
|
|
||||||
if (cmd === 'release') {
|
|
||||||
buildCmd = 'cdvBuildRelease';
|
|
||||||
} else if (cmd === 'debug') {
|
|
||||||
buildCmd = 'cdvBuildDebug';
|
|
||||||
}
|
|
||||||
|
|
||||||
args = [buildCmd, '-b', path.join(this.root, 'build.gradle')];
|
|
||||||
|
|
||||||
if (opts.arch) {
|
|
||||||
args.push('-PcdvBuildArch=' + opts.arch);
|
|
||||||
}
|
|
||||||
|
|
||||||
args.push.apply(args, opts.extraArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return args;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This returns a promise
|
|
||||||
*/
|
|
||||||
runGradleWrapper (gradle_cmd) {
|
|
||||||
var gradlePath = path.join(this.root, 'gradlew');
|
|
||||||
var wrapperGradle = path.join(this.root, 'wrapper.gradle');
|
|
||||||
if (fs.existsSync(gradlePath)) {
|
|
||||||
// Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
|
|
||||||
} else {
|
|
||||||
return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], { stdio: 'inherit' });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readProjectProperties () {
|
|
||||||
function findAllUniq (data, r) {
|
|
||||||
var s = {};
|
|
||||||
var m;
|
|
||||||
while ((m = r.exec(data))) {
|
|
||||||
s[m[1]] = 1;
|
|
||||||
}
|
|
||||||
return Object.keys(s);
|
|
||||||
}
|
|
||||||
|
|
||||||
var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
|
|
||||||
return {
|
|
||||||
libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
|
|
||||||
gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
|
|
||||||
systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
extractRealProjectNameFromManifest () {
|
|
||||||
var manifestPath = path.join(this.root, 'app', 'src', 'main', 'AndroidManifest.xml');
|
|
||||||
var manifestData = fs.readFileSync(manifestPath, 'utf8');
|
|
||||||
var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
|
|
||||||
if (!m) {
|
|
||||||
throw new CordovaError('Could not find package name in ' + manifestPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
var packageName = m[1];
|
|
||||||
var lastDotIndex = packageName.lastIndexOf('.');
|
|
||||||
return packageName.substring(lastDotIndex + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Makes the project buildable, minus the gradle wrapper.
|
|
||||||
prepBuildFiles () {
|
|
||||||
// Update the version of build.gradle in each dependent library.
|
|
||||||
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
|
|
||||||
var propertiesObj = this.readProjectProperties();
|
|
||||||
var subProjects = propertiesObj.libs;
|
|
||||||
|
|
||||||
// Check and copy the gradle file into the subproject
|
|
||||||
// Called by the loop before this function def
|
|
||||||
|
|
||||||
var checkAndCopy = function (subProject, root) {
|
|
||||||
var subProjectGradle = path.join(root, subProject, 'build.gradle');
|
|
||||||
// This is the future-proof way of checking if a file exists
|
|
||||||
// This must be synchronous to satisfy a Travis test
|
|
||||||
try {
|
|
||||||
fs.accessSync(subProjectGradle, fs.F_OK);
|
|
||||||
} catch (e) {
|
|
||||||
shell.cp('-f', pluginBuildGradle, subProjectGradle);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (var i = 0; i < subProjects.length; ++i) {
|
|
||||||
if (subProjects[i] !== 'CordovaLib') {
|
|
||||||
checkAndCopy(subProjects[i], this.root);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var name = this.extractRealProjectNameFromManifest();
|
|
||||||
// Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
|
|
||||||
var settingsGradlePaths = subProjects.map(function (p) {
|
|
||||||
var realDir = p.replace(/[/\\]/g, ':');
|
|
||||||
var libName = realDir.replace(name + '-', '');
|
|
||||||
var str = 'include ":' + libName + '"\n';
|
|
||||||
if (realDir.indexOf(name + '-') !== -1) {
|
|
||||||
str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n';
|
|
||||||
}
|
|
||||||
return str;
|
|
||||||
});
|
|
||||||
|
|
||||||
fs.writeFileSync(path.join(this.root, 'settings.gradle'),
|
|
||||||
'// GENERATED FILE - DO NOT EDIT\n' +
|
|
||||||
'include ":"\n' + settingsGradlePaths.join(''));
|
|
||||||
|
|
||||||
// Update dependencies within build.gradle.
|
|
||||||
var buildGradle = fs.readFileSync(path.join(this.root, 'app', 'build.gradle'), 'utf8');
|
|
||||||
var depsList = '';
|
|
||||||
var root = this.root;
|
|
||||||
var insertExclude = function (p) {
|
|
||||||
var gradlePath = path.join(root, p, 'build.gradle');
|
|
||||||
var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
|
|
||||||
if (projectGradleFile.indexOf('CordovaLib') !== -1) {
|
|
||||||
depsList += '{\n exclude module:("CordovaLib")\n }\n';
|
|
||||||
} else {
|
|
||||||
depsList += '\n';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
subProjects.forEach(function (p) {
|
|
||||||
events.emit('log', 'Subproject Path: ' + p);
|
|
||||||
var libName = p.replace(/[/\\]/g, ':').replace(name + '-', '');
|
|
||||||
if (libName !== 'app') {
|
|
||||||
depsList += ' implementation(project(path: ":' + libName + '"))';
|
|
||||||
insertExclude(p);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
|
|
||||||
var SYSTEM_LIBRARY_MAPPINGS = [
|
|
||||||
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
|
|
||||||
[/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
|
|
||||||
];
|
|
||||||
|
|
||||||
propertiesObj.systemLibs.forEach(function (p) {
|
|
||||||
var mavenRef;
|
|
||||||
// It's already in gradle form if it has two ':'s
|
|
||||||
if (/:.*:/.exec(p)) {
|
|
||||||
mavenRef = p;
|
|
||||||
} else {
|
|
||||||
for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
|
|
||||||
var pair = SYSTEM_LIBRARY_MAPPINGS[i];
|
|
||||||
if (pair[0].exec(p)) {
|
|
||||||
mavenRef = p.replace(pair[0], pair[1]);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!mavenRef) {
|
|
||||||
throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
depsList += ' implementation "' + mavenRef + '"\n';
|
|
||||||
});
|
|
||||||
|
|
||||||
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
|
|
||||||
var includeList = '';
|
|
||||||
|
|
||||||
propertiesObj.gradleIncludes.forEach(function (includePath) {
|
|
||||||
includeList += 'apply from: "../' + includePath + '"\n';
|
|
||||||
});
|
|
||||||
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
|
|
||||||
// This needs to be stored in the app gradle, not the root grade
|
|
||||||
fs.writeFileSync(path.join(this.root, 'app', 'build.gradle'), buildGradle);
|
|
||||||
}
|
|
||||||
|
|
||||||
prepEnv (opts) {
|
|
||||||
var self = this;
|
|
||||||
return check_reqs.check_gradle()
|
|
||||||
.then(function (gradlePath) {
|
|
||||||
return self.runGradleWrapper(gradlePath);
|
|
||||||
}).then(function () {
|
|
||||||
return self.prepBuildFiles();
|
|
||||||
}).then(function () {
|
|
||||||
// If the gradle distribution URL is set, make sure it points to version we want.
|
|
||||||
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
|
|
||||||
// For some reason, using ^ and $ don't work. This does the job, though.
|
|
||||||
var distributionUrlRegex = /distributionUrl.*zip/;
|
|
||||||
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-4.10.3-all.zip';
|
|
||||||
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
|
|
||||||
shell.chmod('u+w', gradleWrapperPropertiesPath);
|
|
||||||
shell.sed('-i', distributionUrlRegex, 'distributionUrl=' + distributionUrl, gradleWrapperPropertiesPath);
|
|
||||||
|
|
||||||
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
|
|
||||||
var propertiesFilePath = path.join(self.root, propertiesFile);
|
|
||||||
if (opts.packageInfo) {
|
|
||||||
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
|
|
||||||
} else if (isAutoGenerated(propertiesFilePath)) {
|
|
||||||
shell.rm('-f', propertiesFilePath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Builds the project with gradle.
|
|
||||||
* Returns a promise.
|
|
||||||
*/
|
|
||||||
build (opts) {
|
|
||||||
var wrapper = path.join(this.root, 'gradlew');
|
|
||||||
var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);
|
|
||||||
|
|
||||||
return spawn(wrapper, args, { stdio: 'pipe' })
|
|
||||||
.progress(function (stdio) {
|
|
||||||
if (stdio.stderr) {
|
|
||||||
/*
|
|
||||||
* Workaround for the issue with Java printing some unwanted information to
|
|
||||||
* stderr instead of stdout.
|
|
||||||
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
|
|
||||||
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
|
|
||||||
* explanation.
|
|
||||||
*/
|
|
||||||
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
|
|
||||||
if (suppressThisLine) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
process.stderr.write(stdio.stderr);
|
|
||||||
} else {
|
|
||||||
process.stdout.write(stdio.stdout);
|
|
||||||
}
|
|
||||||
}).catch(function (error) {
|
|
||||||
if (error.toString().indexOf('failed to find target with hash string') >= 0) {
|
|
||||||
return check_reqs.check_android_target(error).then(function () {
|
|
||||||
// If due to some odd reason - check_android_target succeeds
|
|
||||||
// we should still fail here.
|
|
||||||
return Q.reject(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return Q.reject(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
clean (opts) {
|
|
||||||
var builder = this;
|
|
||||||
var wrapper = path.join(this.root, 'gradlew');
|
|
||||||
var args = builder.getArgs('clean', opts);
|
|
||||||
return Q().then(function () {
|
|
||||||
return spawn(wrapper, args, { stdio: 'inherit' });
|
|
||||||
})
|
|
||||||
.then(function () {
|
|
||||||
shell.rm('-rf', path.join(builder.root, 'out'));
|
|
||||||
|
|
||||||
['debug', 'release'].forEach(function (config) {
|
|
||||||
var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
|
|
||||||
if (isAutoGenerated(propertiesFilePath)) {
|
|
||||||
shell.rm('-f', propertiesFilePath);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
findOutputApks (build_type, arch) {
|
|
||||||
return findOutputApksHelper(this.apkDir, build_type, arch).sort(apkSorter);
|
|
||||||
}
|
|
||||||
|
|
||||||
findOutputBundles (build_type) {
|
|
||||||
return findOutputBundlesHelper(this.aabDir, build_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchBuildResults (build_type, arch) {
|
|
||||||
return {
|
|
||||||
apkPaths: this.findOutputApks(build_type, arch),
|
|
||||||
buildType: build_type
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = ProjectBuilder;
|
|
||||||
|
|
||||||
const apkSorter = compareFunc([
|
|
||||||
// Sort arch specific builds after generic ones
|
|
||||||
apkPath => /-x86|-arm/.test(apkPath),
|
|
||||||
|
|
||||||
// Sort unsigned builds after signed ones
|
|
||||||
apkPath => /-unsigned/.test(apkPath),
|
|
||||||
|
|
||||||
// Sort by file modification time, latest first
|
|
||||||
apkPath => -fs.statSync(apkPath).mtime.getTime(),
|
|
||||||
|
|
||||||
// Sort by file name length, ascending
|
|
||||||
'length'
|
|
||||||
]);
|
|
||||||
|
|
||||||
function findOutputApksHelper (dir, build_type, arch) {
|
|
||||||
var shellSilent = shell.config.silent;
|
|
||||||
shell.config.silent = true;
|
|
||||||
|
|
||||||
// list directory recursively
|
|
||||||
var ret = shell.ls('-R', dir).map(function (file) {
|
|
||||||
// ls does not include base directory
|
|
||||||
return path.join(dir, file);
|
|
||||||
}).filter(function (file) {
|
|
||||||
// find all APKs
|
|
||||||
return file.match(/\.apk?$/i);
|
|
||||||
}).filter(function (candidate) {
|
|
||||||
var apkName = path.basename(candidate);
|
|
||||||
// Need to choose between release and debug .apk.
|
|
||||||
if (build_type === 'debug') {
|
|
||||||
return /-debug/.exec(apkName) && !/-unaligned|-unsigned/.exec(apkName);
|
|
||||||
}
|
|
||||||
if (build_type === 'release') {
|
|
||||||
return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}).sort(apkSorter);
|
|
||||||
|
|
||||||
shellSilent = shellSilent;
|
|
||||||
|
|
||||||
if (ret.length === 0) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
// Assume arch-specific build if newest apk has -x86 or -arm.
|
|
||||||
var archSpecific = !!/-x86|-arm/.exec(path.basename(ret[0]));
|
|
||||||
// And show only arch-specific ones (or non-arch-specific)
|
|
||||||
ret = ret.filter(function (p) {
|
|
||||||
return !!/-x86|-arm/.exec(path.basename(p)) === archSpecific;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (archSpecific && ret.length > 1 && arch) {
|
|
||||||
ret = ret.filter(function (p) {
|
|
||||||
return path.basename(p).indexOf('-' + arch) !== -1;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This method was a copy of findOutputApksHelper and modified to look for bundles
|
|
||||||
// While replacing shell with fs-extra, it might be a good idea to see if we can
|
|
||||||
// generalise these findOutput methods.
|
|
||||||
function findOutputBundlesHelper (dir, build_type) {
|
|
||||||
// This is an unused variable that was copied from findOutputApksHelper
|
|
||||||
// we are pretty sure it was meant to reset shell.config.silent back to
|
|
||||||
// the original value. However shell is planned to be replaced,
|
|
||||||
// it was left as is to avoid unintended consequences.
|
|
||||||
const shellSilent = shell.config.silent;
|
|
||||||
shell.config.silent = true;
|
|
||||||
|
|
||||||
// list directory recursively
|
|
||||||
const ret = shell.ls('-R', dir).map(function (file) {
|
|
||||||
return path.join(dir, file); // ls does not include base directory
|
|
||||||
}).filter(function (file) {
|
|
||||||
return file.match(/\.aab?$/i); // find all bundles
|
|
||||||
}).filter(function (candidate) {
|
|
||||||
// Need to choose between release and debug bundle.
|
|
||||||
if (build_type === 'debug') {
|
|
||||||
return /debug/.exec(candidate);
|
|
||||||
}
|
|
||||||
if (build_type === 'release') {
|
|
||||||
return /release/.exec(candidate);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isAutoGenerated (file) {
|
|
||||||
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
|
|
||||||
}
|
|
||||||
@@ -1,34 +1,47 @@
|
|||||||
/*
|
/*
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
or more contributor license agreements. See the NOTICE file
|
or more contributor license agreements. See the NOTICE file
|
||||||
distributed with this work for additional information
|
distributed with this work for additional information
|
||||||
regarding copyright ownership. The ASF licenses this file
|
regarding copyright ownership. The ASF licenses this file
|
||||||
to you under the Apache License, Version 2.0 (the
|
to you under the Apache License, Version 2.0 (the
|
||||||
"License"); you may not use this file except in compliance
|
"License"); you may not use this file except in compliance
|
||||||
with the License. You may obtain a copy of the License at
|
with the License. You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const CordovaError = require('cordova-common').CordovaError;
|
var CordovaError = require('cordova-common').CordovaError;
|
||||||
|
|
||||||
|
var knownBuilders = {
|
||||||
|
ant: 'AntBuilder',
|
||||||
|
gradle: 'GradleBuilder',
|
||||||
|
none: 'GenericBuilder'
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper method that instantiates and returns a builder for specified build type.
|
* Helper method that instantiates and returns a builder for specified build
|
||||||
|
* type.
|
||||||
*
|
*
|
||||||
* @return {Builder} A builder instance for specified build type.
|
* @param {String} builderType Builder name to construct and return. Must
|
||||||
|
* be one of 'ant', 'gradle' or 'none'
|
||||||
|
*
|
||||||
|
* @return {Builder} A builder instance for specified build type.
|
||||||
*/
|
*/
|
||||||
module.exports.getBuilder = function (projectPath) {
|
module.exports.getBuilder = function (builderType, projectRoot) {
|
||||||
|
if (!knownBuilders[builderType])
|
||||||
|
throw new CordovaError('Builder ' + builderType + ' is not supported.');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const Builder = require('./ProjectBuilder');
|
var Builder = require('./' + knownBuilders[builderType]);
|
||||||
return new Builder(projectPath);
|
return new Builder(projectRoot);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new CordovaError('Failed to instantiate ProjectBuilder builder: ' + err);
|
throw new CordovaError('Failed to instantiate ' + knownBuilders[builderType] + ' builder: ' + err);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,19 +19,21 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var shelljs = require('shelljs');
|
/* jshint sub:true */
|
||||||
var child_process = require('child_process');
|
|
||||||
var Q = require('q');
|
var shelljs = require('shelljs'),
|
||||||
var path = require('path');
|
child_process = require('child_process'),
|
||||||
var fs = require('fs');
|
Q = require('q'),
|
||||||
var os = require('os');
|
path = require('path'),
|
||||||
var REPO_ROOT = path.join(__dirname, '..', '..', '..', '..');
|
fs = require('fs'),
|
||||||
var PROJECT_ROOT = path.join(__dirname, '..', '..');
|
os = require('os'),
|
||||||
|
REPO_ROOT = path.join(__dirname, '..', '..', '..', '..'),
|
||||||
|
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) {
|
||||||
@@ -39,18 +41,29 @@ function forgivingWhichSync (cmd) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports.isWindows = function () {
|
function tryCommand(cmd, errMsg, catchStderr) {
|
||||||
return (os.platform() === 'win32');
|
var d = Q.defer();
|
||||||
|
child_process.exec(cmd, function(err, stdout, stderr) {
|
||||||
|
if (err) d.reject(new CordovaError(errMsg));
|
||||||
|
// Sometimes it is necessary to return an stderr instead of stdout in case of success, since
|
||||||
|
// some commands prints theirs output to stderr instead of stdout. 'javac' is the example
|
||||||
|
else d.resolve((catchStderr ? stderr : stdout).trim());
|
||||||
|
});
|
||||||
|
return d.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports.isWindows = function() {
|
||||||
|
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);
|
||||||
@@ -70,82 +83,77 @@ 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']).then(function (output) {
|
return superspawn.spawn('ant', ['-version'])
|
||||||
|
.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) {
|
||||||
if (err) {
|
throw new CordovaError('Failed to run `ant -version`. Make sure you have `ant` on your $PATH.');
|
||||||
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;
|
||||||
// OK, This hack only works on Windows, not on Mac OS or Linux. We will be deleting this eventually!
|
if (module.exports.isDarwin()) {
|
||||||
if (module.exports.isWindows()) {
|
program_dir = fs.readdirSync('/Applications');
|
||||||
|
while (i < program_dir.length && !foundStudio) {
|
||||||
var result = child_process.spawnSync(path.join(__dirname, 'getASPath.bat'));
|
if (program_dir[i].startsWith('Android Studio')) {
|
||||||
// console.log('result.stdout =' + result.stdout.toString());
|
//TODO: Check for a specific Android Studio version, make sure it's not Canary
|
||||||
// console.log('result.stderr =' + result.stderr.toString());
|
androidStudioPath = path.join('/Applications', program_dir[i], 'Contents', 'gradle');
|
||||||
|
foundStudio = true;
|
||||||
if (result.stderr.toString().length > 0) {
|
} else { ++i; }
|
||||||
var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/';
|
}
|
||||||
if (fs.existsSync(androidPath)) {
|
} else if (module.exports.isWindows()) {
|
||||||
program_dir = fs.readdirSync(androidPath);
|
var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/';
|
||||||
while (i < program_dir.length && !foundStudio) {
|
if (fs.existsSync(androidPath)) {
|
||||||
if (program_dir[i].startsWith('Android Studio')) {
|
program_dir = fs.readdirSync(androidPath);
|
||||||
foundStudio = true;
|
while (i < program_dir.length && !foundStudio) {
|
||||||
androidStudioPath = path.join(process.env['ProgramFiles'], 'Android', program_dir[i], 'gradle');
|
if (program_dir[i].startsWith('Android Studio')) {
|
||||||
} else { ++i; }
|
foundStudio = true;
|
||||||
}
|
androidStudioPath = path.join(process.env['ProgramFiles'], 'Android', program_dir[i], 'gradle');
|
||||||
|
} else { ++i; }
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
// console.log('got android studio path from registry');
|
|
||||||
// remove the (os independent) new line char at the end of stdout
|
|
||||||
// add gradle to match the above.
|
|
||||||
androidStudioPath = path.join(result.stdout.toString().split('\r\n')[0], 'gradle');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (androidStudioPath !== null && fs.existsSync(androidStudioPath)) {
|
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) { d.resolve(gradlePath); } else {
|
if (gradlePath.length !== 0)
|
||||||
|
d.resolve(gradlePath);
|
||||||
|
else
|
||||||
d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\n' +
|
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) {
|
||||||
@@ -155,14 +163,13 @@ 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 it manually.';
|
var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
|
||||||
if (fs.existsSync(find_java)) {
|
if (fs.existsSync(find_java)) {
|
||||||
return superspawn.spawn(find_java).then(function (stdout) {
|
return superspawn.spawn(find_java)
|
||||||
|
.then(function(stdout) {
|
||||||
process.env['JAVA_HOME'] = stdout.trim();
|
process.env['JAVA_HOME'] = stdout.trim();
|
||||||
}).catch(function (err) {
|
}).catch(function(err) {
|
||||||
if (err) {
|
throw new CordovaError(default_java_error_msg);
|
||||||
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.
|
||||||
@@ -193,36 +200,32 @@ module.exports.check_java = function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}).then(function () {
|
}).then(function() {
|
||||||
return Q.denodeify(child_process.exec)('javac -version')
|
var msg =
|
||||||
.then(outputs => {
|
'Failed to run "javac -version", make sure that you have a JDK installed.\n' +
|
||||||
// outputs contains two entries: stdout and stderr
|
'You can get it from: http://www.oracle.com/technetwork/java/javase/downloads.\n';
|
||||||
// Java <= 8 writes version info to stderr, Java >= 9 to stdout
|
if (process.env['JAVA_HOME']) {
|
||||||
const output = outputs.join('').trim();
|
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'] + '\n';
|
||||||
const match = /javac\s+([\d.]+)/i.exec(output);
|
}
|
||||||
return match && match[1];
|
// We use tryCommand with catchStderr = true, because
|
||||||
}, () => {
|
// javac writes version info to stderr instead of stdout
|
||||||
var msg =
|
return tryCommand('javac -version', msg, true)
|
||||||
'Failed to run "javac -version", make sure that you have a JDK version 8 installed.\n' +
|
.then(function (output) {
|
||||||
'You can get it from the following location:\n' +
|
//Let's check for at least Java 8, and keep it future proof so we can support Java 10
|
||||||
'https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html';
|
var match = /javac ((?:1\.)(?:[8-9]\.)(?:\d+))|((?:1\.)(?:[1-9]\d+\.)(?:\d+))/i.exec(output);
|
||||||
if (process.env['JAVA_HOME']) {
|
return match && match[1];
|
||||||
msg += '\n\n';
|
});
|
||||||
msg += 'Your JAVA_HOME is invalid: ' + process.env['JAVA_HOME'];
|
|
||||||
}
|
|
||||||
throw new CordovaError(msg);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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;
|
||||||
@@ -231,14 +234,6 @@ module.exports.check_android = function () {
|
|||||||
// First ensure ANDROID_HOME is set
|
// First ensure ANDROID_HOME is set
|
||||||
// If we have no hints (nothing in PATH), try a few default locations
|
// If we have no hints (nothing in PATH), try a few default locations
|
||||||
if (!hasAndroidHome && !androidCmdPath && !adbInPath && !avdmanagerInPath) {
|
if (!hasAndroidHome && !androidCmdPath && !adbInPath && !avdmanagerInPath) {
|
||||||
if (process.env['ANDROID_SDK_ROOT']) {
|
|
||||||
// Quick fix to set ANDROID_HOME according to ANDROID_SDK_ROOT
|
|
||||||
// if ANDROID_HOME is **not** defined and
|
|
||||||
// ANDROID_SDK_ROOT **is** defined
|
|
||||||
// according to environment variables as documented in:
|
|
||||||
// https://developer.android.com/studio/command-line/variables
|
|
||||||
maybeSetAndroidHome(path.join(process.env['ANDROID_SDK_ROOT']));
|
|
||||||
}
|
|
||||||
if (module.exports.isWindows()) {
|
if (module.exports.isWindows()) {
|
||||||
// Android Studio 1.0 installer
|
// Android Studio 1.0 installer
|
||||||
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));
|
maybeSetAndroidHome(path.join(process.env['LOCALAPPDATA'], 'Android', 'sdk'));
|
||||||
@@ -270,10 +265,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 it manually.\n' +
|
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
||||||
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
|
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
|
||||||
'Try reinstall Android SDK or update your PATH to include 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.');
|
||||||
}
|
}
|
||||||
@@ -281,10 +276,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 it manually.\n' +
|
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting 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.');
|
||||||
}
|
}
|
||||||
@@ -292,17 +287,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 it manually.\n' +
|
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting 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 it manually.\n' +
|
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
|
||||||
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
|
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
|
||||||
}
|
}
|
||||||
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
|
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
|
||||||
@@ -335,19 +330,20 @@ 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().then(function (targets) {
|
return android_sdk.list_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' +
|
||||||
@@ -361,25 +357,23 @@ 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()]).then(function (values) {
|
return Q.all([this.check_java(), this.check_android()])
|
||||||
console.log('Checking Java JDK and Android SDK versions');
|
.then(function(values) {
|
||||||
console.log('ANDROID_SDK_ROOT=' + process.env['ANDROID_SDK_ROOT'] + ' (recommended setting)');
|
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
|
||||||
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME'] + ' (DEPRECATED)');
|
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
|
||||||
|
|
||||||
if (!String(values[0]).startsWith('1.8.')) {
|
if (!values[0]) {
|
||||||
throw new CordovaError(
|
throw new CordovaError('Requirements check failed for JDK 1.8 or greater');
|
||||||
'Requirements check failed for JDK 8 (\'1.8.*\')! Detected version: ' + values[0] + '\n' +
|
}
|
||||||
'Check your ANDROID_SDK_ROOT / JAVA_HOME / PATH environment variables.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!values[1]) {
|
if (!values[1]) {
|
||||||
throw new CordovaError('Requirements check failed for Android SDK! Android SDK was not detected.');
|
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.
|
||||||
@@ -393,7 +387,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,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -403,7 +397,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'),
|
||||||
@@ -423,13 +417,15 @@ 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).then(function (version) {
|
return promise.then(checkFn)
|
||||||
|
.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()).then(function () {
|
}, Q())
|
||||||
|
.then(function () {
|
||||||
// When chain is completed, return requirements array to upstream API
|
// When chain is completed, return requirements array to upstream API
|
||||||
return requirements;
|
return requirements;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
/**
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
let fs = require('fs');
|
|
||||||
let path = require('path');
|
|
||||||
let propertiesParser = require('properties-parser');
|
|
||||||
let events = require('cordova-common').events;
|
|
||||||
|
|
||||||
class GradlePropertiesParser {
|
|
||||||
/**
|
|
||||||
* Loads and Edits Gradle Properties File.
|
|
||||||
*
|
|
||||||
* @param {String} platformDir is the path of the Android platform directory
|
|
||||||
*/
|
|
||||||
constructor (platformDir) {
|
|
||||||
this._defaults = {
|
|
||||||
// 10 seconds -> 6 seconds
|
|
||||||
'org.gradle.daemon': 'true',
|
|
||||||
|
|
||||||
// to allow dex in process
|
|
||||||
'org.gradle.jvmargs': '-Xmx2048m',
|
|
||||||
|
|
||||||
// allow NDK to be used - required by Gradle 1.5 plugin
|
|
||||||
'android.useDeprecatedNdk': 'true'
|
|
||||||
|
|
||||||
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
|
|
||||||
// 'org.gradle.parallel': 'true'
|
|
||||||
};
|
|
||||||
|
|
||||||
this.gradleFilePath = path.join(platformDir, 'gradle.properties');
|
|
||||||
}
|
|
||||||
|
|
||||||
configure (userConfigs) {
|
|
||||||
events.emit('verbose', '[Gradle Properties] Preparing Configuration');
|
|
||||||
|
|
||||||
this._initializeEditor();
|
|
||||||
|
|
||||||
events.emit('verbose', '[Gradle Properties] Appending default configuration properties');
|
|
||||||
this._configureProperties(this._defaults);
|
|
||||||
|
|
||||||
events.emit('verbose', '[Gradle Properties] Appending custom configuration properties');
|
|
||||||
this._configureProperties(userConfigs);
|
|
||||||
|
|
||||||
this._save();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialize the properties editor for parsing, setting, etc.
|
|
||||||
*/
|
|
||||||
_initializeEditor () {
|
|
||||||
// Touch empty gradle.properties file if missing.
|
|
||||||
if (!fs.existsSync(this.gradleFilePath)) {
|
|
||||||
events.emit('verbose', '[Gradle Properties] File missing, creating file with Cordova defaults.');
|
|
||||||
fs.writeFileSync(this.gradleFilePath, '', 'utf-8');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create an editor for parsing, getting, and setting configurations.
|
|
||||||
this.gradleFile = propertiesParser.createEditor(this.gradleFilePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate that defaults or user configuration properties are set and
|
|
||||||
* set the missing items.
|
|
||||||
*/
|
|
||||||
_configureProperties (properties) {
|
|
||||||
// Iterate though the properties and set only if missing.
|
|
||||||
Object.keys(properties).forEach(key => {
|
|
||||||
let value = this.gradleFile.get(key);
|
|
||||||
|
|
||||||
if (!value) {
|
|
||||||
// Handles the case of adding missing defaults or new properties that are missing.
|
|
||||||
events.emit('verbose', `[Gradle Properties] Appending configuration item: ${key}=${properties[key]}`);
|
|
||||||
this.gradleFile.set(key, properties[key]);
|
|
||||||
} else if (value !== properties[key]) {
|
|
||||||
if (this._defaults[key] && this._defaults[key] !== properties[key]) {
|
|
||||||
// Since the value does not match default, we will notify the discrepancy with Cordova's recommended value.
|
|
||||||
events.emit('info', `[Gradle Properties] Detected Gradle property "${key}" with the value of "${properties[key]}", Cordova's recommended value is "${this._defaults[key]}"`);
|
|
||||||
} else {
|
|
||||||
// When the current value exists but does not match the new value or does matches the default key value, the new value it set.
|
|
||||||
events.emit('verbose', `[Gradle Properties] Updating Gradle property "${key}" with the value of "${properties[key]}"`);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We will set the new value in either case.
|
|
||||||
this.gradleFile.set(key, properties[key]);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves any changes that has been made to the properties file.
|
|
||||||
*/
|
|
||||||
_save () {
|
|
||||||
events.emit('verbose', '[Gradle Properties] Updating and Saving File');
|
|
||||||
this.gradleFile.save();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = GradlePropertiesParser;
|
|
||||||
@@ -19,7 +19,8 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var build = require('./build');
|
var Q = require('q'),
|
||||||
|
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');
|
||||||
@@ -31,16 +32,18 @@ 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().then(function (list) {
|
return Adb.devices()
|
||||||
|
.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']).then(function () {
|
return spawn('killall', ['adb'])
|
||||||
|
.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;
|
||||||
});
|
});
|
||||||
@@ -49,19 +52,21 @@ module.exports.list = function (lookHarder) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.resolveTarget = function (target) {
|
module.exports.resolveTarget = function(target) {
|
||||||
return this.list(true).then(function (device_list) {
|
return this.list(true)
|
||||||
|
.then(function(device_list) {
|
||||||
if (!device_list || !device_list.length) {
|
if (!device_list || !device_list.length) {
|
||||||
return Promise.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
|
||||||
}
|
}
|
||||||
// default device
|
// default device
|
||||||
target = target || device_list[0];
|
target = target || device_list[0];
|
||||||
|
|
||||||
if (device_list.indexOf(target) < 0) {
|
if (device_list.indexOf(target) < 0) {
|
||||||
return Promise.reject(new CordovaError('ERROR: Unable to find target \'' + target + '\'.'));
|
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
|
||||||
}
|
}
|
||||||
|
|
||||||
return build.detectArchitecture(target).then(function (arch) {
|
return build.detectArchitecture(target)
|
||||||
|
.then(function(arch) {
|
||||||
return { target: target, arch: arch, isEmulator: false };
|
return { target: target, arch: arch, isEmulator: false };
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -72,39 +77,43 @@ 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 Promise.resolve().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, '../../app/src/main/AndroidManifest.xml'));
|
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
||||||
var pkgName = manifest.getPackageId();
|
var pkgName = manifest.getPackageId();
|
||||||
var launchName = pkgName + '/.' + manifest.getActivity().getName();
|
var launchName = pkgName + '/.' + manifest.getActivity().getName();
|
||||||
events.emit('log', 'Using apk: ' + apk_path);
|
events.emit('log', 'Using apk: ' + apk_path);
|
||||||
events.emit('log', 'Package name: ' + pkgName);
|
events.emit('log', 'Package name: ' + pkgName);
|
||||||
|
|
||||||
return Adb.install(resolvedTarget.target, apk_path, { replace: true }).catch(function (error) {
|
return Adb.install(resolvedTarget.target, apk_path, {replace: true})
|
||||||
|
.catch(function (error) {
|
||||||
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
|
// 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())) { throw error; }
|
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
|
||||||
|
throw error;
|
||||||
|
|
||||||
events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
|
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).then(function () {
|
return Adb.uninstall(resolvedTarget.target, pkgName)
|
||||||
return Adb.install(resolvedTarget.target, apk_path, { replace: true });
|
.then(function() {
|
||||||
|
return Adb.install(resolvedTarget.target, apk_path, {replace: true});
|
||||||
});
|
});
|
||||||
}).then(function () {
|
})
|
||||||
// unlock screen
|
.then(function() {
|
||||||
|
//unlock screen
|
||||||
return Adb.shell(resolvedTarget.target, 'input keyevent 82');
|
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');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -19,9 +19,10 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var android_versions = require('android-versions');
|
/* jshint sub:true */
|
||||||
var retry = require('./retry');
|
|
||||||
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');
|
||||||
@@ -32,19 +33,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 os = require('os');
|
var Q = require('q');
|
||||||
var fs = require('fs');
|
var os = require('os');
|
||||||
|
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) {
|
||||||
@@ -53,7 +55,8 @@ function forgivingWhichSync (cmd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
module.exports.list_images_using_avdmanager = function () {
|
module.exports.list_images_using_avdmanager = function () {
|
||||||
return superspawn.spawn('avdmanager', ['list', 'avd']).then(function (output) {
|
return superspawn.spawn('avdmanager', ['list', 'avd'])
|
||||||
|
.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++) {
|
||||||
@@ -105,15 +108,16 @@ 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']).then(function (output) {
|
return superspawn.spawn('android', ['list', 'avds'])
|
||||||
|
.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++) {
|
||||||
@@ -148,7 +152,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;
|
||||||
@@ -166,30 +170,26 @@ module.exports.list_images_using_android = function () {
|
|||||||
skin : <skin>
|
skin : <skin>
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
module.exports.list_images = function () {
|
module.exports.list_images = function() {
|
||||||
return Promise.resolve().then(function () {
|
if (forgivingWhichSync('android')) {
|
||||||
if (forgivingWhichSync('avdmanager')) {
|
return module.exports.list_images_using_android()
|
||||||
return module.exports.list_images_using_avdmanager();
|
.catch(function(err) {
|
||||||
} else if (forgivingWhichSync('android')) {
|
// try to use `avdmanager` in case `android` reports it is no longer available.
|
||||||
return module.exports.list_images_using_android();
|
// this likely means the target machine is using a newer version of
|
||||||
} else {
|
// the android sdk, and possibly `avdmanager` is available.
|
||||||
return Promise.reject(new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?'));
|
if (err.code == 1 && err.stdout.indexOf('android command is no longer available')) {
|
||||||
}
|
return module.exports.list_images_using_avdmanager();
|
||||||
}).then(function (avds) {
|
} else {
|
||||||
// In case we're missing the Android OS version string from the target description, add it.
|
throw err;
|
||||||
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);
|
|
||||||
if (level) {
|
|
||||||
avd.target = 'Android ' + level.semver + ' (API level ' + api_level + ')';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return avd;
|
|
||||||
});
|
});
|
||||||
});
|
} else if (forgivingWhichSync('avdmanager')) {
|
||||||
|
return module.exports.list_images_using_avdmanager();
|
||||||
|
} else {
|
||||||
|
return Q().then(function() {
|
||||||
|
throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?');
|
||||||
|
});
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -197,19 +197,20 @@ 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().then(function (images) {
|
return this.list_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 = parseInt(check_reqs.get_target().replace('android-', ''));
|
var project_target = check_reqs.get_target().replace('android-', '');
|
||||||
for (var i in images) {
|
for (var i in images) {
|
||||||
var target = images[i].target;
|
var target = images[i].target;
|
||||||
if (target && target.indexOf('API level') > -1) {
|
if(target) {
|
||||||
var num = parseInt(target.split('(API level ')[1].replace(')', ''));
|
var num = target.split('(API level ')[1].replace(')', '');
|
||||||
if (num === project_target) {
|
if (num == project_target) {
|
||||||
return images[i];
|
return images[i];
|
||||||
} else if (project_target - num < closest && project_target > num) {
|
} else if (project_target - num < closest && project_target > num) {
|
||||||
closest = project_target - num;
|
closest = project_target - num;
|
||||||
@@ -222,18 +223,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
|
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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,8 +249,9 @@ 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().then(function (emulators) {
|
return self.list_started()
|
||||||
for (var p = 5584; p >= 5554; p -= 2) {
|
.then(function (emulators) {
|
||||||
|
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;
|
||||||
@@ -269,26 +271,28 @@ 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 Promise.resolve().then(function () {
|
return Q().then(function() {
|
||||||
if (emulator_ID) return Promise.resolve(emulator_ID);
|
if (emulator_ID) return Q(emulator_ID);
|
||||||
|
|
||||||
return self.best_image().then(function (best) {
|
return self.best_image()
|
||||||
|
.then(function(best) {
|
||||||
if (best && best.name) {
|
if (best && best.name) {
|
||||||
events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
|
events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
|
||||||
return best.name;
|
return best.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
var androidCmd = check_reqs.getAbsoluteAndroidCmd();
|
var androidCmd = check_reqs.getAbsoluteAndroidCmd();
|
||||||
return Promise.reject(new CordovaError('No emulator images (avds) found.\n' +
|
return Q.reject(new CordovaError('No emulator images (avds) found.\n' +
|
||||||
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
|
'1. Download desired System Image by running: ' + androidCmd + ' sdk\n' +
|
||||||
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
|
'2. Create an AVD by running: ' + androidCmd + ' avd\n' +
|
||||||
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
|
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
|
||||||
});
|
});
|
||||||
}).then(function (emulatorId) {
|
}).then(function(emulatorId) {
|
||||||
return self.get_available_port().then(function (port) {
|
return self.get_available_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'));
|
||||||
@@ -302,17 +306,20 @@ 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) { return Promise.reject(new CordovaError('Failed to start emulator')); }
|
if (!emulatorId)
|
||||||
|
return Q.reject(new CordovaError('Failed to start emulator'));
|
||||||
|
|
||||||
// wait for emulator to boot up
|
//wait for emulator to boot up
|
||||||
process.stdout.write('Waiting for emulator to boot (this may take a while)...');
|
process.stdout.write('Waiting for emulator to boot (this may take a while)...');
|
||||||
return self.wait_for_boot(emulatorId, boot_timeout).then(function (success) {
|
return self.wait_for_boot(emulatorId, boot_timeout)
|
||||||
|
.then(function(success) {
|
||||||
if (success) {
|
if (success) {
|
||||||
events.emit('log', 'BOOT COMPLETE');
|
events.emit('log','BOOT COMPLETE');
|
||||||
// unlock screen
|
//unlock screen
|
||||||
return Adb.shell(emulatorId, 'input keyevent 82').then(function () {
|
return Adb.shell(emulatorId, 'input keyevent 82')
|
||||||
// return the new emulator id for the started emulators
|
.then(function() {
|
||||||
|
//return the new emulator id for the started emulators
|
||||||
return emulatorId;
|
return emulatorId;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@@ -327,21 +334,20 @@ 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 Promise.resolve().then(function () {
|
return Q().then(function() {
|
||||||
var emulator_id = 'emulator-' + port;
|
var emulator_id = 'emulator-' + port;
|
||||||
return Adb.shell(emulator_id, 'getprop dev.bootcomplete').then(function (output) {
|
return Adb.shell(emulator_id, 'getprop dev.bootcomplete')
|
||||||
|
.then(function (output) {
|
||||||
if (output.indexOf('1') >= 0) {
|
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) {
|
||||||
(error.message.indexOf('device still connecting') > -1) ||
|
|
||||||
(error.message.indexOf('device still authorizing') > -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 {
|
||||||
@@ -349,7 +355,7 @@ module.exports.wait_for_emulator = function (port) {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -357,9 +363,10 @@ 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').then(function (output) {
|
return Adb.shell(emulator_id, 'ps')
|
||||||
|
.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) {
|
||||||
@@ -367,13 +374,10 @@ module.exports.wait_for_boot = function (emulator_id, time_remaining) {
|
|||||||
} else {
|
} else {
|
||||||
process.stdout.write('.');
|
process.stdout.write('.');
|
||||||
|
|
||||||
return new Promise(resolve => {
|
// Check at regular intervals
|
||||||
const delay = time_remaining < CHECK_BOOTED_INTERVAL ? time_remaining : CHECK_BOOTED_INTERVAL;
|
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;
|
||||||
setTimeout(() => {
|
return self.wait_for_boot(emulator_id, updated_time);
|
||||||
const updated_time = time_remaining >= 0 ? Math.max(time_remaining - CHECK_BOOTED_INTERVAL, 0) : time_remaining;
|
|
||||||
resolve(self.wait_for_boot(emulator_id, updated_time));
|
|
||||||
}, delay);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -384,43 +388,46 @@ 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]).then(null, function (error) {
|
return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target])
|
||||||
|
.then(null, function(error) {
|
||||||
console.error('ERROR : Failed to create emulator image : ');
|
console.error('ERROR : Failed to create emulator image : ');
|
||||||
console.error(' Do you have the latest android targets including ' + target + '?');
|
console.error(' Do you have the latest android targets including ' + target + '?');
|
||||||
console.error(error);
|
console.error(error);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
|
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
|
||||||
// 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 Promise.reject(new CordovaError());
|
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().then(function (emulator_list) {
|
return this.list_started()
|
||||||
|
.then(function(emulator_list) {
|
||||||
if (emulator_list.length < 1) {
|
if (emulator_list.length < 1) {
|
||||||
return Promise.reject(new CordovaError('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.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// default emulator
|
// default emulator
|
||||||
target = target || emulator_list[0];
|
target = target || emulator_list[0];
|
||||||
if (emulator_list.indexOf(target) < 0) {
|
if (emulator_list.indexOf(target) < 0) {
|
||||||
return Promise.reject(new CordovaError('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).then(function (arch) {
|
return build.detectArchitecture(target)
|
||||||
return { target: target, arch: arch, isEmulator: true };
|
.then(function(arch) {
|
||||||
|
return {target:target, arch:arch, isEmulator:true};
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -431,17 +438,15 @@ 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;
|
||||||
// We need to find the proper path to the Android Manifest
|
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
|
||||||
const manifestPath = path.join(__dirname, '..', '..', 'app', 'src', 'main', 'AndroidManifest.xml');
|
var pkgName = manifest.getPackageId();
|
||||||
const manifest = new AndroidManifest(manifestPath);
|
|
||||||
const pkgName = manifest.getPackageId();
|
|
||||||
|
|
||||||
// resolve the target emulator
|
// resolve the target emulator
|
||||||
return Promise.resolve().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);
|
||||||
@@ -455,12 +460,13 @@ 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 Promise.resolve().then(function () {
|
return Q.when()
|
||||||
|
.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
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -471,12 +477,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 new 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.
|
||||||
@@ -496,23 +502,27 @@ module.exports.install = function (givenTarget, buildResults) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function installPromise () {
|
function installPromise () {
|
||||||
return adbInstallWithOptions(target.target, apk_path, execOptions).catch(function (error) {
|
return adbInstallWithOptions(target.target, apk_path, execOptions)
|
||||||
|
.catch(function (error) {
|
||||||
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
|
// 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())) { throw error; }
|
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
|
||||||
|
throw error;
|
||||||
|
|
||||||
events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
|
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).then(function () {
|
return Adb.uninstall(target.target, pkgName)
|
||||||
|
.then(function() {
|
||||||
return adbInstallWithOptions(target.target, apk_path, execOptions);
|
return adbInstallWithOptions(target.target, apk_path, execOptions);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise).then(function (output) {
|
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise)
|
||||||
|
.then(function (output) {
|
||||||
events.emit('log', 'INSTALL SUCCESS');
|
events.emit('log', 'INSTALL SUCCESS');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
@ECHO OFF
|
|
||||||
for /f "tokens=2*" %%a in ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Android Studio" /v Path') do set "ASPath=%%~b"
|
|
||||||
ECHO %ASPath%
|
|
||||||
@@ -19,23 +19,23 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var device = require('./device');
|
var device = require('./device'),
|
||||||
var args = process.argv;
|
args = process.argv;
|
||||||
|
|
||||||
if (args.length > 2) {
|
if(args.length > 2) {
|
||||||
var install_target;
|
var install_target;
|
||||||
if (args[2].substring(0, 9) === '--target=') {
|
if (args[2].substring(0, 9) == '--target=') {
|
||||||
install_target = args[2].substring(9, args[2].length);
|
install_target = args[2].substring(9, args[2].length);
|
||||||
device.install(install_target).catch(function (err) {
|
device.install(install_target).done(null, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
device.install().catch(function (err) {
|
device.install().done(null, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -19,20 +19,20 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var emulator = require('./emulator');
|
var emulator = require('./emulator'),
|
||||||
var args = process.argv;
|
args = process.argv;
|
||||||
|
|
||||||
var install_target;
|
var install_target;
|
||||||
if (args.length > 2) {
|
if(args.length > 2) {
|
||||||
if (args[2].substring(0, 9) === '--target=') {
|
if (args[2].substring(0, 9) == '--target=') {
|
||||||
install_target = args[2].substring(9, args[2].length);
|
install_target = args[2].substring(9, args[2].length);
|
||||||
} else {
|
} else {
|
||||||
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emulator.install(install_target).catch(function (err) {
|
emulator.install(install_target).done(null, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(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
|
||||||
|
|||||||
@@ -22,12 +22,12 @@
|
|||||||
var devices = require('./device');
|
var devices = require('./device');
|
||||||
|
|
||||||
// Usage support for when args are given
|
// Usage support for when args are given
|
||||||
require('./check_reqs').check_android().then(function () {
|
require('./check_reqs').check_android().then(function() {
|
||||||
devices.list().then(function (device_list) {
|
devices.list().done(function(device_list) {
|
||||||
device_list && device_list.forEach(function (dev) {
|
device_list && device_list.forEach(function(dev) {
|
||||||
console.log(dev);
|
console.log(dev);
|
||||||
});
|
});
|
||||||
}, function (err) {
|
}, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -22,12 +22,12 @@
|
|||||||
var emulators = require('./emulator');
|
var emulators = require('./emulator');
|
||||||
|
|
||||||
// Usage support for when args are given
|
// Usage support for when args are given
|
||||||
require('./check_reqs').check_android().then(function () {
|
require('./check_reqs').check_android().then(function() {
|
||||||
emulators.list_images().then(function (emulator_list) {
|
emulators.list_images().done(function(emulator_list) {
|
||||||
emulator_list && emulator_list.forEach(function (emu) {
|
emulator_list && emulator_list.forEach(function(emu) {
|
||||||
console.log(emu.name);
|
console.log(emu.name);
|
||||||
});
|
});
|
||||||
}, function (err) {
|
}, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(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
|
||||||
|
|||||||
@@ -22,12 +22,12 @@
|
|||||||
var emulators = require('./emulator');
|
var emulators = require('./emulator');
|
||||||
|
|
||||||
// Usage support for when args are given
|
// Usage support for when args are given
|
||||||
require('./check_reqs').check_android().then(function () {
|
require('./check_reqs').check_android().then(function() {
|
||||||
emulators.list_started().then(function (emulator_list) {
|
emulators.list_started().done(function(emulator_list) {
|
||||||
emulator_list && emulator_list.forEach(function (emu) {
|
emulator_list && emulator_list.forEach(function(emu) {
|
||||||
console.log(emu);
|
console.log(emu);
|
||||||
});
|
});
|
||||||
}, function (err) {
|
}, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(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
|
||||||
|
|||||||
@@ -19,28 +19,28 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var path = require('path');
|
var path = require('path'),
|
||||||
var os = require('os');
|
os = require('os'),
|
||||||
var Q = require('q');
|
Q = require('q'),
|
||||||
var child_process = require('child_process');
|
child_process = require('child_process'),
|
||||||
var ROOT = path.join(__dirname, '..', '..');
|
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,7 +20,7 @@
|
|||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
mavenCentral()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +36,7 @@ buildscript {
|
|||||||
apply plugin: 'com.android.library'
|
apply plugin: 'com.android.library'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(dir: 'libs', include: '*.jar')
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
debugCompile project(path: ":CordovaLib", configuration: "debug")
|
debugCompile project(path: ":CordovaLib", configuration: "debug")
|
||||||
releaseCompile project(path: ":CordovaLib", configuration: "release")
|
releaseCompile project(path: ":CordovaLib", configuration: "release")
|
||||||
}
|
}
|
||||||
@@ -44,6 +44,7 @@ dependencies {
|
|||||||
android {
|
android {
|
||||||
compileSdkVersion cdvCompileSdkVersion
|
compileSdkVersion cdvCompileSdkVersion
|
||||||
buildToolsVersion cdvBuildToolsVersion
|
buildToolsVersion cdvBuildToolsVersion
|
||||||
|
publishNonDefault true
|
||||||
|
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_6
|
sourceCompatibility JavaVersion.VERSION_1_6
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
|
*
|
||||||
|
* Copyright 2013 Anis Kadri
|
||||||
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@@ -14,6 +17,8 @@
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* jshint unused: vars */
|
||||||
|
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var shell = require('shelljs');
|
var shell = require('shelljs');
|
||||||
@@ -21,12 +26,16 @@ 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 = getInstallDestination(obj);
|
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
||||||
|
|
||||||
|
if(options && options.android_studio === true) {
|
||||||
|
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
|
||||||
|
}
|
||||||
|
|
||||||
if (options && options.force) {
|
if (options && options.force) {
|
||||||
copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
|
copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
|
||||||
@@ -34,40 +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 = getInstallDestination(obj);
|
var dest = path.join(obj.targetDir, path.basename(obj.src));
|
||||||
|
|
||||||
// TODO: Add Koltin extension to uninstall, since they are handled like Java files
|
if(options && options.android_studio === true) {
|
||||||
if (obj.src.endsWith('java')) {
|
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
|
||||||
deleteJava(project.projectDir, dest);
|
|
||||||
} else {
|
|
||||||
// Just remove the file, not the whole parent directory
|
|
||||||
removeFile(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('app/libs', path.basename(obj.src));
|
var dest = path.join('libs', path.basename(obj.src));
|
||||||
|
if(options && options.android_studio === true) {
|
||||||
|
dest = path.join('app/libs', path.basename(obj.src));
|
||||||
|
}
|
||||||
copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
|
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('app/libs', path.basename(obj.src));
|
var dest = path.join('libs', path.basename(obj.src));
|
||||||
|
if(options && options.android_studio === true) {
|
||||||
|
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) {
|
||||||
var dest = path.join('app', 'src', 'main', obj.target);
|
copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(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('app', 'src', 'main', obj.target);
|
removeFile(project.projectDir, path.normalize(obj.target));
|
||||||
removeFile(project.projectDir, dest);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'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));
|
||||||
|
|
||||||
@@ -84,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));
|
||||||
|
|
||||||
@@ -114,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));
|
||||||
}
|
}
|
||||||
@@ -138,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));
|
||||||
@@ -156,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
|
||||||
@@ -195,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;
|
||||||
}
|
}
|
||||||
@@ -210,19 +221,21 @@ 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) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }
|
if (real_path.indexOf(real_plugin_path) !== 0)
|
||||||
|
throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"');
|
||||||
|
|
||||||
dest = path.resolve(project_dir, dest);
|
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) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }
|
if (dest.indexOf(project_dir) !== 0)
|
||||||
|
throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project');
|
||||||
|
|
||||||
shell.mkdir('-p', path.dirname(dest));
|
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);
|
||||||
}
|
}
|
||||||
@@ -231,22 +244,24 @@ 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)) { throw new CordovaError('"' + target_path + '" already exists!'); }
|
if (fs.existsSync(target_path))
|
||||||
|
throw new CordovaError('"' + target_path + '" already exists!');
|
||||||
|
|
||||||
copyFile(plugin_dir, src, project_dir, dest, !!link);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -277,8 +292,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 {
|
||||||
@@ -288,47 +303,6 @@ function removeFileAndParents (baseDir, destFile, stopper) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function generateAttributeError (attribute, element, id) {
|
function generateAttributeError(attribute, element, id) {
|
||||||
return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
|
return 'Required attribute "' + attribute + '" not specified in <' + element + '> element from plugin: ' + id;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getInstallDestination (obj) {
|
|
||||||
var APP_MAIN_PREFIX = 'app/src/main';
|
|
||||||
var PATH_SEPARATOR = '/';
|
|
||||||
|
|
||||||
var PATH_SEP_MATCH = '\\' + PATH_SEPARATOR;
|
|
||||||
var PATH_SEP_OR_EOL_MATCH = '(\\' + PATH_SEPARATOR + '|$)';
|
|
||||||
|
|
||||||
var appReg = new RegExp('^app' + PATH_SEP_OR_EOL_MATCH);
|
|
||||||
var libsReg = new RegExp('^libs' + PATH_SEP_OR_EOL_MATCH);
|
|
||||||
var srcReg = new RegExp('^src' + PATH_SEP_OR_EOL_MATCH);
|
|
||||||
var srcMainReg = new RegExp('^src' + PATH_SEP_MATCH + 'main' + PATH_SEP_OR_EOL_MATCH);
|
|
||||||
|
|
||||||
if (appReg.test(obj.targetDir)) {
|
|
||||||
// If any source file is using the new app directory structure,
|
|
||||||
// don't penalize it
|
|
||||||
return path.join(obj.targetDir, path.basename(obj.src));
|
|
||||||
} else {
|
|
||||||
// Plugin using deprecated target directory structure (GH-580)
|
|
||||||
if (obj.src.endsWith('.java')) {
|
|
||||||
return path.join(APP_MAIN_PREFIX, 'java', obj.targetDir.replace(srcReg, ''),
|
|
||||||
path.basename(obj.src));
|
|
||||||
} else if (obj.src.endsWith('.aidl')) {
|
|
||||||
return path.join(APP_MAIN_PREFIX, 'aidl', obj.targetDir.replace(srcReg, ''),
|
|
||||||
path.basename(obj.src));
|
|
||||||
} else if (libsReg.test(obj.targetDir)) {
|
|
||||||
if (obj.src.endsWith('.so')) {
|
|
||||||
return path.join(APP_MAIN_PREFIX, 'jniLibs', obj.targetDir.replace(libsReg, ''),
|
|
||||||
path.basename(obj.src));
|
|
||||||
} else {
|
|
||||||
return path.join('app', obj.targetDir, path.basename(obj.src));
|
|
||||||
}
|
|
||||||
} else if (srcMainReg.test(obj.targetDir)) {
|
|
||||||
return path.join('app', obj.targetDir, path.basename(obj.src));
|
|
||||||
}
|
|
||||||
|
|
||||||
// For all other source files not using the new app directory structure,
|
|
||||||
// add 'app/src/main' to the targetDir
|
|
||||||
return path.join(APP_MAIN_PREFIX, obj.targetDir, path.basename(obj.src));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
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');
|
||||||
@@ -24,7 +23,6 @@ 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;
|
||||||
@@ -33,8 +31,6 @@ var PlatformJson = require('cordova-common').PlatformJson;
|
|||||||
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
|
var PlatformMunger = require('cordova-common').ConfigChanges.PlatformMunger;
|
||||||
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
|
var PluginInfoProvider = require('cordova-common').PluginInfoProvider;
|
||||||
|
|
||||||
const GradlePropertiesParser = require('./config/GradlePropertiesParser');
|
|
||||||
|
|
||||||
module.exports.prepare = function (cordovaProject, options) {
|
module.exports.prepare = function (cordovaProject, options) {
|
||||||
var self = this;
|
var self = this;
|
||||||
|
|
||||||
@@ -43,28 +39,18 @@ module.exports.prepare = function (cordovaProject, options) {
|
|||||||
|
|
||||||
this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
|
this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
|
||||||
|
|
||||||
// Get the min SDK version from config.xml
|
|
||||||
const minSdkVersion = this._config.getPreference('android-minSdkVersion', 'android');
|
|
||||||
const maxSdkVersion = this._config.getPreference('android-maxSdkVersion', 'android');
|
|
||||||
const targetSdkVersion = this._config.getPreference('android-targetSdkVersion', 'android');
|
|
||||||
|
|
||||||
let gradlePropertiesUserConfig = {};
|
|
||||||
if (minSdkVersion) gradlePropertiesUserConfig.cdvMinSdkVersion = minSdkVersion;
|
|
||||||
if (maxSdkVersion) gradlePropertiesUserConfig.cdvMaxSdkVersion = maxSdkVersion;
|
|
||||||
if (targetSdkVersion) gradlePropertiesUserConfig.cdvTargetSdkVersion = targetSdkVersion;
|
|
||||||
|
|
||||||
let gradlePropertiesParser = new GradlePropertiesParser(this.locations.root);
|
|
||||||
gradlePropertiesParser.configure(gradlePropertiesUserConfig);
|
|
||||||
|
|
||||||
// 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)).then(function () {
|
return Q.when(updateWww(cordovaProject, this.locations))
|
||||||
|
.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');
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -105,7 +91,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
|
||||||
@@ -120,7 +106,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;
|
||||||
@@ -129,7 +115,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,7 +128,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)
|
||||||
@@ -165,7 +151,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);
|
||||||
|
|
||||||
@@ -181,26 +167,19 @@ 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 strings = xmlHelpers.parseElementtreeSync(locations.strings);
|
|
||||||
|
|
||||||
var name = platformConfig.name();
|
var name = platformConfig.name();
|
||||||
|
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
|
||||||
strings.find('string[@name="app_name"]').text = name.replace(/\'/g, '\\\'');
|
strings.find('string[@name="app_name"]').text = name.replace(/\'/g, '\\\'');
|
||||||
|
fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
|
||||||
var shortName = platformConfig.shortName && platformConfig.shortName();
|
|
||||||
if (shortName && shortName !== name) {
|
|
||||||
strings.find('string[@name="launcher_name"]').text = shortName.replace(/\'/g, '\\\'');
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.writeFileSync(locations.strings, strings.write({ indent: 4 }), 'utf-8');
|
|
||||||
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
|
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
|
||||||
|
|
||||||
// Java packages cannot support dashes
|
// Java packages cannot support dashes
|
||||||
var androidPkgName = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
|
var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
|
||||||
|
|
||||||
var manifest = new AndroidManifest(locations.manifest);
|
var manifest = new AndroidManifest(locations.manifest);
|
||||||
var manifestId = manifest.getPackageId();
|
var orig_pkg = manifest.getPackageId();
|
||||||
|
|
||||||
manifest.getActivity()
|
manifest.getActivity()
|
||||||
.setOrientation(platformConfig.getPreference('orientation'))
|
.setOrientation(platformConfig.getPreference('orientation'))
|
||||||
@@ -208,38 +187,36 @@ 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(androidPkgName)
|
.setPackageId(pkg)
|
||||||
|
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
|
||||||
|
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
|
||||||
|
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
|
||||||
.write();
|
.write();
|
||||||
|
|
||||||
// Java file paths shouldn't be hard coded
|
var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
|
||||||
var javaPattern = path.join(locations.javaSrc, 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, 'app', 'src', 'main', 'java', androidPkgName.replace(/\./g, '/'), path.basename(java_files[0]));
|
var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
|
||||||
shell.mkdir('-p', path.dirname(destFile));
|
shell.mkdir('-p', path.dirname(destFile));
|
||||||
shell.sed(/package [\w\.]*;/, 'package ' + androidPkgName + ';', java_files[0]).to(destFile);
|
shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
|
||||||
events.emit('verbose', 'Wrote out Android package name "' + androidPkgName + '" to ' + destFile);
|
events.emit('verbose', 'Wrote out Android package name "' + pkg + '" to ' + destFile);
|
||||||
|
|
||||||
var removeOrigPkg = checkReqs.isWindows() || checkReqs.isDarwin() ?
|
if (orig_pkg !== pkg) {
|
||||||
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 {
|
||||||
@@ -252,7 +229,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]) {
|
||||||
@@ -269,7 +246,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');
|
||||||
}
|
}
|
||||||
@@ -277,15 +254,7 @@ function getImageResourcePath (resourcesDir, type, density, name, sourceName) {
|
|||||||
return resourcePath;
|
return resourcePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getAdaptiveImageResourcePath (resourcesDir, type, density, name, sourceName) {
|
function updateSplashes(cordovaProject, platformResourcesDir) {
|
||||||
if (/\.9\.png$/.test(sourceName)) {
|
|
||||||
name = name.replace(/\.png$/, '.9.png');
|
|
||||||
}
|
|
||||||
var resourcePath = path.join(resourcesDir, (density ? type + '-' + density + '-v26' : type), name);
|
|
||||||
return resourcePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
||||||
@@ -301,7 +270,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(
|
||||||
@@ -321,7 +290,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');
|
||||||
@@ -333,198 +302,21 @@ function cleanSplashes (projectRoot, projectConfig, platformResourcesDir) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateIcons (cordovaProject, platformResourcesDir) {
|
function updateIcons(cordovaProject, platformResourcesDir) {
|
||||||
let icons = cordovaProject.projectConfig.getIcons('android');
|
var icons = cordovaProject.projectConfig.getIcons('android');
|
||||||
|
|
||||||
// Skip if there are no app defined icons in config.xml
|
// if there are icon elements in config.xml
|
||||||
if (icons.length === 0) {
|
if (icons.length === 0) {
|
||||||
events.emit('verbose', 'This app does not have launcher icons defined');
|
events.emit('verbose', 'This app does not have launcher icons defined');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. loop icons determin if there is an error in the setup.
|
var resourceMap = mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'icon.png');
|
||||||
// 2. during initial loop, also setup for legacy support.
|
|
||||||
let errorMissingAttributes = [];
|
|
||||||
let errorLegacyIconNeeded = [];
|
|
||||||
let hasAdaptive = false;
|
|
||||||
icons.forEach((icon, key) => {
|
|
||||||
if (
|
|
||||||
(icon.background && !icon.foreground)
|
|
||||||
|| (!icon.background && icon.foreground)
|
|
||||||
|| (!icon.background && !icon.foreground && !icon.src)
|
|
||||||
) {
|
|
||||||
errorMissingAttributes.push(icon.density ? icon.density : 'size=' + (icon.height || icon.width));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (icon.foreground) {
|
var android_icons = {};
|
||||||
hasAdaptive = true;
|
var default_icon;
|
||||||
|
|
||||||
if (
|
|
||||||
!icon.src
|
|
||||||
&& (
|
|
||||||
icon.foreground.startsWith('@color')
|
|
||||||
|| path.extname(path.basename(icon.foreground)) === '.xml'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
errorLegacyIconNeeded.push(icon.density ? icon.density : 'size=' + (icon.height || icon.width));
|
|
||||||
} else if (!icon.src) {
|
|
||||||
icons[key].src = icon.foreground;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let errorMessage = [];
|
|
||||||
if (errorMissingAttributes.length > 0) {
|
|
||||||
errorMessage.push('One of the following attributes are set but missing the other for the density type: ' + errorMissingAttributes.join(', ') + '. Please ensure that all require attributes are defined.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorLegacyIconNeeded.length > 0) {
|
|
||||||
errorMessage.push('For the following icons with the density of: ' + errorLegacyIconNeeded.join(', ') + ', adaptive foreground with a defined color or vector can not be used as a standard fallback icon for older Android devices. To support older Android environments, please provide a value for the src attribute.');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (errorMessage.length > 0) {
|
|
||||||
throw new CordovaError(errorMessage.join(' '));
|
|
||||||
}
|
|
||||||
|
|
||||||
let resourceMap = Object.assign(
|
|
||||||
{},
|
|
||||||
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher.png'),
|
|
||||||
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.png'),
|
|
||||||
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_background.png'),
|
|
||||||
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.xml'),
|
|
||||||
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_background.xml'),
|
|
||||||
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher.xml')
|
|
||||||
);
|
|
||||||
|
|
||||||
let preparedIcons = prepareIcons(icons);
|
|
||||||
|
|
||||||
if (hasAdaptive) {
|
|
||||||
resourceMap = updateIconResourceForAdaptive(preparedIcons, resourceMap, platformResourcesDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
resourceMap = updateIconResourceForLegacy(preparedIcons, resourceMap, platformResourcesDir);
|
|
||||||
|
|
||||||
events.emit('verbose', 'Updating icons at ' + platformResourcesDir);
|
|
||||||
FileUpdater.updatePaths(resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateIconResourceForAdaptive (preparedIcons, resourceMap, platformResourcesDir) {
|
|
||||||
let android_icons = preparedIcons.android_icons;
|
|
||||||
let default_icon = preparedIcons.default_icon;
|
|
||||||
|
|
||||||
// The source paths for icons and splashes are relative to
|
|
||||||
// project's config.xml location, so we use it as base path.
|
|
||||||
let background;
|
|
||||||
let foreground;
|
|
||||||
let targetPathBackground;
|
|
||||||
let targetPathForeground;
|
|
||||||
|
|
||||||
for (let density in android_icons) {
|
|
||||||
let backgroundVal = '@mipmap/ic_launcher_background';
|
|
||||||
let foregroundVal = '@mipmap/ic_launcher_foreground';
|
|
||||||
|
|
||||||
background = android_icons[density].background;
|
|
||||||
foreground = android_icons[density].foreground;
|
|
||||||
|
|
||||||
if (background.startsWith('@color')) {
|
|
||||||
// Colors Use Case
|
|
||||||
backgroundVal = background; // Example: @color/background_foobar_1
|
|
||||||
} else if (path.extname(path.basename(background)) === '.xml') {
|
|
||||||
// Vector Use Case
|
|
||||||
targetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_background.xml', path.basename(android_icons[density].background));
|
|
||||||
resourceMap[targetPathBackground] = android_icons[density].background;
|
|
||||||
} else if (path.extname(path.basename(background)) === '.png') {
|
|
||||||
// Images Use Case
|
|
||||||
targetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_background.png', path.basename(android_icons[density].background));
|
|
||||||
resourceMap[targetPathBackground] = android_icons[density].background;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foreground.startsWith('@color')) {
|
|
||||||
// Colors Use Case
|
|
||||||
foregroundVal = foreground;
|
|
||||||
} else if (path.extname(path.basename(foreground)) === '.xml') {
|
|
||||||
// Vector Use Case
|
|
||||||
targetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_foreground.xml', path.basename(android_icons[density].foreground));
|
|
||||||
resourceMap[targetPathForeground] = android_icons[density].foreground;
|
|
||||||
} else if (path.extname(path.basename(foreground)) === '.png') {
|
|
||||||
// Images Use Case
|
|
||||||
targetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_foreground.png', path.basename(android_icons[density].foreground));
|
|
||||||
resourceMap[targetPathForeground] = android_icons[density].foreground;
|
|
||||||
}
|
|
||||||
|
|
||||||
// create an XML for DPI and set color
|
|
||||||
const icLauncherTemplate = `<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="` + backgroundVal + `" />
|
|
||||||
<foreground android:drawable="` + foregroundVal + `" />
|
|
||||||
</adaptive-icon>`;
|
|
||||||
|
|
||||||
let launcherXmlPath = path.join(platformResourcesDir, 'mipmap-' + density + '-v26', 'ic_launcher.xml');
|
|
||||||
|
|
||||||
// Remove the XML from the resourceMap so the file does not get removed.
|
|
||||||
delete resourceMap[launcherXmlPath];
|
|
||||||
|
|
||||||
fs.writeFileSync(path.resolve(launcherXmlPath), icLauncherTemplate);
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's no "default" drawable, so assume default == mdpi.
|
|
||||||
if (default_icon && !android_icons.mdpi) {
|
|
||||||
let defaultTargetPathBackground;
|
|
||||||
let defaultTargetPathForeground;
|
|
||||||
|
|
||||||
if (background.startsWith('@color')) {
|
|
||||||
// Colors Use Case
|
|
||||||
targetPathBackground = default_icon.background;
|
|
||||||
} else if (path.extname(path.basename(background)) === '.xml') {
|
|
||||||
// Vector Use Case
|
|
||||||
defaultTargetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_background.xml', path.basename(default_icon.background));
|
|
||||||
resourceMap[defaultTargetPathBackground] = default_icon.background;
|
|
||||||
} else if (path.extname(path.basename(background)) === '.png') {
|
|
||||||
// Images Use Case
|
|
||||||
defaultTargetPathBackground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_background.png', path.basename(default_icon.background));
|
|
||||||
resourceMap[defaultTargetPathBackground] = default_icon.background;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (foreground.startsWith('@color')) {
|
|
||||||
// Colors Use Case
|
|
||||||
targetPathForeground = default_icon.foreground;
|
|
||||||
} else if (path.extname(path.basename(foreground)) === '.xml') {
|
|
||||||
// Vector Use Case
|
|
||||||
defaultTargetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_foreground.xml', path.basename(default_icon.foreground));
|
|
||||||
resourceMap[defaultTargetPathForeground] = default_icon.foreground;
|
|
||||||
} else if (path.extname(path.basename(foreground)) === '.png') {
|
|
||||||
// Images Use Case
|
|
||||||
defaultTargetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_foreground.png', path.basename(default_icon.foreground));
|
|
||||||
resourceMap[defaultTargetPathForeground] = default_icon.foreground;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return resourceMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateIconResourceForLegacy (preparedIcons, resourceMap, platformResourcesDir) {
|
|
||||||
let android_icons = preparedIcons.android_icons;
|
|
||||||
let default_icon = preparedIcons.default_icon;
|
|
||||||
|
|
||||||
// The source paths for icons and splashes are relative to
|
|
||||||
// project's config.xml location, so we use it as base path.
|
|
||||||
for (var density in android_icons) {
|
|
||||||
var targetPath = getImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher.png', path.basename(android_icons[density].src));
|
|
||||||
resourceMap[targetPath] = android_icons[density].src;
|
|
||||||
}
|
|
||||||
|
|
||||||
// There's no "default" drawable, so assume default == mdpi.
|
|
||||||
if (default_icon && !android_icons.mdpi) {
|
|
||||||
var defaultTargetPath = getImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher.png', path.basename(default_icon.src));
|
|
||||||
resourceMap[defaultTargetPath] = default_icon.src;
|
|
||||||
}
|
|
||||||
|
|
||||||
return resourceMap;
|
|
||||||
}
|
|
||||||
|
|
||||||
function prepareIcons (icons) {
|
|
||||||
// http://developer.android.com/design/style/iconography.html
|
// http://developer.android.com/design/style/iconography.html
|
||||||
const SIZE_TO_DENSITY_MAP = {
|
var sizeToDensityMap = {
|
||||||
36: 'ldpi',
|
36: 'ldpi',
|
||||||
48: 'mdpi',
|
48: 'mdpi',
|
||||||
72: 'hdpi',
|
72: 'hdpi',
|
||||||
@@ -532,15 +324,11 @@ function prepareIcons (icons) {
|
|||||||
144: 'xxhdpi',
|
144: 'xxhdpi',
|
||||||
192: 'xxxhdpi'
|
192: 'xxxhdpi'
|
||||||
};
|
};
|
||||||
|
|
||||||
let android_icons = {};
|
|
||||||
let default_icon;
|
|
||||||
|
|
||||||
// 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 || SIZE_TO_DENSITY_MAP[icon_size];
|
var density = icon.density || sizeToDensityMap[icon_size];
|
||||||
if (!density) {
|
if (!density) {
|
||||||
// invalid icon defition ( or unsupported size)
|
// invalid icon defition ( or unsupported size)
|
||||||
return;
|
return;
|
||||||
@@ -553,37 +341,15 @@ function prepareIcons (icons) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// iterate over all icon elements to find the default icon and call parseIcon
|
// iterate over all icon elements to find the default icon and call parseIcon
|
||||||
for (var i = 0; i < icons.length; i++) {
|
for (var i=0; i<icons.length; i++) {
|
||||||
var icon = icons[i];
|
var icon = icons[i];
|
||||||
var size = icon.width;
|
var size = icon.width;
|
||||||
|
|
||||||
if (!size) {
|
if (!size) {
|
||||||
size = icon.height;
|
size = icon.height;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!size && !icon.density) {
|
if (!size && !icon.density) {
|
||||||
if (default_icon) {
|
if (default_icon) {
|
||||||
let found = {};
|
events.emit('verbose', 'Found extra default icon: ' + icon.src + ' (ignoring in favor of ' + default_icon.src + ')');
|
||||||
let favor = {};
|
|
||||||
|
|
||||||
// populating found icon.
|
|
||||||
if (icon.background && icon.foreground) {
|
|
||||||
found.background = icon.background;
|
|
||||||
found.foreground = icon.foreground;
|
|
||||||
}
|
|
||||||
if (icon.src) {
|
|
||||||
found.src = icon.src;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (default_icon.background && default_icon.foreground) {
|
|
||||||
favor.background = default_icon.background;
|
|
||||||
favor.foreground = default_icon.foreground;
|
|
||||||
}
|
|
||||||
if (default_icon.src) {
|
|
||||||
favor.src = default_icon.src;
|
|
||||||
}
|
|
||||||
|
|
||||||
events.emit('verbose', 'Found extra default icon: ' + JSON.stringify(found) + ' and ignoring in favor of ' + JSON.stringify(favor) + '.');
|
|
||||||
} else {
|
} else {
|
||||||
default_icon = icon;
|
default_icon = icon;
|
||||||
}
|
}
|
||||||
@@ -592,50 +358,53 @@ function prepareIcons (icons) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
// The source paths for icons and splashes are relative to
|
||||||
android_icons: android_icons,
|
// project's config.xml location, so we use it as base path.
|
||||||
default_icon: default_icon
|
for (var density in android_icons) {
|
||||||
};
|
var targetPath = getImageResourcePath(
|
||||||
}
|
platformResourcesDir, 'mipmap', density, 'icon.png', path.basename(android_icons[density].src));
|
||||||
|
resourceMap[targetPath] = android_icons[density].src;
|
||||||
function cleanIcons (projectRoot, projectConfig, platformResourcesDir) {
|
|
||||||
var icons = projectConfig.getIcons('android');
|
|
||||||
|
|
||||||
// Skip if there are no app defined icons in config.xml
|
|
||||||
if (icons.length === 0) {
|
|
||||||
events.emit('verbose', 'This app does not have launcher icons defined');
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let resourceMap = Object.assign(
|
// There's no "default" drawable, so assume default == mdpi.
|
||||||
{},
|
if (default_icon && !android_icons.mdpi) {
|
||||||
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher.png'),
|
var defaultTargetPath = getImageResourcePath(
|
||||||
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.png'),
|
platformResourcesDir, 'mipmap', 'mdpi', 'icon.png', path.basename(default_icon.src));
|
||||||
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_background.png'),
|
resourceMap[defaultTargetPath] = default_icon.src;
|
||||||
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.xml'),
|
}
|
||||||
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_background.xml'),
|
|
||||||
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher.xml')
|
|
||||||
);
|
|
||||||
|
|
||||||
events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);
|
events.emit('verbose', 'Updating icons at ' + platformResourcesDir);
|
||||||
|
FileUpdater.updatePaths(
|
||||||
|
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
||||||
|
}
|
||||||
|
|
||||||
// No source paths are specified in the map, so updatePaths() will delete the target files.
|
function cleanIcons(projectRoot, projectConfig, platformResourcesDir) {
|
||||||
FileUpdater.updatePaths(resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
|
var icons = projectConfig.getIcons('android');
|
||||||
|
if (icons.length > 0) {
|
||||||
|
var resourceMap = mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'icon.png');
|
||||||
|
events.emit('verbose', 'Cleaning icons at ' + platformResourcesDir);
|
||||||
|
|
||||||
|
// No source paths are specified in the map, so updatePaths() will delete the target files.
|
||||||
|
FileUpdater.updatePaths(
|
||||||
|
resourceMap, { rootDir: projectRoot, all: true }, logFileOp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 + '-*')).forEach(function (drawableFolder) {
|
shell.ls(path.join(rootDir, subDir, type + '-*'))
|
||||||
|
.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
|
||||||
@@ -645,7 +414,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;
|
||||||
});
|
});
|
||||||
@@ -655,20 +424,20 @@ function updateFileResources (cordovaProject, platformDir) {
|
|||||||
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
|
||||||
}
|
}
|
||||||
|
|
||||||
function cleanFileResources (projectRoot, projectConfig, platformDir) {
|
|
||||||
var files = projectConfig.getFileResources('android', true);
|
function cleanFileResources(projectRoot, projectConfig, platformDir) {
|
||||||
|
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, {
|
resourceMap, { rootDir: projectRoot, all: true}, logFileOp);
|
||||||
rootDir: projectRoot, all: true }, logFileOp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -683,7 +452,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
|
||||||
|
|||||||
@@ -19,6 +19,8 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* jshint node: true */
|
||||||
|
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
var events = require('cordova-common').events;
|
var events = require('cordova-common').events;
|
||||||
@@ -27,37 +29,39 @@ var events = require('cordova-common').events;
|
|||||||
* Retry a promise-returning function a number of times, propagating its
|
* Retry a promise-returning function a number of times, propagating its
|
||||||
* results on success or throwing its error on a failed final attempt.
|
* results on success or throwing its error on a failed final attempt.
|
||||||
*
|
*
|
||||||
* @arg {Number} attemptsLeft - The number of times to retry the passed call.
|
* @arg {Number} attemts_left - The number of times to retry the passed call.
|
||||||
* @arg {Function} promiseFunction - A function that returns a promise.
|
* @arg {Function} promiseFunction - A function that returns a promise.
|
||||||
* @arg {...} - Arguments to pass to promiseFunction.
|
* @arg {...} - Arguments to pass to promiseFunction.
|
||||||
*
|
*
|
||||||
* @returns {Promise}
|
* @returns {Promise}
|
||||||
*/
|
*/
|
||||||
module.exports.retryPromise = function (attemptsLeft, promiseFunction) {
|
module.exports.retryPromise = function (attemts_left, promiseFunction) {
|
||||||
|
|
||||||
// NOTE:
|
// NOTE:
|
||||||
// get all trailing arguments, by skipping the first two (attemptsLeft and
|
// get all trailing arguments, by skipping the first two (attemts_left and
|
||||||
// promiseFunction) because they shouldn't get passed to promiseFunction
|
// promiseFunction) because they shouldn't get passed to promiseFunction
|
||||||
var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);
|
var promiseFunctionArguments = Array.prototype.slice.call(arguments, 2);
|
||||||
|
|
||||||
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) {
|
||||||
attemptsLeft -= 1;
|
|
||||||
|
|
||||||
if (attemptsLeft < 1) {
|
attemts_left -= 1;
|
||||||
|
|
||||||
|
if (attemts_left < 1) {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
events.emit('verbose', 'A retried call failed. Retrying ' + attemptsLeft + ' more time(s).');
|
events.emit('verbose', 'A retried call failed. Retrying ' + attemts_left + ' more time(s).');
|
||||||
|
|
||||||
// retry call self again with the same arguments, except attemptsLeft is now lower
|
// retry call self again with the same arguments, except attemts_left is now lower
|
||||||
var fullArguments = [attemptsLeft, promiseFunction].concat(promiseFunctionArguments);
|
var fullArguments = [attemts_left, promiseFunction].concat(promiseFunctionArguments);
|
||||||
return module.exports.retryPromise.apply(undefined, fullArguments);
|
return module.exports.retryPromise.apply(undefined, fullArguments);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -19,14 +19,16 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var path = require('path');
|
/* jshint loopfunc:true */
|
||||||
var emulator = require('./emulator');
|
|
||||||
var device = require('./device');
|
|
||||||
var Q = require('q');
|
|
||||||
var PackageType = require('./PackageType');
|
|
||||||
var events = require('cordova-common').events;
|
|
||||||
|
|
||||||
function getInstallTarget (runOptions) {
|
var path = require('path'),
|
||||||
|
build = require('./build'),
|
||||||
|
emulator = require('./emulator'),
|
||||||
|
device = require('./device'),
|
||||||
|
Q = require('q'),
|
||||||
|
events = require('cordova-common').events;
|
||||||
|
|
||||||
|
function getInstallTarget(runOptions) {
|
||||||
var install_target;
|
var install_target;
|
||||||
if (runOptions.target) {
|
if (runOptions.target) {
|
||||||
install_target = runOptions.target;
|
install_target = runOptions.target;
|
||||||
@@ -49,16 +51,17 @@ function getInstallTarget (runOptions) {
|
|||||||
*
|
*
|
||||||
* @return {Promise}
|
* @return {Promise}
|
||||||
*/
|
*/
|
||||||
module.exports.run = function (runOptions) {
|
module.exports.run = function(runOptions) {
|
||||||
runOptions = runOptions || {};
|
|
||||||
|
|
||||||
var self = this;
|
var self = this;
|
||||||
var install_target = getInstallTarget(runOptions);
|
var install_target = getInstallTarget(runOptions);
|
||||||
|
|
||||||
return Q().then(function () {
|
return Q()
|
||||||
|
.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().then(function (device_list) {
|
return 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];
|
||||||
@@ -68,31 +71,36 @@ module.exports.run = function (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().then(function (started) {
|
return emulator.list_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().then(function (devices) {
|
return device.list()
|
||||||
|
.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().then(function (started_emulators) {
|
return emulator.list_started()
|
||||||
|
.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().then(function (avds) {
|
return emulator.list_images()
|
||||||
|
.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).then(function (emulatorId) {
|
return emulator.start(install_target)
|
||||||
|
.then(function(emulatorId) {
|
||||||
return emulator.resolveTarget(emulatorId);
|
return emulator.resolveTarget(emulatorId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -101,32 +109,25 @@ module.exports.run = function (runOptions) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).then(function (resolvedTarget) {
|
}).then(function(resolvedTarget) {
|
||||||
return new Promise((resolve) => {
|
// Better just call self.build, but we're doing some processing of
|
||||||
const builder = require('./builders/builders').getBuilder();
|
// build results (according to platformApi spec) so they are in different
|
||||||
const buildOptions = require('./build').parseBuildOptions(runOptions, null, self.root);
|
// format than emulator.install expects.
|
||||||
|
// TODO: Update emulator/device.install to handle this change
|
||||||
// Android app bundles cannot be deployed directly to the device
|
return build.run.call(self, runOptions, resolvedTarget)
|
||||||
if (buildOptions.packageType === PackageType.BUNDLE) {
|
.then(function(buildResults) {
|
||||||
const packageTypeErrorMessage = 'Package type "bundle" is not supported during cordova run.';
|
if (resolvedTarget.isEmulator) {
|
||||||
events.emit('error', packageTypeErrorMessage);
|
return emulator.wait_for_boot(resolvedTarget.target)
|
||||||
throw packageTypeErrorMessage;
|
.then(function () {
|
||||||
}
|
|
||||||
|
|
||||||
resolve(builder.fetchBuildResults(buildOptions.buildType, buildOptions.arch));
|
|
||||||
}).then(function (buildResults) {
|
|
||||||
if (resolvedTarget && resolvedTarget.isEmulator) {
|
|
||||||
return emulator.wait_for_boot(resolvedTarget.target).then(function () {
|
|
||||||
return emulator.install(resolvedTarget, buildResults);
|
return emulator.install(resolvedTarget, buildResults);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return device.install(resolvedTarget, buildResults);
|
return device.install(resolvedTarget, buildResults);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
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');
|
||||||
|
|||||||
@@ -19,20 +19,21 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var emulator = require('./emulator');
|
var emulator = require('./emulator'),
|
||||||
var args = process.argv;
|
args = process.argv;
|
||||||
|
|
||||||
var install_target;
|
var install_target;
|
||||||
if (args.length > 2) {
|
if(args.length > 2) {
|
||||||
if (args[2].substring(0, 9) === '--target=') {
|
if (args[2].substring(0, 9) == '--target=') {
|
||||||
install_target = args[2].substring(9, args[2].length);
|
install_target = args[2].substring(9, args[2].length);
|
||||||
} else {
|
} else {
|
||||||
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
console.error('ERROR : argument \'' + args[2] + '\' not recognized.');
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
emulator.start(install_target).catch(function (err) {
|
emulator.start(install_target).done(null, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -19,17 +19,17 @@
|
|||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var log = require('./lib/log');
|
var log = require('./lib/log'),
|
||||||
var reqs = require('./lib/check_reqs');
|
reqs = require('./lib/check_reqs'),
|
||||||
var args = process.argv;
|
args = process.argv;
|
||||||
|
|
||||||
// Usage support for when args are given
|
// Usage support for when args are given
|
||||||
if (args.length > 2) {
|
if(args.length > 2) {
|
||||||
log.help();
|
log.help();
|
||||||
} else {
|
} else {
|
||||||
reqs.run().done(function () {
|
reqs.run().done(function() {
|
||||||
return log.run();
|
return log.run();
|
||||||
}, function (err) {
|
}, function(err) {
|
||||||
console.error('ERROR: ' + err);
|
console.error('ERROR: ' + err);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,23 +24,22 @@ var nopt = require('nopt');
|
|||||||
var path = require('path');
|
var path = require('path');
|
||||||
|
|
||||||
// Support basic help commands
|
// Support basic help commands
|
||||||
if (['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0) {
|
if(['--help', '/?', '-h', 'help', '-help', '/help'].indexOf(process.argv[2]) >= 0)
|
||||||
require('./lib/run').help();
|
require('./lib/run').help();
|
||||||
}
|
|
||||||
|
|
||||||
// Do some basic argument parsing
|
// Do some basic argument parsing
|
||||||
var runOpts = nopt({
|
var runOpts = nopt({
|
||||||
'verbose': Boolean,
|
'verbose' : Boolean,
|
||||||
'silent': Boolean,
|
'silent' : Boolean,
|
||||||
'debug': Boolean,
|
'debug' : Boolean,
|
||||||
'release': Boolean,
|
'release' : Boolean,
|
||||||
'nobuild': Boolean,
|
'nobuild': Boolean,
|
||||||
'buildConfig': path,
|
'buildConfig' : path,
|
||||||
'archs': String,
|
'archs' : String,
|
||||||
'device': Boolean,
|
'device' : Boolean,
|
||||||
'emulator': Boolean,
|
'emulator': Boolean,
|
||||||
'target': String
|
'target' : String
|
||||||
}, { 'd': '--verbose' });
|
}, { 'd' : '--verbose' });
|
||||||
|
|
||||||
// Make runOptions compatible with PlatformApi run method spec
|
// Make runOptions compatible with PlatformApi run method spec
|
||||||
runOpts.argv = runOpts.argv.remain;
|
runOpts.argv = runOpts.argv.remain;
|
||||||
@@ -48,7 +47,7 @@ runOpts.argv = runOpts.argv.remain;
|
|||||||
require('./loggingHelper').adjustLoggerLevel(runOpts);
|
require('./loggingHelper').adjustLoggerLevel(runOpts);
|
||||||
|
|
||||||
new Api().run(runOpts)
|
new Api().run(runOpts)
|
||||||
.catch(function (err) {
|
.catch(function(err) {
|
||||||
console.error(err, err.stack);
|
console.error(err, err.stack);
|
||||||
process.exit(2);
|
process.exit(2);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Coho updates this line:
|
// Coho updates this line:
|
||||||
var VERSION = "8.1.0";
|
var VERSION = "6.2.0";
|
||||||
|
|
||||||
module.exports.version = VERSION;
|
module.exports.version = VERSION;
|
||||||
|
|
||||||
|
|||||||
@@ -30,18 +30,20 @@
|
|||||||
|
|
||||||
<uses-permission android:name="android.permission.INTERNET" />
|
<uses-permission android:name="android.permission.INTERNET" />
|
||||||
|
|
||||||
<application android:icon="@mipmap/ic_launcher" android:label="@string/app_name"
|
<application android:icon="@mipmap/icon" android:label="@string/app_name"
|
||||||
android:hardwareAccelerated="true" android:supportsRtl="true">
|
android:hardwareAccelerated="true" android:supportsRtl="true">
|
||||||
<activity android:name="__ACTIVITY__"
|
<activity android:name="__ACTIVITY__"
|
||||||
android:label="@string/activity_name"
|
android:label="@string/activity_name"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
|
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
|
||||||
android:windowSoftInputMode="adjustResize"
|
android:windowSoftInputMode="adjustResize"
|
||||||
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode">
|
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale">
|
||||||
<intent-filter android:label="@string/launcher_name">
|
<intent-filter android:label="@string/launcher_name">
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
|
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="__APILEVEL__"/>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|||||||
@@ -1,358 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
google()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:3.3.0'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow plugins to declare Maven dependencies via build-extras.gradle.
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task wrapper(type: Wrapper) {
|
|
||||||
gradleVersion = '4.10.3'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
|
|
||||||
// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html
|
|
||||||
ext {
|
|
||||||
apply from: '../CordovaLib/cordova.gradle'
|
|
||||||
|
|
||||||
// The value for android.compileSdkVersion.
|
|
||||||
if (!project.hasProperty('cdvCompileSdkVersion')) {
|
|
||||||
cdvCompileSdkVersion = null;
|
|
||||||
}
|
|
||||||
// The value for android.buildToolsVersion.
|
|
||||||
if (!project.hasProperty('cdvBuildToolsVersion')) {
|
|
||||||
cdvBuildToolsVersion = null;
|
|
||||||
}
|
|
||||||
// Sets the versionCode to the given value.
|
|
||||||
if (!project.hasProperty('cdvVersionCode')) {
|
|
||||||
cdvVersionCode = null
|
|
||||||
}
|
|
||||||
// Sets the minSdkVersion to the given value.
|
|
||||||
if (!project.hasProperty('cdvMinSdkVersion')) {
|
|
||||||
cdvMinSdkVersion = null
|
|
||||||
}
|
|
||||||
// Sets the maxSdkVersion to the given value.
|
|
||||||
if (!project.hasProperty('cdvMaxSdkVersion')) {
|
|
||||||
cdvMaxSdkVersion = null
|
|
||||||
}
|
|
||||||
// The value for android.targetSdkVersion.
|
|
||||||
if (!project.hasProperty('cdvTargetSdkVersion')) {
|
|
||||||
cdvTargetSdkVersion = null;
|
|
||||||
}
|
|
||||||
// Whether to build architecture-specific APKs.
|
|
||||||
if (!project.hasProperty('cdvBuildMultipleApks')) {
|
|
||||||
cdvBuildMultipleApks = null
|
|
||||||
}
|
|
||||||
// Whether to append a 0 "abi digit" to versionCode when only a single APK is build
|
|
||||||
if (!project.hasProperty('cdvVersionCodeForceAbiDigit')) {
|
|
||||||
cdvVersionCodeForceAbiDigit = null
|
|
||||||
}
|
|
||||||
// .properties files to use for release signing.
|
|
||||||
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
|
|
||||||
cdvReleaseSigningPropertiesFile = null
|
|
||||||
}
|
|
||||||
// .properties files to use for debug signing.
|
|
||||||
if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {
|
|
||||||
cdvDebugSigningPropertiesFile = null
|
|
||||||
}
|
|
||||||
// Set by build.js script.
|
|
||||||
if (!project.hasProperty('cdvBuildArch')) {
|
|
||||||
cdvBuildArch = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin gradle extensions can append to this to have code run at the end.
|
|
||||||
cdvPluginPostBuildExtras = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLUGIN GRADLE EXTENSIONS START
|
|
||||||
// PLUGIN GRADLE EXTENSIONS END
|
|
||||||
|
|
||||||
def hasBuildExtras1 = file('build-extras.gradle').exists()
|
|
||||||
if (hasBuildExtras1) {
|
|
||||||
apply from: 'build-extras.gradle'
|
|
||||||
}
|
|
||||||
|
|
||||||
def hasBuildExtras2 = file('../build-extras.gradle').exists()
|
|
||||||
if (hasBuildExtras2) {
|
|
||||||
apply from: '../build-extras.gradle'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set property defaults after extension .gradle files.
|
|
||||||
ext.cdvCompileSdkVersion = cdvCompileSdkVersion == null ? (
|
|
||||||
defaultCompileSdkVersion == null
|
|
||||||
? privateHelpers.getProjectTarget()
|
|
||||||
: defaultCompileSdkVersion
|
|
||||||
) : Integer.parseInt('' + cdvCompileSdkVersion);
|
|
||||||
|
|
||||||
if (ext.cdvBuildToolsVersion == null) {
|
|
||||||
ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
|
||||||
//ext.cdvBuildToolsVersion = project.ext.defaultBuildToolsVersion
|
|
||||||
}
|
|
||||||
if (ext.cdvDebugSigningPropertiesFile == null && file('../debug-signing.properties').exists()) {
|
|
||||||
ext.cdvDebugSigningPropertiesFile = '../debug-signing.properties'
|
|
||||||
}
|
|
||||||
if (ext.cdvReleaseSigningPropertiesFile == null && file('../release-signing.properties').exists()) {
|
|
||||||
ext.cdvReleaseSigningPropertiesFile = '../release-signing.properties'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cast to appropriate types.
|
|
||||||
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
|
|
||||||
ext.cdvVersionCodeForceAbiDigit = cdvVersionCodeForceAbiDigit == null ? false : cdvVersionCodeForceAbiDigit.toBoolean();
|
|
||||||
|
|
||||||
// minSdkVersion, maxSdkVersion and targetSdkVersion
|
|
||||||
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? defaultMinSdkVersion : Integer.parseInt('' + cdvMinSdkVersion)
|
|
||||||
if (cdvMaxSdkVersion != null) {
|
|
||||||
ext.cdvMaxSdkVersion = Integer.parseInt('' + cdvMaxSdkVersion)
|
|
||||||
}
|
|
||||||
ext.cdvTargetSdkVersion = cdvTargetSdkVersion == null ? defaultTargetSdkVersion : Integer.parseInt('' + cdvTargetSdkVersion)
|
|
||||||
|
|
||||||
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
|
|
||||||
|
|
||||||
def computeBuildTargetName(debugBuild) {
|
|
||||||
def ret = 'assemble'
|
|
||||||
if (cdvBuildMultipleApks && cdvBuildArch) {
|
|
||||||
def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch
|
|
||||||
ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);
|
|
||||||
}
|
|
||||||
return ret + (debugBuild ? 'Debug' : 'Release')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make cdvBuild a task that depends on the debug/arch-sepecific task.
|
|
||||||
task cdvBuildDebug
|
|
||||||
cdvBuildDebug.dependsOn {
|
|
||||||
return computeBuildTargetName(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
task cdvBuildRelease
|
|
||||||
cdvBuildRelease.dependsOn {
|
|
||||||
return computeBuildTargetName(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
task cdvPrintProps {
|
|
||||||
doLast {
|
|
||||||
println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
|
|
||||||
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
|
|
||||||
println('cdvVersionCode=' + cdvVersionCode)
|
|
||||||
println('cdvVersionCodeForceAbiDigit=' + cdvVersionCodeForceAbiDigit)
|
|
||||||
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
|
|
||||||
println('cdvMaxSdkVersion=' + cdvMaxSdkVersion)
|
|
||||||
println('cdvTargetSdkVersion=' + cdvTargetSdkVersion)
|
|
||||||
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
|
|
||||||
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
|
|
||||||
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
|
|
||||||
println('cdvBuildArch=' + cdvBuildArch)
|
|
||||||
println('computedVersionCode=' + android.defaultConfig.versionCode)
|
|
||||||
android.productFlavors.each { flavor ->
|
|
||||||
println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
defaultConfig {
|
|
||||||
versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
|
|
||||||
applicationId privateHelpers.extractStringFromManifest("package")
|
|
||||||
|
|
||||||
if (cdvMinSdkVersion != null) {
|
|
||||||
minSdkVersion cdvMinSdkVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdvMaxSdkVersion != null) {
|
|
||||||
maxSdkVersion cdvMaxSdkVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cdvTargetSdkVersion != null) {
|
|
||||||
targetSdkVersion cdvTargetSdkVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
abortOnError false;
|
|
||||||
}
|
|
||||||
|
|
||||||
compileSdkVersion cdvCompileSdkVersion
|
|
||||||
buildToolsVersion cdvBuildToolsVersion
|
|
||||||
|
|
||||||
// This code exists for Crosswalk and other Native APIs.
|
|
||||||
// By default, we multiply the existing version code in the
|
|
||||||
// Android Manifest by 10 and add a number for each architecture.
|
|
||||||
// If you are not using Crosswalk or SQLite, you can
|
|
||||||
// ignore this chunk of code, and your version codes will be respected.
|
|
||||||
|
|
||||||
if (Boolean.valueOf(cdvBuildMultipleApks)) {
|
|
||||||
flavorDimensions "default"
|
|
||||||
|
|
||||||
productFlavors {
|
|
||||||
armeabi {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 1
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["armeabi"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
armv7 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 2
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["armeabi-v7a"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
arm64 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 3
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["arm64-v8a"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x86 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 4
|
|
||||||
ndk {
|
|
||||||
abiFilters = ["x86"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x86_64 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 5
|
|
||||||
ndk {
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdvReleaseSigningPropertiesFile) {
|
|
||||||
signingConfigs {
|
|
||||||
release {
|
|
||||||
// These must be set or Gradle will complain (even if they are overridden).
|
|
||||||
keyAlias = ""
|
|
||||||
keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph.
|
|
||||||
storeFile = null
|
|
||||||
storePassword = "__unset"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
signingConfig signingConfigs.release
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdvDebugSigningPropertiesFile) {
|
|
||||||
addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* WARNING: Cordova Lib and platform scripts do management inside of this code here,
|
|
||||||
* if you are adding the dependencies manually, do so outside the comments, otherwise
|
|
||||||
* the Cordova tools will overwrite them
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation fileTree(dir: 'libs', include: '*.jar')
|
|
||||||
// SUB-PROJECT DEPENDENCIES START
|
|
||||||
debugCompile(project(path: ":CordovaLib", configuration: "debug"))
|
|
||||||
releaseCompile(project(path: ":CordovaLib", configuration: "release"))
|
|
||||||
// SUB-PROJECT DEPENDENCIES END
|
|
||||||
}
|
|
||||||
|
|
||||||
def promptForReleaseKeyPassword() {
|
|
||||||
if (!cdvReleaseSigningPropertiesFile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ('__unset'.equals(android.signingConfigs.release.storePassword)) {
|
|
||||||
android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')
|
|
||||||
}
|
|
||||||
if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {
|
|
||||||
android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gradle.taskGraph.whenReady { taskGraph ->
|
|
||||||
taskGraph.getAllTasks().each() { task ->
|
|
||||||
if(['validateReleaseSigning', 'validateSigningRelease', 'validateSigningArmv7Release', 'validateSigningX76Release'].contains(task.name)) {
|
|
||||||
promptForReleaseKeyPassword()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def addSigningProps(propsFilePath, signingConfig) {
|
|
||||||
def propsFile = file(propsFilePath)
|
|
||||||
def props = new Properties()
|
|
||||||
propsFile.withReader { reader ->
|
|
||||||
props.load(reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
|
|
||||||
if (!storeFile.isAbsolute()) {
|
|
||||||
storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
|
|
||||||
}
|
|
||||||
if (!storeFile.exists()) {
|
|
||||||
throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
|
|
||||||
}
|
|
||||||
signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
|
|
||||||
signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
|
|
||||||
signingConfig.storeFile = storeFile
|
|
||||||
signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
|
|
||||||
def storeType = props.get('storeType', props.get('key.store.type', ''))
|
|
||||||
if (!storeType) {
|
|
||||||
def filename = storeFile.getName().toLowerCase();
|
|
||||||
if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
|
|
||||||
storeType = 'pkcs12'
|
|
||||||
} else {
|
|
||||||
storeType = signingConfig.storeType // "jks"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signingConfig.storeType = storeType
|
|
||||||
}
|
|
||||||
|
|
||||||
for (def func : cdvPluginPostBuildExtras) {
|
|
||||||
func()
|
|
||||||
}
|
|
||||||
|
|
||||||
// This can be defined within build-extras.gradle as:
|
|
||||||
// ext.postBuildExtras = { ... code here ... }
|
|
||||||
if (hasProperty('postBuildExtras')) {
|
|
||||||
postBuildExtras()
|
|
||||||
}
|
|
||||||
@@ -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();
|
||||||
@@ -1,52 +1,311 @@
|
|||||||
/* Licensed to the Apache Software Foundation (ASF) under one
|
/*
|
||||||
or more contributor license agreements. See the NOTICE file
|
Licensed to the Apache Software Foundation (ASF) under one
|
||||||
distributed with this work for additional information
|
or more contributor license agreements. See the NOTICE file
|
||||||
regarding copyright ownership. The ASF licenses this file
|
distributed with this work for additional information
|
||||||
to you under the Apache License, Version 2.0 (the
|
regarding copyright ownership. The ASF licenses this file
|
||||||
"License"); you may not use this file except in compliance
|
to you under the Apache License, Version 2.0 (the
|
||||||
with the License. You may obtain a copy of the License at
|
"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
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
Unless required by applicable law or agreed to in writing,
|
||||||
software distributed under the License is distributed on an
|
software distributed under the License is distributed on an
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||||
KIND, either express or implied. See the License for the
|
KIND, either express or implied. See the License for the
|
||||||
specific language governing permissions and limitations
|
specific language governing permissions and limitations
|
||||||
under the License.
|
under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
apply plugin: 'com.android.application'
|
||||||
|
|
||||||
buildscript {
|
buildscript {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
mavenCentral()
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Switch the Android Gradle plugin version requirement depending on the
|
||||||
|
// installed version of Gradle. This dependency is documented at
|
||||||
|
// http://tools.android.com/tech-docs/new-build-system/version-compatibility
|
||||||
|
// and https://issues.apache.org/jira/browse/CB-8143
|
||||||
dependencies {
|
dependencies {
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
classpath 'com.android.tools.build:gradle:2.2.3'
|
||||||
// in the individual module build.gradle files
|
|
||||||
|
|
||||||
classpath 'com.android.tools.build:gradle:3.3.0'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allow plugins to declare Maven dependencies via build-extras.gradle.
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
mavenCentral();
|
||||||
jcenter()
|
jcenter()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//This replaces project.properties w.r.t. build settings
|
task wrapper(type: Wrapper) {
|
||||||
project.ext {
|
gradleVersion = '2.14.1'
|
||||||
defaultBuildToolsVersion="28.0.3" //String
|
}
|
||||||
defaultMinSdkVersion=19 //Integer - Minimum requirement is Android 4.4
|
|
||||||
defaultTargetSdkVersion=28 //Integer - We ALWAYS target the latest by default
|
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
|
||||||
defaultCompileSdkVersion=28 //Integer - We ALWAYS compile with the latest by default
|
// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html
|
||||||
|
ext {
|
||||||
|
apply from: 'CordovaLib/cordova.gradle'
|
||||||
|
// The value for android.compileSdkVersion.
|
||||||
|
if (!project.hasProperty('cdvCompileSdkVersion')) {
|
||||||
|
cdvCompileSdkVersion = null;
|
||||||
|
}
|
||||||
|
// The value for android.buildToolsVersion.
|
||||||
|
if (!project.hasProperty('cdvBuildToolsVersion')) {
|
||||||
|
cdvBuildToolsVersion = null;
|
||||||
|
}
|
||||||
|
// Sets the versionCode to the given value.
|
||||||
|
if (!project.hasProperty('cdvVersionCode')) {
|
||||||
|
cdvVersionCode = null
|
||||||
|
}
|
||||||
|
// Sets the minSdkVersion to the given value.
|
||||||
|
if (!project.hasProperty('cdvMinSdkVersion')) {
|
||||||
|
cdvMinSdkVersion = null
|
||||||
|
}
|
||||||
|
// Whether to build architecture-specific APKs.
|
||||||
|
if (!project.hasProperty('cdvBuildMultipleApks')) {
|
||||||
|
cdvBuildMultipleApks = null
|
||||||
|
}
|
||||||
|
// .properties files to use for release signing.
|
||||||
|
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
|
||||||
|
cdvReleaseSigningPropertiesFile = null
|
||||||
|
}
|
||||||
|
// .properties files to use for debug signing.
|
||||||
|
if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {
|
||||||
|
cdvDebugSigningPropertiesFile = null
|
||||||
|
}
|
||||||
|
// Set by build.js script.
|
||||||
|
if (!project.hasProperty('cdvBuildArch')) {
|
||||||
|
cdvBuildArch = null
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin gradle extensions can append to this to have code run at the end.
|
||||||
|
cdvPluginPostBuildExtras = []
|
||||||
|
}
|
||||||
|
|
||||||
|
// PLUGIN GRADLE EXTENSIONS START
|
||||||
|
// PLUGIN GRADLE EXTENSIONS END
|
||||||
|
|
||||||
|
def hasBuildExtras = file('build-extras.gradle').exists()
|
||||||
|
if (hasBuildExtras) {
|
||||||
|
apply from: 'build-extras.gradle'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set property defaults after extension .gradle files.
|
||||||
|
if (ext.cdvCompileSdkVersion == null) {
|
||||||
|
ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
|
||||||
|
}
|
||||||
|
if (ext.cdvBuildToolsVersion == null) {
|
||||||
|
ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
||||||
|
}
|
||||||
|
if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) {
|
||||||
|
ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties'
|
||||||
|
}
|
||||||
|
if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) {
|
||||||
|
ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast to appropriate types.
|
||||||
|
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
|
||||||
|
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)
|
||||||
|
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
|
||||||
|
|
||||||
|
def computeBuildTargetName(debugBuild) {
|
||||||
|
def ret = 'assemble'
|
||||||
|
if (cdvBuildMultipleApks && cdvBuildArch) {
|
||||||
|
def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch
|
||||||
|
ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);
|
||||||
|
}
|
||||||
|
return ret + (debugBuild ? 'Debug' : 'Release')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make cdvBuild a task that depends on the debug/arch-sepecific task.
|
||||||
|
task cdvBuildDebug
|
||||||
|
cdvBuildDebug.dependsOn {
|
||||||
|
return computeBuildTargetName(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
task cdvBuildRelease
|
||||||
|
cdvBuildRelease.dependsOn {
|
||||||
|
return computeBuildTargetName(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
task cdvPrintProps << {
|
||||||
|
println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
|
||||||
|
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
|
||||||
|
println('cdvVersionCode=' + cdvVersionCode)
|
||||||
|
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
|
||||||
|
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
|
||||||
|
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
|
||||||
|
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
|
||||||
|
println('cdvBuildArch=' + cdvBuildArch)
|
||||||
|
println('computedVersionCode=' + android.defaultConfig.versionCode)
|
||||||
|
android.productFlavors.each { flavor ->
|
||||||
|
println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
android {
|
||||||
delete rootProject.buildDir
|
sourceSets {
|
||||||
|
main {
|
||||||
|
manifest.srcFile 'AndroidManifest.xml'
|
||||||
|
java.srcDirs = ['src']
|
||||||
|
resources.srcDirs = ['src']
|
||||||
|
aidl.srcDirs = ['src']
|
||||||
|
renderscript.srcDirs = ['src']
|
||||||
|
res.srcDirs = ['res']
|
||||||
|
assets.srcDirs = ['assets']
|
||||||
|
jniLibs.srcDirs = ['libs']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultConfig {
|
||||||
|
versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
|
||||||
|
applicationId privateHelpers.extractStringFromManifest("package")
|
||||||
|
|
||||||
|
if (cdvMinSdkVersion != null) {
|
||||||
|
minSdkVersion cdvMinSdkVersion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lintOptions {
|
||||||
|
abortOnError false;
|
||||||
|
}
|
||||||
|
|
||||||
|
compileSdkVersion cdvCompileSdkVersion
|
||||||
|
buildToolsVersion cdvBuildToolsVersion
|
||||||
|
|
||||||
|
if (Boolean.valueOf(cdvBuildMultipleApks)) {
|
||||||
|
productFlavors {
|
||||||
|
armv7 {
|
||||||
|
versionCode defaultConfig.versionCode*10 + 2
|
||||||
|
ndk {
|
||||||
|
abiFilters "armeabi-v7a", ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
x86 {
|
||||||
|
versionCode defaultConfig.versionCode*10 + 4
|
||||||
|
ndk {
|
||||||
|
abiFilters "x86", ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
all {
|
||||||
|
ndk {
|
||||||
|
abiFilters "all", ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
|
||||||
|
ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO!
|
||||||
|
|
||||||
|
else if (!cdvVersionCode) {
|
||||||
|
def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
|
||||||
|
// Vary versionCode by the two most common API levels:
|
||||||
|
// 14 is ICS, which is the lowest API level for many apps.
|
||||||
|
// 20 is Lollipop, which is the lowest API level for the updatable system webview.
|
||||||
|
if (minSdkVersion >= 20) {
|
||||||
|
defaultConfig.versionCode += 9
|
||||||
|
} else if (minSdkVersion >= 14) {
|
||||||
|
defaultConfig.versionCode += 8
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
compileOptions {
|
||||||
|
sourceCompatibility JavaVersion.VERSION_1_6
|
||||||
|
targetCompatibility JavaVersion.VERSION_1_6
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cdvReleaseSigningPropertiesFile) {
|
||||||
|
signingConfigs {
|
||||||
|
release {
|
||||||
|
// These must be set or Gradle will complain (even if they are overridden).
|
||||||
|
keyAlias = ""
|
||||||
|
keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph.
|
||||||
|
storeFile = null
|
||||||
|
storePassword = "__unset"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
buildTypes {
|
||||||
|
release {
|
||||||
|
signingConfig signingConfigs.release
|
||||||
|
}
|
||||||
|
}
|
||||||
|
addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)
|
||||||
|
}
|
||||||
|
if (cdvDebugSigningPropertiesFile) {
|
||||||
|
addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
compile fileTree(dir: 'libs', include: '*.jar')
|
||||||
|
// SUB-PROJECT DEPENDENCIES START
|
||||||
|
// SUB-PROJECT DEPENDENCIES END
|
||||||
|
}
|
||||||
|
|
||||||
|
def promptForReleaseKeyPassword() {
|
||||||
|
if (!cdvReleaseSigningPropertiesFile) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ('__unset'.equals(android.signingConfigs.release.storePassword)) {
|
||||||
|
android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')
|
||||||
|
}
|
||||||
|
if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {
|
||||||
|
android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gradle.taskGraph.whenReady { taskGraph ->
|
||||||
|
taskGraph.getAllTasks().each() { task ->
|
||||||
|
if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') {
|
||||||
|
promptForReleaseKeyPassword()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
def addSigningProps(propsFilePath, signingConfig) {
|
||||||
|
def propsFile = file(propsFilePath)
|
||||||
|
def props = new Properties()
|
||||||
|
propsFile.withReader { reader ->
|
||||||
|
props.load(reader)
|
||||||
|
}
|
||||||
|
|
||||||
|
def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
|
||||||
|
if (!storeFile.isAbsolute()) {
|
||||||
|
storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
|
||||||
|
}
|
||||||
|
if (!storeFile.exists()) {
|
||||||
|
throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
|
||||||
|
}
|
||||||
|
signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
|
||||||
|
signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
|
||||||
|
signingConfig.storeFile = storeFile
|
||||||
|
signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
|
||||||
|
def storeType = props.get('storeType', props.get('key.store.type', ''))
|
||||||
|
if (!storeType) {
|
||||||
|
def filename = storeFile.getName().toLowerCase();
|
||||||
|
if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
|
||||||
|
storeType = 'pkcs12'
|
||||||
|
} else {
|
||||||
|
storeType = signingConfig.storeType // "jks"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
signingConfig.storeType = storeType
|
||||||
|
}
|
||||||
|
|
||||||
|
for (def func : cdvPluginPostBuildExtras) {
|
||||||
|
func()
|
||||||
|
}
|
||||||
|
|
||||||
|
// This can be defined within build-extras.gradle as:
|
||||||
|
// ext.postBuildExtras = { ... code here ... }
|
||||||
|
if (hasProperty('postBuildExtras')) {
|
||||||
|
postBuildExtras()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,12 +10,5 @@ ant-gen
|
|||||||
# Eclipse builds
|
# Eclipse builds
|
||||||
gen
|
gen
|
||||||
out
|
out
|
||||||
# Gradle build artifacts
|
# Gradle builds
|
||||||
.gradle
|
|
||||||
.gradletasknamecache
|
|
||||||
/build
|
/build
|
||||||
/CordovaLib/build
|
|
||||||
/app/build
|
|
||||||
gradle-app.setting
|
|
||||||
# Android Studio
|
|
||||||
.idea
|
|
||||||
|
|||||||
@@ -1,334 +0,0 @@
|
|||||||
/*
|
|
||||||
Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
or more contributor license agreements. See the NOTICE file
|
|
||||||
distributed with this work for additional information
|
|
||||||
regarding copyright ownership. The ASF licenses this file
|
|
||||||
to you under the Apache License, Version 2.0 (the
|
|
||||||
"License"); you may not use this file except in compliance
|
|
||||||
with the License. You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing,
|
|
||||||
software distributed under the License is distributed on an
|
|
||||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
KIND, either express or implied. See the License for the
|
|
||||||
specific language governing permissions and limitations
|
|
||||||
under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
apply plugin: 'com.android.application'
|
|
||||||
|
|
||||||
buildscript {
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switch the Android Gradle plugin version requirement depending on the
|
|
||||||
// installed version of Gradle. This dependency is documented at
|
|
||||||
// http://tools.android.com/tech-docs/new-build-system/version-compatibility
|
|
||||||
// and https://issues.apache.org/jira/browse/CB-8143
|
|
||||||
dependencies {
|
|
||||||
classpath 'com.android.tools.build:gradle:2.2.3'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Allow plugins to declare Maven dependencies via build-extras.gradle.
|
|
||||||
allprojects {
|
|
||||||
repositories {
|
|
||||||
mavenCentral();
|
|
||||||
jcenter()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
task wrapper(type: Wrapper) {
|
|
||||||
gradleVersion = '2.14.1'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
|
|
||||||
// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html
|
|
||||||
ext {
|
|
||||||
apply from: 'CordovaLib/cordova.gradle'
|
|
||||||
// The value for android.compileSdkVersion.
|
|
||||||
if (!project.hasProperty('cdvCompileSdkVersion')) {
|
|
||||||
cdvCompileSdkVersion = null;
|
|
||||||
}
|
|
||||||
// The value for android.buildToolsVersion.
|
|
||||||
if (!project.hasProperty('cdvBuildToolsVersion')) {
|
|
||||||
cdvBuildToolsVersion = null;
|
|
||||||
}
|
|
||||||
// Sets the versionCode to the given value.
|
|
||||||
if (!project.hasProperty('cdvVersionCode')) {
|
|
||||||
cdvVersionCode = null
|
|
||||||
}
|
|
||||||
// Sets the minSdkVersion to the given value.
|
|
||||||
if (!project.hasProperty('cdvMinSdkVersion')) {
|
|
||||||
cdvMinSdkVersion = null
|
|
||||||
}
|
|
||||||
// Sets the maxSdkVersion to the given value.
|
|
||||||
if (!project.hasProperty('cdvMaxSdkVersion')) {
|
|
||||||
cdvMaxSdkVersion = null
|
|
||||||
}
|
|
||||||
// The value for android.targetSdkVersion.
|
|
||||||
if (!project.hasProperty('cdvTargetSdkVersion')) {
|
|
||||||
cdvTargetSdkVersion = null;
|
|
||||||
}
|
|
||||||
// Whether to build architecture-specific APKs.
|
|
||||||
if (!project.hasProperty('cdvBuildMultipleApks')) {
|
|
||||||
cdvBuildMultipleApks = null
|
|
||||||
}
|
|
||||||
// .properties files to use for release signing.
|
|
||||||
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
|
|
||||||
cdvReleaseSigningPropertiesFile = null
|
|
||||||
}
|
|
||||||
// .properties files to use for debug signing.
|
|
||||||
if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {
|
|
||||||
cdvDebugSigningPropertiesFile = null
|
|
||||||
}
|
|
||||||
// Set by build.js script.
|
|
||||||
if (!project.hasProperty('cdvBuildArch')) {
|
|
||||||
cdvBuildArch = null
|
|
||||||
}
|
|
||||||
|
|
||||||
// Plugin gradle extensions can append to this to have code run at the end.
|
|
||||||
cdvPluginPostBuildExtras = []
|
|
||||||
}
|
|
||||||
|
|
||||||
// PLUGIN GRADLE EXTENSIONS START
|
|
||||||
// PLUGIN GRADLE EXTENSIONS END
|
|
||||||
|
|
||||||
def hasBuildExtras = file('build-extras.gradle').exists()
|
|
||||||
if (hasBuildExtras) {
|
|
||||||
apply from: 'build-extras.gradle'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set property defaults after extension .gradle files.
|
|
||||||
if (ext.cdvCompileSdkVersion == null) {
|
|
||||||
ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
|
|
||||||
}
|
|
||||||
if (ext.cdvBuildToolsVersion == null) {
|
|
||||||
ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
|
|
||||||
}
|
|
||||||
if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) {
|
|
||||||
ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties'
|
|
||||||
}
|
|
||||||
if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) {
|
|
||||||
ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties'
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cast to appropriate types.
|
|
||||||
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
|
|
||||||
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)
|
|
||||||
|
|
||||||
if(cdvMaxSdkVersion != null) {
|
|
||||||
ext.cdvMaxSdkVersion = Integer.parseInt('' + cdvMaxSdkVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
|
|
||||||
|
|
||||||
def computeBuildTargetName(debugBuild) {
|
|
||||||
def ret = 'assemble'
|
|
||||||
if (cdvBuildMultipleApks && cdvBuildArch) {
|
|
||||||
def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch
|
|
||||||
ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);
|
|
||||||
}
|
|
||||||
return ret + (debugBuild ? 'Debug' : 'Release')
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make cdvBuild a task that depends on the debug/arch-sepecific task.
|
|
||||||
task cdvBuildDebug
|
|
||||||
cdvBuildDebug.dependsOn {
|
|
||||||
return computeBuildTargetName(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
task cdvBuildRelease
|
|
||||||
cdvBuildRelease.dependsOn {
|
|
||||||
return computeBuildTargetName(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
task cdvPrintProps << {
|
|
||||||
println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
|
|
||||||
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
|
|
||||||
println('cdvVersionCode=' + cdvVersionCode)
|
|
||||||
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
|
|
||||||
println('cdvMaxSdkVersion=' + cdvMaxSdkVersion)
|
|
||||||
println('cdvTargetSdkVersion=' + cdvTargetSdkVersion)
|
|
||||||
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
|
|
||||||
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
|
|
||||||
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
|
|
||||||
println('cdvBuildArch=' + cdvBuildArch)
|
|
||||||
println('computedVersionCode=' + android.defaultConfig.versionCode)
|
|
||||||
android.productFlavors.each { flavor ->
|
|
||||||
println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
android {
|
|
||||||
sourceSets {
|
|
||||||
main {
|
|
||||||
manifest.srcFile 'AndroidManifest.xml'
|
|
||||||
java.srcDirs = ['src']
|
|
||||||
resources.srcDirs = ['src']
|
|
||||||
aidl.srcDirs = ['src']
|
|
||||||
renderscript.srcDirs = ['src']
|
|
||||||
res.srcDirs = ['res']
|
|
||||||
assets.srcDirs = ['assets']
|
|
||||||
jniLibs.srcDirs = ['libs']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultConfig {
|
|
||||||
versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
|
|
||||||
applicationId privateHelpers.extractStringFromManifest("package")
|
|
||||||
|
|
||||||
if (cdvMinSdkVersion != null) {
|
|
||||||
minSdkVersion cdvMinSdkVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdvMaxSdkVersion != null) {
|
|
||||||
maxSdkVersion cdvMaxSdkVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cdvTargetSdkVersion != null) {
|
|
||||||
targetSdkVersion cdvTargetSdkVersion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
lintOptions {
|
|
||||||
abortOnError false;
|
|
||||||
}
|
|
||||||
|
|
||||||
compileSdkVersion cdvCompileSdkVersion
|
|
||||||
buildToolsVersion cdvBuildToolsVersion
|
|
||||||
|
|
||||||
if (Boolean.valueOf(cdvBuildMultipleApks)) {
|
|
||||||
productFlavors {
|
|
||||||
armv7 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 2
|
|
||||||
ndk {
|
|
||||||
abiFilters "armeabi-v7a", ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x86 {
|
|
||||||
versionCode defaultConfig.versionCode*10 + 4
|
|
||||||
ndk {
|
|
||||||
abiFilters "x86", ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
all {
|
|
||||||
ndk {
|
|
||||||
abiFilters "all", ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
|
|
||||||
ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO!
|
|
||||||
|
|
||||||
else if (!cdvVersionCode) {
|
|
||||||
def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
|
|
||||||
// Vary versionCode by the two most common API levels:
|
|
||||||
// 14 is ICS, which is the lowest API level for many apps.
|
|
||||||
// 20 is Lollipop, which is the lowest API level for the updatable system webview.
|
|
||||||
if (minSdkVersion >= 20) {
|
|
||||||
defaultConfig.versionCode += 9
|
|
||||||
} else if (minSdkVersion >= 14) {
|
|
||||||
defaultConfig.versionCode += 8
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_6
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_6
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cdvReleaseSigningPropertiesFile) {
|
|
||||||
signingConfigs {
|
|
||||||
release {
|
|
||||||
// These must be set or Gradle will complain (even if they are overridden).
|
|
||||||
keyAlias = ""
|
|
||||||
keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph.
|
|
||||||
storeFile = null
|
|
||||||
storePassword = "__unset"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
buildTypes {
|
|
||||||
release {
|
|
||||||
signingConfig signingConfigs.release
|
|
||||||
}
|
|
||||||
}
|
|
||||||
addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)
|
|
||||||
}
|
|
||||||
if (cdvDebugSigningPropertiesFile) {
|
|
||||||
addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dependencies {
|
|
||||||
implementation fileTree(dir: 'libs', include: '*.jar')
|
|
||||||
// SUB-PROJECT DEPENDENCIES START
|
|
||||||
// SUB-PROJECT DEPENDENCIES END
|
|
||||||
}
|
|
||||||
|
|
||||||
def promptForReleaseKeyPassword() {
|
|
||||||
if (!cdvReleaseSigningPropertiesFile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ('__unset'.equals(android.signingConfigs.release.storePassword)) {
|
|
||||||
android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')
|
|
||||||
}
|
|
||||||
if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {
|
|
||||||
android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gradle.taskGraph.whenReady { taskGraph ->
|
|
||||||
taskGraph.getAllTasks().each() { task ->
|
|
||||||
if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') {
|
|
||||||
promptForReleaseKeyPassword()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
def addSigningProps(propsFilePath, signingConfig) {
|
|
||||||
def propsFile = file(propsFilePath)
|
|
||||||
def props = new Properties()
|
|
||||||
propsFile.withReader { reader ->
|
|
||||||
props.load(reader)
|
|
||||||
}
|
|
||||||
|
|
||||||
def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
|
|
||||||
if (!storeFile.isAbsolute()) {
|
|
||||||
storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
|
|
||||||
}
|
|
||||||
if (!storeFile.exists()) {
|
|
||||||
throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
|
|
||||||
}
|
|
||||||
signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
|
|
||||||
signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
|
|
||||||
signingConfig.storeFile = storeFile
|
|
||||||
signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
|
|
||||||
def storeType = props.get('storeType', props.get('key.store.type', ''))
|
|
||||||
if (!storeType) {
|
|
||||||
def filename = storeFile.getName().toLowerCase();
|
|
||||||
if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
|
|
||||||
storeType = 'pkcs12'
|
|
||||||
} else {
|
|
||||||
storeType = signingConfig.storeType // "jks"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
signingConfig.storeType = storeType
|
|
||||||
}
|
|
||||||
|
|
||||||
for (def func : cdvPluginPostBuildExtras) {
|
|
||||||
func()
|
|
||||||
}
|
|
||||||
|
|
||||||
// This can be defined within build-extras.gradle as:
|
|
||||||
// ext.postBuildExtras = { ... code here ... }
|
|
||||||
if (hasProperty('postBuildExtras')) {
|
|
||||||
postBuildExtras()
|
|
||||||
}
|
|
||||||
@@ -1,13 +1,15 @@
|
|||||||
# This file was originally created by the Android Tools, but is now
|
# This file is automatically generated by Android Tools.
|
||||||
# used by cordova-android to manage the state of the various third party
|
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
|
||||||
# libraries used in your application
|
#
|
||||||
|
# This file must be checked in Version Control Systems.
|
||||||
|
#
|
||||||
|
# To customize properties used by the Ant build system edit
|
||||||
|
# "ant.properties", and override values to adapt the script to your
|
||||||
|
# project structure.
|
||||||
|
#
|
||||||
|
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
|
||||||
|
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
|
||||||
|
|
||||||
# This is the Library Module that contains the Cordova Library, this is not
|
|
||||||
# required when using an AAR
|
|
||||||
android.library.reference.1=CordovaLib
|
android.library.reference.1=CordovaLib
|
||||||
|
|
||||||
# This is the application project. This is only required for Android Studio Gradle projects
|
|
||||||
android.library.reference.2=app
|
|
||||||
|
|
||||||
# Project target.
|
# Project target.
|
||||||
target=This_gets_replaced
|
target=This_gets_replaced
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 213 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 90 KiB |
|
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 478 KiB |
|
Before Width: | Height: | Size: 129 KiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 190 KiB After Width: | Height: | Size: 1.4 MiB |
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 217 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 493 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 1.1 MiB |
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 1.5 MiB |
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@mipmap/ic_launcher_background" />
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
|
||||||
</adaptive-icon>
|
|
||||||
|
Before Width: | Height: | Size: 86 B |
|
Before Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.6 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@mipmap/ic_launcher_background" />
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
|
||||||
</adaptive-icon>
|
|
||||||
|
Before Width: | Height: | Size: 83 B |
|
Before Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
@@ -1,5 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
||||||
<background android:drawable="@mipmap/ic_launcher_background" />
|
|
||||||
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
|
|
||||||
</adaptive-icon>
|
|
||||||
|
Before Width: | Height: | Size: 84 B |
|
Before Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 4.0 KiB |