Compare commits

..

34 Commits
8.0.0 ... 8.1.0

Author SHA1 Message Date
Erisu
f1f472297a Set VERSION to 8.1.0 (via coho) 2019-09-11 13:58:04 +09:00
Erisu
030af05839 Update JS snapshot to version 8.1.0 (via coho) 2019-09-11 13:58:04 +09:00
Erisu
7e8b47d012 minor-8.1.0 Updated version and RELEASENOTES.md for release 8.1.0 2019-09-11 12:41:25 +09:00
エリス
902aa32dda chore: bump dependencies for release 8.1.0 (#827) 2019-09-11 11:34:33 +09:00
MatusFiala
42c0cba7f7 feat: added multiple selection for filepicker (#651)
* GH-621 (Cordova-Android)
2019-09-09 08:44:40 +09:00
Jan Piotrowski
f2b84d8d83 chore: compress files in /res with tinypng.com (#672) 2019-09-07 22:45:43 +09:00
Norman Breau
1b11206174 fix: clean command (#815)
* fix clean command
* added unit tests for the getArgs clean
* Cleaned up ProjectBuilder.getArgs for readability
2019-09-07 13:54:32 +09:00
Darryl Pogue
c93e3e9f6f Merge pull request #750 from goffioul/patch-1
Don't request focus explicitly if not needed
2019-08-28 15:31:25 -07:00
Norman Breau
9808a0d4d3 GH-799 (android) Stop webview from restarting when activity resizes (#800) 2019-08-26 19:57:11 +00:00
Norman Breau
bd1697dbd2 feat: Build app bundles (.aab files) (#764)
* (android) Added android bundle support

  with some corrected tests

  added bundle specific output

* with --packageType flag to have consistency with cordova-ios

* warn about missing required signing params only if at least one signing param is present

* produce error on run if packageType = bundle

* added comments relating to shelljs as suggested

* unit test case added by @brodybits - Chris Brody

* Filled in error message and unit test spec

Primary author: @breautek - Norman Breau <norman@normanbreau.com>

Co-authored-by: Norman Breau <norman@normanbreau.com>
Co-authored-by: Chris Brody <chris@brody.consulting>
2019-08-08 12:53:10 -04:00
Raphael von der Grün
b3b8690bbd Simplify apkSorter using compare-func package (#788) 2019-07-18 11:59:54 +02:00
Raphael von der Grün
ad742ec93c Simplify and fix promise handling in specs (#787) 2019-07-17 14:56:36 +02:00
Raphael von der Grün
1de7c38134 Properly handle promise in create script (#784)
* Properly handle promise in create script

* Add regression test
2019-07-17 09:52:19 +02:00
Raphael von der Grün
997943a194 Do not clobber process properties with test mocks (#783) 2019-07-17 03:01:56 +02:00
Raphael von der Grün
47c6048d53 Do not clobber console.log to spy on it (#782) 2019-07-17 00:18:12 +02:00
エリス
a64d459c8e Add Node.js 12 to CI Services (#724)
and remove trailing whitespace from .travis.yml

Co-authored-by: エリス <erisu@users.noreply.github.com>
Co-authored-by: Christopher J. Brody <brodybits@users.noreply.github.com>
2019-07-14 17:20:47 -04:00
Chris Brody
a5ad440f17 ci(travis): set dist: trusty in .travis.yml (#777)
to avoid errored Travis CI build on Node.js 12

including NOTE with a TODO item
2019-07-14 16:54:26 -04:00
Chris Brody
acad24d62a Consistent order from ProjectBuilder.apkSorter (#779)
This function used to give a different order depending on the behavior
of Array.prototype.sort(), which led to a test failure on Node.js 12
(see apache/cordova-android#767).

This update gives a consistent sort order, regardless of the
JavaScript engine implementation, now succeeds on Node.js
versions 6, 8, 10, and 12.

Resolves #767

For reference:
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
2019-07-14 16:35:44 -04:00
Chris Brody
989b4cc913 test: use verbose spec reporter (#778)
Co-authored-by: Christopher J. Brody <chris@brody.consulting>
Co-authored-by: Raphael von der Grün <raphinesse@users.noreply.github.com>
2019-07-14 15:36:46 -04:00
Norman Breau
38c6627999 rewire workaround for NodeJS 12 (#774)
* rewire workaround for NodeJS 12

* additional comment with a link to the underlying issue in jhnns/rewire#167
2019-07-12 02:09:57 -04:00
Chris Brody
4b9e18c6b8 nyc@14 update in devDependencies (#772) 2019-07-12 01:46:55 -04:00
Jan Piotrowski
906f8cc002 ci(travis): Fix Android SDK (#765)
* add node 12

* try to cleanup and fix

* fix

* fix

* no node 12 then...
2019-07-11 12:16:29 +02:00
goffioul
01ab11644c Don't request focus explicitly if not needed
Requesting the focus explicitly actually makes the child WebView to move the focus to the first visible focusable element on the page. This makes it impossible to simply let the WebView restore the focus to the last focused element, before the activity was paused. To prevent this problem on devices other that the Samsung Galaxy Note 3, only request the focus if necessary (it might as well be possible that the original fix is not needed anymore on newer versions of Android and/or WebView).
2019-06-20 15:28:08 -04:00
Raphael von der Grün
4cf3dcfaae Do not explicitly require modules from project directory (#713)
* Allow to pass-through projectPath to Builder

* Do not explicitly require modules from project directory
2019-04-13 17:34:59 +02:00
エリス
b177f84825 Added allprojects repositories for Framework Release Builds (#676) 2019-04-06 13:33:04 +09:00
エリス
485e6e0e4d Improve Gradle Build Arguments (#699)
* Remove `uses-sdk` from AndroidManifest
* Remove dependency `elementtree`
* Updated Build Command Help Menu Printout
  * Cleanup `minSdkVersion` printout
  * Added  `maxSdkVersion`, but not recommended to set.
  * Added `targetSdkVersion`
* Update the `GradlePropertiesParser` & Test Spec
  * Always Set Overriding Changes
  * Update existing properties
  * Update configure method
2019-04-06 13:28:25 +09:00
Darryl Pogue
516c3411aa Merge pull request #710 from dpogue/cookie-deprecation
Fix deprecation warning in SystemCookieManager
2019-04-02 13:27:20 -07:00
Darryl Pogue
908354e7fa Fix deprecation warning in SystemCookieManager 2019-04-02 07:16:08 -07:00
Darryl Pogue
9531dbbc7b Merge pull request #691 from dpogue/common-configparser
Run prepare with the correct ConfigParser version
2019-03-15 11:08:35 -07:00
Darryl Pogue
d10dd1c0b4 Remove unused browserify paths 2019-03-14 23:03:14 -07:00
Darryl Pogue
6533474070 GH-690: Run prepare with the correct ConfigParser 2019-03-14 23:02:53 -07:00
エリス
576edb53bb Updated ANDROID_HOME Test to Follow #656 Change (#673) 2019-02-18 09:34:55 +09:00
エリス
20e390af85 Update JS snapshot to version 8.1.0-dev (via coho) 2019-02-13 15:22:10 +09:00
エリス
931251a5a8 Set VERSION to 8.1.0-dev (via coho) 2019-02-13 15:22:06 +09:00
68 changed files with 680 additions and 424 deletions

View File

@@ -1,37 +1,48 @@
language: android
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
jdk:
- oraclejdk8
- oraclejdk8
android:
components:
- build-tools-28.0.3
env:
global:
# Keep gradle from crapping all over the log
- TERM=dumb
matrix:
- nodejs_version=6
- nodejs_version=8
- nodejs_version=10
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:
- nvm install $nodejs_version
- node --version
- npm --version
- gradle --version
install:
# Install a sdkmanager version that supports the --licenses switch and
# accept any Android SDK licenses. The output redirection prevents us from
# hitting the travis log size limit of 4MB which would fail the build.
- yes | sdkmanager tools > /dev/null
- yes | sdkmanager --licenses > /dev/null
- nvm install $nodejs_version
- npm install
- npm install -g codecov
- npm install
- npm install -g codecov
script:
- gradle --version
- node --version
- npm --version
- npm test
- npm run cover
- npm test
- npm run cover
after_script:
- codecov
- codecov

View File

@@ -20,6 +20,34 @@
-->
## 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`

View File

@@ -1 +1 @@
8.0.0
8.1.0

View File

@@ -11,6 +11,7 @@ environment:
- nodejs_version: 6
- nodejs_version: 8
- nodejs_version: 10
- nodejs_version: 12
install:
# Install Android SDK Tools

View File

@@ -142,8 +142,8 @@ function writeProjectProperties (projectPath, target_api) {
// This makes no sense, what if you're building with a different build system?
function prepBuildFiles (projectPath) {
var buildModule = require(path.resolve(projectPath, 'cordova/lib/builders/builders'));
buildModule.getBuilder().prepBuildFiles();
var buildModule = require('../templates/cordova/lib/builders/builders');
buildModule.getBuilder(projectPath).prepBuildFiles();
}
function copyBuildRules (projectPath, isLegacy) {
@@ -272,7 +272,7 @@ exports.create = function (project_path, config, options, events) {
// Make the package conform to Java package types
return exports.validatePackageName(package_name)
.then(function () {
exports.validateProjectName(project_name);
return exports.validateProjectName(project_name);
}).then(function () {
// Log the given values for the project
events.emit('log', 'Creating Cordova project for the Android platform:');
@@ -321,7 +321,6 @@ exports.create = function (project_path, config, options, events) {
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
manifest.setPackageId(package_name)
.setTargetSdkVersion(target_api.split('-')[1])
.getActivity().setName(safe_activity_name);
var manifest_path = path.join(app_path, 'AndroidManifest.xml');

View File

@@ -25,6 +25,7 @@ var PluginManager = require('cordova-common').PluginManager;
var CordovaLogger = require('cordova-common').CordovaLogger;
var selfEvents = require('cordova-common').events;
var ConfigParser = require('cordova-common').ConfigParser;
var PLATFORM = 'android';
@@ -71,10 +72,7 @@ function Api (platform, platformRootDir, events) {
strings: path.join(appRes, 'values', 'strings.xml'),
manifest: path.join(appMain, 'AndroidManifest.xml'),
build: path.join(this.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'
javaSrc: path.join(appMain, 'java')
};
}
@@ -101,8 +99,7 @@ Api.createPlatform = function (destination, config, options, events) {
var result;
try {
result = require('../../lib/create').create(destination, config, options, events).then(function (destination) {
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
return new PlatformApi(PLATFORM, destination, events);
return new Api(PLATFORM, destination, events);
});
} catch (e) {
events.emit('error', 'createPlatform is not callable from the android project API.');
@@ -132,8 +129,7 @@ Api.updatePlatform = function (destination, options, events) {
var result;
try {
result = require('../../lib/create').update(destination, options, events).then(function (destination) {
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
return new PlatformApi('android', destination, events);
return new Api(PLATFORM, destination, events);
});
} catch (e) {
events.emit('error', 'updatePlatform is not callable from the android project API, you will need to do this manually.');
@@ -174,6 +170,8 @@ Api.prototype.getPlatformInfo = function () {
* CordovaError instance.
*/
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);
};
@@ -304,12 +302,12 @@ Api.prototype.build = function (buildOptions) {
return require('./lib/build').run.call(self, buildOptions);
}).then(function (buildResults) {
// Cast build result to array of build artifacts
return buildResults.apkPaths.map(function (apkPath) {
return buildResults.paths.map(function (apkPath) {
return {
buildType: buildResults.buildType,
buildMethod: buildResults.buildMethod,
path: apkPath,
type: 'apk'
type: path.extname(apkPath).replace(/\./g, '')
};
});
});

View File

@@ -18,7 +18,6 @@
*/
var fs = require('fs');
var et = require('elementtree');
var xml = require('cordova-common').xmlHelpers;
var DEFAULT_ORIENTATION = 'default';
@@ -98,31 +97,6 @@ AndroidManifest.prototype.getActivity = 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';
};
@@ -150,7 +124,3 @@ AndroidManifest.prototype.write = function (destPath) {
};
module.exports = AndroidManifest;
function capitalize (str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}

View File

@@ -0,0 +1,25 @@
/**
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;

View File

@@ -30,6 +30,7 @@ var builders = require('./builders/builders');
var events = require('cordova-common').events;
var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError;
var PackageType = require('./PackageType');
module.exports.parseBuildOptions = parseOpts;
function parseOpts (options, resolvedTarget, projectRoot) {
@@ -38,12 +39,15 @@ function parseOpts (options, resolvedTarget, projectRoot) {
prepenv: Boolean,
versionCode: String,
minSdkVersion: String,
maxSdkVersion: String,
targetSdkVersion: String,
gradleArg: [String, Array],
keystore: path,
alias: String,
storePassword: String,
password: String,
keystoreType: String
keystoreType: String,
packageType: String
}, {}, options.argv, 0);
// Android Studio Build method is the default
@@ -56,6 +60,8 @@ function parseOpts (options, resolvedTarget, projectRoot) {
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.maxSdkVersion) { ret.extraArgs.push('-PcdvMaxSdkVersion=' + options.argv.maxSdkVersion); }
if (options.argv.targetSdkVersion) { ret.extraArgs.push('-PcdvTargetSdkVersion=' + options.argv.targetSdkVersion); }
if (options.argv.gradleArg) {
ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
}
@@ -64,14 +70,14 @@ function parseOpts (options, resolvedTarget, projectRoot) {
if (options.argv.keystore) { packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore)); }
['alias', 'storePassword', 'password', 'keystoreType'].forEach(function (flagName) {
['alias', 'storePassword', 'password', 'keystoreType', 'packageType'].forEach(function (flagName) {
if (options.argv[flagName]) { packageArgs[flagName] = options.argv[flagName]; }
});
var buildConfig = options.buildConfig;
// If some values are not specified as command line arguments - use build config to supplement them.
// Command line arguemnts have precedence over build config.
// Command line arguments have precedence over build config.
if (buildConfig) {
if (!fs.existsSync(buildConfig)) {
throw new Error('Specified build config file does not exist: ' + buildConfig);
@@ -89,7 +95,7 @@ function parseOpts (options, resolvedTarget, projectRoot) {
events.emit('log', 'Reading the keystore from: ' + packageArgs.keystore);
}
['alias', 'storePassword', 'password', 'keystoreType'].forEach(function (key) {
['alias', 'storePassword', 'password', 'keystoreType', 'packageType'].forEach(function (key) {
packageArgs[key] = packageArgs[key] || androidInfo[key];
});
}
@@ -101,11 +107,38 @@ function parseOpts (options, resolvedTarget, projectRoot) {
}
if (!ret.packageInfo) {
if (Object.keys(packageArgs).length > 0) {
// The following loop is to decide whether to print a warning about generating a signed archive
// 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.');
}
}
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;
}
@@ -144,10 +177,17 @@ module.exports.run = function (options, optResolvedTarget) {
return;
}
return builder.build(opts).then(function () {
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
var paths;
if (opts.packageType === PackageType.BUNDLE) {
paths = builder.findOutputBundles(opts.buildType);
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 {
apkPaths: apkPaths,
paths: paths,
buildType: opts.buildType
};
});
@@ -265,8 +305,11 @@ module.exports.help = function () {
console.log(' \'--nobuild\': will skip build process (useful when using run command)');
console.log(' \'--prepenv\': don\'t build, but copy in build scripts where necessary');
console.log(' \'--versionCode=#\': Override versionCode for this build. Useful for uploading multiple APKs.');
console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build. Useful for uploading multiple APKs.');
console.log(' \'--minSdkVersion=#\': Override minSdkVersion for this build.');
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(' \'--packageType=<apk|bundle>\': Builds an APK or a bundle');
console.log('');
console.log('Signed APK flags (overwrites debug/release-signing.proprties) :');
console.log(' \'--keystore=<path to keystore>\': Key store used to build a signed archive. (Required)');

View File

@@ -27,6 +27,8 @@ 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';
@@ -37,24 +39,37 @@ const TEMPLATE =
class ProjectBuilder {
constructor (rootDirectory) {
this.root = rootDirectory || path.resolve(__dirname, '../../..');
this.binDir = path.join(this.root, 'app', 'build', 'outputs', 'apk');
this.apkDir = path.join(this.root, 'app', 'build', 'outputs', 'apk');
this.aabDir = path.join(this.root, 'app', 'build', 'outputs', 'bundle');
}
getArgs (cmd, opts) {
if (cmd === 'release') {
cmd = 'cdvBuildRelease';
} else if (cmd === 'debug') {
cmd = 'cdvBuildDebug';
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);
}
let args = [cmd, '-b', path.join(this.root, 'build.gradle')];
if (opts.arch) {
args.push('-PcdvBuildArch=' + opts.arch);
}
args.push.apply(args, opts.extraArgs);
return args;
}
@@ -287,7 +302,11 @@ class ProjectBuilder {
}
findOutputApks (build_type, arch) {
return findOutputApksHelper(this.binDir, build_type, arch).sort(apkSorter);
return findOutputApksHelper(this.apkDir, build_type, arch).sort(apkSorter);
}
findOutputBundles (build_type) {
return findOutputBundlesHelper(this.aabDir, build_type);
}
fetchBuildResults (build_type, arch) {
@@ -300,26 +319,19 @@ class ProjectBuilder {
module.exports = ProjectBuilder;
function apkSorter (fileA, fileB) {
// De-prioritize arch specific builds
var archSpecificRE = /-x86|-arm/;
if (archSpecificRE.exec(fileA)) {
return 1;
} else if (archSpecificRE.exec(fileB)) {
return -1;
}
const apkSorter = compareFunc([
// Sort arch specific builds after generic ones
apkPath => /-x86|-arm/.test(apkPath),
// De-prioritize unsigned builds
var unsignedRE = /-unsigned/;
if (unsignedRE.exec(fileA)) {
return 1;
} else if (unsignedRE.exec(fileB)) {
return -1;
}
// Sort unsigned builds after signed ones
apkPath => /-unsigned/.test(apkPath),
var timeDiff = fs.statSync(fileB).mtime - fs.statSync(fileA).mtime;
return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
}
// 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;
@@ -365,6 +377,36 @@ function findOutputApksHelper (dir, build_type, arch) {
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;
}

View File

@@ -24,10 +24,10 @@ const CordovaError = require('cordova-common').CordovaError;
*
* @return {Builder} A builder instance for specified build type.
*/
module.exports.getBuilder = function () {
module.exports.getBuilder = function (projectPath) {
try {
const Builder = require('./ProjectBuilder');
return new Builder();
return new Builder(projectPath);
} catch (err) {
throw new CordovaError('Failed to instantiate ProjectBuilder builder: ' + err);
}

View File

@@ -84,10 +84,20 @@ class GradlePropertiesParser {
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]) {
events.emit('info', `[Gradle Properties] Detected Gradle property "${key}" with the value of "${value}", Cordova's recommended value is "${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]);
}
});
}

View File

@@ -45,9 +45,13 @@ module.exports.prepare = function (cordovaProject, options) {
// 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);
@@ -205,9 +209,6 @@ function updateProjectAccordingTo (platformConfig, locations) {
manifest.setVersionName(platformConfig.version())
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
.setPackageId(androidPkgName)
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
.write();
// Java file paths shouldn't be hard coded

View File

@@ -23,6 +23,7 @@ var path = require('path');
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) {
@@ -104,6 +105,14 @@ module.exports.run = function (runOptions) {
return new Promise((resolve) => {
const builder = require('./builders/builders').getBuilder();
const buildOptions = require('./build').parseBuildOptions(runOptions, null, self.root);
// Android app bundles cannot be deployed directly to the device
if (buildOptions.packageType === PackageType.BUNDLE) {
const packageTypeErrorMessage = 'Package type "bundle" is not supported during cordova run.';
events.emit('error', packageTypeErrorMessage);
throw packageTypeErrorMessage;
}
resolve(builder.fetchBuildResults(buildOptions.buildType, buildOptions.arch));
}).then(function (buildResults) {
if (resolvedTarget && resolvedTarget.isEmulator) {

View File

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

View File

@@ -37,13 +37,11 @@
android:launchMode="singleTop"
android:theme="@android:style/Theme.DeviceDefault.NoActionBar"
android:windowSoftInputMode="adjustResize"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale">
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode">
<intent-filter android:label="@string/launcher_name">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="__APILEVEL__"/>
</manifest>

View File

@@ -64,6 +64,14 @@ ext {
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
@@ -103,10 +111,12 @@ if (hasBuildExtras2) {
}
// Set property defaults after extension .gradle files.
if (ext.cdvCompileSdkVersion == null) {
ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
//ext.cdvCompileSdkVersion = project.ext.defaultCompileSdkVersion
}
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
@@ -121,7 +131,14 @@ if (ext.cdvReleaseSigningPropertiesFile == null && file('../release-signing.prop
// 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) {
@@ -151,6 +168,8 @@ task cdvPrintProps {
println('cdvVersionCode=' + cdvVersionCode)
println('cdvVersionCodeForceAbiDigit=' + cdvVersionCodeForceAbiDigit)
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
println('cdvMaxSdkVersion=' + cdvMaxSdkVersion)
println('cdvTargetSdkVersion=' + cdvTargetSdkVersion)
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
@@ -170,6 +189,14 @@ android {
if (cdvMinSdkVersion != null) {
minSdkVersion cdvMinSdkVersion
}
if (cdvMaxSdkVersion != null) {
maxSdkVersion cdvMaxSdkVersion
}
if(cdvTargetSdkVersion != null) {
targetSdkVersion cdvTargetSdkVersion
}
}
lintOptions {

View File

@@ -1,5 +1,5 @@
// Platform: android
// 882658ab17740dbdece764e68c1f1f1f44fe3f9d
// 74fdba8b327b2a13b4366dd141b52def96d4cb56
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -8,9 +8,9 @@
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
@@ -19,9 +19,8 @@
under the License.
*/
;(function() {
var PLATFORM_VERSION_BUILD_LABEL = '8.0.0';
var PLATFORM_VERSION_BUILD_LABEL = '8.1.0';
// file: src/scripts/require.js
var require;
var define;
@@ -70,7 +69,7 @@ var define;
};
define = function (id, factory) {
if (modules[id]) {
if (Object.prototype.hasOwnProperty.call(modules, id)) {
throw 'module ' + id + ' already defined';
}
@@ -205,8 +204,8 @@ var cordova = {
* @return object
*/
getOriginalHandlers: function () {
return {'document': {'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener},
'window': {'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener}};
return { 'document': { 'addEventListener': m_document_addEventListener, 'removeEventListener': m_document_removeEventListener },
'window': { 'addEventListener': m_window_addEventListener, 'removeEventListener': m_window_removeEventListener } };
},
/**
* Method to fire event from native code
@@ -324,7 +323,7 @@ module.exports = cordova;
});
// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js
// file: ../cordova-android/cordova-js-src/android/nativeapiprovider.js
define("cordova/android/nativeapiprovider", function(require, exports, module) {
/**
@@ -347,7 +346,7 @@ module.exports = {
});
// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js
// file: ../cordova-android/cordova-js-src/android/promptbasednativeapi.js
define("cordova/android/promptbasednativeapi", function(require, exports, module) {
/**
@@ -386,9 +385,38 @@ var typeMap = {
};
function extractParamName (callee, argIndex) {
return (/.*?\((.*?)\)/).exec(callee)[1].split(', ')[argIndex];
return (/\(\s*([^)]*?)\s*\)/).exec(callee)[1].split(/\s*,\s*/)[argIndex];
}
/**
* Checks the given arguments' types and throws if they are not as expected.
*
* `spec` is a string where each character stands for the required type of the
* argument at the same position. In other words: the character at `spec[i]`
* specifies the required type for `args[i]`. The characters in `spec` are the
* first letter of the required type's name. The supported types are:
*
* Array, Date, Number, String, Function, Object
*
* Lowercase characters specify arguments that must not be `null` or `undefined`
* while uppercase characters allow those values to be passed.
*
* Finally, `*` can be used to allow any type at the corresponding position.
*
* @example
* function foo (arr, opts) {
* // require `arr` to be an Array and `opts` an Object, null or undefined
* checkArgs('aO', 'my.package.foo', arguments);
* // ...
* }
* @param {String} spec - the type specification for `args` as described above
* @param {String} functionName - full name of the callee.
* Used in the error message
* @param {Array|arguments} args - the arguments to be checked against `spec`
* @param {Function} [opt_callee=args.callee] - the recipient of `args`.
* Used to extract parameter names for the error message
* @throws {TypeError} if args do not satisfy spec
*/
function checkArgs (spec, functionName, args, opt_callee) {
if (!moduleExports.enableChecks) {
return;
@@ -879,7 +907,7 @@ module.exports = channel;
});
// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/exec.js
// file: ../cordova-android/cordova-js-src/exec.js
define("cordova/exec", function(require, exports, module) {
/**
@@ -1406,7 +1434,7 @@ exports.reset();
});
// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/platform.js
// file: ../cordova-android/cordova-js-src/platform.js
define("cordova/platform", function(require, exports, module) {
// The last resume event that was received that had the result of a plugin call.
@@ -1516,7 +1544,7 @@ function onMessageFromNative(msg) {
});
// file: /Users/erisu/git/apache/cordova/cordova-android/cordova-js-src/plugin/android/app.js
// file: ../cordova-android/cordova-js-src/plugin/android/app.js
define("cordova/plugin/android/app", function(require, exports, module) {
var exec = require('cordova/exec');
@@ -1902,7 +1930,6 @@ utils.alert = function (msg) {
window.cordova = require('cordova');
// file: src/scripts/bootstrap.js
require('cordova/init');
})();
})();

View File

@@ -66,6 +66,14 @@ ext {
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
@@ -112,6 +120,11 @@ if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.propert
// 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) {
@@ -139,6 +152,8 @@ task cdvPrintProps << {
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
println('cdvVersionCode=' + cdvVersionCode)
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
println('cdvMaxSdkVersion=' + cdvMaxSdkVersion)
println('cdvTargetSdkVersion=' + cdvTargetSdkVersion)
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
@@ -170,6 +185,14 @@ android {
if (cdvMinSdkVersion != null) {
minSdkVersion cdvMinSdkVersion
}
if (cdvMaxSdkVersion != null) {
maxSdkVersion cdvMaxSdkVersion
}
if(cdvTargetSdkVersion != null) {
targetSdkVersion cdvTargetSdkVersion
}
}
lintOptions {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 63 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 139 KiB

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 222 KiB

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 286 KiB

After

Width:  |  Height:  |  Size: 190 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 292 KiB

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 86 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 83 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 84 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.5 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 113 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 121 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 131 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@@ -19,5 +19,4 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.apache.cordova" android:versionName="1.0" android:versionCode="1">
<uses-sdk android:minSdkVersion="19" />
</manifest>

View File

@@ -37,12 +37,19 @@ buildscript {
}
}
allprojects {
repositories {
google()
jcenter()
}
}
apply plugin: 'com.android.library'
apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
group = 'org.apache.cordova'
version = '8.0.0'
version = '8.1.0'
android {
compileSdkVersion cdvCompileSdkVersion
@@ -53,6 +60,11 @@ android {
targetCompatibility JavaVersion.VERSION_1_8
}
// For the Android Cordova Lib, we will hardcode the minSdkVersion and not allow changes.
defaultConfig {
minSdkVersion 19
}
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
@@ -128,9 +140,9 @@ bintray {
licenses = ['Apache-2.0']
labels = ['android', 'cordova', 'phonegap']
version {
name = '8.0.0'
name = '8.1.0'
released = new Date()
vcsTag = '8.0.0'
vcsTag = '8.1.0'
}
}
}

View File

@@ -268,9 +268,11 @@ public class CordovaActivity extends Activity {
if (this.appView == null) {
return;
}
// Force window to have focus, so application always
// receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)
this.getWindow().getDecorView().requestFocus();
if (! this.getWindow().getDecorView().hasFocus()) {
// Force window to have focus, so application always
// receive user input. Workaround for some devices (Samsung Galaxy Note 3 at least)
this.getWindow().getDecorView().requestFocus();
}
this.appView.handleResume(this.keepRunning);
}

View File

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

View File

@@ -57,6 +57,7 @@ class SystemCookieManager implements ICordovaCookieManager {
return cookieManager.getCookie(url);
}
@SuppressWarnings("deprecation")
public void clearCookies() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
cookieManager.removeAllCookies(null);

View File

@@ -250,13 +250,34 @@ public class SystemWebChromeClient extends WebChromeClient {
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
@Override
public boolean onShowFileChooser(WebView webView, final ValueCallback<Uri[]> filePathsCallback, final WebChromeClient.FileChooserParams fileChooserParams) {
// Check if multiple-select is specified
Boolean selectMultiple = false;
if (fileChooserParams.getMode() == WebChromeClient.FileChooserParams.MODE_OPEN_MULTIPLE) {
selectMultiple = true;
}
Intent intent = fileChooserParams.createIntent();
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, selectMultiple);
try {
parentEngine.cordova.startActivityForResult(new CordovaPlugin() {
@Override
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
Uri[] result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent);
LOG.d(LOG_TAG, "Receive file chooser URL: " + result);
Uri[] result = null;
if (resultCode == Activity.RESULT_OK && intent != null) {
if (intent.getClipData() != null) {
// handle multiple-selected files
final int numSelectedFiles = intent.getClipData().getItemCount();
result = new Uri[numSelectedFiles];
for (int i = 0; i < numSelectedFiles; i++) {
result[i] = intent.getClipData().getItemAt(i).getUri();
LOG.d(LOG_TAG, "Receive file chooser URL: " + result[i]);
}
}
else if (intent.getData() != null) {
// handle single-selected file
result = WebChromeClient.FileChooserParams.parseResult(resultCode, intent);
LOG.d(LOG_TAG, "Receive file chooser URL: " + result);
}
}
filePathsCallback.onReceiveValue(result);
}
}, intent, FILECHOOSER_RESULTCODE);

View File

@@ -1,6 +1,6 @@
{
"name": "cordova-android",
"version": "8.0.0",
"version": "8.1.0",
"description": "cordova-android release",
"bin": {
"create": "bin/create"
@@ -29,12 +29,12 @@
"author": "Apache Software Foundation",
"license": "Apache-2.0",
"dependencies": {
"android-versions": "^1.3.0",
"cordova-common": "^3.1.0",
"elementtree": "^0.1.7",
"android-versions": "^1.4.0",
"compare-func": "^1.3.2",
"cordova-common": "^3.2.0",
"nopt": "^4.0.1",
"properties-parser": "^0.3.1",
"q": "^1.4.1",
"q": "^1.5.1",
"shelljs": "^0.5.3"
},
"devDependencies": {
@@ -46,7 +46,8 @@
"eslint-plugin-promise": "^4.0.1",
"eslint-plugin-standard": "^4.0.0",
"jasmine": "^3.3.1",
"nyc": "^13.1.0",
"jasmine-spec-reporter": "^4.2.1",
"nyc": "^14.1.1",
"rewire": "^4.0.1"
},
"engines": {

View File

@@ -4,6 +4,9 @@
"unit/**/*[sS]pec.js",
"e2e/**/*[sS]pec.js"
],
"helpers": [
"helper.js"
],
"stopSpecOnExpectationFailure": false,
"random": false
}

View File

@@ -3,6 +3,9 @@
"spec_files": [
"e2e/**/*[sS]pec.js"
],
"helpers": [
"helper.js"
],
"stopSpecOnExpectationFailure": false,
"random": false
}

31
spec/helper.js Normal file
View File

@@ -0,0 +1,31 @@
/**
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 SpecReporter = require('jasmine-spec-reporter').SpecReporter;
jasmine.getEnv().clearReporters();
jasmine.getEnv().addReporter(new SpecReporter({
spec: {
displayPending: true,
displayDuration: true
},
summary: {
displayDuration: true,
displayStacktrace: true
}
}));

View File

@@ -29,9 +29,6 @@ describe('AndroidManifest', () => {
const ACTIVITY_LAUNCH_MODE = 'singleTop';
const ACTIVITY_NAME = 'MainActivity';
const ACTIVITY_ORIENTATION = 'portrait';
const MIN_SDK_VERSION = '12';
const MAX_SDK_VERSION = '88';
const TARGET_SDK_VERSION = '27';
const DEFAULT_MANIFEST = `<?xml version='1.0' encoding='utf-8'?>
<manifest android:hardwareAccelerated="true" android:versionCode="${VERSION_CODE}" android:versionName="${VERSION_NAME}"
@@ -51,7 +48,6 @@ describe('AndroidManifest', () => {
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="${MIN_SDK_VERSION}" android:maxSdkVersion="${MAX_SDK_VERSION}" android:targetSdkVersion="${TARGET_SDK_VERSION}" />
</manifest>`;
const manifestPath = path.join(os.tmpdir(), `AndroidManifest${Date.now()}.xml`);
@@ -190,78 +186,6 @@ describe('AndroidManifest', () => {
});
});
describe('minSdkVersion', () => {
it('should get minSdkVersion', () => {
expect(manifest.getMinSdkVersion()).toBe(MIN_SDK_VERSION);
});
it('should set minSdkVersion', () => {
const newMinSdkVersion = `${MIN_SDK_VERSION}111`;
manifest.setMinSdkVersion(newMinSdkVersion);
expect(manifest.getMinSdkVersion()).toBe(newMinSdkVersion);
});
it('should create the uses-sdk node if it does not exist when setting minSdkVersion', () => {
const root = manifest.doc.getroot();
root.remove(root.find('./uses-sdk'));
expect(root.find('./uses-sdk')).toBe(null);
manifest.setMinSdkVersion(1);
expect(root.find('./uses-sdk')).not.toBe(null);
expect(manifest.getMinSdkVersion()).toBe(1);
});
});
describe('maxSdkVersion', () => {
it('should get maxSdkVersion', () => {
expect(manifest.getMaxSdkVersion()).toBe(MAX_SDK_VERSION);
});
it('should set maxSdkVersion', () => {
const newMaxSdkVersion = `${MAX_SDK_VERSION}999`;
manifest.setMaxSdkVersion(newMaxSdkVersion);
expect(manifest.getMaxSdkVersion()).toBe(newMaxSdkVersion);
});
it('should create the uses-sdk node if it does not exist when setting maxSdkVersion', () => {
const root = manifest.doc.getroot();
root.remove(root.find('./uses-sdk'));
expect(root.find('./uses-sdk')).toBe(null);
manifest.setMaxSdkVersion(1);
expect(root.find('./uses-sdk')).not.toBe(null);
expect(manifest.getMaxSdkVersion()).toBe(1);
});
});
describe('targetSdkVersion', () => {
it('should get targetSdkVersion', () => {
expect(manifest.getTargetSdkVersion()).toBe(TARGET_SDK_VERSION);
});
it('should set targetSdkVersion', () => {
const newTargetSdkVersion = `${TARGET_SDK_VERSION}555`;
manifest.setTargetSdkVersion(newTargetSdkVersion);
expect(manifest.getTargetSdkVersion()).toBe(newTargetSdkVersion);
});
it('should create the uses-sdk node if it does not exist when setting targetSdkVersion', () => {
const root = manifest.doc.getroot();
root.remove(root.find('./uses-sdk'));
expect(root.find('./uses-sdk')).toBe(null);
manifest.setTargetSdkVersion(1);
expect(root.find('./uses-sdk')).not.toBe(null);
expect(manifest.getTargetSdkVersion()).toBe(1);
});
});
describe('debuggable', () => {
it('should get debuggable', () => {
expect(manifest.getDebuggable()).toBe(true);

View File

@@ -32,7 +32,7 @@ var FIXTURES = path.join(__dirname, '../e2e/fixtures');
var FAKE_PROJECT_DIR = path.join(os.tmpdir(), 'plugin-test-project');
describe('addPlugin method', function () {
var api, Api, fail, gradleBuilder;
var api, Api, gradleBuilder;
beforeEach(function () {
Api = rewire('../../bin/templates/cordova/Api');
@@ -51,24 +51,21 @@ describe('addPlugin method', function () {
api = new Api('android', FAKE_PROJECT_DIR);
fail = jasmine.createSpy('fail');
gradleBuilder = jasmine.createSpyObj('gradleBuilder', ['prepBuildFiles']);
spyOn(builders, 'getBuilder').and.returnValue(gradleBuilder);
});
it('Test#001 : should call gradleBuilder.prepBuildFiles for every plugin with frameworks', function (done) {
api.addPlugin(new PluginInfo(path.join(FIXTURES, 'cordova-plugin-fake'))).catch(fail).fin(function () {
expect(fail).not.toHaveBeenCalled();
const getPluginFixture = name => new PluginInfo(path.join(FIXTURES, name));
it('Test#001 : should call gradleBuilder.prepBuildFiles for every plugin with frameworks', () => {
return api.addPlugin(getPluginFixture('cordova-plugin-fake')).then(() => {
expect(gradleBuilder.prepBuildFiles).toHaveBeenCalled();
done();
});
});
it('Test#002 : shouldn\'t trigger gradleBuilder.prepBuildFiles for plugins without android frameworks', function (done) {
api.addPlugin(new PluginInfo(path.join(FIXTURES, 'cordova-plugin-fake-ios-frameworks'))).catch(fail).fin(function () {
expect(fail).not.toHaveBeenCalled();
it('Test#002 : shouldn\'t trigger gradleBuilder.prepBuildFiles for plugins without android frameworks', () => {
return api.addPlugin(getPluginFixture('cordova-plugin-fake-ios-frameworks')).then(() => {
expect(gradleBuilder.prepBuildFiles).not.toHaveBeenCalled();
done();
});
});
});

View File

@@ -45,16 +45,14 @@ describe('android_sdk', () => {
describe('print_newest_available_sdk_target', () => {
it('should log the newest version', () => {
const sortedIds = ['android-27', 'android-24', 'android-23', 'android-19'];
const logSpy = jasmine.createSpy('log');
spyOn(android_sdk, 'list_targets').and.returnValue(Promise.resolve(sortedIds));
spyOn(sortedIds, 'sort');
android_sdk.__set__({ console: { log: logSpy } });
spyOn(console, 'log');
return android_sdk.print_newest_available_sdk_target().then(() => {
expect(sortedIds.sort).toHaveBeenCalledWith(android_sdk.__get__('sort_by_largest_numerical_suffix'));
expect(logSpy).toHaveBeenCalledWith(sortedIds[0]);
expect(console.log).toHaveBeenCalledWith(sortedIds[0]);
});
});
});

View File

@@ -66,12 +66,54 @@ describe('ProjectBuilder', () => {
expect(args[0]).toBe('cdvBuildDebug');
});
it('should set apk release', () => {
const args = builder.getArgs('release', {
packageType: 'apk'
});
expect(args[0]).withContext(args).toBe('cdvBuildRelease');
});
it('should set apk debug', () => {
const args = builder.getArgs('debug', {
packageType: 'apk'
});
expect(args[0]).withContext(args).toBe('cdvBuildDebug');
});
it('should set bundle release', () => {
const args = builder.getArgs('release', {
packageType: 'bundle'
});
expect(args[0]).withContext(args).toBe(':app:bundleRelease');
});
it('should set bundle debug', () => {
const args = builder.getArgs('debug', {
packageType: 'bundle'
});
expect(args[0]).withContext(args).toBe(':app:bundleDebug');
});
it('should add architecture if it is passed', () => {
const arch = 'unittest';
const args = builder.getArgs('debug', { arch });
expect(args).toContain(`-PcdvBuildArch=${arch}`);
});
it('should clean apk', () => {
const args = builder.getArgs('clean', {
packageType: 'apk'
});
expect(args[0]).toBe('clean');
});
it('should clean bundle', () => {
const args = builder.getArgs('clean', {
packageType: 'bundle'
});
expect(args[0]).toBe('clean');
});
});
describe('runGradleWrapper', () => {
@@ -248,11 +290,11 @@ describe('ProjectBuilder', () => {
};
const expectedResult = ['app-release.apk', 'app-debug.apk', 'app-release-unsigned.apk',
'app-release-arm.apk', 'app-debug-arm.apk', 'app-release-x86.apk', 'app-debug-x86.apk'];
'app-release-arm.apk', 'app-release-x86.apk', 'app-debug-x86.apk', 'app-debug-arm.apk'];
const fsSpy = jasmine.createSpyObj('fs', ['statSync']);
fsSpy.statSync.and.callFake(filename => {
return { mtime: APKs[filename].getTime() };
return { mtime: APKs[filename] };
});
ProjectBuilder.__set__('fs', fsSpy);

View File

@@ -35,42 +35,35 @@ describe('check_reqs', function () {
});
});
describe('check_android', function () {
describe('set ANDROID_HOME if not set', function () {
describe('find and set ANDROID_HOME when ANDROID_HOME and ANDROID_SDK_ROOT is not set', function () {
beforeEach(function () {
delete process.env.ANDROID_HOME;
delete process.env.ANDROID_SDK_ROOT;
});
describe('even if no Android binaries are on the PATH', function () {
beforeEach(function () {
spyOn(shelljs, 'which').and.returnValue(null);
spyOn(fs, 'existsSync').and.returnValue(true);
});
it('it should set ANDROID_HOME on Windows', function (done) {
it('it should set ANDROID_HOME on Windows', () => {
spyOn(check_reqs, 'isWindows').and.returnValue(true);
process.env.LOCALAPPDATA = 'windows-local-app-data';
process.env.ProgramFiles = 'windows-program-files';
return check_reqs.check_android().then(function () {
expect(process.env.ANDROID_HOME).toContain('windows-local-app-data');
}).fail(function (err) {
expect(err).toBeUndefined();
console.log(err);
}).fin(function () {
delete process.env.LOCALAPPDATA;
delete process.env.ProgramFiles;
done();
});
});
it('it should set ANDROID_HOME on Darwin', function (done) {
it('it should set ANDROID_HOME on Darwin', () => {
spyOn(check_reqs, 'isWindows').and.returnValue(false);
spyOn(check_reqs, 'isDarwin').and.returnValue(true);
process.env.HOME = 'home is where the heart is';
return check_reqs.check_android().then(function () {
expect(process.env.ANDROID_HOME).toContain('home is where the heart is');
}).fail(function (err) {
expect(err).toBeUndefined();
console.log(err);
}).fin(function () {
delete process.env.HOME;
done();
});
});
});
@@ -80,7 +73,7 @@ describe('check_reqs', function () {
return path;
});
});
it('should set ANDROID_HOME based on `android` command if command exists in a SDK-like directory structure', function (done) {
it('should set ANDROID_HOME based on `android` command if command exists in a SDK-like directory structure', () => {
spyOn(fs, 'existsSync').and.returnValue(true);
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'android') {
@@ -91,13 +84,9 @@ describe('check_reqs', function () {
});
return check_reqs.check_android().then(function () {
expect(process.env.ANDROID_HOME).toEqual('/android/sdk');
done();
}).fail(function (err) {
expect(err).toBeUndefined();
console.log(err);
});
});
it('should error out if `android` command exists in a non-SDK-like directory structure', function (done) {
it('should error out if `android` command exists in a non-SDK-like directory structure', () => {
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'android') {
return '/just/some/random/path/android';
@@ -105,15 +94,14 @@ describe('check_reqs', function () {
return null;
}
});
return check_reqs.check_android().then(function () {
done.fail();
}).fail(function (err) {
expect(err).toBeDefined();
return check_reqs.check_android().then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('update your PATH to include valid path');
done();
});
});
it('should set ANDROID_HOME based on `adb` command if command exists in a SDK-like directory structure', function (done) {
it('should set ANDROID_HOME based on `adb` command if command exists in a SDK-like directory structure', () => {
spyOn(fs, 'existsSync').and.returnValue(true);
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'adb') {
@@ -124,13 +112,9 @@ describe('check_reqs', function () {
});
return check_reqs.check_android().then(function () {
expect(process.env.ANDROID_HOME).toEqual('/android/sdk');
done();
}).fail(function (err) {
expect(err).toBeUndefined();
console.log(err);
});
});
it('should error out if `adb` command exists in a non-SDK-like directory structure', function (done) {
it('should error out if `adb` command exists in a non-SDK-like directory structure', () => {
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'adb') {
return '/just/some/random/path/adb';
@@ -138,15 +122,14 @@ describe('check_reqs', function () {
return null;
}
});
return check_reqs.check_android().then(function () {
done.fail();
}).fail(function (err) {
expect(err).toBeDefined();
return check_reqs.check_android().then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('update your PATH to include valid path');
done();
});
});
it('should set ANDROID_HOME based on `avdmanager` command if command exists in a SDK-like directory structure', function (done) {
it('should set ANDROID_HOME based on `avdmanager` command if command exists in a SDK-like directory structure', () => {
spyOn(fs, 'existsSync').and.returnValue(true);
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'avdmanager') {
@@ -157,13 +140,9 @@ describe('check_reqs', function () {
});
return check_reqs.check_android().then(function () {
expect(process.env.ANDROID_HOME).toEqual('/android/sdk');
done();
}).fail(function (err) {
expect(err).toBeUndefined();
console.log(err);
});
});
it('should error out if `avdmanager` command exists in a non-SDK-like directory structure', function (done) {
it('should error out if `avdmanager` command exists in a non-SDK-like directory structure', () => {
spyOn(shelljs, 'which').and.callFake(function (cmd) {
if (cmd === 'avdmanager') {
return '/just/some/random/path/avdmanager';
@@ -171,12 +150,11 @@ describe('check_reqs', function () {
return null;
}
});
return check_reqs.check_android().then(function () {
done.fail();
}).fail(function (err) {
expect(err).toBeDefined();
return check_reqs.check_android().then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('update your PATH to include valid path');
done();
});
});
});
@@ -190,15 +168,11 @@ describe('check_reqs', function () {
afterEach(function () {
delete process.env.ANDROID_HOME;
});
it('should add tools/bin,tools,platform-tools to PATH if `avdmanager`,`android`,`adb` is not found', function (done) {
it('should add tools/bin,tools,platform-tools to PATH if `avdmanager`,`android`,`adb` is not found', () => {
return check_reqs.check_android().then(function () {
expect(process.env.PATH).toContain('let the children play' + path.sep + 'tools');
expect(process.env.PATH).toContain('let the children play' + path.sep + 'platform-tools');
expect(process.env.PATH).toContain('let the children play' + path.sep + 'tools' + path.sep + 'bin');
done();
}).fail(function (err) {
expect(err).toBeUndefined();
console.log(err);
});
});
});
@@ -211,7 +185,7 @@ describe('check_reqs', function () {
});
});
describe('check_android_target', function () {
it('should should return full list of supported targets if there is a match to ideal api level', function (done) {
it('should should return full list of supported targets if there is a match to ideal api level', () => {
var deferred = Q.defer();
spyOn(android_sdk, 'list_targets').and.returnValue(deferred.promise);
var fake_targets = ['you are my fire', 'my one desire'];
@@ -220,19 +194,19 @@ describe('check_reqs', function () {
return check_reqs.check_android_target().then(function (targets) {
expect(targets).toBeDefined();
expect(targets).toEqual(fake_targets);
done();
});
});
it('should error out if there is no match between ideal api level and installed targets', function (done) {
it('should error out if there is no match between ideal api level and installed targets', () => {
var deferred = Q.defer();
spyOn(android_sdk, 'list_targets').and.returnValue(deferred.promise);
var fake_targets = ['you are my fire', 'my one desire'];
deferred.resolve(fake_targets);
spyOn(check_reqs, 'get_target').and.returnValue('and i knowwwwwwwwwwww');
return check_reqs.check_android_target().catch(function (err) {
expect(err).toBeDefined();
return check_reqs.check_android_target().then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('Please install Android target');
done();
});
});
});

View File

@@ -106,7 +106,7 @@ describe('Gradle Builder', () => {
expect(emitSpy.calls.argsFor(0)[1]).toContain('Appending configuration item');
});
it('should not detect missing defaults and not call set.', () => {
it('should not detect missing defaults and call set.', () => {
let setSpy = jasmine.createSpy('set');
let getSpy = jasmine.createSpy('get').and.returnValue(true);
@@ -118,10 +118,10 @@ describe('Gradle Builder', () => {
parser._configureProperties(parser._defaults);
expect(getSpy).toHaveBeenCalled();
expect(setSpy).not.toHaveBeenCalled();
expect(setSpy).toHaveBeenCalled();
});
it('should detect default with changed value.', () => {
it('should detect default with changed value to match default and set.', () => {
let setSpy = jasmine.createSpy('set');
let getSpy = jasmine.createSpy('get').and.returnValue('-Xmx512m');
@@ -133,7 +133,23 @@ describe('Gradle Builder', () => {
parser._configureProperties(parser._defaults);
expect(getSpy).toHaveBeenCalled();
expect(setSpy).not.toHaveBeenCalled();
expect(setSpy).toHaveBeenCalled();
expect(emitSpy.calls.argsFor(0)[1]).toContain('Updating Gradle property');
});
it('should detect default with changed value different from default and set.', () => {
let setSpy = jasmine.createSpy('set');
let getSpy = jasmine.createSpy('get').and.returnValue('-Xmx2048m');
parser.gradleFile = {
set: setSpy,
get: getSpy
};
parser._configureProperties({ 'org.gradle.jvmargs': '-Xmx512m' });
expect(getSpy).toHaveBeenCalled();
expect(setSpy).toHaveBeenCalled();
expect(emitSpy.calls.argsFor(0)[1]).toContain('Cordova\'s recommended value is');
});
});

View File

@@ -35,54 +35,42 @@ describe('create', function () {
'ball8.ball8.ball8ball'
];
valid.forEach(function (package_name) {
it('Test#001 : should accept ' + package_name, function (done) {
create.validatePackageName(package_name).fail(fail).done(done);
it('Test#001 : should accept ' + package_name, () => {
return create.validatePackageName(package_name);
});
});
});
describe('failure cases (invalid package names)', function () {
it('should reject empty package names', function (done) {
create.validatePackageName('').then(fail).fail(function (err) {
expect(err).toBeDefined();
function expectPackageNameToBeRejected (name) {
return create.validatePackageName(name).then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('Error validating package name');
}).done(done);
});
}
it('should reject empty package names', () => {
return expectPackageNameToBeRejected('');
});
it('should reject package names containing "class"', function (done) {
create.validatePackageName('com.class.is.bad').then(fail).fail(function (err) {
expect(err).toBeDefined();
expect(err.message).toContain('Error validating package name');
}).done(done);
it('should reject package names containing "class"', () => {
return expectPackageNameToBeRejected('com.class.is.bad');
});
it('should reject package names that do not start with a latin letter', function (done) {
create.validatePackageName('_un.der.score').then(fail).fail(function (err) {
expect(err).toBeDefined();
expect(err.message).toContain('Error validating package name');
}).done(done);
it('should reject package names that do not start with a latin letter', () => {
return expectPackageNameToBeRejected('_un.der.score');
});
it('should reject package names with terms that do not start with a latin letter', function (done) {
create.validatePackageName('un._der.score').then(fail).fail(function (err) {
expect(err).toBeDefined();
expect(err.message).toContain('Error validating package name');
}).done(done);
it('should reject package names with terms that do not start with a latin letter', () => {
return expectPackageNameToBeRejected('un._der.score');
});
it('should reject package names containing non-alphanumeric or underscore characters', function (done) {
create.validatePackageName('th!$.!$.b@d').then(fail).fail(function (err) {
expect(err).toBeDefined();
expect(err.message).toContain('Error validating package name');
}).done(done);
it('should reject package names containing non-alphanumeric or underscore characters', () => {
return expectPackageNameToBeRejected('th!$.!$.b@d');
});
it('should reject package names that do not contain enough dots', function (done) {
create.validatePackageName('therearenodotshere').then(fail).fail(function (err) {
expect(err).toBeDefined();
expect(err.message).toContain('Error validating package name');
}).done(done);
it('should reject package names that do not contain enough dots', () => {
return expectPackageNameToBeRejected('therearenodotshere');
});
it('should reject package names that end with a dot', function (done) {
create.validatePackageName('this.is.a.complete.sentence.').then(fail).fail(function (err) {
expect(err).toBeDefined();
expect(err.message).toContain('Error validating package name');
}).done(done);
it('should reject package names that end with a dot', () => {
return expectPackageNameToBeRejected('this.is.a.complete.sentence.');
});
});
});
@@ -95,29 +83,35 @@ describe('create', function () {
'CordovaLib'
];
valid.forEach(function (project_name) {
it('Test#003 : should accept ' + project_name, function (done) {
create.validateProjectName(project_name).fail(fail).done(done);
it('Test#003 : should accept ' + project_name, () => {
return create.validateProjectName(project_name);
});
});
});
describe('failure cases (invalid project names)', function () {
it('should reject empty project names', function (done) {
create.validateProjectName('').then(fail).fail(function (err) {
expect(err).toBeDefined();
it('should reject empty project names', () => {
return create.validateProjectName('').then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('Project name cannot be empty');
}).done(done);
});
});
it('should reject "CordovaActivity" as a project name', function (done) {
create.validateProjectName('CordovaActivity').then(fail).fail(function (err) {
expect(err).toBeDefined();
it('should reject "CordovaActivity" as a project name', () => {
return create.validateProjectName('CordovaActivity').then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('Project name cannot be CordovaActivity');
}).done(done);
});
});
it('should reject project names that begin with a number', function (done) {
create.validateProjectName('1337').then(fail).fail(function (err) {
expect(err).toBeDefined();
it('should reject project names that begin with a number', () => {
return create.validateProjectName('1337').then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('Project name must not begin with a number');
}).done(done);
});
});
});
});
@@ -131,9 +125,8 @@ describe('create', function () {
var default_templates = path.join(__dirname, '..', '..', 'bin', 'templates', 'project');
var fake_android_target = 'android-1337';
beforeEach(function () {
Manifest_mock.prototype = jasmine.createSpyObj('AndroidManifest instance mock', ['setPackageId', 'setTargetSdkVersion', 'getActivity', 'setName', 'write']);
Manifest_mock.prototype = jasmine.createSpyObj('AndroidManifest instance mock', ['setPackageId', 'getActivity', 'setName', 'write']);
Manifest_mock.prototype.setPackageId.and.returnValue(new Manifest_mock());
Manifest_mock.prototype.setTargetSdkVersion.and.returnValue(new Manifest_mock());
Manifest_mock.prototype.getActivity.and.returnValue(new Manifest_mock());
Manifest_mock.prototype.setName.and.returnValue(new Manifest_mock());
spyOn(create, 'validatePackageName').and.returnValue(Q());
@@ -157,125 +150,138 @@ describe('create', function () {
revert_manifest_mock();
});
describe('parameter values and defaults', function () {
it('should have a default package name of my.cordova.project', function (done) {
it('should have a default package name of my.cordova.project', () => {
config_mock.packageName.and.returnValue(undefined);
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.validatePackageName).toHaveBeenCalledWith('my.cordova.project');
}).fail(fail).done(done);
});
});
it('should use the ConfigParser-provided package name, if exists', function (done) {
it('should use the ConfigParser-provided package name, if exists', () => {
config_mock.packageName.and.returnValue('org.apache.cordova');
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.validatePackageName).toHaveBeenCalledWith('org.apache.cordova');
}).fail(fail).done(done);
});
});
it('should have a default project name of CordovaExample', function (done) {
it('should have a default project name of CordovaExample', () => {
config_mock.name.and.returnValue(undefined);
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.validateProjectName).toHaveBeenCalledWith('CordovaExample');
}).fail(fail).done(done);
});
});
it('should use the ConfigParser-provided project name, if exists', function (done) {
it('should use the ConfigParser-provided project name, if exists', () => {
config_mock.name.and.returnValue('MySweetAppName');
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.validateProjectName).toHaveBeenCalledWith('MySweetAppName');
}).fail(fail).done(done);
});
});
it('should replace any non-word characters (including unicode and spaces) in the ConfigParser-provided project name with underscores', function (done) {
it('should replace any non-word characters (including unicode and spaces) in the ConfigParser-provided project name with underscores', () => {
config_mock.name.and.returnValue('応応応応 hello 用用用用');
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.validateProjectName).toHaveBeenCalledWith('_____hello_____');
}).fail(fail).done(done);
});
});
it('should have a default activity name of MainActivity', function (done) {
it('should have a default activity name of MainActivity', () => {
config_mock.android_activityName.and.returnValue(undefined);
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(Manifest_mock.prototype.setName).toHaveBeenCalledWith('MainActivity');
}).fail(fail).done(done);
});
});
it('should use the activityName provided via options parameter, if exists', function (done) {
it('should use the activityName provided via options parameter, if exists', () => {
config_mock.android_activityName.and.returnValue(undefined);
create.create(project_path, config_mock, { activityName: 'AwesomeActivity' }, events_mock).then(function () {
return create.create(project_path, config_mock, { activityName: 'AwesomeActivity' }, events_mock).then(() => {
expect(Manifest_mock.prototype.setName).toHaveBeenCalledWith('AwesomeActivity');
}).fail(fail).done(done);
});
});
it('should use the ConfigParser-provided activity name, if exists', function (done) {
it('should use the ConfigParser-provided activity name, if exists', () => {
config_mock.android_activityName.and.returnValue('AmazingActivity');
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(Manifest_mock.prototype.setName).toHaveBeenCalledWith('AmazingActivity');
}).fail(fail).done(done);
});
});
});
describe('failure', function () {
it('should fail if the target path already exists', function (done) {
it('should fail if the target path already exists', () => {
fs.existsSync.and.returnValue(true);
create.create(project_path, config_mock, {}, events_mock).then(fail).fail(function (err) {
expect(err).toBeDefined();
return create.create(project_path, config_mock, {}, events_mock).then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toEqual(jasmine.any(Error));
expect(err.message).toContain('Project already exists!');
}).done(done);
});
});
it('should fail if validateProjectName rejects', () => {
const fakeError = new Error();
create.validateProjectName.and.callFake(() => Promise.reject(fakeError));
return create.create(project_path, config_mock, {}, events_mock).then(() => {
fail('Expected promise to be rejected');
}, err => {
expect(err).toBe(fakeError);
});
});
});
describe('happy path', function () {
it('should copy project templates from a specified custom template', function (done) {
create.create(project_path, config_mock, { customTemplate: '/template/path' }, events_mock).then(function () {
it('should copy project templates from a specified custom template', () => {
return create.create(project_path, config_mock, { customTemplate: '/template/path' }, events_mock).then(() => {
expect(shell.cp).toHaveBeenCalledWith('-r', path.join('/template/path', 'assets'), app_path);
expect(shell.cp).toHaveBeenCalledWith('-r', path.join('/template/path', 'res'), app_path);
expect(shell.cp).toHaveBeenCalledWith(path.join('/template/path', 'gitignore'), path.join(project_path, '.gitignore'));
}).fail(fail).done(done);
});
});
it('should copy project templates from the default templates location if no custom template is provided', function (done) {
create.create(project_path, config_mock, {}, events_mock).then(function () {
it('should copy project templates from the default templates location if no custom template is provided', () => {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(shell.cp).toHaveBeenCalledWith('-r', path.join(default_templates, 'assets'), app_path);
expect(shell.cp).toHaveBeenCalledWith('-r', path.join(default_templates, 'res'), app_path);
expect(shell.cp).toHaveBeenCalledWith(path.join(default_templates, 'gitignore'), path.join(project_path, '.gitignore'));
}).fail(fail).done(done);
});
});
it('should copy JS and library assets', function (done) {
create.create(project_path, config_mock, {}, events_mock).then(function () {
it('should copy JS and library assets', () => {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.copyJsAndLibrary).toHaveBeenCalled();
}).fail(fail).done(done);
});
});
it('should create a java src directory based on the provided project package name', function (done) {
it('should create a java src directory based on the provided project package name', () => {
config_mock.packageName.and.returnValue('org.apache.cordova');
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(shell.mkdir).toHaveBeenCalledWith('-p', path.join(app_path, 'java', 'org', 'apache', 'cordova'));
}).fail(fail).done(done);
});
});
it('should copy, rename and interpolate the template Activity java class with the project-specific activity name and package name', function (done) {
it('should copy, rename and interpolate the template Activity java class with the project-specific activity name and package name', () => {
config_mock.packageName.and.returnValue('org.apache.cordova');
config_mock.android_activityName.and.returnValue('CEEDEEVEE');
var activity_path = path.join(app_path, 'java', 'org', 'apache', 'cordova', 'CEEDEEVEE.java');
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(shell.cp).toHaveBeenCalledWith('-f', path.join(default_templates, 'Activity.java'), activity_path);
expect(shell.sed).toHaveBeenCalledWith('-i', /__ACTIVITY__/, 'CEEDEEVEE', activity_path);
expect(shell.sed).toHaveBeenCalledWith('-i', /__ID__/, 'org.apache.cordova', activity_path);
}).fail(fail).done(done);
});
});
it('should interpolate the project name into strings.xml', function (done) {
it('should interpolate the project name into strings.xml', () => {
config_mock.name.and.returnValue('IncredibleApp');
create.create(project_path, config_mock, {}, events_mock).then(function () {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(shell.sed).toHaveBeenCalledWith('-i', /__NAME__/, 'IncredibleApp', path.join(app_path, 'res', 'values', 'strings.xml'));
}).fail(fail).done(done);
});
});
it('should copy template scripts into generated project', function (done) {
create.create(project_path, config_mock, {}, events_mock).then(function () {
it('should copy template scripts into generated project', () => {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.copyScripts).toHaveBeenCalledWith(project_path);
}).fail(fail).done(done);
});
});
it('should copy build rules / gradle files into generated project', function (done) {
create.create(project_path, config_mock, {}, events_mock).then(function () {
it('should copy build rules / gradle files into generated project', () => {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.copyBuildRules).toHaveBeenCalledWith(project_path);
}).fail(fail).done(done);
});
});
it('should write project.properties file with project details and target API', function (done) {
create.create(project_path, config_mock, {}, events_mock).then(function () {
it('should write project.properties file with project details and target API', () => {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.writeProjectProperties).toHaveBeenCalledWith(project_path, fake_android_target);
}).fail(fail).done(done);
});
});
it('should prepare build files', function (done) {
create.create(project_path, config_mock, {}, events_mock).then(function () {
it('should prepare build files', () => {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.prepBuildFiles).toHaveBeenCalledWith(project_path);
}).fail(fail).done(done);
});
});
});
});

View File

@@ -3,6 +3,9 @@
"spec_files": [
"unit/**/*[sS]pec.js"
],
"helpers": [
"helper.js"
],
"stopSpecOnExpectationFailure": false,
"random": true
}

View File

@@ -196,16 +196,27 @@ describe('run', () => {
expect(emulatorSpyObj.install).toHaveBeenCalledWith(emulatorTarget, { apkPaths: [], buildType: 'debug' });
});
});
it('should fail with the error message if --packageType=bundle setting is used', () => {
const deviceList = ['testDevice1', 'testDevice2'];
getInstallTargetSpy.and.returnValue(null);
deviceSpyObj.list.and.returnValue(Promise.resolve(deviceList));
return run.run({ argv: ['--packageType=bundle'] }).then(
() => fail('Expected error to be thrown'),
err => expect(err).toContain('Package type "bundle" is not supported during cordova run.')
);
});
});
describe('help', () => {
it('should print out usage and help', () => {
const logSpy = jasmine.createSpy();
const procStub = { exit: _ => null, cwd: _ => '', argv: ['', ''] };
run.__set__({ console: { log: logSpy }, process: procStub });
spyOn(console, 'log');
spyOn(process, 'exit');
run.help();
expect(logSpy).toHaveBeenCalledWith(jasmine.stringMatching(/^Usage:/));
expect(console.log).toHaveBeenCalledWith(jasmine.stringMatching(/^Usage:/));
});
});
});