Compare commits

...

36 Commits

Author SHA1 Message Date
jcesarmobile
468c35e99f java 17 2023-04-15 00:21:12 +02:00
jcesarmobile
d308a9a9b5 merge master 2023-04-15 00:20:24 +02:00
喻志强
7efe90faac fix(BuildHelper): get package name from ApplicationInfo (#1575) 2023-04-14 10:15:55 -03:00
Norman Breau
5b546a27e6 deprecate: CoreAndroid.getBuildConfigValue (#1597) 2023-04-14 10:15:09 -03:00
Norman Breau
2252c09a49 feat: bump default kotlin to version 1.7.21 (#1594)
The rationale is based on the Gradle Compatibility Matrix: https://docs.gradle.org/current/userguide/compatibility.html

1.7.21 is the current latest version of the 1.7 Kotlin release.
2023-04-14 07:17:15 -03:00
Norman Breau
3a9c87d3b8 fix(test): Native test namespace refactor (#1595) 2023-04-14 18:47:03 +09:00
jcesarmobile
fd13993c89 feat!: Upgrade to Gradle and AGP 8 2023-04-14 10:38:04 +02:00
エリス
a9d4d4ebd2 feat!: bump Gradle 7.6 & AGP 7.4.2 (#1539)
* feat: bump gradle 7.6
* feat: bump android gradle plugin 7.3.1
* feat: bump android gradle plugin 7.4.2
* fix!: move android package name to build.gradle namespace
* fix!: remove deprecated package name from AndroidManifest
* fix: package name
* fix: rename CordovaGradleConfigParser's _save to write
* test: fix CordovaGradleConfigParser related specs
* fix: test refactoring for gradle namespace
* fix: accidental variable naming mixing

---------

Co-authored-by: Norman Breau <norman@nbsolutions.ca>
2023-04-12 14:39:47 +09:00
Alexis THOMAS
841710edf7 fix: ANDROID_HOME is the new default, to check first and give advice (#1471) 2023-04-09 20:43:11 -03:00
Mahendra Liya
016018513e feat: add monochrome app icon support (#1550)
* Added the monochrome version for Cordova's icon

* android: modified the ic_launcher.xml to include the monochrome drawable

* android: replaced monochrome image with  rasterized images

* android: Added support for custom monochrome icons defined in config.xml

* android: Updated Tests

* android: wrapped inside if(monochrome)

* android: Update templates/project/res/mipmap-hdpi-v26/ic_launcher.xml

Co-authored-by: エリス <erisu@users.noreply.github.com>

* Update lib/prepare.js

Co-authored-by: エリス <erisu@users.noreply.github.com>

* android: Update templates/project/res/mipmap-ldpi-v26/ic_launcher.xml

Co-authored-by: エリス <erisu@users.noreply.github.com>

* android: Update templates/project/res/mipmap-mdpi-v26/ic_launcher.xml

Co-authored-by: エリス <erisu@users.noreply.github.com>

* android Update templates/project/res/mipmap-xhdpi-v26/ic_launcher.xml

Co-authored-by: エリス <erisu@users.noreply.github.com>

* android: Update templates/project/res/mipmap-xxhdpi-v26/ic_launcher.xml

Co-authored-by: エリス <erisu@users.noreply.github.com>

* android: Update templates/project/res/mipmap-xxxhdpi-v26/ic_launcher.xml

Co-authored-by: エリス <erisu@users.noreply.github.com>

* android: Update lib/prepare.js

Co-authored-by: エリス <erisu@users.noreply.github.com>

* Resolved lint errors

* fix: test failure

---------

Co-authored-by: エリス <erisu@users.noreply.github.com>
2023-04-09 20:41:38 -03:00
Norman Breau
a78fad1783 feat: InspectableWebview preference (#1589) 2023-04-09 20:41:00 -03:00
Norman Breau
b91639dbb5 refactor: Removed obsolete version code checks (#1588)
Now that our Min SDK is 24, testing for >= N (API 24) and >= M (API 22) is obsolete as it will always be true.
Simplify the codebase by removing the conditions and keeping only the API 24 or later codepath.
2023-04-08 15:32:19 -03:00
エリス
c2013439bc dep: bump npm dependencies (#1587)
* dep: bump npm dependencies
  - fs-extra@11.1.1
  - nopt@7.1.0
  - @cordova/eslint-config@5.0.0
  - jasmine@4.6.0
* chore: apply eslint fix
2023-04-06 12:35:00 +09:00
Norman Breau
d4bfd5079b fix(GH-1432): Default content src when content tag is missing (#1573) 2023-03-21 13:24:13 -03:00
Norman Breau
dbddbf253b feat!: Bump min SDK to 24 (#1571)
Rationale:
API 22 & API 23 both account for an insignificant part of the market share.
While API 24 - API 26 has similar market share, we felt that bumping to API 26
from API 22 is too large of a jump.

Legacy devices may be completely out of support by Google and may not be able
to receive the latest webview version. As of writing, Chromium's latest
tag shows they are using a Min SDK version of 24. (Ref: https://chromium.googlesource.com/chromium/src/+/refs/tags/113.0.5653.1/build/config/android/config.gni#46)

Based on AOSP emulators, API 24 (Android 7.0) will ship with
Chrome 52 webview, which has good support for ECMAscript 2015 (ES6) (Ref: https://caniuse.com/?search=es6)

While in most cases, app users will likely have a modern webview vesion installed, this means
you can be confident that the app user will have a chrome webview version with good ES6 support,
even if they happen to be running on a factory versioned device.

See the mailing thread for the full discussion:
https://lists.apache.org/thread/zcgof080hdzzo2j96mjz0qpj0gotmn57
2023-03-16 19:45:01 -03:00
エリス
04723eb8f3 feat: bump androidx.appcompat.appcompat 1.6.1 (#1568) 2023-03-11 16:41:38 +09:00
エリス
862d33694e feat: bump androidx.webkit.webkit 1.6.0 (#1567) 2023-03-11 12:19:16 +09:00
エリス
fe3940a73c feat: bump androidx.webkit.webkit 1.5.0 (#1545) 2023-03-11 03:07:19 +09:00
エリス
81c678c58d feat: bump com.google.gms.google-services 4.3.15 (#1547)
* feat: bump com.google.gms.google-services 4.3.14
* feat: bump com.google.gms.google-services 4.3.15
Co-authored-by: jcesarmobile <jcesarmobile@gmail.com>
2023-03-11 03:06:56 +09:00
エリス
bfe086a2d7 feat: bump androidx.core.core-splashscreen 1.0.0 (#1546) 2023-03-11 02:51:33 +09:00
エリス
8fb707567a feat: bump androidx.appcompat.appcompat 1.5.1 (#1544) 2023-03-11 02:45:42 +09:00
エリス
992a60a434 feat!: bump target sdk & build tools for SDK 33 support (#1538)
* feat!: bump target sdk version 33
* feat!: bump minimum build tools version 33.0.1
* feat!: bump minimum build tools version 33.0.2
2023-03-10 12:12:17 +09:00
エリス
2318ef58ad dep(npm)!: bump acceptable modules w/ rebuilt package-lock (#1541)
* dep(npm)!: bump acceptable modules
* chore: rebuilt package-lock
2023-03-09 18:57:19 +09:00
エリス
968bd85cc3 feat!: bump node engine requirement >=16.13.0 (#1540) 2023-03-09 18:40:16 +09:00
エリス
9ef3ee9539 dep(npm)!: bump cordova-common@5.0.0 (#1566) 2023-03-09 18:34:31 +09:00
エリス
5347054efb chore: prepare package version for next major 12.0.0-dev (#1537) 2023-03-09 18:33:28 +09:00
エリス
3340e98519 ci(workflow): update codecov/codecov-action@v3 (#1542) 2023-01-18 23:53:36 +09:00
jcesarmobile
ce19a3b445 chore: add lint:fix script for fixing lint errors (#1493)
* chore: Add fmt command for fixing lint errors
* rename to lint:fix
2023-01-11 10:06:16 +09:00
Jesse MacFadyen
d02f8eafe8 Update codecoverage reporting (#1532) 2022-12-30 12:18:54 -08:00
jcesarmobile
56d4b8312b fix: only do fadeout animation if FadeSplashScreen is true (#1506) 2022-10-27 23:38:30 +02:00
Darryl Pogue
80f232aa79 fix: correctly flag API dependency on AppCompat for Maven (#1505)
* Correctly flag API dependency on AppCompat for Maven

Currently when cordova-android is published to Maven, it lists no
dependencies. However, `CordovaActivity` extends `AppCompatActivity`
which requires that the AndroidX AppCompat library be available.

Marking this as an API dependency (rather than an implementation/compile
dependency) should cause the AndroidX AppCompat library to be installed
when the cordova-android framework is added to the build.gradle of an
existing Android application.

* Publish to Maven with proper metadata

This allows the Maven publish to pick up information from the android
library component and include things like dependencies in the pom.xml
file.
2022-10-15 13:39:47 +09:00
jcesarmobile
954d3e0e75 fix: Add android prefix to windowSplashScreenBrandingImage (#1487) 2022-09-16 09:34:20 +02:00
jcesarmobile
8a1ffeeafd chore: Use gradle 7.4.2 distribution url (#1491) 2022-09-16 09:33:15 +02:00
jcesarmobile
7793db97cc refactor: replace deprecated Handler constructor (#1492) 2022-09-16 09:32:38 +02:00
Philip Peitsch
248257bd37 fix: import type definitions from obsolete cordova-plugin-splashscreen (#1489) 2022-09-13 10:03:53 -03:00
Erisu
60e3803c67 chore: bump version 11.0.1-dev (2) 2022-07-04 23:12:43 +09:00
54 changed files with 2772 additions and 1656 deletions

View File

@@ -27,7 +27,7 @@ jobs:
strategy:
matrix:
node-version: [14.x, 16.x, 18.x]
node-version: [16.x, 18.x]
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
@@ -38,11 +38,11 @@ jobs:
with:
node-version: ${{ matrix.node-version }}
- name: set up JDK 11
- name: set up JDK 17
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'
java-version: '17'
- name: Environment Information
run: |
@@ -57,6 +57,8 @@ jobs:
env:
CI: true
- uses: codecov/codecov-action@v3
- name: upload coverage
if: success()
uses: codecov/codecov-action@v3
with:
fail_ci_if_error: true
name: ${{ runner.os }} node.js ${{ matrix.node-version }}

View File

@@ -18,5 +18,6 @@
under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.apache.cordova" android:versionName="1.0" android:versionCode="1">
android:versionName="1.0"
android:versionCode="1">
</manifest>

View File

@@ -44,6 +44,8 @@ allprojects {
apply plugin: 'com.android.library'
android {
namespace 'org.apache.cordova'
compileSdkVersion cordovaConfig.COMPILE_SDK_VERSION
buildToolsVersion cordovaConfig.BUILD_TOOLS_VERSION
@@ -75,10 +77,16 @@ android {
exclude 'META-INF/DEPENDENCIES'
exclude 'META-INF/NOTICE'
}
publishing {
singleVariant('release') {
withSourcesJar()
}
}
}
dependencies {
implementation "androidx.appcompat:appcompat:${cordovaConfig.ANDROIDX_APP_COMPAT_VERSION}"
api "androidx.appcompat:appcompat:${cordovaConfig.ANDROIDX_APP_COMPAT_VERSION}"
implementation "androidx.webkit:webkit:${cordovaConfig.ANDROIDX_WEBKIT_VERSION}"
implementation "androidx.core:core-splashscreen:${cordovaConfig.ANDROIDX_CORE_SPLASHSCREEN_VERSION}"
}

View File

@@ -1,15 +1,16 @@
{
"MIN_SDK_VERSION": 22,
"SDK_VERSION": 32,
"MIN_SDK_VERSION": 24,
"SDK_VERSION": 33,
"COMPILE_SDK_VERSION": null,
"GRADLE_VERSION": "7.4.2",
"MIN_BUILD_TOOLS_VERSION": "32.0.0",
"AGP_VERSION": "7.2.1",
"KOTLIN_VERSION": "1.5.21",
"ANDROIDX_APP_COMPAT_VERSION": "1.4.2",
"ANDROIDX_WEBKIT_VERSION": "1.4.0",
"ANDROIDX_CORE_SPLASHSCREEN_VERSION": "1.0.0-rc01",
"GRADLE_PLUGIN_GOOGLE_SERVICES_VERSION": "4.3.10",
"GRADLE_VERSION": "8.0.2",
"MIN_BUILD_TOOLS_VERSION": "33.0.2",
"AGP_VERSION": "8.0.0",
"KOTLIN_VERSION": "1.7.21",
"ANDROIDX_APP_COMPAT_VERSION": "1.6.1",
"ANDROIDX_WEBKIT_VERSION": "1.6.0",
"ANDROIDX_CORE_SPLASHSCREEN_VERSION": "1.0.0",
"GRADLE_PLUGIN_GOOGLE_SERVICES_VERSION": "4.3.15",
"IS_GRADLE_PLUGIN_GOOGLE_SERVICES_ENABLED": false,
"IS_GRADLE_PLUGIN_KOTLIN_ENABLED": false
"IS_GRADLE_PLUGIN_KOTLIN_ENABLED": false,
"PACKAGE_NAMESPACE": "io.cordova.helloCordova"
}

View File

@@ -46,73 +46,69 @@ if (project.hasProperty('signEnabled')) {
}
}
task sourcesJar(type: Jar) {
from android.sourceSets.main.java.srcDirs
classifier = 'sources'
}
afterEvaluate {
publishing {
publications {
mavenJava(MavenPublication) {
groupId = 'org.apache.cordova'
artifactId = 'framework'
version = getCordovaAndroidVersion()
publishing {
publications {
mavenJava(MavenPublication) {
groupId = 'org.apache.cordova'
artifactId = 'framework'
version = getCordovaAndroidVersion()
from components.release
artifact(sourcesJar)
artifact("$buildDir/outputs/aar/framework-release.aar")
pom {
name = 'Cordova'
description = 'A library to build Cordova-based projects for the Android platform.'
url = 'https://cordova.apache.org'
pom {
name = 'Cordova'
description = 'A library to build Cordova-based projects for the Android platform.'
url = 'https://cordova.apache.org'
licenses {
license {
name = 'Apache License, Version 2.0'
url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
licenses {
license {
name = 'Apache License, Version 2.0'
url = 'https://www.apache.org/licenses/LICENSE-2.0.txt'
}
}
}
developers {
developer {
id = 'stevengill'
name = 'Steve Gill'
developers {
developer {
id = 'stevengill'
name = 'Steve Gill'
}
developer {
id = 'erisu'
name = 'Bryan Ellis'
email = 'erisu@apache.org'
}
}
developer {
id = 'erisu'
name = 'Bryan Ellis'
email = 'erisu@apache.org'
}
}
scm {
connection = 'scm:git:https://github.com/apache/cordova-android.git'
developerConnection = 'scm:git:git@github.com:apache/cordova-android.git'
url = 'https://github.com/apache/cordova-android'
scm {
connection = 'scm:git:https://github.com/apache/cordova-android.git'
developerConnection = 'scm:git:git@github.com:apache/cordova-android.git'
url = 'https://github.com/apache/cordova-android'
}
}
}
}
}
repositories {
maven {
def releasesRepoUrl = 'https://repository.apache.org/content/repositories/releases'
def snapshotsRepoUrl = 'https://repository.apache.org/content/repositories/snapshots'
repositories {
maven {
def releasesRepoUrl = 'https://repository.apache.org/content/repositories/releases'
def snapshotsRepoUrl = 'https://repository.apache.org/content/repositories/snapshots'
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
url = version.endsWith('SNAPSHOT') ? snapshotsRepoUrl : releasesRepoUrl
credentials {
if (project.hasProperty('apacheUsername') && project.hasProperty('apachePassword')) {
username apacheUsername
password apachePassword
credentials {
if (project.hasProperty('apacheUsername') && project.hasProperty('apachePassword')) {
username apacheUsername
password apachePassword
}
}
}
}
}
signing {
if (Boolean.valueOf(cdvEnableSigning)) {
sign publishing.publications.mavenJava
signing {
if (Boolean.valueOf(cdvEnableSigning)) {
sign publishing.publications.mavenJava
}
}
}
}

View File

@@ -83,9 +83,9 @@ String doFindLatestInstalledBuildTools(String minBuildToolsVersionString) {
String getAndroidSdkDir() {
def rootDir = project.rootDir
def androidSdkDir = null
String envVar = System.getenv("ANDROID_SDK_ROOT")
String envVar = System.getenv("ANDROID_HOME")
if (envVar == null) {
envVar = System.getenv("ANDROID_HOME")
envVar = System.getenv("ANDROID_SDK_ROOT")
}
def localProperties = new File(rootDir, 'local.properties')
@@ -125,14 +125,6 @@ def doExtractIntFromManifest(name) {
return new BigInteger(matcher.group(1))
}
def doExtractStringFromManifest(name) {
def manifestFile = file(android.sourceSets.main.manifest.srcFile)
def pattern = Pattern.compile(name + "=\"(\\S+)\"")
def matcher = pattern.matcher(manifestFile.getText())
matcher.find()
return matcher.group(1)
}
def doGetConfigXml() {
def xml = file("src/main/res/xml/config.xml").getText()
// Disable namespace awareness since Cordova doesn't use them properly
@@ -231,7 +223,6 @@ ext {
privateHelpers.getProjectTarget = { doGetProjectTarget() }
privateHelpers.applyCordovaConfigCustomization = { doApplyCordovaConfigCustomization() }
privateHelpers.extractIntFromManifest = { name -> doExtractIntFromManifest(name) }
privateHelpers.extractStringFromManifest = { name -> doExtractStringFromManifest(name) }
privateHelpers.ensureValueExists = { filePath, props, key -> doEnsureValueExists(filePath, props, key) }
// These helpers can be used by plugins / projects and will not change.

View File

@@ -51,7 +51,8 @@ public class BuildHelper {
{
try
{
Class<?> clazz = Class.forName(ctx.getClass().getPackage().getName() + ".BuildConfig");
String packageName = ctx.getApplicationInfo().packageName;
Class<?> clazz = Class.forName(packageName + ".BuildConfig");
Field field = clazz.getField(key);
return field.get(null);
} catch (ClassNotFoundException e) {

View File

@@ -34,6 +34,7 @@ public class ConfigXmlParser {
private static String SCHEME_HTTP = "http";
private static String SCHEME_HTTPS = "https";
private static String DEFAULT_HOSTNAME = "localhost";
private static final String DEFAULT_CONTENT_SRC = "index.html";
private String launchUrl;
private String contentSrc;
@@ -110,6 +111,18 @@ public class ConfigXmlParser {
e.printStackTrace();
}
}
onPostParse();
}
private void onPostParse() {
// After parsing, if contentSrc is still null, it signals
// that <content> tag was completely missing. In this case,
// default it.
// https://github.com/apache/cordova-android/issues/1432
if (contentSrc == null) {
contentSrc = DEFAULT_CONTENT_SRC;
}
}
public void handleStartTag(XmlPullParser xml) {
@@ -140,7 +153,7 @@ public class ConfigXmlParser {
contentSrc = src;
} else {
// Default
contentSrc = "index.html";
contentSrc = DEFAULT_CONTENT_SRC;
}
}
}

View File

@@ -237,14 +237,6 @@ public class CordovaInterfaceImpl implements CordovaInterface {
public boolean hasPermission(String permission)
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
{
int result = activity.checkSelfPermission(permission);
return PackageManager.PERMISSION_GRANTED == result;
}
else
{
return true;
}
return PackageManager.PERMISSION_GRANTED == activity.checkSelfPermission(permission);
}
}

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

View File

@@ -19,6 +19,8 @@
package org.apache.cordova;
import org.apache.cordova.BuildHelper;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -30,7 +32,6 @@ import android.content.IntentFilter;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import java.lang.reflect.Field;
import java.util.HashMap;
/**
@@ -376,35 +377,19 @@ public class CoreAndroid extends CordovaPlugin {
}
}
/*
/*
* This needs to be implemented if you wish to use the Camera Plugin or other plugins
* that read the Build Configuration.
*
* Thanks to Phil@Medtronic and Graham Borland for finding the answer and posting it to
* StackOverflow. This is annoying as hell!
*
* @deprecated Use {@link BuildHelper#getBuildConfigValue} instead.
*/
@Deprecated
public static Object getBuildConfigValue(Context ctx, String key)
{
try
{
Class<?> clazz = Class.forName(ctx.getClass().getPackage().getName() + ".BuildConfig");
Field field = clazz.getField(key);
return field.get(null);
} catch (ClassNotFoundException e) {
LOG.d(TAG, "Unable to get the BuildConfig, is this built with ANT?");
e.printStackTrace();
} catch (NoSuchFieldException e) {
LOG.d(TAG, key + " is not a valid field. Check your build.gradle");
} catch (IllegalAccessException e) {
LOG.d(TAG, "Illegal Access Exception: Let's print a stack trace.");
e.printStackTrace();
} catch (NullPointerException e) {
LOG.d(TAG, "Null Pointer Exception: Let's print a stack trace.");
e.printStackTrace();
}
return null;
LOG.w(TAG, "CoreAndroid.getBuildConfigValue is deprecated and will be removed in a future release. Use BuildHelper.getBuildConfigValue instead.");
return BuildHelper.getBuildConfigValue(ctx, key);
}
}

View File

@@ -339,22 +339,11 @@ public class PluginManager {
public Object postMessage(String id, Object data) {
LOG.d(TAG, "postMessage: " + id);
synchronized (this.pluginMap) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
this.pluginMap.forEach((s, plugin) -> {
if (plugin != null) {
plugin.onMessage(id, data);
}
});
} else {
for (CordovaPlugin plugin : this.pluginMap.values()) {
if (plugin != null) {
Object obj = plugin.onMessage(id, data);
if (obj != null) {
return obj;
}
}
this.pluginMap.forEach((s, plugin) -> {
if (plugin != null) {
plugin.onMessage(id, data);
}
}
});
}
return ctx.onMessage(id, data);
}

View File

@@ -127,7 +127,7 @@ public class SplashScreenPlugin extends CordovaPlugin {
// auto hide splash screen when custom delay is defined.
if (autoHide && delayTime != DEFAULT_DELAY_TIME) {
Handler splashScreenDelayHandler = new Handler();
Handler splashScreenDelayHandler = new Handler(cordova.getContext().getMainLooper());
splashScreenDelayHandler.postDelayed(() -> keepOnScreen = false, delayTime);
}
@@ -137,27 +137,29 @@ public class SplashScreenPlugin extends CordovaPlugin {
// If auto hide is disabled (false), the hiding of the splash screen must be determined &
// triggered by the front-end code with the `navigator.splashscreen.hide()` method.
// Setup the fade
splashScreen.setOnExitAnimationListener(new SplashScreen.OnExitAnimationListener() {
@Override
public void onSplashScreenExit(@NonNull SplashScreenViewProvider splashScreenViewProvider) {
View splashScreenView = splashScreenViewProvider.getView();
if (isFadeEnabled) {
// Setup the fade
splashScreen.setOnExitAnimationListener(new SplashScreen.OnExitAnimationListener() {
@Override
public void onSplashScreenExit(@NonNull SplashScreenViewProvider splashScreenViewProvider) {
View splashScreenView = splashScreenViewProvider.getView();
splashScreenView
.animate()
.alpha(0.0f)
.setDuration(isFadeEnabled ? fadeDuration : 0)
.setStartDelay(isFadeEnabled ? 0 : fadeDuration)
.setInterpolator(new AccelerateInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashScreenViewProvider.remove();
}
}).start();
}
});
splashScreenView
.animate()
.alpha(0.0f)
.setDuration(fadeDuration)
.setStartDelay(0)
.setInterpolator(new AccelerateInterpolator())
.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
splashScreenViewProvider.remove();
}
}).start();
}
});
}
}
private void attemptCloseOnPageFinished() {

View File

@@ -175,9 +175,20 @@ public class SystemWebViewEngine implements CordovaWebViewEngine {
String databasePath = webView.getContext().getApplicationContext().getDir("database", Context.MODE_PRIVATE).getPath();
settings.setDatabaseEnabled(true);
//Determine whether we're in debug or release mode, and turn on Debugging!
ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo();
if ((appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) {
// The default is to use the module's debuggable state to decide if the webview inspecter
// should be enabled. However, users can configure InspectableWebview preference to forcefully enable
// or disable the webview inspecter.
String inspectableWebview = preferences.getString("InspectableWebview", null);
boolean shouldEnableInspector = false;
if (inspectableWebview == null) {
ApplicationInfo appInfo = webView.getContext().getApplicationContext().getApplicationInfo();
shouldEnableInspector = (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
}
else if ("true".equals(inspectableWebview)) {
shouldEnableInspector = true;
}
if (shouldEnableInspector) {
enableRemoteDebugging();
}

View File

@@ -50,15 +50,6 @@ class AndroidManifest {
return this;
}
getPackageId () {
return this.doc.getroot().attrib.package;
}
setPackageId (pkgId) {
this.doc.getroot().attrib.package = pkgId;
return this;
}
getActivity () {
const activity = this.doc.getroot().find('./application/activity');
return {

View File

@@ -20,8 +20,8 @@
const fs = require('fs');
const path = require('path');
const properties_parser = require('properties-parser');
const AndroidManifest = require('./AndroidManifest');
const pluginHandlers = require('./pluginHandlers');
const CordovaGradleConfigParserFactory = require('./config/CordovaGradleConfigParserFactory');
let projectFileCache = {};
@@ -63,17 +63,17 @@ class AndroidProject {
this.projectDir = projectDir;
this.platformWww = path.join(this.projectDir, 'platform_www');
this.www = path.join(this.projectDir, 'app/src/main/assets/www');
this.cordovaGradleConfigParser = CordovaGradleConfigParserFactory.create(this.projectDir);
}
/**
* Reads the package name out of the Android Manifest file
* Reads the package name out of the Cordova's Gradle Config file
*
* @param {String} projectDir The absolute path to the directory containing the project
* @return {String} The name of the package
*/
getPackageName () {
const manifestPath = path.join(this.projectDir, 'app/src/main/AndroidManifest.xml');
return new AndroidManifest(manifestPath).getPackageId();
return this.cordovaGradleConfigParser.getPackageName();
}
getCustomSubprojectRelativeDir (plugin_id, src) {

View File

@@ -184,7 +184,7 @@ module.exports.run = function (options, optResolvedTarget) {
}
return {
paths: paths,
paths,
buildType: opts.buildType
};
});

View File

@@ -27,6 +27,7 @@ const check_reqs = require('../check_reqs');
const PackageType = require('../PackageType');
const { compareByAll } = require('../utils');
const { createEditor } = require('properties-parser');
const CordovaGradleConfigParserFactory = require('../config/CordovaGradleConfigParserFactory');
const MARKER = 'YOUR CHANGES WILL BE ERASED!';
const SIGNING_PROPERTIES = '-signing.properties';
@@ -145,19 +146,6 @@ class ProjectBuilder {
};
}
extractRealProjectNameFromManifest () {
const manifestPath = path.join(this.root, 'app', 'src', 'main', 'AndroidManifest.xml');
const manifestData = fs.readFileSync(manifestPath, 'utf8');
const m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
if (!m) {
throw new CordovaError('Could not find package name in ' + manifestPath);
}
const packageName = m[1];
const lastDotIndex = packageName.lastIndexOf('.');
return packageName.substring(lastDotIndex + 1);
}
// Makes the project buildable, minus the gradle wrapper.
prepBuildFiles () {
// Update the version of build.gradle in each dependent library.
@@ -184,7 +172,11 @@ class ProjectBuilder {
checkAndCopy(subProjects[i], this.root);
}
}
const projectName = this.extractRealProjectNameFromManifest();
// get project name cdv-gradle-config.
const cdvGradleConfig = CordovaGradleConfigParserFactory.create(this.root);
const projectName = cdvGradleConfig.getProjectNameFromPackageName();
// Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
const settingsGradlePaths = subProjects.map(function (p) {
const realDir = p.replace(/[/\\]/g, ':');

View File

@@ -149,7 +149,7 @@ module.exports.check_gradle = function () {
const sdkDir = process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT;
if (!sdkDir) {
return Promise.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
'Might need to install Android SDK or set up \'ANDROID_SDK_ROOT\' env variable.'));
'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
}
const gradlePath = module.exports.get_gradle_wrapper();
@@ -270,7 +270,7 @@ module.exports.check_android = function () {
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
}
if (!fs.existsSync(process.env.ANDROID_HOME)) {
throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env.ANDROID_SDK_ROOT +
throw new CordovaError('\'ANDROID_HOME\' environment variable is set to non-existent path: ' + process.env.ANDROID_HOME +
'\nTry update it manually to point to valid SDK directory.');
}
// Next let's make sure relevant parts of the SDK tooling is in our PATH
@@ -306,7 +306,7 @@ module.exports.run = function () {
console.log('ANDROID_SDK_ROOT=' + process.env.ANDROID_SDK_ROOT + ' (DEPRECATED)');
return Promise.all([this.check_java(), this.check_android()]).then(function (values) {
console.log('Using Android SDK: ' + process.env.ANDROID_SDK_ROOT);
console.log('Using Android SDK: ' + (process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT));
if (!values[1]) {
throw new CordovaError('Requirements check failed for Android SDK! Android SDK was not detected.');
@@ -327,7 +327,7 @@ const Requirement = function (id, name, version, installed) {
this.name = name;
this.installed = installed || false;
this.metadata = {
version: version
version
};
};

View File

@@ -0,0 +1,71 @@
/**
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 fs = require('fs-extra');
const path = require('path');
const events = require('cordova-common').events;
class CordovaGradleConfigParser {
/**
* Loads and Edits Gradle Properties File.
*
* Do not construct this directly. Use CordovaGradleConfigParserFactory instead.
*
* @param {String} platformDir is the path of the Android platform directory
*/
constructor (platformDir) {
this._cdvGradleConfigFilePath = path.join(platformDir, 'cdv-gradle-config.json');
this._cdvGradleConfig = this._readConfig(this._cdvGradleConfigFilePath);
}
/**
* Reads and parses the configuration JSON file
*
* @param {String} configPath
* @returns {Record<any, any>} The parsed JSON object representing the gradle config.
*/
_readConfig (configPath) {
return fs.readJSONSync(configPath, 'utf-8');
}
setPackageName (packageName) {
events.emit('verbose', '[Cordova Gradle Config] Setting "PACKAGE_NAMESPACE" to ' + packageName);
this._cdvGradleConfig.PACKAGE_NAMESPACE = packageName;
return this;
}
getPackageName () {
return this._cdvGradleConfig.PACKAGE_NAMESPACE;
}
getProjectNameFromPackageName () {
const packageName = this._cdvGradleConfig.PACKAGE_NAMESPACE;
return packageName.substring(packageName.lastIndexOf('.') + 1);
}
/**
* Saves any changes that has been made to the properties file.
*/
write () {
events.emit('verbose', '[Cordova Gradle Config] Saving File');
fs.writeJSONSync(this._cdvGradleConfigFilePath, this._cdvGradleConfig, 'utf-8');
}
}
module.exports = CordovaGradleConfigParser;

View File

@@ -0,0 +1,35 @@
/**
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 CordovaGradleConfigParser = require('./CordovaGradleConfigParser');
/**
* Builds new gradle config parsers
*/
module.exports = class CordovaGradleConfigParserFactory {
/**
* Loads and Edits Gradle Properties File.
*
* @param {String} platformDir is the path of the Android platform directory
*/
static create (platformDir) {
return new CordovaGradleConfigParser(platformDir);
}
};

View File

@@ -23,6 +23,7 @@ const utils = require('./utils');
const check_reqs = require('./check_reqs');
const ROOT = path.join(__dirname, '..');
const { createEditor } = require('properties-parser');
const CordovaGradleConfigParserFactory = require('./config/CordovaGradleConfigParserFactory');
const CordovaError = require('cordova-common').CordovaError;
const AndroidManifest = require('./AndroidManifest');
@@ -249,6 +250,11 @@ exports.create = function (project_path, config, options, events) {
fs.ensureDirSync(assets_path);
fs.ensureDirSync(resource_path);
// store package name in cdv-gradle-config
const cdvGradleConfig = CordovaGradleConfigParserFactory.create(project_path);
cdvGradleConfig.setPackageName(package_name)
.write();
// interpolate the activity name and package
const packagePath = package_name.replace(/\./g, path.sep);
const activity_dir = path.join(java_path, packagePath);
@@ -261,8 +267,7 @@ exports.create = function (project_path, config, options, events) {
utils.replaceFileContents(activity_path, /__ID__/, package_name);
const manifest = new AndroidManifest(path.join(project_template_dir, 'AndroidManifest.xml'));
manifest.setPackageId(package_name)
.getActivity().setName(safe_activity_name);
manifest.getActivity().setName(safe_activity_name);
const manifest_path = path.join(app_path, 'AndroidManifest.xml');
manifest.write(manifest_path);

View File

@@ -34,6 +34,7 @@ const utils = require('./utils');
const gradleConfigDefaults = require('./gradle-config-defaults');
const checkReqs = require('./check_reqs');
const GradlePropertiesParser = require('./config/GradlePropertiesParser');
const CordovaGradleConfigParserFactory = require('./config/CordovaGradleConfigParserFactory');
function parseArguments (argv) {
return nopt({
@@ -278,20 +279,22 @@ function updateProjectAccordingTo (platformConfig, locations) {
// Java packages cannot support dashes
const androidPkgName = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
const manifest = new AndroidManifest(locations.manifest);
const manifestId = manifest.getPackageId();
// updating cdv-gradle-config with new androidPkgName.
const cdvGradleConfig = CordovaGradleConfigParserFactory.create(locations.root);
cdvGradleConfig.setPackageName(androidPkgName)
.write();
const manifest = new AndroidManifest(locations.manifest);
manifest.getActivity()
.setOrientation(platformConfig.getPreference('orientation'))
.setLaunchMode(findAndroidLaunchModePreference(platformConfig));
manifest.setVersionName(platformConfig.version())
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
.setPackageId(androidPkgName)
.write();
// Java file paths shouldn't be hard coded
const javaDirectory = path.join(locations.javaSrc, manifestId.replace(/\./g, '/'));
const javaDirectory = path.join(locations.javaSrc, androidPkgName.replace(/\./g, '/'));
const java_files = glob.sync('**/*.java', { cwd: javaDirectory, absolute: true }).filter(f => {
const contents = fs.readFileSync(f, 'utf-8');
return /extends\s+CordovaActivity/.test(contents);
@@ -378,11 +381,12 @@ function updateProjectSplashScreen (platformConfig, locations) {
'windowSplashScreenAnimatedIcon',
'windowSplashScreenAnimationDuration',
'windowSplashScreenBackground',
'windowSplashScreenBrandingImage',
'android:windowSplashScreenBrandingImage',
'windowSplashScreenIconBackgroundColor',
'postSplashScreenTheme'
].forEach(themeKey => {
const cdvConfigPrefKey = 'Android' + themeKey.charAt(0).toUpperCase() + themeKey.slice(1);
const index = themeKey.indexOf(':') + 1;
const cdvConfigPrefKey = 'Android' + themeKey.charAt(index).toUpperCase() + themeKey.slice(index + 1);
const cdvConfigPrefValue = platformConfig.getPreference(cdvConfigPrefKey, this.platform);
let themeTargetNode = splashScreenTheme.find(`item[@name="${themeKey}"]`);
@@ -411,7 +415,7 @@ function updateProjectSplashScreen (platformConfig, locations) {
updateProjectSplashScreenImage(locations, themeKey, cdvConfigPrefKey, cdvConfigPrefValue);
break;
case 'windowSplashScreenBrandingImage':
case 'android:windowSplashScreenBrandingImage':
// display warning only when set.
if (cdvConfigPrefValue) {
events.emit('warn', `"${themeKey}" is currently not supported by the splash screen compatibility library. https://issuetracker.google.com/issues/194301890`);
@@ -422,13 +426,14 @@ function updateProjectSplashScreen (platformConfig, locations) {
// force the themes value to `@color/cdv_splashscreen_icon_background`
if (!cdvConfigPrefValue && themeTargetNode) {
splashScreenTheme.remove(themeTargetNode);
delete themes.getroot().attrib['xmlns:tools'];
} else if (cdvConfigPrefValue) {
// if there is no current node, create a new node.
if (!themeTargetNode) {
themeTargetNode = themes.getroot().makeelement('item', { name: themeKey });
themeTargetNode = themes.getroot().makeelement('item', { name: themeKey, 'tools:targetApi': '31' });
splashScreenTheme.append(themeTargetNode);
themes.getroot().attrib['xmlns:tools'] = 'http://schemas.android.com/tools';
}
// set the user defined color.
themeTargetNode.text = '@drawable/ic_cdv_splashscreen_branding';
}
@@ -537,7 +542,7 @@ function cleanupAndSetProjectSplashScreenImage (srcFile, destFilePath, possibleP
function updateProjectSplashScreenImage (locations, themeKey, cdvConfigPrefKey, cdvConfigPrefValue = '') {
const SPLASH_SCREEN_IMAGE_BY_THEME_KEY = {
windowSplashScreenAnimatedIcon: 'ic_cdv_splashscreen',
windowSplashScreenBrandingImage: 'ic_cdv_splashscreen_branding'
'android:windowSplashScreenBrandingImage': 'ic_cdv_splashscreen_branding'
};
const destFileName = SPLASH_SCREEN_IMAGE_BY_THEME_KEY[themeKey] || null;
@@ -555,7 +560,7 @@ function updateProjectSplashScreenImage (locations, themeKey, cdvConfigPrefKey,
// Default Drawable Source File
let defaultSrcFilePath = null;
if (themeKey !== 'windowSplashScreenBrandingImage') {
if (themeKey !== 'android:windowSplashScreenBrandingImage') {
try {
// coming from user project
defaultSrcFilePath = require.resolve('cordova-android/templates/project/res/drawable/' + destFileNameExt);
@@ -575,7 +580,7 @@ function updateProjectSplashScreenImage (locations, themeKey, cdvConfigPrefKey,
}
events.emit(emitType, emmitMessage);
const cleanupOnly = themeKey === 'windowSplashScreenBrandingImage';
const cleanupOnly = themeKey === 'android:windowSplashScreenBrandingImage';
cleanupAndSetProjectSplashScreenImage(defaultSrcFilePath, destFilePath, possiblePreviousDestFilePath, cleanupOnly);
return;
}
@@ -701,8 +706,10 @@ function updateIcons (cordovaProject, platformResourcesDir) {
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher.png'),
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.png'),
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_background.png'),
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_monochrome.png'),
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.xml'),
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_background.xml'),
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher_monochrome.xml'),
mapImageResources(cordovaProject.root, platformResourcesDir, 'mipmap', 'ic_launcher.xml')
);
@@ -726,17 +733,23 @@ function updateIconResourceForAdaptive (preparedIcons, resourceMap, platformReso
// project's config.xml location, so we use it as base path.
let background;
let foreground;
let monochrome;
let targetPathBackground;
let targetPathForeground;
let targetPathMonochrome;
for (const density in android_icons) {
let backgroundVal = '@mipmap/ic_launcher_background';
let foregroundVal = '@mipmap/ic_launcher_foreground';
const monochromeVal = '@mipmap/ic_launcher_monochrome';
background = android_icons[density].background;
foreground = android_icons[density].foreground;
monochrome = android_icons[density].monochrome;
if (!background || !foreground) {
const isAdaptiveIcon = background && foreground;
const isMonochromeIcon = monochrome && isAdaptiveIcon;
if (!isMonochromeIcon || !isAdaptiveIcon) {
// This icon isn't an adaptive icon, so skip it
continue;
}
@@ -767,12 +780,34 @@ function updateIconResourceForAdaptive (preparedIcons, resourceMap, platformReso
resourceMap[targetPathForeground] = android_icons[density].foreground;
}
if (monochrome) {
if (path.extname(path.basename(monochrome)) === '.xml') {
// Vector Use Case
targetPathMonochrome = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_monochrome.xml', path.basename(android_icons[density].monochrome));
resourceMap[targetPathMonochrome] = android_icons[density].monochrome;
} else if (path.extname(path.basename(monochrome)) === '.png') {
// Images Use Case
targetPathMonochrome = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', density, 'ic_launcher_monochrome.png', path.basename(android_icons[density].monochrome));
resourceMap[targetPathMonochrome] = android_icons[density].monochrome;
}
}
// create an XML for DPI and set color
const icLauncherTemplate = `<?xml version="1.0" encoding="utf-8"?>
let icLauncherTemplate = '';
if (monochrome) {
icLauncherTemplate = `<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="` + backgroundVal + `" />
<foreground android:drawable="` + foregroundVal + `" />
<monochrome android:drawable="` + monochromeVal + `" />
</adaptive-icon>`;
} else {
icLauncherTemplate = `<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="` + backgroundVal + `" />
<foreground android:drawable="` + foregroundVal + `" />
</adaptive-icon>`;
}
const launcherXmlPath = path.join(platformResourcesDir, 'mipmap-' + density + '-v26', 'ic_launcher.xml');
@@ -786,6 +821,7 @@ function updateIconResourceForAdaptive (preparedIcons, resourceMap, platformReso
if (default_icon && !android_icons.mdpi) {
let defaultTargetPathBackground;
let defaultTargetPathForeground;
let defaultTargetPathMonochrome;
if (background.startsWith('@color')) {
// Colors Use Case
@@ -812,6 +848,18 @@ function updateIconResourceForAdaptive (preparedIcons, resourceMap, platformReso
defaultTargetPathForeground = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_foreground.png', path.basename(default_icon.foreground));
resourceMap[defaultTargetPathForeground] = default_icon.foreground;
}
if (monochrome) {
if (path.extname(path.basename(monochrome)) === '.xml') {
// Vector Use Case
defaultTargetPathMonochrome = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_monochrome.xml', path.basename(default_icon.monochrome));
resourceMap[defaultTargetPathMonochrome] = default_icon.monochrome;
} else if (path.extname(path.basename(monochrome)) === '.png') {
// Images Use Case
defaultTargetPathMonochrome = getAdaptiveImageResourcePath(platformResourcesDir, 'mipmap', 'mdpi', 'ic_launcher_monochrome.png', path.basename(default_icon.monochrome));
resourceMap[defaultTargetPathMonochrome] = default_icon.monochrome;
}
}
}
return resourceMap;
@@ -882,6 +930,11 @@ function prepareIcons (icons) {
const favor = {};
// populating found icon.
if (icon.background && icon.foreground && icon.monochrome) {
found.background = icon.background;
found.foreground = icon.foreground;
found.monochrome = icon.monochrome;
}
if (icon.background && icon.foreground) {
found.background = icon.background;
found.foreground = icon.foreground;
@@ -890,6 +943,11 @@ function prepareIcons (icons) {
found.src = icon.src;
}
if (default_icon.background && default_icon.foreground && default_icon.monochrome) {
favor.background = default_icon.background;
favor.foreground = default_icon.foreground;
favor.monochrome = default_icon.monochrome;
}
if (default_icon.background && default_icon.foreground) {
favor.background = default_icon.background;
favor.foreground = default_icon.foreground;
@@ -908,8 +966,8 @@ function prepareIcons (icons) {
}
return {
android_icons: android_icons,
default_icon: default_icon
android_icons,
default_icon
};
}
@@ -927,8 +985,10 @@ function cleanIcons (projectRoot, projectConfig, platformResourcesDir) {
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher.png'),
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.png'),
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_background.png'),
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_monochrome.png'),
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_foreground.xml'),
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_background.xml'),
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher_monochrome.xml'),
mapImageResources(projectRoot, platformResourcesDir, 'mipmap', 'ic_launcher.xml')
);

View File

@@ -23,6 +23,7 @@ const build = require('./build');
const PackageType = require('./PackageType');
const AndroidManifest = require('./AndroidManifest');
const { CordovaError, events } = require('cordova-common');
const CordovaGradleConfigParserFactory = require('./config/CordovaGradleConfigParserFactory');
/**
* Builds a target spec from a runOptions object
@@ -78,6 +79,7 @@ module.exports.run = async function (runOptions = {}) {
}
const manifest = new AndroidManifest(this.locations.manifest);
const cordovaGradleConfigParser = CordovaGradleConfigParserFactory.create(this.locations.root);
return target.install(resolvedTarget, { manifest, buildResults });
return target.install(resolvedTarget, { manifest, buildResults, cordovaGradleConfigParser });
};

View File

@@ -127,9 +127,9 @@ exports.resolve = async (spec, buildResults) => {
};
};
exports.install = async function ({ id: target, arch, type }, { manifest, buildResults }) {
exports.install = async function ({ id: target, arch, type }, { manifest, buildResults, cordovaGradleConfigParser }) {
const apk_path = build.findBestApkForArchitecture(buildResults, arch);
const pkgName = manifest.getPackageId();
const pkgName = cordovaGradleConfigParser.getPackageName();
const launchName = pkgName + '/.' + manifest.getActivity().getName();
events.emit('log', 'Using apk: ' + apk_path);

3551
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,8 @@
{
"name": "cordova-android",
"version": "11.0.0",
"version": "12.0.0-dev",
"description": "cordova-android release",
"types": "./types/index.d.ts",
"main": "lib/Api.js",
"repository": "github:apache/cordova-android",
"bugs": "https://github.com/apache/cordova-android/issues",
@@ -14,6 +15,7 @@
"prepare": "cordova-js build > templates/project/assets/www/cordova.js",
"test": "npm run lint && npm run cover && npm run java-unit-tests",
"lint": "eslint lib spec test \"templates/cordova/**/!(*.*)\"",
"lint:fix": "npm run lint -- --fix",
"unit-tests": "jasmine --config=spec/unit/jasmine.json",
"cover": "nyc jasmine --config=spec/coverage.json",
"e2e-tests": "jasmine --config=spec/e2e/jasmine.json",
@@ -23,29 +25,29 @@
"author": "Apache Software Foundation",
"license": "Apache-2.0",
"dependencies": {
"android-versions": "^1.7.0",
"cordova-common": "^4.0.2",
"android-versions": "^1.8.1",
"cordova-common": "^5.0.0",
"execa": "^5.1.1",
"fast-glob": "^3.2.11",
"fs-extra": "^10.1.0",
"fast-glob": "^3.2.12",
"fs-extra": "^11.1.1",
"is-path-inside": "^3.0.3",
"nopt": "^5.0.0",
"nopt": "^7.1.0",
"properties-parser": "^0.3.1",
"semver": "^7.3.7",
"semver": "^7.3.8",
"untildify": "^4.0.0",
"which": "^2.0.2"
"which": "^3.0.0"
},
"devDependencies": {
"@cordova/eslint-config": "^4.0.0",
"@cordova/eslint-config": "^5.0.0",
"cordova-js": "^6.1.0",
"elementtree": "^0.1.7",
"jasmine": "^4.2.1",
"jasmine": "^4.6.0",
"jasmine-spec-reporter": "^7.0.0",
"nyc": "^15.1.0",
"rewire": "^6.0.0"
},
"engines": {
"node": ">=14.0.0"
"node": ">=16.13.0"
},
"nyc": {
"include": [

View File

@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-all.zip

View File

@@ -110,18 +110,6 @@ describe('AndroidManifest', () => {
});
});
describe('packageId', () => {
it('should get the package ID', () => {
expect(manifest.getPackageId()).toBe(PACKAGE_ID);
});
it('should set the package ID', () => {
const newPackageId = `${PACKAGE_ID}new`;
manifest.setPackageId(newPackageId);
expect(manifest.getPackageId()).toBe(newPackageId);
});
});
describe('activity', () => {
let activity;

View File

@@ -19,6 +19,8 @@
const path = require('path');
const rewire = require('rewire');
const MockCordovaGradleConfigParser = require('./mocks/config/MockCordovaGradleConfigParser');
const CordovaGradleConfigParserFactory = require('../../lib/config/CordovaGradleConfigParserFactory');
describe('AndroidProject', () => {
const PROJECT_DIR = 'platforms/android';
@@ -30,6 +32,8 @@ describe('AndroidProject', () => {
AndroidStudioSpy = jasmine.createSpyObj('AndroidStudio', ['isAndroidStudioProject']);
AndroidProject.__set__('AndroidStudio', AndroidStudioSpy);
spyOn(CordovaGradleConfigParserFactory, 'create').and.returnValue(new MockCordovaGradleConfigParser(PROJECT_DIR));
});
describe('constructor', () => {
@@ -87,26 +91,20 @@ describe('AndroidProject', () => {
});
describe('getPackageName', () => {
let AndroidManifestSpy;
let AndroidManifestFns;
let androidProject;
beforeEach(() => {
AndroidManifestFns = jasmine.createSpyObj('AndroidManifestFns', ['getPackageId']);
AndroidManifestSpy = jasmine.createSpy('AndroidManifest').and.returnValue(AndroidManifestFns);
AndroidProject.__set__('AndroidManifest', AndroidManifestSpy);
androidProject = new AndroidProject(PROJECT_DIR);
});
it('should get the package name AndroidManifest', () => {
it('should get the package name Cordova Gradle Config file', () => {
spyOn(MockCordovaGradleConfigParser.prototype, 'getPackageName');
androidProject.getPackageName();
expect(AndroidManifestSpy).toHaveBeenCalledWith(path.join(PROJECT_DIR, 'app/src/main/AndroidManifest.xml'));
expect(MockCordovaGradleConfigParser.prototype.getPackageName).toHaveBeenCalled();
});
it('should return the package name', () => {
const packageName = 'io.cordova.unittest';
AndroidManifestFns.getPackageId.and.returnValue(packageName);
expect(androidProject.getPackageName()).toBe(packageName);
});

View File

@@ -21,8 +21,6 @@ const fs = require('fs-extra');
const path = require('path');
const rewire = require('rewire');
const CordovaError = require('cordova-common').CordovaError;
describe('ProjectBuilder', () => {
const rootDir = '/root';
@@ -143,30 +141,6 @@ describe('ProjectBuilder', () => {
expect(execaSpy).not.toHaveBeenCalledWith('/my/sweet/gradle', jasmine.any(Array), jasmine.any(Object));
});
});
describe('extractRealProjectNameFromManifest', () => {
it('should get the project name from the Android Manifest', () => {
const projectName = 'unittestproject';
const projectId = `io.cordova.${projectName}`;
const manifest = `<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="${projectId}"></manifest>`;
spyOn(fs, 'readFileSync').and.returnValue(manifest);
expect(builder.extractRealProjectNameFromManifest()).toBe(projectName);
});
it('should throw an error if there is no package in the Android manifest', () => {
const manifest = `<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"></manifest>`;
spyOn(fs, 'readFileSync').and.returnValue(manifest);
expect(() => builder.extractRealProjectNameFromManifest()).toThrow(jasmine.any(CordovaError));
});
});
describe('build', () => {
beforeEach(() => {
spyOn(builder, 'getArgs');

View File

@@ -58,7 +58,7 @@ describe('check_reqs', function () {
});
describe('check_android', function () {
describe('find and set ANDROID_HOME when ANDROID_HOME and ANDROID_SDK_ROOT is not set', function () {
describe('find and set ANDROID_HOME when neither ANDROID_HOME nor ANDROID_SDK_ROOT is set', function () {
beforeEach(function () {
delete process.env.ANDROID_HOME;
delete process.env.ANDROID_SDK_ROOT;
@@ -150,32 +150,24 @@ describe('check_reqs', function () {
});
});
describe('ANDROID_SDK_ROOT environment variable detection', () => {
describe('ANDROID_HOME environment variable detection', () => {
beforeEach(() => {
delete process.env.ANDROID_SDK_ROOT;
delete process.env.ANDROID_HOME;
delete process.env.ANDROID_SDK_ROOT;
check_reqs.__set__('forgivingWhichSync', jasmine.createSpy().and.returnValue(''));
});
const expectedAndroidSdkPath = path.sep + 'android' + path.sep + 'sdk';
const expectedAndroidRootSdkPath = path.sep + 'android' + path.sep + 'sdk' + path.sep + 'root';
it('should error if neither ANDROID_SDK_ROOT or ANDROID_HOME is defined', () => {
it('should error if neither ANDROID_HOME nor ANDROID_SDK_ROOT is defined', () => {
spyOn(fs, 'existsSync').and.returnValue(true);
return check_reqs.check_android().catch((error) => {
expect(error.toString()).toContain('Failed to find \'ANDROID_SDK_ROOT\' environment variable.');
expect(error.toString()).toContain('Failed to find \'ANDROID_HOME\' environment variable.');
});
});
it('should use ANDROID_SDK_ROOT if defined', () => {
spyOn(fs, 'existsSync').and.returnValue(true);
process.env.ANDROID_SDK_ROOT = path.normalize('/android/sdk');
return check_reqs.check_android().then(() => {
expect(process.env.ANDROID_SDK_ROOT).toContain(expectedAndroidSdkPath);
});
});
it('should use ANDROID_HOME if defined and ANDROID_SDK_ROOT is not defined', () => {
it('should use ANDROID_HOME if defined', () => {
spyOn(fs, 'existsSync').and.returnValue(true);
process.env.ANDROID_HOME = path.normalize('/android/sdk');
return check_reqs.check_android().then(() => {
@@ -183,15 +175,23 @@ describe('check_reqs', function () {
});
});
it('should use ANDROID_HOME if defined and ANDROID_SDK_ROOT is defined', () => {
it('should use ANDROID_SDK_ROOT if defined and ANDROID_HOME is not defined', () => {
spyOn(fs, 'existsSync').and.returnValue(true);
process.env.ANDROID_SDK_ROOT = path.normalize('/android/sdk/root');
process.env.ANDROID_HOME = path.normalize('/android/sdk');
return check_reqs.check_android().then(() => {
expect(process.env.ANDROID_SDK_ROOT).toContain(expectedAndroidRootSdkPath);
});
});
it('should use ANDROID_HOME if defined and ANDROID_SDK_ROOT is defined', () => {
spyOn(fs, 'existsSync').and.returnValue(true);
process.env.ANDROID_HOME = path.normalize('/android/sdk');
process.env.ANDROID_SDK_ROOT = path.normalize('/android/sdk/root');
return check_reqs.check_android().then(() => {
expect(process.env.ANDROID_HOME).toContain(expectedAndroidSdkPath);
});
});
it('should throw if ANDROID_HOME points to an invalid path', () => {
process.env.ANDROID_HOME = path.normalize('/android/sdk');
return check_reqs.check_android().catch((error) => {
@@ -219,30 +219,30 @@ describe('check_reqs', function () {
describe('check_gradle', () => {
describe('environment variable checks', () => {
beforeEach(() => {
delete process.env.ANDROID_SDK_ROOT;
delete process.env.ANDROID_HOME;
delete process.env.ANDROID_SDK_ROOT;
spyOn(check_reqs, 'get_gradle_wrapper').and.callFake(() => {
return path.normalize((process.env.ANDROID_HOME || process.env.ANDROID_SDK_ROOT) + '/bin/gradle');
});
});
it('with ANDROID_SDK_ROOT / without ANDROID_HOME', async () => {
it('with ANDROID_HOME / without ANDROID_SDK_ROOT', async () => {
process.env.ANDROID_HOME = path.normalize('/android/sdk/home');
await expectAsync(check_reqs.check_gradle()).toBeResolvedTo(path.normalize('/android/sdk/home/bin/gradle'));
});
it('without ANDROID_HOME / with ANDROID_SDK_ROOT', async () => {
process.env.ANDROID_SDK_ROOT = path.normalize('/android/sdk/root');
await expectAsync(check_reqs.check_gradle()).toBeResolvedTo(path.normalize('/android/sdk/root/bin/gradle'));
});
it('with ANDROID_SDK_ROOT / with ANDROID_HOME', async () => {
it('with ANDROID_HOME / with ANDROID_SDK_ROOT', async () => {
process.env.ANDROID_HOME = path.normalize('/android/sdk/home');
process.env.ANDROID_SDK_ROOT = path.normalize('/android/sdk/root');
process.env.ANDROID_HOME = path.normalize('/android/sdk/home');
await expectAsync(check_reqs.check_gradle()).toBeResolvedTo(path.normalize('/android/sdk/home/bin/gradle'));
});
it('without ANDROID_SDK_ROOT / with ANDROID_HOME', async () => {
process.env.ANDROID_HOME = path.normalize('/android/sdk/home');
await expectAsync(check_reqs.check_gradle()).toBeResolvedTo(path.normalize('/android/sdk/home/bin/gradle'));
});
it('without ANDROID_SDK_ROOT / without ANDROID_HOME', () => {
it('without ANDROID_HOME / without ANDROID_SDK_ROOT', () => {
return check_reqs.check_gradle().catch((error) => {
expect(error.toString()).toContain('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.');
});
@@ -250,7 +250,7 @@ describe('check_reqs', function () {
});
it('should error if sdk is installed but no gradle found', () => {
process.env.ANDROID_SDK_ROOT = path.normalize('/android/sdk');
process.env.ANDROID_HOME = path.normalize('/android/sdk');
spyOn(check_reqs, 'get_gradle_wrapper').and.callFake(() => {
return '';
});

View File

@@ -23,8 +23,16 @@ const create = rewire('../../lib/create');
const check_reqs = require('../../lib/check_reqs');
const fs = require('fs-extra');
const path = require('path');
const MockCordovaGradleConfigParser = require('./mocks/config/MockCordovaGradleConfigParser');
const CordovaGradleConfigParserFactory = require('../../lib/config/CordovaGradleConfigParserFactory');
describe('create', function () {
const PROJECT_DIR = 'platforms/android';
beforeAll(() => {
spyOn(CordovaGradleConfigParserFactory, 'create').and.returnValue(new MockCordovaGradleConfigParser(PROJECT_DIR));
});
describe('validatePackageName helper method', function () {
describe('happy path (valid package names)', function () {
const valid = [

View File

@@ -0,0 +1,32 @@
/**
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 CordovaGradleConfigParser = require('../../../../lib/config/CordovaGradleConfigParser');
module.exports = class MockCordoCordovaGradleConfigParservaGradleConfigParser extends CordovaGradleConfigParser {
_readConfig (configPath) {
return {
PACKAGE_NAMESPACE: 'io.cordova.unittest'
};
}
write () {
// Pretend write :)
}
};

View File

@@ -32,6 +32,9 @@ const android_studio_project = path.join(__dirname, '../../fixtures/android_stud
const PluginInfo = require('cordova-common').PluginInfo;
const AndroidProject = require('../../../lib/AndroidProject');
const MockCordovaGradleConfigParser = require('../mocks/config/MockCordovaGradleConfigParser');
const CordovaGradleConfigParserFactory = require('../../../lib/config/CordovaGradleConfigParserFactory');
const dummyPluginInfo = new PluginInfo(dummyplugin);
const valid_source = dummyPluginInfo.getSourceFiles('android');
const valid_resources = dummyPluginInfo.getResourceFiles('android');
@@ -41,6 +44,12 @@ const faultyPluginInfo = new PluginInfo(faultyplugin);
const invalid_source = faultyPluginInfo.getSourceFiles('android');
describe('android project handler', function () {
const PROJECT_DIR = 'platforms/android';
beforeAll(() => {
spyOn(CordovaGradleConfigParserFactory, 'create').and.returnValue(new MockCordovaGradleConfigParser(PROJECT_DIR));
});
describe('installation', function () {
const copyFileOrig = common.__get__('copyFile');
const copyFileSpy = jasmine.createSpy('copyFile');

View File

@@ -23,6 +23,8 @@ const CordovaError = require('cordova-common').CordovaError;
const GradlePropertiesParser = require('../../lib/config/GradlePropertiesParser');
const utils = require('../../lib/utils');
const et = require('elementtree');
const MockCordovaGradleConfigParser = require('./mocks/config/MockCordovaGradleConfigParser');
const CordovaGradleConfigParserFactory = require('../../lib/config/CordovaGradleConfigParserFactory');
const PATH_RESOURCE = path.join('platforms', 'android', 'app', 'src', 'main', 'res');
@@ -51,8 +53,10 @@ function createResourceMap (target) {
if (!target || target === 'ic_launcher.png') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher.png')] = null;
if (!target || target === 'ic_launcher_foreground.png') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_foreground.png')] = null;
if (!target || target === 'ic_launcher_background.png') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_background.png')] = null;
if (!target || target === 'ic_launcher_background.png') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_monochrome.png')] = null;
if (!target || target === 'ic_launcher_foreground.xml') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_foreground.xml')] = null;
if (!target || target === 'ic_launcher_background.xml') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_background.xml')] = null;
if (!target || target === 'ic_launcher_background.xml') resources[path.join(PATH_RESOURCE, mipmap, 'ic_launcher_monochrome.xml')] = null;
if (
!mipmap.includes('-v26') &&
@@ -91,6 +95,12 @@ describe('prepare', () => {
let emitSpy;
let updatePathsSpy;
const PROJECT_DIR = 'platforms/android';
beforeAll(() => {
spyOn(CordovaGradleConfigParserFactory, 'create').and.returnValue(new MockCordovaGradleConfigParser(PROJECT_DIR));
});
beforeEach(() => {
prepare = rewire('../../lib/prepare');
@@ -136,10 +146,14 @@ describe('prepare', () => {
return createResourceMap('ic_launcher_foreground.png');
} else if (resourceName.includes('ic_launcher_background.png')) {
return createResourceMap('ic_launcher_background.png');
} else if (resourceName.includes('ic_launcher_monochrome.png')) {
return createResourceMap('ic_launcher_monochrome.png');
} else if (resourceName.includes('ic_launcher_foreground.xml')) {
return createResourceMap('ic_launcher_foreground.xml');
} else if (resourceName.includes('ic_launcher_background.xml')) {
return createResourceMap('ic_launcher_background.xml');
} else if (resourceName.includes('ic_launcher_monochrome.xml')) {
return createResourceMap('ic_launcher_monochrome.xml');
} else if (resourceName.includes('ic_launcher.xml')) {
return createResourceMap('ic_launcher.xml');
}
@@ -305,7 +319,9 @@ describe('prepare', () => {
return [mockGetIconItem({
density: 'mdpi',
background: 'res/icon/android/mdpi-background.png',
foreground: 'res/icon/android/mdpi-foreground.xml'
foreground: 'res/icon/android/mdpi-foreground.xml',
monochrome: 'res/icon/android/mdpi-monochrome.png'
})];
};
@@ -343,7 +359,8 @@ describe('prepare', () => {
return [mockGetIconItem({
density: 'mdpi',
background: 'res/icon/android/mdpi-background.png',
foreground: 'res/icon/android/mdpi-foreground.png'
foreground: 'res/icon/android/mdpi-foreground.png',
monochrome: 'res/icon/android/mdpi-monochrome.png'
})];
};
@@ -352,6 +369,7 @@ describe('prepare', () => {
const phaseOneModification = {};
phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_foreground.png')] = 'res/icon/android/mdpi-foreground.png';
phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_monochrome.png')] = 'res/icon/android/mdpi-monochrome.png';
const phaseOneUpdatedIconsForAdaptive = Object.assign({}, resourceMap, phaseOneModification);
updateIconResourceForAdaptiveSpy = jasmine.createSpy('updateIconResourceForAdaptiveSpy');
@@ -363,6 +381,7 @@ describe('prepare', () => {
const phaseTwoModification = {};
phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi', 'ic_launcher.png')] = 'res/icon/android/mdpi-foreground.png';
phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_monochrome.png')] = 'res/icon/android/mdpi-monochrome.png';
const phaseTwoUpdatedIconsForLegacy = Object.assign({}, phaseOneUpdatedIconsForAdaptive, phaseTwoModification);
updateIconResourceForLegacySpy = jasmine.createSpy('updateIconResourceForLegacySpy');
@@ -400,7 +419,8 @@ describe('prepare', () => {
density: 'mdpi',
src: 'res/icon/android/mdpi-icon.png',
background: 'res/icon/android/mdpi-background.png',
foreground: 'res/icon/android/mdpi-foreground.png'
foreground: 'res/icon/android/mdpi-foreground.png',
monochrome: 'res/icon/android/mdpi-monochrome.png'
})];
};
@@ -409,6 +429,7 @@ describe('prepare', () => {
const phaseOneModification = {};
phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_foreground.png')] = 'res/icon/android/mdpi-foreground.png';
phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
phaseOneModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_monochrome.png')] = 'res/icon/android/mdpi-monochrome.png';
const phaseOneUpdatedIconsForAdaptive = Object.assign({}, resourceMap, phaseOneModification);
updateIconResourceForAdaptiveSpy = jasmine.createSpy('updateIconResourceForAdaptiveSpy');
@@ -420,6 +441,7 @@ describe('prepare', () => {
const phaseTwoModification = {};
phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi', 'ic_launcher.png')] = 'res/icon/android/mdpi-foreground.png';
phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
phaseTwoModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_monochrome.png')] = 'res/icon/android/mdpi-monochrome.png';
const phaseTwoUpdatedIconsForLegacy = Object.assign({}, phaseOneUpdatedIconsForAdaptive, phaseTwoModification);
updateIconResourceForLegacySpy = jasmine.createSpy('updateIconResourceForLegacySpy');
@@ -511,13 +533,15 @@ describe('prepare', () => {
const ldpi = mockGetIconItem({
density: 'ldpi',
background: 'res/icon/android/ldpi-background.png',
foreground: 'res/icon/android/ldpi-foreground.png'
foreground: 'res/icon/android/ldpi-foreground.png',
monochrome: 'res/icon/android/ldpi-monochrome.png'
});
const mdpi = mockGetIconItem({
density: 'mdpi',
background: 'res/icon/android/mdpi-background.png',
foreground: 'res/icon/android/mdpi-foreground.png'
foreground: 'res/icon/android/mdpi-foreground.png',
monochrome: 'res/icon/android/mdpi-monochrome.png'
});
const icons = [ldpi, mdpi];
@@ -614,7 +638,8 @@ describe('prepare', () => {
mdpi: mockGetIconItem({
density: 'mdpi',
background: 'res/icon/android/mdpi-background.png',
foreground: 'res/icon/android/mdpi-foreground.png'
foreground: 'res/icon/android/mdpi-foreground.png',
monochrome: 'res/icon/android/mdpi-monochrome.png'
})
},
default_icon: undefined
@@ -636,6 +661,7 @@ describe('prepare', () => {
const expectedModification = {};
expectedModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_background.png')] = 'res/icon/android/mdpi-background.png';
expectedModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_foreground.png')] = 'res/icon/android/mdpi-foreground.png';
expectedModification[path.join(PATH_RESOURCE, 'mipmap-mdpi-v26', 'ic_launcher_monochrome.png')] = 'res/icon/android/mdpi-monochrome.png';
const expected = Object.assign({}, resourceMap, expectedModification);
const actual = updateIconResourceForAdaptive(preparedIcons, resourceMap, platformResourcesDir);
@@ -668,7 +694,8 @@ describe('prepare', () => {
const icons = [mockGetIconItem({
density: 'mdpi',
background: 'res/icon/android/mdpi-background.png',
foreground: 'res/icon/android/mdpi-foreground.png'
foreground: 'res/icon/android/mdpi-foreground.png',
monochrome: 'res/icon/android/mdpi-monochrome.png'
})];
const projectRoot = '/mock';
const projectConfig = {
@@ -893,9 +920,7 @@ describe('prepare', () => {
}),
setVersionName: jasmine.createSpy('setVersionName').and.returnValue({
setVersionCode: jasmine.createSpy('setVersionCode').and.returnValue({
setPackageId: jasmine.createSpy('setPackageId').and.returnValue({
write: jasmine.createSpy('write')
})
write: jasmine.createSpy('write')
})
})
}));

View File

@@ -19,10 +19,19 @@
const rewire = require('rewire');
const builders = require('../../lib/builders/builders');
const MockCordovaGradleConfigParser = require('./mocks/config/MockCordovaGradleConfigParser');
const CordovaGradleConfigParser = require('../../lib/config/CordovaGradleConfigParser');
const CordovaGradleConfigParserFactory = require('../../lib/config/CordovaGradleConfigParserFactory');
describe('run', () => {
let run;
const PROJECT_DIR = 'platforms/android';
beforeAll(() => {
spyOn(CordovaGradleConfigParserFactory, 'create').and.returnValue(new MockCordovaGradleConfigParser(PROJECT_DIR));
});
beforeEach(() => {
run = rewire('../../lib/run');
run.__set__({
@@ -84,7 +93,8 @@ describe('run', () => {
buildResults: {
buildType: 'debug',
apkPaths: ['fake.apk']
}
},
cordovaGradleConfigParser: jasmine.any(CordovaGradleConfigParser)
}
);
});

View File

@@ -19,10 +19,18 @@
const rewire = require('rewire');
const { CordovaError } = require('cordova-common');
const MockCordovaGradleConfigParser = require('./mocks/config/MockCordovaGradleConfigParser');
const CordovaGradleConfigParserFactory = require('../../lib/config/CordovaGradleConfigParserFactory');
describe('target', () => {
let target;
const PROJECT_DIR = 'platforms/android';
beforeAll(() => {
spyOn(CordovaGradleConfigParserFactory, 'create').and.returnValue(new MockCordovaGradleConfigParser(PROJECT_DIR));
});
beforeEach(() => {
target = rewire('../../lib/target');
});
@@ -228,14 +236,18 @@ describe('target', () => {
describe('install', () => {
let AdbSpy;
let buildSpy;
let installTarget, manifest, appSpec;
let installTarget, manifest, cordovaGradleConfigParser, appSpec;
beforeEach(() => {
installTarget = { id: 'emulator-5556', type: 'emulator', arch: 'atari' };
manifest = jasmine.createSpyObj('manifestStub', ['getPackageId', 'getActivity']);
manifest = jasmine.createSpyObj('manifestStub', ['getActivity']);
manifest.getActivity.and.returnValue(jasmine.createSpyObj('Activity', ['getName']));
appSpec = { manifest, buildResults: {} };
cordovaGradleConfigParser = jasmine.createSpyObj('cordovaGradleConfigParserStub', ['getPackageName']);
cordovaGradleConfigParser.getPackageName.and.returnValue('unittestapp');
appSpec = { manifest, buildResults: {}, cordovaGradleConfigParser };
buildSpy = jasmine.createSpyObj('build', ['findBestApkForArchitecture']);
target.__set__('build', buildSpy);
@@ -267,7 +279,7 @@ describe('target', () => {
const apkPath = 'my/apk/path/app.apk';
buildSpy.findBestApkForArchitecture.and.returnValue(apkPath);
return target.install(installTarget, { manifest, buildResults }).then(() => {
return target.install(installTarget, { manifest, buildResults, cordovaGradleConfigParser: CordovaGradleConfigParserFactory.create(PROJECT_DIR) }).then(() => {
expect(buildSpy.findBestApkForArchitecture).toHaveBeenCalledWith(buildResults, installTarget.arch);
expect(AdbSpy.install.calls.argsFor(0)[1]).toBe(apkPath);
@@ -308,7 +320,7 @@ describe('target', () => {
it('should start the newly installed app on the device', () => {
const packageId = 'unittestapp';
const activityName = 'TestActivity';
manifest.getPackageId.and.returnValue(packageId);
cordovaGradleConfigParser.getPackageName.and.returnValue(packageId);
manifest.getActivity().getName.and.returnValue(activityName);
return target.install(installTarget, appSpec).then(() => {

View File

@@ -18,7 +18,9 @@
under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="__PACKAGE__" android:versionName="1.0" android:versionCode="1" android:hardwareAccelerated="true">
android:versionName="1.0"
android:versionCode="1"
android:hardwareAccelerated="true">
<supports-screens
android:largeScreens="true"
android:normalScreens="true"

View File

@@ -179,9 +179,11 @@ task cdvPrintProps {
}
android {
namespace cordovaConfig.PACKAGE_NAMESPACE
defaultConfig {
versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
applicationId privateHelpers.extractStringFromManifest("package")
applicationId cordovaConfig.PACKAGE_NAMESPACE
minSdkVersion cordovaConfig.MIN_SDK_VERSION
if (cordovaConfig.MAX_SDK_VERSION != null) {

View File

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

View File

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 916 B

View File

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

@@ -2,4 +2,5 @@
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@mipmap/ic_launcher_background" />
<foreground android:drawable="@mipmap/ic_launcher_foreground" />
</adaptive-icon>
<monochrome android:drawable="@mipmap/ic_launcher_monochrome" />
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

View File

@@ -24,6 +24,8 @@ android {
compileSdkVersion cordovaConfig.COMPILE_SDK_VERSION
buildToolsVersion cordovaConfig.BUILD_TOOLS_VERSION
namespace 'org.apache.cordova.unittests'
defaultConfig {
applicationId "org.apache.cordova.unittests"
minSdkVersion cordovaConfig.MIN_SDK_VERSION

View File

@@ -17,8 +17,7 @@
specific language governing permissions and limitations
under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.apache.cordova.unittests">
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application
android:allowBackup="true"

26
types/index.d.ts vendored Normal file
View File

@@ -0,0 +1,26 @@
/**
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.
*/
interface Navigator {
/** This plugin displays and hides a splash screen during application launch. */
splashscreen: {
/** Dismiss the splash screen. */
hide(): void;
}
}