Compare commits

...

18 Commits

Author SHA1 Message Date
Erisu
f12080b7e2 android-v10.1.2 Updated version and RELEASENOTES.md for release 10.1.2 2022-04-11 22:01:02 +09:00
Norman Breau
51291f8985 chore: update package-lock to satisfy npm audit (#1413) 2022-04-06 11:59:21 -03:00
Lars Mikkelsen
112f0a61a8 fix: detect JAVA_HOME with Java 11 (#1406) 2022-03-17 20:38:04 -03:00
Norman Breau
6d3ce211dd fix(GH-1391): Reword minimum build tools version to make it more clear what is actually required. (#1401) 2022-02-22 10:14:22 -04:00
Tiago Pereira
f100809bf3 fix: escape strings.xml app name (#1384) 2022-02-08 11:29:36 +09:00
エリス
a1ed1c0af7 feat(AndroidManifest): explicitly define the activity attribute android:exported (#1372) 2021-10-28 17:29:55 +09:00
Norman Breau
05e3e3cf8d chore: npmrc (#1348) 2021-09-17 09:54:59 -03:00
Erisu
8a957fb9c9 chore: bump version 10.1.2-dev 2021-09-13 20:17:31 +09:00
Erisu
e188c61c86 android-v10.1.1 Updated version and RELEASENOTES.md for release 10.1.1 2021-09-13 15:56:27 +09:00
エリス
ca19084b1c fix(PluginManager): AllowNavigation default policy to handle scheme & hostname (#1349) 2021-09-13 15:48:02 +09:00
Joel Skrepnek
aea6b7f6f4 fix(AllowListPlugin): Safely handle default allow navigation policy in allow request (#1342) 2021-09-09 14:58:58 +09:00
エリス
7a67e00b9f fix(PluginManager): AllowBridgeAccess default policy to handle scheme & hostname (#1332) 2021-09-07 19:52:23 +09:00
Erisu
dc4e065f61 chore: bump version 10.1.1-dev 2021-08-13 13:42:59 +09:00
Erisu
c3fd6bca4a android-v10.1.0 Updated version and RELEASENOTES.md for release 10.1.0 2021-08-13 13:26:31 +09:00
Alexis THOMAS
13bd3f4a9f feat: unify create default values & stop project name transform (#1213) 2021-08-13 12:52:30 +09:00
Alexis THOMAS
09c75237d9 fix: display project name in Android Studio (#1214) 2021-08-13 12:08:18 +09:00
Alexis THOMAS
b5e79b5a4d doc: update README about development & testing (#1308)
Co-authored-by: エリス <erisu@users.noreply.github.com>
2021-08-13 11:28:47 +09:00
Mosab A
5db850890d feat: bump ANDROIDX_APP_COMPAT@1.3.1 (#1306) 2021-08-02 16:34:06 +09:00
17 changed files with 5505 additions and 764 deletions

2
.npmrc Normal file
View File

@@ -0,0 +1,2 @@
registry=https://registry.npmjs.org

View File

@@ -28,22 +28,44 @@
Cordova Android is an Android application library that allows for Cordova-based projects to be built for the Android Platform. Cordova based applications are, 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)](https://apache.org/).
## Requirements
- Java Development Kit (JDK) 11
- [Android SDK](https://developer.android.com/)
* Java Development Kit (JDK) 11
* [Android SDK](https://developer.android.com/)
* [Node.js](https://nodejs.org)
## Cordova Android Developer Tools
## Create a Cordova project
Use the [Cordova command-line tool](https://www.npmjs.com/package/cordova) to create projects and install plugins.
Follow the instructions in the [**Create your first Cordova app**](https://cordova.apache.org/docs/en/latest/guide/cli/index.html) section of [Apache Cordova Docs](https://cordova.apache.org/docs/en/latest/)
## Using Android Studio
To use a **shared framework**, for example in development, link the appropriate cordova-android platform folder path:
1. Create a project
2. Import it via "Non-Android Studio Project"
```bash
cordova platform add --link /path/to/cordova-android
```
## Running the Native Tests
## Updating a Cordova project
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!
When you install a new version of the [`Cordova CLI`](https://www.npmjs.com/package/cordova) that pins a new version of the [`Cordova-Android`](https://www.npmjs.com/package/cordova-android) platform, you can follow these simple upgrade steps within your project:
```bash
cordova platform rm android
cordova platform add android
```
## Debugging in Android Studio
Import project in Android Studio through _File > Open_ and targeting `/path/to/your-cdv-project/platforms/android/`.
## How to Test Repo Development
```bash
npm install
npm test
```
## Further reading
* [Apache Cordova](https://cordova.apache.org/)

View File

@@ -20,6 +20,47 @@
-->
## Release Notes for Cordova (Android)
### 10.1.2 (Apr 11, 2022)
**Fixes:**
* [GH-1372](https://github.com/apache/cordova-android/pull/1372) fix(`AndroidManifest`): explicitly define the `activity` attribute `android:exported`
* [GH-1406](https://github.com/apache/cordova-android/pull/1406) fix: detect `JAVA_HOME` with Java 11
* [GH-1401](https://github.com/apache/cordova-android/pull/1401) fix(GH-1391): Reword minimum build tools version to make it more clear what is actually required.
* [GH-1384](https://github.com/apache/cordova-android/pull/1384) fix: escape `strings.xml` app name
**Chores:**
* [GH-1413](https://github.com/apache/cordova-android/pull/1413) chore: update `package-lock` to satisfy `npm audit`
* [GH-1348](https://github.com/apache/cordova-android/pull/1348) chore: `npmrc`
### 10.1.1 (Sep 13, 2021)
**Fixes:**
* [GH-1349](https://github.com/apache/cordova-android/pull/1349) fix(`PluginManager`): `AllowNavigation` default policy to handle scheme & hostname
* [GH-1342](https://github.com/apache/cordova-android/pull/1342) fix(`AllowListPlugin`): Safely handle default allow navigation policy in allow request
* [GH-1332](https://github.com/apache/cordova-android/pull/1332) fix(`PluginManager`): `AllowBridgeAccess` default policy to handle scheme & hostname
### 10.1.0 (Aug 13, 2021)
**Features:**
* [GH-1213](https://github.com/apache/cordova-android/pull/1213) feat: unify `create` default values & stop project name transform
* [GH-1306](https://github.com/apache/cordova-android/pull/1306) feat: bump `ANDROIDX_APP_COMPAT@1.3.1`
* [GH-1303](https://github.com/apache/cordova-android/pull/1303) feat: bump `Google Services Gradle Plugin@4.3.8`
* [GH-1302](https://github.com/apache/cordova-android/pull/1302) feat: bump `kotlin@1.5.21`
* [GH-1298](https://github.com/apache/cordova-android/pull/1298) feat: support `http` w/ `content` `src` fix
**Fixes:**
* [GH-1214](https://github.com/apache/cordova-android/pull/1214) fix: display project name in Android Studio
* [GH-1300](https://github.com/apache/cordova-android/pull/1300) fix: fall back to project root `repositories.gradle`
**Docs:**
* [GH-1308](https://github.com/apache/cordova-android/pull/1308) doc: update `README` about development & testing
### 10.0.1 (Jul 27, 2021)
**Fixes:**

View File

@@ -5,7 +5,7 @@
"MIN_BUILD_TOOLS_VERSION": "30.0.3",
"AGP_VERSION": "4.2.2",
"KOTLIN_VERSION": "1.5.21",
"ANDROIDX_APP_COMPAT_VERSION": "1.3.0",
"ANDROIDX_APP_COMPAT_VERSION": "1.3.1",
"ANDROIDX_WEBKIT_VERSION": "1.4.0",
"GRADLE_PLUGIN_GOOGLE_SERVICES_VERSION": "4.3.8",
"IS_GRADLE_PLUGIN_GOOGLE_SERVICES_ENABLED": false,

View File

@@ -64,16 +64,16 @@ String doFindLatestInstalledBuildTools(String minBuildToolsVersionString) {
if (highestBuildToolsVersion == null) {
throw new RuntimeException("""
No installed build tools found. Install the Android build tools
version ${minBuildToolsVersionString} or higher.
No installed build tools found. Please install the Android build tools
version ${minBuildToolsVersionString}.
""".replaceAll(/\s+/, ' ').trim())
}
if (highestBuildToolsVersion.isLowerThan(minBuildToolsVersionString)) {
throw new RuntimeException("""
No usable Android build tools found. Highest ${minBuildToolsVersion.getMajor()}.x installed version is
${highestBuildToolsVersion.getOriginalString()}; minimum version
required is ${minBuildToolsVersionString}.
${highestBuildToolsVersion.getOriginalString()}; Recommended version
is ${minBuildToolsVersionString}.
""".replaceAll(/\s+/, ' ').trim())
}

View File

@@ -82,11 +82,6 @@ public class AllowListPlugin extends CordovaPlugin {
if (strNode.equals("content")) {
String startPage = xml.getAttributeValue(null, "src");
allowedNavigations.addAllowListEntry(startPage, false);
// Allow origin for WebViewAssetLoader
if (!this.prefs.getBoolean("AndroidInsecureFileModeEnabled", false)) {
allowedNavigations.addAllowListEntry("https://" + this.prefs.getString("hostname", "localhost"), false);
}
} else if (strNode.equals("allow-navigation")) {
String origin = xml.getAttributeValue(null, "href");
if ("*".equals(origin)) {
@@ -127,7 +122,7 @@ public class AllowListPlugin extends CordovaPlugin {
@Override
public Boolean shouldAllowRequest(String url) {
return (this.shouldAllowNavigation(url) || this.allowedRequests.isUrlAllowListed(url))
return (Boolean.TRUE.equals(this.shouldAllowNavigation(url)) || this.allowedRequests.isUrlAllowListed(url))
? true
: null; // default policy
}

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 = "10.1.0-dev";
public static final String CORDOVA_VERSION = "10.1.2";
void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences);

View File

@@ -41,6 +41,12 @@ import android.os.Build;
*/
public class PluginManager {
private static String TAG = "PluginManager";
// @todo same as ConfigXmlParser. Research centralizing ideas, maybe create CordovaConstants
private static String SCHEME_HTTPS = "https";
// @todo same as ConfigXmlParser. Research centralizing ideas, maybe create CordovaConstants
private static String DEFAULT_HOSTNAME = "localhost";
private static final int SLOW_EXEC_WARNING_THRESHOLD = Debug.isDebuggerConnected() ? 60 : 16;
// List of service entries
@@ -366,6 +372,24 @@ public class PluginManager {
}
}
/**
* @todo should we move this somewhere public and accessible by all plugins?
* For now, it is placed where it is used and kept private so we can decide later and move without causing a breaking change.
* An ideal location might be in the "ConfigXmlParser" at the time it generates the "launchUrl".
*
* @todo should we be restrictive on the "file://" return? e.g. "file:///android_asset/www/"
* Would be considered as a breaking change if we apply a more granular check.
*/
private String getLaunchUrlPrefix() {
if (!app.getPreferences().getBoolean("AndroidInsecureFileModeEnabled", false)) {
String scheme = app.getPreferences().getString("scheme", SCHEME_HTTPS).toLowerCase();
String hostname = app.getPreferences().getString("hostname", DEFAULT_HOSTNAME);
return scheme + "://" + hostname + '/';
}
return "file://";
}
/**
* Called when the webview is going to request an external resource.
*
@@ -431,7 +455,7 @@ public class PluginManager {
}
// Default policy:
return url.startsWith("file://") || url.startsWith("about:blank");
return url.startsWith(getLaunchUrlPrefix()) || url.startsWith("about:blank");
}
@@ -452,7 +476,7 @@ public class PluginManager {
}
// Default policy:
return url.startsWith("file://");
return url.startsWith(getLaunchUrlPrefix());
}
/**

View File

@@ -183,21 +183,29 @@ class ProjectBuilder {
checkAndCopy(subProjects[i], this.root);
}
}
var name = this.extractRealProjectNameFromManifest();
var projectName = 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 libName = realDir.replace(projectName + '-', '');
var str = 'include ":' + libName + '"\n';
if (realDir.indexOf(name + '-') !== -1) {
if (realDir.indexOf(projectName + '-') !== -1) {
str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n';
}
return str;
});
// Update subprojects within settings.gradle.
fs.writeFileSync(path.join(this.root, 'settings.gradle'),
'// GENERATED FILE - DO NOT EDIT\n' +
'include ":"\n' + settingsGradlePaths.join(''));
'apply from: "cdv-gradle-name.gradle"\n' +
'include ":"\n' +
settingsGradlePaths.join(''));
// Touch empty cdv-gradle-name.gradle file if missing.
if (!fs.pathExistsSync(path.join(this.root, 'cdv-gradle-name.gradle'))) {
fs.writeFileSync(path.join(this.root, 'cdv-gradle-name.gradle'), '');
}
// Update dependencies within build.gradle.
var buildGradle = fs.readFileSync(path.join(this.root, 'app', 'build.gradle'), 'utf8');
@@ -214,7 +222,7 @@ class ProjectBuilder {
};
subProjects.forEach(function (p) {
events.emit('log', 'Subproject Path: ' + p);
var libName = p.replace(/[/\\]/g, ':').replace(name + '-', '');
var libName = p.replace(/[/\\]/g, ':').replace(projectName + '-', '');
if (libName !== 'app') {
depsList += ' implementation(project(path: ":' + libName + '"))';
insertExclude(p);

View File

@@ -37,7 +37,6 @@ exports.copyScripts = copyScripts;
exports.copyBuildRules = copyBuildRules;
exports.writeProjectProperties = writeProjectProperties;
exports.prepBuildFiles = prepBuildFiles;
exports.writeNameForAndroidStudio = writeNameForAndroidStudio;
function getFrameworkDir (projectPath, shared) {
return shared ? path.join(ROOT, 'framework') : path.join(projectPath, 'CordovaLib');
@@ -176,19 +175,6 @@ function validateProjectName (project_name) {
return Promise.resolve();
}
/**
* Write the name of the app in "platforms/android/.idea/.name" so that Android Studio can show that name in the
* project listing. This is helpful to quickly look in the Android Studio listing if there are so many projects in
* Android Studio.
*
* https://github.com/apache/cordova-android/issues/1172
*/
function writeNameForAndroidStudio (project_path, project_name) {
const ideaPath = path.join(project_path, '.idea');
fs.ensureDirSync(ideaPath);
fs.writeFileSync(path.join(ideaPath, '.name'), project_name);
}
/**
* Creates an android application with the given options.
*
@@ -211,15 +197,14 @@ exports.create = function (project_path, config, options, events) {
options = options || {};
// Set default values for path, package and name
project_path = path.relative(process.cwd(), (project_path || 'CordovaExample'));
project_path = path.relative(process.cwd(), project_path);
// Check if project already exists
if (fs.existsSync(project_path)) {
return Promise.reject(new CordovaError('Project already exists! Delete and recreate'));
}
var package_name = config.android_packageName() || config.packageName() || 'my.cordova.project';
var project_name = config.name()
? config.name().replace(/[^\w.]/g, '_') : 'CordovaExample';
var package_name = config.android_packageName() || config.packageName() || 'io.cordova.helloCordova';
var project_name = config.name() || 'Hello Cordova';
var safe_activity_name = config.android_activityName() || options.activityName || 'MainActivity';
var target_api = check_reqs.get_target(project_path);
@@ -229,7 +214,7 @@ exports.create = function (project_path, config, options, events) {
.then(function () {
return exports.validateProjectName(project_name);
}).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', '\tPath: ' + project_path);
events.emit('log', '\tPackage: ' + package_name);
@@ -270,7 +255,7 @@ exports.create = function (project_path, config, options, events) {
fs.ensureDirSync(activity_dir);
fs.copySync(path.join(project_template_dir, 'Activity.java'), activity_path);
utils.replaceFileContents(activity_path, /__ACTIVITY__/, safe_activity_name);
utils.replaceFileContents(path.join(app_path, 'res', 'values', 'strings.xml'), /__NAME__/, project_name);
utils.replaceFileContents(path.join(app_path, 'res', 'values', 'strings.xml'), /__NAME__/, utils.escape(project_name));
utils.replaceFileContents(activity_path, /__ID__/, package_name);
var manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
@@ -286,7 +271,6 @@ exports.create = function (project_path, config, options, events) {
// Link it to local android install.
exports.writeProjectProperties(project_path, target_api);
exports.prepBuildFiles(project_path);
exports.writeNameForAndroidStudio(project_path, project_name);
events.emit('log', generateDoneMessage('create', options.link));
}).then(() => project_path);
};

3
lib/env/java.js vendored
View File

@@ -99,7 +99,8 @@ const java = {
} else {
// See if we can derive it from javac's location.
var maybeJavaHome = path.dirname(path.dirname(javacPath));
if (fs.existsSync(path.join(maybeJavaHome, 'lib', 'tools.jar'))) {
if (fs.existsSync(path.join(maybeJavaHome, 'bin', 'java')) ||
fs.existsSync(path.join(maybeJavaHome, 'bin', 'java.exe'))) {
environment.JAVA_HOME = maybeJavaHome;
} else {
throw new CordovaError(default_java_error_msg);

View File

@@ -273,6 +273,11 @@ function updateProjectAccordingTo (platformConfig, locations) {
fs.writeFileSync(locations.strings, strings.write({ indent: 4 }), 'utf-8');
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
// Update app name for gradle project
fs.writeFileSync(path.join(locations.root, 'cdv-gradle-name.gradle'),
'// GENERATED FILE - DO NOT EDIT\n' +
'rootProject.name = "' + name.replace(/[/\\:<>"?*|]/g, '_') + '"\n');
// Java packages cannot support dashes
var androidPkgName = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');

View File

@@ -66,3 +66,21 @@ exports.forgivingWhichSync = (cmd) => {
exports.isWindows = () => os.platform() === 'win32';
exports.isDarwin = () => os.platform() === 'darwin';
const UNESCAPED_REGEX = /[&<>"']/g;
const escapes = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
'"': '&quot;',
"'": '&#39;'
};
/**
* Converts the characters "&", "<", ">", '"' and "'" in the given string to
* their corresponding escaped value
* @param {string} str the string to be escaped
* @returns the escaped string
*/
exports.escape = (str) => UNESCAPED_REGEX.test(str) ? str.replace(UNESCAPED_REGEX, (key) => escapes[key]) : str;

6022
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cordova-android",
"version": "10.1.0-dev",
"version": "10.1.2",
"description": "cordova-android release",
"main": "lib/Api.js",
"repository": "github:apache/cordova-android",

View File

@@ -132,7 +132,6 @@ describe('create', function () {
spyOn(create, 'copyBuildRules');
spyOn(create, 'writeProjectProperties');
spyOn(create, 'prepBuildFiles');
spyOn(create, 'writeNameForAndroidStudio');
revert_manifest_mock = create.__set__('AndroidManifest', Manifest_mock);
spyOn(fs, 'existsSync').and.returnValue(false);
spyOn(fs, 'copySync');
@@ -148,10 +147,10 @@ describe('create', function () {
});
describe('parameter values and defaults', function () {
it('should have a default package name of my.cordova.project', () => {
it('should have a default package name of io.cordova.helloCordova', () => {
config_mock.packageName.and.returnValue(undefined);
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.validatePackageName).toHaveBeenCalledWith('my.cordova.project');
expect(create.validatePackageName).toHaveBeenCalledWith('io.cordova.helloCordova');
});
});
@@ -162,10 +161,10 @@ describe('create', function () {
});
});
it('should have a default project name of CordovaExample', () => {
it('should have a default project name of Hello Cordova', () => {
config_mock.name.and.returnValue(undefined);
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.validateProjectName).toHaveBeenCalledWith('CordovaExample');
expect(create.validateProjectName).toHaveBeenCalledWith('Hello Cordova');
});
});
@@ -176,10 +175,10 @@ describe('create', function () {
});
});
it('should replace any non-word characters (including unicode and spaces) in the ConfigParser-provided project name with underscores', () => {
it('should keep non-word characters (including unicode and spaces) in the ConfigParser-provided project name', () => {
config_mock.name.and.returnValue('応応応応 hello 用用用用');
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.validateProjectName).toHaveBeenCalledWith('_____hello_____');
expect(create.validateProjectName).toHaveBeenCalledWith('応応応応 hello 用用用用');
});
});
@@ -276,6 +275,13 @@ describe('create', function () {
});
});
it('should interpolate the escaped project name into strings.xml', () => {
config_mock.name.and.returnValue('<Incredible&App>');
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(utils.replaceFileContents).toHaveBeenCalledWith(path.join(app_path, 'res', 'values', 'strings.xml'), /__NAME__/, '&lt;Incredible&amp;App&gt;');
});
});
it('should copy template scripts into generated project', () => {
return create.create(project_path, config_mock, {}, events_mock).then(() => {
expect(create.copyScripts).toHaveBeenCalledWith(project_path);
@@ -301,24 +307,4 @@ describe('create', function () {
});
});
});
describe('writeNameForAndroidStudio', () => {
const project_path = path.join('some', 'path');
const appName = 'Test Cordova';
beforeEach(function () {
spyOn(fs, 'ensureDirSync');
spyOn(fs, 'writeFileSync');
});
it('should call ensureDirSync with path', () => {
create.writeNameForAndroidStudio(project_path, appName);
expect(fs.ensureDirSync).toHaveBeenCalledWith(path.join(project_path, '.idea'));
});
it('should call writeFileSync with content', () => {
create.writeNameForAndroidStudio(project_path, appName);
expect(fs.writeFileSync).toHaveBeenCalledWith(path.join(project_path, '.idea', '.name'), appName);
});
});
});

View File

@@ -37,7 +37,8 @@
android:launchMode="singleTop"
android:theme="@style/Theme.AppCompat.NoActionBar"
android:windowSoftInputMode="adjustResize"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode">
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|smallestScreenSize|screenLayout|uiMode"
android:exported="true">
<intent-filter android:label="@string/launcher_name">
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />