FIX: There was some issue with cordova android 7.0.0 that was preventing the build. going back to 6.2.3

This commit is contained in:
walljm 2018-01-19 23:47:57 -05:00
parent f38d8c1b21
commit 2542da4ac0
124 changed files with 7339 additions and 1784 deletions

File diff suppressed because one or more lines are too long

View File

@ -97,5 +97,5 @@
<variable name="ANDROID_PATHPREFIX" value="/" />
</plugin>
<preference name="AndroidLaunchMode" value="singleTask" />
<engine name="android" spec="7.0.0" />
<engine name="android" spec="6.2.3" />
</widget>

View File

@ -2255,25 +2255,20 @@
}
},
"cordova-android": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-7.0.0.tgz",
"integrity": "sha1-yVvt/PvDhjsYDE0p7/7E95Nh0Z0=",
"version": "6.2.3",
"resolved": "https://registry.npmjs.org/cordova-android/-/cordova-android-6.2.3.tgz",
"integrity": "sha1-JJ8hts5fHxyEenq4OxaQnb7Vqig=",
"requires": {
"android-versions": "1.2.1",
"cordova-common": "2.2.0",
"cordova-common": "2.0.2",
"elementtree": "0.1.6",
"nopt": "3.0.6",
"properties-parser": "0.2.3",
"q": "1.5.1",
"q": "1.5.0",
"shelljs": "0.5.3"
},
"dependencies": {
"abbrev": {
"version": "1.1.1",
"bundled": true
},
"android-versions": {
"version": "1.2.1",
"version": "1.1.0",
"bundled": true
},
"ansi": {
@ -2281,7 +2276,7 @@
"bundled": true
},
"balanced-match": {
"version": "1.0.0",
"version": "0.4.2",
"bundled": true
},
"base64-js": {
@ -2289,21 +2284,21 @@
"bundled": true
},
"big-integer": {
"version": "1.6.26",
"version": "1.6.22",
"bundled": true
},
"bplist-parser": {
"version": "0.1.1",
"bundled": true,
"requires": {
"big-integer": "1.6.26"
"big-integer": "1.6.22"
}
},
"brace-expansion": {
"version": "1.1.8",
"version": "1.1.7",
"bundled": true,
"requires": {
"balanced-match": "1.0.0",
"balanced-match": "0.4.2",
"concat-map": "0.0.1"
}
},
@ -2312,7 +2307,7 @@
"bundled": true
},
"cordova-common": {
"version": "2.2.0",
"version": "2.0.2",
"bundled": true,
"requires": {
"ansi": "0.3.1",
@ -2320,11 +2315,11 @@
"cordova-registry-mapper": "1.1.15",
"elementtree": "0.1.6",
"glob": "5.0.15",
"minimatch": "3.0.4",
"minimatch": "3.0.3",
"osenv": "0.1.4",
"plist": "1.2.0",
"q": "1.5.1",
"semver": "5.4.1",
"q": "1.5.0",
"semver": "5.3.0",
"shelljs": "0.5.3",
"underscore": "1.8.3",
"unorm": "1.4.1"
@ -2347,7 +2342,7 @@
"requires": {
"inflight": "1.0.6",
"inherits": "2.0.3",
"minimatch": "3.0.4",
"minimatch": "3.0.3",
"once": "1.4.0",
"path-is-absolute": "1.0.1"
}
@ -2369,17 +2364,17 @@
"bundled": true
},
"minimatch": {
"version": "3.0.4",
"version": "3.0.3",
"bundled": true,
"requires": {
"brace-expansion": "1.1.8"
"brace-expansion": "1.1.7"
}
},
"nopt": {
"version": "3.0.6",
"bundled": true,
"requires": {
"abbrev": "1.1.1"
"abbrev": "1.1.0"
}
},
"once": {
@ -2424,7 +2419,7 @@
"bundled": true
},
"q": {
"version": "1.5.1",
"version": "1.5.0",
"bundled": true
},
"sax": {
@ -2432,7 +2427,7 @@
"bundled": true
},
"semver": {
"version": "5.4.1",
"version": "5.3.0",
"bundled": true
},
"shelljs": {

View File

@ -33,7 +33,7 @@
"@ionic-native/status-bar": "4.3.1",
"@ionic/storage": "2.1.3",
"angularfire2": "^5.0.0-rc.4",
"cordova-android": "7.0.0",
"cordova-android": "6.2.3",
"cordova-plugin-browsertab": "^0.2.0",
"cordova-plugin-buildinfo": "^2.0.1",
"cordova-plugin-compat": "^1.2.0",

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<manifest android:hardwareAccelerated="true" android:versionCode="30003" android:versionName="3.0.3" package="walljm.dynamicbible" xmlns:android="http://schemas.android.com/apk/res/android">
<supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:resizeable="true" android:smallScreens="true" android:xlargeScreens="true"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<application android:hardwareAccelerated="true" android:icon="@mipmap/icon" android:label="@string/app_name" android:supportsRtl="true">
<activity android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale" android:label="@string/activity_name" android:launchMode="singleTask" android:name="MainActivity" android:theme="@android:style/Theme.DeviceDefault.NoActionBar" android:windowSoftInputMode="adjustResize">
<intent-filter android:label="@string/launcher_name">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="com.firebase.cordova"/>
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="bhgx5.app.goo.gl/XktS" android:scheme="https"/>
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:host="dynamicbible-7c6cf.firebaseapp.com" android:scheme="https" android:path="/__/auth/callback"/>
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="16" android:targetSdkVersion="25"/>
</manifest>

View File

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

View File

@ -24,14 +24,12 @@ ext {
buildscript {
repositories {
mavenCentral()
jcenter()
maven {
url "https://maven.google.com"
}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'com.android.tools.build:gradle:2.2.3'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7.3'
}
@ -42,7 +40,7 @@ apply plugin: 'com.github.dcendents.android-maven'
apply plugin: 'com.jfrog.bintray'
group = 'org.apache.cordova'
version = '7.0.0'
version = '6.2.3'
android {
compileSdkVersion cdvCompileSdkVersion
@ -50,8 +48,8 @@ android {
publishNonDefault true
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
}
sourceSets {
@ -129,9 +127,9 @@ bintray {
licenses = ['Apache-2.0']
labels = ['android', 'cordova', 'phonegap']
version {
name = '7.0.0'
name = '6.2.3'
released = new Date()
vcsTag = '7.0.0'
vcsTag = '6.2.3'
}
}
}

View File

@ -29,11 +29,7 @@ String doEnsureValueExists(filePath, props, key) {
String doGetProjectTarget() {
def props = new Properties()
def propertiesFile = 'project.properties';
if(!(file(propertiesFile).exists())) {
propertiesFile = '../project.properties';
}
file(propertiesFile).withReader { reader ->
file('project.properties').withReader { reader ->
props.load(reader)
}
return doEnsureValueExists('project.properties', props, 'target')

View File

@ -10,7 +10,7 @@
# Indicates whether an apk should be generated for each density.
split.density=false
# Project target.
target=android-26
target=android-25
apk-configurations=
renderscript.opt.level=O0
android.library=true

View File

@ -319,7 +319,6 @@ public class CordovaActivity extends Activity {
/**
* Called when view focus is changed
*/
@SuppressLint("InlinedApi")
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);

View File

@ -18,8 +18,6 @@
*/
package org.apache.cordova;
import android.annotation.SuppressLint;
import java.security.SecureRandom;
import org.json.JSONArray;
@ -112,9 +110,6 @@ public class CordovaBridge {
}
/** Called by cordova.js to initialize the bridge. */
//On old Androids SecureRandom isn't really secure, this is the least of your problems if
//you're running Android 4.3 and below in 2017
@SuppressLint("TrulyRandom")
int generateBridgeSecret() {
SecureRandom randGen = new SecureRandom();
expectedBridgeSecret = randGen.nextInt(Integer.MAX_VALUE);

View File

@ -22,12 +22,10 @@ import java.security.Principal;
import java.security.PrivateKey;
import java.security.cert.X509Certificate;
import android.annotation.SuppressLint;
import android.webkit.ClientCertRequest;
/**
* Implementation of the ICordovaClientCertRequest for Android WebView.
*
*/
public class CordovaClientCertRequest implements ICordovaClientCertRequest {
@ -40,7 +38,6 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest {
/**
* Cancel this request
*/
@SuppressLint("NewApi")
public void cancel()
{
request.cancel();
@ -49,7 +46,6 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest {
/*
* Returns the host name of the server requesting the certificate.
*/
@SuppressLint("NewApi")
public String getHost()
{
return request.getHost();
@ -58,7 +54,6 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest {
/*
* Returns the acceptable types of asymmetric keys (can be null).
*/
@SuppressLint("NewApi")
public String[] getKeyTypes()
{
return request.getKeyTypes();
@ -67,7 +62,6 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest {
/*
* Returns the port number of the server requesting the certificate.
*/
@SuppressLint("NewApi")
public int getPort()
{
return request.getPort();
@ -76,7 +70,6 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest {
/*
* Returns the acceptable certificate issuers for the certificate matching the private key (can be null).
*/
@SuppressLint("NewApi")
public Principal[] getPrincipals()
{
return request.getPrincipals();
@ -85,7 +78,6 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest {
/*
* Ignore the request for now. Do not remember user's choice.
*/
@SuppressLint("NewApi")
public void ignore()
{
request.ignore();
@ -97,7 +89,6 @@ public class CordovaClientCertRequest implements ICordovaClientCertRequest {
* @param privateKey The privateKey
* @param chain The certificate chain
*/
@SuppressLint("NewApi")
public void proceed(PrivateKey privateKey, X509Certificate[] chain)
{
request.proceed(privateKey, chain);

View File

@ -19,7 +19,6 @@
package org.apache.cordova;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import org.apache.cordova.CordovaPlugin;
@ -52,18 +51,10 @@ public interface CordovaInterface {
/**
* Get the Android activity.
*
* If a custom engine lives outside of the Activity's lifecycle the return value may be null.
*
* @return the Activity
*/
public abstract Activity getActivity();
/**
* Get the Android context.
*
* @return the Context
*/
public Context getContext();
/**
* Called when a message is sent to plugin.

View File

@ -19,9 +19,7 @@
package org.apache.cordova;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
@ -86,11 +84,6 @@ public class CordovaInterfaceImpl implements CordovaInterface {
return activity;
}
@Override
public Context getContext() {
return activity;
}
@Override
public Object onMessage(String id, Object data) {
if ("exit".equals(id)) {
@ -228,7 +221,6 @@ public class CordovaInterfaceImpl implements CordovaInterface {
requestPermissions(plugin, requestCode, permissions);
}
@SuppressLint("NewApi")
public void requestPermissions(CordovaPlugin plugin, int requestCode, String [] permissions) {
int mappedRequestCode = permissionResultCallbacks.registerCallback(plugin, requestCode);
getActivity().requestPermissions(permissions, mappedRequestCode);

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

View File

@ -18,7 +18,6 @@
*/
package org.apache.cordova;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
@ -92,7 +91,6 @@ public class CordovaWebViewImpl implements CordovaWebView {
init(cordova, new ArrayList<PluginEntry>(), new CordovaPreferences());
}
@SuppressLint("Assert")
@Override
public void init(CordovaInterface cordova, List<PluginEntry> pluginEntries, CordovaPreferences preferences) {
if (this.cordova != null) {

View File

@ -1,87 +0,0 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
package org.apache.cordova;
import java.util.Arrays;
import org.json.JSONException;
import android.content.pm.PackageManager;
/**
* This class provides reflective methods for permission requesting and checking so that plugins
* written for cordova-android 5.0.0+ can still compile with earlier cordova-android versions.
*/
public class PermissionHelper {
private static final String LOG_TAG = "CordovaPermissionHelper";
/**
* Requests a "dangerous" permission for the application at runtime. This is a helper method
* alternative to cordovaInterface.requestPermission() that does not require the project to be
* built with cordova-android 5.0.0+
*
* @param plugin The plugin the permission is being requested for
* @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult()
* along with the result of the permission request
* @param permission The permission to be requested
*/
public static void requestPermission(CordovaPlugin plugin, int requestCode, String permission) {
PermissionHelper.requestPermissions(plugin, requestCode, new String[] {permission});
}
/**
* Requests "dangerous" permissions for the application at runtime. This is a helper method
* alternative to cordovaInterface.requestPermissions() that does not require the project to be
* built with cordova-android 5.0.0+
*
* @param plugin The plugin the permissions are being requested for
* @param requestCode A requestCode to be passed to the plugin's onRequestPermissionResult()
* along with the result of the permissions request
* @param permissions The permissions to be requested
*/
public static void requestPermissions(CordovaPlugin plugin, int requestCode, String[] permissions) {
plugin.cordova.requestPermissions(plugin, requestCode, permissions);
}
/**
* Checks at runtime to see if the application has been granted a permission. This is a helper
* method alternative to cordovaInterface.hasPermission() that does not require the project to
* be built with cordova-android 5.0.0+
*
* @param plugin The plugin the permission is being checked against
* @param permission The permission to be checked
*
* @return True if the permission has already been granted and false otherwise
*/
public static boolean hasPermission(CordovaPlugin plugin, String permission) {
return plugin.cordova.hasPermission(permission);
}
private static void deliverPermissionResult(CordovaPlugin plugin, int requestCode, String[] permissions) {
// Generate the request results
int[] requestResults = new int[permissions.length];
Arrays.fill(requestResults, PackageManager.PERMISSION_GRANTED);
try {
plugin.onRequestPermissionResult(requestCode, permissions, requestResults);
} catch (JSONException e) {
LOG.e(LOG_TAG, "JSONException when delivering permissions results", e);
}
}
}

View File

@ -110,12 +110,8 @@ public class SystemWebViewEngine implements CordovaWebViewEngine {
nativeToJsMessageQueue.addBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode(new NativeToJsMessageQueue.OnlineEventsBridgeMode.OnlineEventsBridgeModeDelegate() {
@Override
public void setNetworkAvailable(boolean value) {
//sometimes this can be called after calling webview.destroy() on destroy()
//thus resulting in a NullPointerException
if(webView!=null) {
webView.setNetworkAvailable(value);
}
}
@Override
public void runOnUiThread(Runnable r) {
SystemWebViewEngine.this.cordova.getActivity().runOnUiThread(r);
@ -214,6 +210,11 @@ public class SystemWebViewEngine implements CordovaWebViewEngine {
settings.setAppCachePath(databasePath);
settings.setAppCacheEnabled(true);
// Enable scaling
// Fix for CB-12015
settings.setUseWideViewPort(true);
settings.setLoadWithOverviewMode(true);
// Fix for CB-1405
// Google issue 4641
String defaultUserAgent = settings.getUserAgentString();
@ -254,9 +255,6 @@ public class SystemWebViewEngine implements CordovaWebViewEngine {
}
}
// Yeah, we know, which is why we makes ure that we don't do this if the bridge is
// below JELLYBEAN_MR1. It'd be great if lint was just a little smarter.
@SuppressLint("AddJavascriptInterface")
private static void exposeJsInterface(WebView webView, CordovaBridge bridge) {
if ((Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1)) {
LOG.i(TAG, "Disabled addJavascriptInterface() bridge since Android version is old.");

View File

@ -8,6 +8,14 @@
"res/xml/config.xml": {
"parents": {
"/*": [
{
"xml": "<feature name=\"BrowserTab\"><param name=\"android-package\" value=\"com.google.cordova.plugin.browsertab.BrowserTab\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"BuildInfo\"><param name=\"android-package\" value=\"org.apache.cordova.buildinfo.BuildInfo\" /></feature>",
"count": 1
},
{
"xml": "<preference name=\"webView\" value=\"org.crosswalk.engine.XWalkWebViewEngine\" />",
"count": 1
@ -36,10 +44,18 @@
"xml": "<preference name=\"android-minSdkVersion\" value=\"16\" />",
"count": 1
},
{
"xml": "<feature name=\"LaunchMyApp\"><param name=\"android-package\" value=\"nl.xservices.plugins.LaunchMyApp\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"Device\"><param name=\"android-package\" value=\"org.apache.cordova.device.Device\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"InAppBrowser\"><param name=\"android-package\" value=\"org.apache.cordova.inappbrowser.InAppBrowser\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"SplashScreen\"><param name=\"android-package\" value=\"org.apache.cordova.splashscreen.SplashScreen\" /><param name=\"onload\" value=\"true\" /></feature>",
"count": 1
@ -52,28 +68,12 @@
"xml": "<feature name=\"Whitelist\"><param name=\"android-package\" value=\"org.apache.cordova.whitelist.WhitelistPlugin\" /><param name=\"onload\" value=\"true\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"Keyboard\"><param name=\"android-package\" value=\"io.ionic.keyboard.IonicKeyboard\" /><param name=\"onload\" value=\"true\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"BuildInfo\"><param name=\"android-package\" value=\"org.apache.cordova.buildinfo.BuildInfo\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"UniversalLinks\"><param name=\"android-package\" value=\"com.nordnetab.cordova.ul.UniversalLinksPlugin\" /><param name=\"onload\" value=\"true\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"BrowserTab\"><param name=\"android-package\" value=\"com.google.cordova.plugin.browsertab.BrowserTab\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"InAppBrowser\"><param name=\"android-package\" value=\"org.apache.cordova.inappbrowser.InAppBrowser\" /></feature>",
"count": 1
},
{
"xml": "<feature name=\"LaunchMyApp\"><param name=\"android-package\" value=\"nl.xservices.plugins.LaunchMyApp\" /></feature>",
"xml": "<feature name=\"Keyboard\"><param name=\"android-package\" value=\"io.ionic.keyboard.IonicKeyboard\" /><param name=\"onload\" value=\"true\" /></feature>",
"count": 1
}
]
@ -106,6 +106,15 @@
}
},
"installed_plugins": {
"cordova-plugin-compat": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-browsertab": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-buildinfo": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-console": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
@ -117,9 +126,19 @@
"XWALK_MULTIPLEAPK": "true",
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-customurlscheme": {
"URL_SCHEME": "com.firebase.cordova",
"ANDROID_SCHEME": " ",
"ANDROID_HOST": " ",
"ANDROID_PATHPREFIX": "/",
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-device": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-inappbrowser": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-splashscreen": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
@ -129,31 +148,39 @@
"cordova-plugin-whitelist": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"ionic-plugin-keyboard": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-buildinfo": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-universal-links-plugin": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-browsertab": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-inappbrowser": {
"PACKAGE_NAME": "walljm.dynamicbible"
},
"cordova-plugin-customurlscheme": {
"URL_SCHEME": "com.firebase.cordova",
"ANDROID_SCHEME": " ",
"ANDROID_HOST": " ",
"ANDROID_PATHPREFIX": "/",
"ionic-plugin-keyboard": {
"PACKAGE_NAME": "walljm.dynamicbible"
}
},
"dependent_plugins": {},
"modules": [
{
"id": "cordova-plugin-browsertab.BrowserTab",
"file": "plugins/cordova-plugin-browsertab/www/browsertab.js",
"pluginId": "cordova-plugin-browsertab",
"clobbers": [
"cordova.plugins.browsertab"
]
},
{
"id": "cordova-plugin-buildinfo.BuildInfo",
"file": "plugins/cordova-plugin-buildinfo/www/buildinfo.js",
"pluginId": "cordova-plugin-buildinfo",
"clobbers": [
"BuildInfo"
]
},
{
"id": "cordova-plugin-customurlscheme.LaunchMyApp",
"file": "plugins/cordova-plugin-customurlscheme/www/android/LaunchMyApp.js",
"pluginId": "cordova-plugin-customurlscheme",
"clobbers": [
"window.plugins.launchmyapp"
]
},
{
"id": "cordova-plugin-device.device",
"file": "plugins/cordova-plugin-device/www/device.js",
@ -162,6 +189,15 @@
"device"
]
},
{
"id": "cordova-plugin-inappbrowser.inappbrowser",
"file": "plugins/cordova-plugin-inappbrowser/www/inappbrowser.js",
"pluginId": "cordova-plugin-inappbrowser",
"clobbers": [
"cordova.InAppBrowser.open",
"window.open"
]
},
{
"id": "cordova-plugin-splashscreen.SplashScreen",
"file": "plugins/cordova-plugin-splashscreen/www/splashscreen.js",
@ -178,23 +214,6 @@
"window.StatusBar"
]
},
{
"id": "ionic-plugin-keyboard.keyboard",
"file": "plugins/ionic-plugin-keyboard/www/android/keyboard.js",
"pluginId": "ionic-plugin-keyboard",
"clobbers": [
"cordova.plugins.Keyboard"
],
"runs": true
},
{
"id": "cordova-plugin-buildinfo.BuildInfo",
"file": "plugins/cordova-plugin-buildinfo/www/buildinfo.js",
"pluginId": "cordova-plugin-buildinfo",
"clobbers": [
"BuildInfo"
]
},
{
"id": "cordova-universal-links-plugin.universalLinks",
"file": "plugins/cordova-universal-links-plugin/www/universal_links.js",
@ -204,43 +223,28 @@
]
},
{
"id": "cordova-plugin-browsertab.BrowserTab",
"file": "plugins/cordova-plugin-browsertab/www/browsertab.js",
"pluginId": "cordova-plugin-browsertab",
"id": "ionic-plugin-keyboard.keyboard",
"file": "plugins/ionic-plugin-keyboard/www/android/keyboard.js",
"pluginId": "ionic-plugin-keyboard",
"clobbers": [
"cordova.plugins.browsertab"
]
},
{
"id": "cordova-plugin-inappbrowser.inappbrowser",
"file": "plugins/cordova-plugin-inappbrowser/www/inappbrowser.js",
"pluginId": "cordova-plugin-inappbrowser",
"clobbers": [
"cordova.InAppBrowser.open",
"window.open"
]
},
{
"id": "cordova-plugin-customurlscheme.LaunchMyApp",
"file": "plugins/cordova-plugin-customurlscheme/www/android/LaunchMyApp.js",
"pluginId": "cordova-plugin-customurlscheme",
"clobbers": [
"window.plugins.launchmyapp"
]
"cordova.plugins.Keyboard"
],
"runs": true
}
],
"plugin_metadata": {
"cordova-plugin-compat": "1.2.0",
"cordova-plugin-browsertab": "0.2.0",
"cordova-plugin-buildinfo": "2.0.1",
"cordova-plugin-console": "1.1.0",
"cordova-plugin-crosswalk-webview": "2.3.0",
"cordova-plugin-customurlscheme": "4.3.0",
"cordova-plugin-device": "1.1.7",
"cordova-plugin-inappbrowser": "2.0.1",
"cordova-plugin-splashscreen": "4.1.0",
"cordova-plugin-statusbar": "2.4.1",
"cordova-plugin-whitelist": "1.3.3",
"ionic-plugin-keyboard": "2.2.1",
"cordova-plugin-buildinfo": "2.0.1",
"cordova-universal-links-plugin": "1.2.1",
"cordova-plugin-browsertab": "0.2.0",
"cordova-plugin-inappbrowser": "2.0.1",
"cordova-plugin-customurlscheme": "4.3.0"
"ionic-plugin-keyboard": "2.2.1"
}
}

View File

@ -1,4 +1,5 @@
/* Licensed to the Apache Software Foundation (ASF) under one
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
@ -16,39 +17,301 @@
under the License.
*/
// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply plugin: 'com.android.application'
buildscript {
repositories {
mavenCentral()
jcenter()
maven {
url "https://maven.google.com"
}
}
// Switch the Android Gradle plugin version requirement depending on the
// installed version of Gradle. This dependency is documented at
// http://tools.android.com/tech-docs/new-build-system/version-compatibility
// and https://issues.apache.org/jira/browse/CB-8143
dependencies {
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
classpath 'com.android.tools.build:gradle:3.0.0'
classpath 'com.android.tools.build:gradle:2.2.3'
}
}
// Allow plugins to declare Maven dependencies via build-extras.gradle.
allprojects {
repositories {
mavenCentral();
jcenter()
maven {
url "https://maven.google.com"
}
}
//This replaces project.properties w.r.t. build settings
project.ext {
defaultBuildToolsVersion="25.0.2" //String
defaultMinSdkVersion=19 //Integer - Minimum requirement is Android 4.4
defaultTargetSdkVersion=26 //Integer - We ALWAYS target the latest by default
defaultCompileSdkVersion=26 //Integer - We ALWAYS compile with the latest by default
}
}
task clean(type: Delete) {
delete rootProject.buildDir
task wrapper(type: Wrapper) {
gradleVersion = '2.14.1'
}
// Configuration properties. Set these via environment variables, build-extras.gradle, or gradle.properties.
// Refer to: http://www.gradle.org/docs/current/userguide/tutorial_this_and_that.html
ext {
apply from: 'CordovaLib/cordova.gradle'
// The value for android.compileSdkVersion.
if (!project.hasProperty('cdvCompileSdkVersion')) {
cdvCompileSdkVersion = null;
}
// The value for android.buildToolsVersion.
if (!project.hasProperty('cdvBuildToolsVersion')) {
cdvBuildToolsVersion = null;
}
// Sets the versionCode to the given value.
if (!project.hasProperty('cdvVersionCode')) {
cdvVersionCode = null
}
// Sets the minSdkVersion to the given value.
if (!project.hasProperty('cdvMinSdkVersion')) {
cdvMinSdkVersion = null
}
// Whether to build architecture-specific APKs.
if (!project.hasProperty('cdvBuildMultipleApks')) {
cdvBuildMultipleApks = null
}
// .properties files to use for release signing.
if (!project.hasProperty('cdvReleaseSigningPropertiesFile')) {
cdvReleaseSigningPropertiesFile = null
}
// .properties files to use for debug signing.
if (!project.hasProperty('cdvDebugSigningPropertiesFile')) {
cdvDebugSigningPropertiesFile = null
}
// Set by build.js script.
if (!project.hasProperty('cdvBuildArch')) {
cdvBuildArch = null
}
// Plugin gradle extensions can append to this to have code run at the end.
cdvPluginPostBuildExtras = []
}
// PLUGIN GRADLE EXTENSIONS START
apply from: "cordova-plugin-browsertab/dynamicbible-BrowserTab.gradle"
apply from: "cordova-plugin-buildinfo/dynamicbible-BuildInfo.gradle"
apply from: "cordova-plugin-crosswalk-webview/dynamicbible-xwalk.gradle"
// PLUGIN GRADLE EXTENSIONS END
def hasBuildExtras = file('build-extras.gradle').exists()
if (hasBuildExtras) {
apply from: 'build-extras.gradle'
}
// Set property defaults after extension .gradle files.
if (ext.cdvCompileSdkVersion == null) {
ext.cdvCompileSdkVersion = privateHelpers.getProjectTarget()
}
if (ext.cdvBuildToolsVersion == null) {
ext.cdvBuildToolsVersion = privateHelpers.findLatestInstalledBuildTools()
}
if (ext.cdvDebugSigningPropertiesFile == null && file('debug-signing.properties').exists()) {
ext.cdvDebugSigningPropertiesFile = 'debug-signing.properties'
}
if (ext.cdvReleaseSigningPropertiesFile == null && file('release-signing.properties').exists()) {
ext.cdvReleaseSigningPropertiesFile = 'release-signing.properties'
}
// Cast to appropriate types.
ext.cdvBuildMultipleApks = cdvBuildMultipleApks == null ? false : cdvBuildMultipleApks.toBoolean();
ext.cdvMinSdkVersion = cdvMinSdkVersion == null ? null : Integer.parseInt('' + cdvMinSdkVersion)
ext.cdvVersionCode = cdvVersionCode == null ? null : Integer.parseInt('' + cdvVersionCode)
def computeBuildTargetName(debugBuild) {
def ret = 'assemble'
if (cdvBuildMultipleApks && cdvBuildArch) {
def arch = cdvBuildArch == 'arm' ? 'armv7' : cdvBuildArch
ret += '' + arch.toUpperCase().charAt(0) + arch.substring(1);
}
return ret + (debugBuild ? 'Debug' : 'Release')
}
// Make cdvBuild a task that depends on the debug/arch-sepecific task.
task cdvBuildDebug
cdvBuildDebug.dependsOn {
return computeBuildTargetName(true)
}
task cdvBuildRelease
cdvBuildRelease.dependsOn {
return computeBuildTargetName(false)
}
task cdvPrintProps << {
println('cdvCompileSdkVersion=' + cdvCompileSdkVersion)
println('cdvBuildToolsVersion=' + cdvBuildToolsVersion)
println('cdvVersionCode=' + cdvVersionCode)
println('cdvMinSdkVersion=' + cdvMinSdkVersion)
println('cdvBuildMultipleApks=' + cdvBuildMultipleApks)
println('cdvReleaseSigningPropertiesFile=' + cdvReleaseSigningPropertiesFile)
println('cdvDebugSigningPropertiesFile=' + cdvDebugSigningPropertiesFile)
println('cdvBuildArch=' + cdvBuildArch)
println('computedVersionCode=' + android.defaultConfig.versionCode)
android.productFlavors.each { flavor ->
println('computed' + flavor.name.capitalize() + 'VersionCode=' + flavor.versionCode)
}
}
android {
sourceSets {
main {
manifest.srcFile 'AndroidManifest.xml'
java.srcDirs = ['src']
resources.srcDirs = ['src']
aidl.srcDirs = ['src']
renderscript.srcDirs = ['src']
res.srcDirs = ['res']
assets.srcDirs = ['assets']
jniLibs.srcDirs = ['libs']
}
}
defaultConfig {
versionCode cdvVersionCode ?: new BigInteger("" + privateHelpers.extractIntFromManifest("versionCode"))
applicationId privateHelpers.extractStringFromManifest("package")
if (cdvMinSdkVersion != null) {
minSdkVersion cdvMinSdkVersion
}
}
lintOptions {
abortOnError false;
}
compileSdkVersion cdvCompileSdkVersion
buildToolsVersion cdvBuildToolsVersion
if (Boolean.valueOf(cdvBuildMultipleApks)) {
productFlavors {
armv7 {
versionCode defaultConfig.versionCode*10 + 2
ndk {
abiFilters "armeabi-v7a", ""
}
}
x86 {
versionCode defaultConfig.versionCode*10 + 4
ndk {
abiFilters "x86", ""
}
}
all {
ndk {
abiFilters "all", ""
}
}
}
}
/*
ELSE NOTHING! DON'T MESS WITH THE VERSION CODE IF YOU DON'T HAVE TO!
else if (!cdvVersionCode) {
def minSdkVersion = cdvMinSdkVersion ?: privateHelpers.extractIntFromManifest("minSdkVersion")
// Vary versionCode by the two most common API levels:
// 14 is ICS, which is the lowest API level for many apps.
// 20 is Lollipop, which is the lowest API level for the updatable system webview.
if (minSdkVersion >= 20) {
defaultConfig.versionCode += 9
} else if (minSdkVersion >= 14) {
defaultConfig.versionCode += 8
}
}
*/
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_6
targetCompatibility JavaVersion.VERSION_1_6
}
if (cdvReleaseSigningPropertiesFile) {
signingConfigs {
release {
// These must be set or Gradle will complain (even if they are overridden).
keyAlias = ""
keyPassword = "__unset" // And these must be set to non-empty in order to have the signing step added to the task graph.
storeFile = null
storePassword = "__unset"
}
}
buildTypes {
release {
signingConfig signingConfigs.release
}
}
addSigningProps(cdvReleaseSigningPropertiesFile, signingConfigs.release)
}
if (cdvDebugSigningPropertiesFile) {
addSigningProps(cdvDebugSigningPropertiesFile, signingConfigs.debug)
}
}
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
// SUB-PROJECT DEPENDENCIES START
debugCompile(project(path: "CordovaLib", configuration: "debug"))
releaseCompile(project(path: "CordovaLib", configuration: "release"))
compile "com.android.support:customtabs:23.3.0"
// SUB-PROJECT DEPENDENCIES END
}
def promptForReleaseKeyPassword() {
if (!cdvReleaseSigningPropertiesFile) {
return;
}
if ('__unset'.equals(android.signingConfigs.release.storePassword)) {
android.signingConfigs.release.storePassword = privateHelpers.promptForPassword('Enter key store password: ')
}
if ('__unset'.equals(android.signingConfigs.release.keyPassword)) {
android.signingConfigs.release.keyPassword = privateHelpers.promptForPassword('Enter key password: ');
}
}
gradle.taskGraph.whenReady { taskGraph ->
taskGraph.getAllTasks().each() { task ->
if (task.name == 'validateReleaseSigning' || task.name == 'validateSigningRelease') {
promptForReleaseKeyPassword()
}
}
}
def addSigningProps(propsFilePath, signingConfig) {
def propsFile = file(propsFilePath)
def props = new Properties()
propsFile.withReader { reader ->
props.load(reader)
}
def storeFile = new File(props.get('key.store') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'storeFile'))
if (!storeFile.isAbsolute()) {
storeFile = RelativePath.parse(true, storeFile.toString()).getFile(propsFile.getParentFile())
}
if (!storeFile.exists()) {
throw new FileNotFoundException('Keystore file does not exist: ' + storeFile.getAbsolutePath())
}
signingConfig.keyAlias = props.get('key.alias') ?: privateHelpers.ensureValueExists(propsFilePath, props, 'keyAlias')
signingConfig.keyPassword = props.get('keyPassword', props.get('key.alias.password', signingConfig.keyPassword))
signingConfig.storeFile = storeFile
signingConfig.storePassword = props.get('storePassword', props.get('key.store.password', signingConfig.storePassword))
def storeType = props.get('storeType', props.get('key.store.type', ''))
if (!storeType) {
def filename = storeFile.getName().toLowerCase();
if (filename.endsWith('.p12') || filename.endsWith('.pfx')) {
storeType = 'pkcs12'
} else {
storeType = signingConfig.storeType // "jks"
}
}
signingConfig.storeType = storeType
}
for (def func : cdvPluginPostBuildExtras) {
func()
}
// This can be defined within build-extras.gradle as:
// ext.postBuildExtras = { ... code here ... }
if (hasProperty('postBuildExtras')) {
postBuildExtras()
}

View File

@ -29,7 +29,7 @@ def DEFAULT_MIN_SDK_VERSION = 14
def getConfigPreference(name) {
name = name.toLowerCase()
def xml = file("src/main/res/xml/config.xml").getText()
def xml = file("res/xml/config.xml").getText()
// Disable namespace awareness since Cordova doesn't use them properly
def root = new XmlParser(false, false).parseText(xml)

View File

@ -0,0 +1,10 @@
{
"node": true
, "bitwise": true
, "undef": true
, "trailing": true
, "quotmark": true
, "indent": 4
, "unused": "vars"
, "latedef": "nofunc"
}

View File

@ -29,6 +29,7 @@ var selfEvents = require('cordova-common').events;
var PLATFORM = 'android';
function setupEvents(externalEventEmitter) {
if (externalEventEmitter) {
// This will make the platform internal events visible outside
@ -42,6 +43,7 @@ function setupEvents (externalEventEmitter) {
return selfEvents;
}
/**
* Class, that acts as abstraction over particular platform. Encapsulates the
* platform's properties and methods.
@ -56,7 +58,6 @@ function setupEvents (externalEventEmitter) {
function Api(platform, platformRootDir, events) {
this.platform = PLATFORM;
this.root = path.resolve(__dirname, '..');
this.builder = 'gradle';
setupEvents(events);
@ -72,7 +73,6 @@ function Api (platform, platformRootDir, events) {
strings: path.join(self.root, 'res/values/strings.xml'),
manifest: path.join(self.root, 'AndroidManifest.xml'),
build: path.join(self.root, 'build'),
javaSrc: path.join(self.root, 'src'),
// NOTE: Due to platformApi spec we need to return relative paths here
cordovaJs: 'bin/templates/project/assets/www/cordova.js',
cordovaJsSrc: 'cordova-js-src'
@ -81,13 +81,10 @@ function Api (platform, platformRootDir, events) {
// XXX Override some locations for Android Studio projects
if(AndroidStudio.isAndroidStudioProject(self.root) === true) {
selfEvents.emit('log', 'Android Studio project detected');
this.builder = 'studio';
this.android_studio = true;
this.locations.configXml = path.join(self.root, 'app/src/main/res/xml/config.xml');
this.locations.strings = path.join(self.root, 'app/src/main/res/values/strings.xml');
this.locations.strings = path.join(self.root, 'app/src/main/res/xml/strings.xml');
this.locations.manifest = path.join(self.root, 'app/src/main/AndroidManifest.xml');
// We could have Java Source, we could have other languages
this.locations.javaSrc = path.join(self.root, 'app/src/main/java/');
this.locations.www = path.join(self.root, 'app/src/main/assets/www');
this.locations.res = path.join(self.root, 'app/src/main/res');
}
@ -115,11 +112,14 @@ Api.createPlatform = function (destination, config, options, events) {
events = setupEvents(events);
var result;
try {
result = require('../../lib/create').create(destination, config, options, events).then(function (destination) {
result = require('../../lib/create')
.create(destination, config, options, events)
.then(function (destination) {
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
return new PlatformApi(PLATFORM, destination, events);
});
} catch (e) {
}
catch (e) {
events.emit('error','createPlatform is not callable from the android project API.');
throw(e);
}
@ -146,11 +146,14 @@ Api.updatePlatform = function (destination, options, events) {
events = setupEvents(events);
var result;
try {
result = require('../../lib/create').update(destination, options, events).then(function (destination) {
result = require('../../lib/create')
.update(destination, options, events)
.then(function (destination) {
var PlatformApi = require(path.resolve(destination, 'cordova/Api'));
return new PlatformApi('android', destination, events);
});
} catch (e) {
}
catch (e) {
events.emit('error','updatePlatform is not callable from the android project API, you will need to do this manually.');
throw(e);
}
@ -227,10 +230,12 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
installOptions.android_studio = true;
}
return Q().then(function () {
return Q()
.then(function () {
//CB-11964: Do a clean when installing the plugin code to get around
//the Gradle bug introduced by the Android Gradle Plugin Version 2.2
//TODO: Delete when the next version of Android Gradle plugin comes out
// Since clean doesn't just clean the build, it also wipes out www, we need
// to pass additional options.
@ -243,13 +248,16 @@ Api.prototype.addPlugin = function (plugin, installOptions) {
if(!AndroidStudio.isAndroidStudioProject(self.root) && !project.isClean()) {
return self.clean(opts);
}
}).then(function () {
return PluginManager.get(self.platform, self.locations, project).addPlugin(plugin, installOptions);
}).then(function () {
})
.then(function () {
return PluginManager.get(self.platform, self.locations, project)
.addPlugin(plugin, installOptions);
})
.then(function () {
if (plugin.getFrameworks(this.platform).length === 0) return;
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
// This should pick the correct builder, not just get gradle
require('./lib/builders/builders').getBuilder(this.builder).prepBuildFiles();
require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
}.bind(this))
// CB-11022 Return truthy value to prevent running prepare after
.thenResolve(true);
@ -282,7 +290,7 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) {
if (plugin.getFrameworks(this.platform).length === 0) return;
selfEvents.emit('verbose', 'Updating build files since android plugin contained <framework>');
require('./lib/builders/builders').getBuilder(this.builder).prepBuildFiles();
require('./lib/builders/builders').getBuilder('gradle').prepBuildFiles();
}.bind(this))
// CB-11022 Return truthy value to prevent running prepare after
.thenResolve(true);
@ -335,12 +343,11 @@ Api.prototype.removePlugin = function (plugin, uninstallOptions) {
*/
Api.prototype.build = function (buildOptions) {
var self = this;
if (this.android_studio) {
buildOptions.studio = true;
}
return require('./lib/check_reqs').run().then(function () {
return require('./lib/check_reqs').run()
.then(function () {
return require('./lib/build').run.call(self, buildOptions);
}).then(function (buildResults) {
})
.then(function (buildResults) {
// Cast build result to array of build artifacts
return buildResults.apkPaths.map(function (apkPath) {
return {
@ -367,7 +374,8 @@ Api.prototype.build = function (buildOptions) {
*/
Api.prototype.run = function(runOptions) {
var self = this;
return require('./lib/check_reqs').run().then(function () {
return require('./lib/check_reqs').run()
.then(function () {
return require('./lib/run').run.call(self, runOptions);
});
};
@ -381,21 +389,17 @@ Api.prototype.run = function (runOptions) {
*/
Api.prototype.clean = function(cleanOptions) {
var self = this;
if (this.android_studio) {
// This will lint, checking for null won't
if (typeof cleanOptions === 'undefined') {
cleanOptions = {};
}
cleanOptions.studio = true;
}
return require('./lib/check_reqs').run().then(function () {
return require('./lib/check_reqs').run()
.then(function () {
return require('./lib/build').runClean.call(self, cleanOptions);
}).then(function () {
})
.then(function () {
return require('./lib/prepare').clean.call(self, cleanOptions);
});
};
/**
* Performs a requirements check for current platform. Each platform defines its
* own set of requirements, which should be resolved before platform can be

View File

@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0android_sdk_version"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'android_sdk_version' script in 'bin' folder, aborting...>&2

View File

@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0check_reqs"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'check_reqs' script in 'bin' folder, aborting...>&2

View File

@ -44,7 +44,8 @@ function isEmulator (line) {
* devices/emulators
*/
Adb.devices = function (opts) {
return spawn('adb', ['devices'], {cwd: os.tmpdir()}).then(function (output) {
return spawn('adb', ['devices'], {cwd: os.tmpdir()})
.then(function(output) {
return output.split('\n').filter(function (line) {
// Filter out either real devices or emulators, depending on options
return (line && opts && opts.emulators) ? isEmulator(line) : isDevice(line);
@ -58,7 +59,8 @@ Adb.install = function (target, packagePath, opts) {
events.emit('verbose', 'Installing apk ' + packagePath + ' on target ' + target + '...');
var args = ['-s', target, 'install'];
if (opts && opts.replace) args.push('-r');
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()}).then(function (output) {
return spawn('adb', args.concat(packagePath), {cwd: os.tmpdir()})
.then(function(output) {
// 'adb install' seems to always returns no error, even if installation fails
// so we catching output to detect installation failure
if (output.match(/Failure/)) {
@ -84,7 +86,8 @@ Adb.shell = function (target, shellCommand) {
events.emit('verbose', 'Running adb shell command "' + shellCommand + '" on target ' + target + '...');
var args = ['-s', target, 'shell'];
shellCommand = shellCommand.split(/\s+/);
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()}).catch(function (output) {
return spawn('adb', args.concat(shellCommand), {cwd: os.tmpdir()})
.catch(function (output) {
return Q.reject(new CordovaError('Failed to execute shell command "' +
shellCommand + '"" on device: ' + output));
});
@ -92,7 +95,8 @@ Adb.shell = function (target, shellCommand) {
Adb.start = function (target, activityName) {
events.emit('verbose', 'Starting application "' + activityName + '" on target ' + target + '...');
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName).catch(function (output) {
return Adb.shell(target, 'am start -W -a android.intent.action.MAIN -n' + activityName)
.catch(function (output) {
return Q.reject(new CordovaError('Failed to start application "' +
activityName + '"" on device: ' + output));
});

View File

@ -102,7 +102,8 @@ AndroidManifest.prototype.getActivity = function () {
};
};
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion'].forEach(function (sdkPrefName) {
['minSdkVersion', 'maxSdkVersion', 'targetSdkVersion']
.forEach(function(sdkPrefName) {
// Copy variable reference to avoid closure issues
var prefName = sdkPrefName;

View File

@ -28,7 +28,8 @@ var projectFileCache = {};
function addToPropertyList(projectProperties, key, value) {
var i = 1;
while (projectProperties.get(key + '.' + i)) { i++; }
while (projectProperties.get(key + '.' + i))
i++;
projectProperties.set(key + '.' + i, value);
projectProperties.dirty = true;
@ -53,7 +54,7 @@ function removeFromPropertyList (projectProperties, key, value) {
function getRelativeLibraryPath (parentDir, subDir) {
var libraryPath = path.relative(parentDir, subDir);
return (path.sep === '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
return (path.sep == '\\') ? libraryPath.replace(/\\/g, '/') : libraryPath;
}
function AndroidProject(projectDir) {

View File

@ -11,8 +11,8 @@ var fs = require('fs');
var CordovaError = require('cordova-common').CordovaError;
module.exports.isAndroidStudioProject = function isAndroidStudioProject(root) {
var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res'];
var androidStudioFiles = ['app', 'app/src/main'];
var eclipseFiles = ['AndroidManifest.xml', 'libs', 'res', 'project.properties', 'platform_www'];
var androidStudioFiles = ['app', 'gradle', 'app/src/main/res'];
// assume it is an AS project and not an Eclipse project
var isEclipse = false;

View File

@ -17,8 +17,8 @@
under the License.
*/
var Q = require('q');
var superspawn = require('cordova-common').superspawn;
var Q = require('q'),
superspawn = require('cordova-common').superspawn;
var suffix_number_regex = /(\d+)$/;
// Used for sorting Android targets, example strings to sort:
@ -44,7 +44,8 @@ function sort_by_largest_numerical_suffix (a, b) {
}
module.exports.print_newest_available_sdk_target = function() {
return module.exports.list_targets().then(function (targets) {
return module.exports.list_targets()
.then(function(targets) {
targets.sort(sort_by_largest_numerical_suffix);
console.log(targets[0]);
});
@ -77,22 +78,26 @@ function parse_targets (output) {
}
module.exports.list_targets_with_android = function() {
return superspawn.spawn('android', ['list', 'target']).then(parse_targets);
return superspawn.spawn('android', ['list', 'target'])
.then(parse_targets);
};
module.exports.list_targets_with_avdmanager = function() {
return superspawn.spawn('avdmanager', ['list', 'target']).then(parse_targets);
return superspawn.spawn('avdmanager', ['list', 'target'])
.then(parse_targets);
};
module.exports.list_targets = function() {
return module.exports.list_targets_with_avdmanager().catch(function (err) {
return module.exports.list_targets_with_avdmanager()
.catch(function(err) {
// If there's an error, like avdmanager could not be found, we can try
// as a last resort, to run `android`, in case this is a super old
// SDK installation.
if (err && (err.code === 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) {
if (err && (err.code == 'ENOENT' || (err.stderr && err.stderr.match(/not recognized/)))) {
return module.exports.list_targets_with_android();
} else throw err;
}).then(function (targets) {
})
.then(function(targets) {
if (targets.length === 0) {
return Q.reject(new Error('No android targets (SDKs) installed!'));
}

View File

@ -19,10 +19,10 @@
under the License.
*/
var Q = require('q');
var path = require('path');
var fs = require('fs');
var nopt = require('nopt');
var Q = require('q'),
path = require('path'),
fs = require('fs'),
nopt = require('nopt');
var Adb = require('./Adb');
@ -35,7 +35,7 @@ function parseOpts (options, resolvedTarget, projectRoot) {
options = options || {};
options.argv = nopt({
gradle: Boolean,
studio: Boolean,
ant: Boolean,
prepenv: Boolean,
versionCode: String,
minSdkVersion: String,
@ -47,28 +47,24 @@ function parseOpts (options, resolvedTarget, projectRoot) {
keystoreType: String
}, {}, options.argv, 0);
// Android Studio Build method is the default
var ret = {
buildType: options.release ? 'release' : 'debug',
buildMethod: process.env.ANDROID_BUILD || 'studio',
buildMethod: process.env.ANDROID_BUILD || 'gradle',
prepEnv: options.argv.prepenv,
arch: resolvedTarget && resolvedTarget.arch,
extraArgs: []
};
if (options.argv.gradle || options.argv.studio) {
ret.buildMethod = options.argv.studio ? 'studio' : 'gradle';
}
// This comes from cordova/run
if (options.studio) ret.buildMethod = 'studio';
if (options.gradle) ret.buildMethod = 'gradle';
if (options.argv.ant || options.argv.gradle)
ret.buildMethod = options.argv.ant ? 'ant' : 'gradle';
if (options.nobuild) ret.buildMethod = 'none';
if (options.argv.versionCode) { ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode); }
if (options.argv.versionCode)
ret.extraArgs.push('-PcdvVersionCode=' + options.argv.versionCode);
if (options.argv.minSdkVersion) { ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion); }
if (options.argv.minSdkVersion)
ret.extraArgs.push('-PcdvMinSdkVersion=' + options.argv.minSdkVersion);
if (options.argv.gradleArg) {
ret.extraArgs = ret.extraArgs.concat(options.argv.gradleArg);
@ -76,10 +72,12 @@ function parseOpts (options, resolvedTarget, projectRoot) {
var packageArgs = {};
if (options.argv.keystore) { packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore)); }
if (options.argv.keystore)
packageArgs.keystore = path.relative(projectRoot, path.resolve(options.argv.keystore));
['alias','storePassword','password','keystoreType'].forEach(function (flagName) {
if (options.argv[flagName]) { packageArgs[flagName] = options.argv[flagName]; }
if (options.argv[flagName])
packageArgs[flagName] = options.argv[flagName];
});
var buildConfig = options.buildConfig;
@ -130,7 +128,8 @@ function parseOpts (options, resolvedTarget, projectRoot) {
module.exports.runClean = function(options) {
var opts = parseOpts(options, null, this.root);
var builder = builders.getBuilder(opts.buildMethod);
return builder.prepEnv(opts).then(function () {
return builder.prepEnv(opts)
.then(function() {
return builder.clean(opts);
});
};
@ -149,14 +148,15 @@ module.exports.runClean = function (options) {
*/
module.exports.run = function(options, optResolvedTarget) {
var opts = parseOpts(options, optResolvedTarget, this.root);
console.log(opts.buildMethod);
var builder = builders.getBuilder(opts.buildMethod);
return builder.prepEnv(opts).then(function () {
return builder.prepEnv(opts)
.then(function() {
if (opts.prepEnv) {
events.emit('verbose', 'Build file successfully prepared.');
return;
}
return builder.build(opts).then(function () {
return builder.build(opts)
.then(function() {
var apkPaths = builder.findOutputApks(opts.buildType, opts.arch);
events.emit('log', 'Built the following apk(s): \n\t' + apkPaths.join('\n\t'));
return {
@ -174,24 +174,31 @@ module.exports.run = function (options, optResolvedTarget) {
*/
module.exports.detectArchitecture = function(target) {
function helper() {
return Adb.shell(target, 'cat /proc/cpuinfo').then(function (output) {
return Adb.shell(target, 'cat /proc/cpuinfo')
.then(function(output) {
return /intel/i.exec(output) ? 'x86' : 'arm';
});
}
// It sometimes happens (at least on OS X), that this command will hang forever.
// To fix it, either unplug & replug device, or restart adb server.
return helper().timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.')).then(null, function (err) {
return helper()
.timeout(1000, new CordovaError('Device communication timed out. Try unplugging & replugging the device.'))
.then(null, function(err) {
if (/timed out/.exec('' + err)) {
// adb kill-server doesn't seem to do the trick.
// Could probably find a x-platform version of killall, but I'm not actually
// sure that this scenario even happens on non-OSX machines.
events.emit('verbose', 'adb timed out while detecting device/emulator architecture. Killing adb and trying again.');
return spawn('killall', ['adb']).then(function () {
return helper().then(null, function () {
return spawn('killall', ['adb'])
.then(function() {
return helper()
.then(null, function() {
// The double kill is sadly often necessary, at least on mac.
events.emit('warn', 'adb timed out a second time while detecting device/emulator architecture. Killing adb and trying again.');
return spawn('killall', ['adb']).then(function () {
return helper().then(null, function () {
return spawn('killall', ['adb'])
.then(function() {
return helper()
.then(null, function() {
return Q.reject(new CordovaError('adb timed out a third time while detecting device/emulator architecture. Try unplugging & replugging the device.'));
});
});
@ -208,7 +215,7 @@ module.exports.detectArchitecture = function (target) {
module.exports.findBestApkForArchitecture = function(buildResults, arch) {
var paths = buildResults.apkPaths.filter(function(p) {
var apkName = path.basename(p);
if (buildResults.buildType === 'debug') {
if (buildResults.buildType == 'debug') {
return /-debug/.exec(apkName);
}
return !/-debug/.exec(apkName);

View File

@ -0,0 +1,156 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
var Q = require('q');
var fs = require('fs');
var path = require('path');
var util = require('util');
var shell = require('shelljs');
var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError;
var check_reqs = require('../check_reqs');
var SIGNING_PROPERTIES = '-signing.properties';
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
var TEMPLATE =
'# This file is automatically generated.\n' +
'# Do not modify this file -- ' + MARKER + '\n';
var GenericBuilder = require('./GenericBuilder');
function AntBuilder (projectRoot) {
GenericBuilder.call(this, projectRoot);
this.binDirs = {ant: this.binDirs.ant};
}
util.inherits(AntBuilder, GenericBuilder);
AntBuilder.prototype.getArgs = function(cmd, opts) {
var args = [cmd, '-f', path.join(this.root, 'build.xml')];
// custom_rules.xml is required for incremental builds.
if (hasCustomRules(this.root)) {
args.push('-Dout.dir=ant-build', '-Dgen.absolute.dir=ant-gen');
}
if(opts.packageInfo) {
args.push('-propertyfile=' + path.join(this.root, opts.buildType + SIGNING_PROPERTIES));
}
return args;
};
AntBuilder.prototype.prepEnv = function(opts) {
var self = this;
return check_reqs.check_ant()
.then(function() {
// Copy in build.xml on each build so that:
// A) we don't require the Android SDK at project creation time, and
// B) we always use the SDK's latest version of it.
/*jshint -W069 */
var sdkDir = process.env['ANDROID_HOME'];
/*jshint +W069 */
var buildTemplate = fs.readFileSync(path.join(sdkDir, 'tools', 'lib', 'build.template'), 'utf8');
function writeBuildXml(projectPath) {
var newData = buildTemplate.replace('PROJECT_NAME', self.extractRealProjectNameFromManifest());
fs.writeFileSync(path.join(projectPath, 'build.xml'), newData);
if (!fs.existsSync(path.join(projectPath, 'local.properties'))) {
fs.writeFileSync(path.join(projectPath, 'local.properties'), TEMPLATE);
}
}
writeBuildXml(self.root);
var propertiesObj = self.readProjectProperties();
var subProjects = propertiesObj.libs;
for (var i = 0; i < subProjects.length; ++i) {
writeBuildXml(path.join(self.root, subProjects[i]));
}
if (propertiesObj.systemLibs.length > 0) {
throw new CordovaError('Project contains at least one plugin that requires a system library. This is not supported with ANT. Use gradle instead.');
}
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
var propertiesFilePath = path.join(self.root, propertiesFile);
if (opts.packageInfo) {
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
} else if(isAutoGenerated(propertiesFilePath)) {
shell.rm('-f', propertiesFilePath);
}
});
};
/*
* Builds the project with ant.
* Returns a promise.
*/
AntBuilder.prototype.build = function(opts) {
// Without our custom_rules.xml, we need to clean before building.
var ret = Q();
if (!hasCustomRules(this.root)) {
// clean will call check_ant() for us.
ret = this.clean(opts);
}
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
return check_reqs.check_ant()
.then(function() {
return spawn('ant', args, {stdio: 'pipe'});
}).progress(function (stdio){
if (stdio.stderr) {
process.stderr.write(stdio.stderr);
} else {
process.stdout.write(stdio.stdout);
}
}).catch(function (error) {
if (error.toString().indexOf('Unable to resolve project target') >= 0) {
return check_reqs.check_android_target(error).then(function() {
// If due to some odd reason - check_android_target succeeds
// we should still fail here.
return Q.reject(error);
});
}
return Q.reject(error);
});
};
AntBuilder.prototype.clean = function(opts) {
var args = this.getArgs('clean', opts);
var self = this;
return check_reqs.check_ant()
.then(function() {
return spawn('ant', args, {stdio: 'inherit'});
})
.then(function () {
shell.rm('-rf', path.join(self.root, 'out'));
['debug', 'release'].forEach(function(config) {
var propertiesFilePath = path.join(self.root, config + SIGNING_PROPERTIES);
if(isAutoGenerated(propertiesFilePath)){
shell.rm('-f', propertiesFilePath);
}
});
});
};
module.exports = AntBuilder;
function hasCustomRules(projectRoot) {
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
}
function isAutoGenerated(file) {
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
}

View File

@ -16,23 +16,26 @@
specific language governing permissions and limitations
under the License.
*/
/* eslint no-self-assign: 0 */
/* eslint no-unused-vars: 0 */
var Q = require('q');
var fs = require('fs');
var path = require('path');
var shell = require('shelljs');
var events = require('cordova-common').events;
var CordovaError = require('cordova-common').CordovaError;
function GenericBuilder (projectDir) {
this.root = projectDir || path.resolve(__dirname, '../../..');
this.binDirs = {
studio: path.join(this.root, 'app', 'build', 'outputs', 'apk'),
ant: path.join(this.root, hasCustomRules(this.root) ? 'ant-build' : 'bin'),
gradle: path.join(this.root, 'build', 'outputs', 'apk')
};
}
function hasCustomRules(projectRoot) {
return fs.existsSync(path.join(projectRoot, 'custom_rules.xml'));
}
GenericBuilder.prototype.prepEnv = function() {
return Q();
};
@ -48,23 +51,48 @@ GenericBuilder.prototype.clean = function () {
GenericBuilder.prototype.findOutputApks = function(build_type, arch) {
var self = this;
return Object.keys(this.binDirs).reduce(function (result, builderName) {
return Object.keys(this.binDirs)
.reduce(function (result, builderName) {
var binDir = self.binDirs[builderName];
return result.concat(findOutputApksHelper(binDir, build_type, builderName === 'ant' ? null : arch));
}, []).sort(apkSorter);
}, [])
.sort(apkSorter);
};
GenericBuilder.prototype.readProjectProperties = function () {
function findAllUniq(data, r) {
var s = {};
var m;
while ((m = r.exec(data))) {
s[m[1]] = 1;
}
return Object.keys(s);
}
var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
return {
libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
};
};
GenericBuilder.prototype.extractRealProjectNameFromManifest = function () {
var manifestPath = path.join(this.root, 'AndroidManifest.xml');
var manifestData = fs.readFileSync(manifestPath, 'utf8');
var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
if (!m) {
throw new CordovaError('Could not find package name in ' + manifestPath);
}
var packageName=m[1];
var lastDotIndex = packageName.lastIndexOf('.');
return packageName.substring(lastDotIndex + 1);
};
module.exports = GenericBuilder;
function apkSorter(fileA, fileB) {
// De-prioritize arch specific builds
var archSpecificRE = /-x86|-arm/;
if (archSpecificRE.exec(fileA)) {
return 1;
} else if (archSpecificRE.exec(fileB)) {
return -1;
}
// De-prioritize unsigned builds
var unsignedRE = /-unsigned/;
if (unsignedRE.exec(fileA)) {
@ -73,7 +101,7 @@ function apkSorter (fileA, fileB) {
return -1;
}
var timeDiff = fs.statSync(fileB).mtime - fs.statSync(fileA).mtime;
var timeDiff = fs.statSync(fileA).mtime - fs.statSync(fileB).mtime;
return timeDiff === 0 ? fileA.length - fileB.length : timeDiff;
}
@ -81,14 +109,8 @@ function findOutputApksHelper (dir, build_type, arch) {
var shellSilent = shell.config.silent;
shell.config.silent = true;
// list directory recursively
var ret = shell.ls('-R', dir).map(function (file) {
// ls does not include base directory
return path.join(dir, file);
}).filter(function (file) {
// find all APKs
return file.match(/\.apk?$/i);
}).filter(function (candidate) {
var ret = shell.ls(path.join(dir, '*.apk'))
.filter(function(candidate) {
var apkName = path.basename(candidate);
// Need to choose between release and debug .apk.
if (build_type === 'debug') {
@ -98,7 +120,8 @@ function findOutputApksHelper (dir, build_type, arch) {
return /-release/.exec(apkName) && !/-unaligned/.exec(apkName);
}
return true;
}).sort(apkSorter);
})
.sort(apkSorter);
shellSilent = shellSilent;
@ -110,13 +133,13 @@ function findOutputApksHelper (dir, build_type, arch) {
// And show only arch-specific ones (or non-arch-specific)
ret = ret.filter(function(p) {
/*jshint -W018 */
return !!/-x86|-arm/.exec(path.basename(p)) === archSpecific;
return !!/-x86|-arm/.exec(path.basename(p)) == archSpecific;
/*jshint +W018 */
});
if (archSpecific && ret.length > 1 && arch) {
ret = ret.filter(function(p) {
return path.basename(p).indexOf('-' + arch) !== -1;
return path.basename(p).indexOf('-' + arch) != -1;
});
}

View File

@ -22,7 +22,7 @@ var fs = require('fs');
var util = require('util');
var path = require('path');
var shell = require('shelljs');
var superspawn = require('cordova-common').superspawn;
var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError;
var check_reqs = require('../check_reqs');
@ -43,9 +43,9 @@ function GradleBuilder (projectRoot) {
util.inherits(GradleBuilder, GenericBuilder);
GradleBuilder.prototype.getArgs = function(cmd, opts) {
if (cmd === 'release') {
if (cmd == 'release') {
cmd = 'cdvBuildRelease';
} else if (cmd === 'debug') {
} else if (cmd == 'debug') {
cmd = 'cdvBuildDebug';
}
var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
@ -69,53 +69,16 @@ GradleBuilder.prototype.getArgs = function (cmd, opts) {
* This returns a promise
*/
GradleBuilder.prototype.runGradleWrapper = function (gradle_cmd, gradle_file) {
GradleBuilder.prototype.runGradleWrapper = function(gradle_cmd) {
var gradlePath = path.join(this.root, 'gradlew');
gradle_file = path.join(this.root, (gradle_file || 'wrapper.gradle'));
var wrapperGradle = path.join(this.root, 'wrapper.gradle');
if(fs.existsSync(gradlePath)) {
//Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
} else {
return superspawn.spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', gradle_file], { stdio: 'pipe' })
.progress(function (stdio) {
suppressJavaOptionsInfo(stdio);
});
return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'});
}
};
/*
* We need to kill this in a fire.
*/
GradleBuilder.prototype.readProjectProperties = function () {
function findAllUniq (data, r) {
var s = {};
var m;
while ((m = r.exec(data))) {
s[m[1]] = 1;
}
return Object.keys(s);
}
var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
return {
libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
};
};
GradleBuilder.prototype.extractRealProjectNameFromManifest = function () {
var manifestPath = path.join(this.root, 'AndroidManifest.xml');
var manifestData = fs.readFileSync(manifestPath, 'utf8');
var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
if (!m) {
throw new CordovaError('Could not find package name in ' + manifestPath);
}
var packageName = m[1];
var lastDotIndex = packageName.lastIndexOf('.');
return packageName.substring(lastDotIndex + 1);
};
// Makes the project buildable, minus the gradle wrapper.
GradleBuilder.prototype.prepBuildFiles = function() {
@ -123,9 +86,6 @@ GradleBuilder.prototype.prepBuildFiles = function () {
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
var propertiesObj = this.readProjectProperties();
var subProjects = propertiesObj.libs;
// Check and copy the gradle file into the subproject.
// Called by the loop below this function def.
var checkAndCopy = function(subProject, root) {
var subProjectGradle = path.join(root, subProject, 'build.gradle');
// This is the future-proof way of checking if a file exists
@ -136,22 +96,19 @@ GradleBuilder.prototype.prepBuildFiles = function () {
shell.cp('-f', pluginBuildGradle, subProjectGradle);
}
};
// Some dependencies on Android don't use gradle, or don't have default
// gradle files. This copies a dummy gradle file into them
for (var i = 0; i < subProjects.length; ++i) {
if (subProjects[i] !== 'CordovaLib' && subProjects[i] !== 'app') {
if (subProjects[i] !== 'CordovaLib') {
checkAndCopy(subProjects[i], this.root);
}
}
var name = this.extractRealProjectNameFromManifest();
//Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
var settingsGradlePaths = subProjects.map(function(p){
var realDir=p.replace(/[/\\]/g, ':');
var libName=realDir.replace(name+'-','');
var str='include ":'+libName+'"\n';
if (realDir.indexOf(name + '-') !== -1) { str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n'; }
if(realDir.indexOf(name+'-')!==-1)
str+='project(":'+libName+'").projectDir = new File("'+p+'")\n';
return str;
});
@ -163,27 +120,24 @@ GradleBuilder.prototype.prepBuildFiles = function () {
var buildGradle = fs.readFileSync(path.join(this.root, 'build.gradle'), 'utf8');
var depsList = '';
var root = this.root;
// Cordova Plugins can be written as library modules that would use Cordova as a
// dependency. Because we need to make sure that Cordova is compiled only once for
// dexing, we make sure to exclude CordovaLib from these modules
var insertExclude = function(p) {
var gradlePath = path.join(root, p, 'build.gradle');
var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
if (projectGradleFile.indexOf('CordovaLib') !== -1) {
if(projectGradleFile.indexOf('CordovaLib') != -1) {
depsList += '{\n exclude module:("CordovaLib")\n }\n';
} else {
}
else {
depsList +='\n';
}
};
subProjects.forEach(function(p) {
console.log('Subproject Path: ' + p);
var libName=p.replace(/[/\\]/g, ':').replace(name+'-','');
depsList += ' implementation(project(path: "' + libName + '"))';
depsList += ' debugCompile(project(path: "' + libName + '", configuration: "debug"))';
insertExclude(p);
depsList += ' releaseCompile(project(path: "' + libName + '", configuration: "release"))';
insertExclude(p);
});
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
var SYSTEM_LIBRARY_MAPPINGS = [
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
@ -208,9 +162,6 @@ GradleBuilder.prototype.prepBuildFiles = function () {
}
depsList += ' compile "' + mavenRef + '"\n';
});
// This code is dangerous and actually writes gradle declarations directly into the build.gradle
// Try not to mess with this if possible
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
var includeList = '';
propertiesObj.gradleIncludes.forEach(function(includePath) {
@ -222,7 +173,8 @@ GradleBuilder.prototype.prepBuildFiles = function () {
GradleBuilder.prototype.prepEnv = function(opts) {
var self = this;
return check_reqs.check_gradle().then(function (gradlePath) {
return check_reqs.check_gradle()
.then(function(gradlePath) {
return self.runGradleWrapper(gradlePath);
}).then(function() {
return self.prepBuildFiles();
@ -247,7 +199,7 @@ GradleBuilder.prototype.prepEnv = function (opts) {
// For some reason, using ^ and $ don't work. This does the job, though.
var distributionUrlRegex = /distributionUrl.*zip/;
/*jshint -W069 */
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-4.1-all.zip';
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-3.3-all.zip';
/*jshint +W069 */
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
shell.chmod('u+w', gradleWrapperPropertiesPath);
@ -269,11 +221,26 @@ GradleBuilder.prototype.prepEnv = function (opts) {
*/
GradleBuilder.prototype.build = function(opts) {
var wrapper = path.join(this.root, 'gradlew');
var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);
var args = this.getArgs(opts.buildType == 'debug' ? 'debug' : 'release', opts);
return superspawn.spawn(wrapper, args, { stdio: 'pipe' })
return spawn(wrapper, args, {stdio: 'pipe'})
.progress(function (stdio){
suppressJavaOptionsInfo(stdio);
if (stdio.stderr) {
/*
* Workaround for the issue with Java printing some unwanted information to
* stderr instead of stdout.
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
* explanation.
*/
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
if (suppressThisLine) {
return;
}
process.stderr.write(stdio.stderr);
} else {
process.stdout.write(stdio.stdout);
}
}).catch(function (error) {
if (error.toString().indexOf('failed to find target with hash string') >= 0) {
return check_reqs.check_android_target(error).then(function() {
@ -291,8 +258,9 @@ GradleBuilder.prototype.clean = function (opts) {
var wrapper = path.join(this.root, 'gradlew');
var args = builder.getArgs('clean', opts);
return Q().then(function() {
return superspawn.spawn(wrapper, args, { stdio: 'inherit' });
}).then(function () {
return spawn(wrapper, args, {stdio: 'inherit'});
})
.then(function () {
shell.rm('-rf', path.join(builder.root, 'out'));
['debug', 'release'].forEach(function(config) {
@ -306,25 +274,6 @@ GradleBuilder.prototype.clean = function (opts) {
module.exports = GradleBuilder;
function suppressJavaOptionsInfo (stdio) {
if (stdio.stderr) {
/*
* Workaround for the issue with Java printing some unwanted information to
* stderr instead of stdout.
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
* explanation.
*/
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
if (suppressThisLine) {
return;
}
process.stderr.write(stdio.stderr);
} else {
process.stdout.write(stdio.stdout);
}
}
function isAutoGenerated(file) {
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
}

View File

@ -1,302 +0,0 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
var Q = require('q');
var fs = require('fs');
var util = require('util');
var path = require('path');
var shell = require('shelljs');
var spawn = require('cordova-common').superspawn.spawn;
var CordovaError = require('cordova-common').CordovaError;
var check_reqs = require('../check_reqs');
var GenericBuilder = require('./GenericBuilder');
var MARKER = 'YOUR CHANGES WILL BE ERASED!';
var SIGNING_PROPERTIES = '-signing.properties';
var TEMPLATE =
'# This file is automatically generated.\n' +
'# Do not modify this file -- ' + MARKER + '\n';
function StudioBuilder (projectRoot) {
GenericBuilder.call(this, projectRoot);
this.binDirs = {gradle: this.binDirs.studio};
}
util.inherits(StudioBuilder, GenericBuilder);
StudioBuilder.prototype.getArgs = function (cmd, opts) {
if (cmd === 'release') {
cmd = 'cdvBuildRelease';
} else if (cmd === 'debug') {
cmd = 'cdvBuildDebug';
}
var args = [cmd, '-b', path.join(this.root, 'build.gradle')];
if (opts.arch) {
args.push('-PcdvBuildArch=' + opts.arch);
}
// 10 seconds -> 6 seconds
args.push('-Dorg.gradle.daemon=true');
// to allow dex in process
args.push('-Dorg.gradle.jvmargs=-Xmx2048m');
// allow NDK to be used - required by Gradle 1.5 plugin
args.push('-Pandroid.useDeprecatedNdk=true');
args.push.apply(args, opts.extraArgs);
// Shaves another 100ms, but produces a "try at own risk" warning. Not worth it (yet):
// args.push('-Dorg.gradle.parallel=true');
return args;
};
/*
* This returns a promise
*/
StudioBuilder.prototype.runGradleWrapper = function (gradle_cmd) {
var gradlePath = path.join(this.root, 'gradlew');
var wrapperGradle = path.join(this.root, 'wrapper.gradle');
if (fs.existsSync(gradlePath)) {
// Literally do nothing, for some reason this works, while !fs.existsSync didn't on Windows
} else {
return spawn(gradle_cmd, ['-p', this.root, 'wrapper', '-b', wrapperGradle], {stdio: 'inherit'});
}
};
StudioBuilder.prototype.readProjectProperties = function () {
function findAllUniq (data, r) {
var s = {};
var m;
while ((m = r.exec(data))) {
s[m[1]] = 1;
}
return Object.keys(s);
}
var data = fs.readFileSync(path.join(this.root, 'project.properties'), 'utf8');
return {
libs: findAllUniq(data, /^\s*android\.library\.reference\.\d+=(.*)(?:\s|$)/mg),
gradleIncludes: findAllUniq(data, /^\s*cordova\.gradle\.include\.\d+=(.*)(?:\s|$)/mg),
systemLibs: findAllUniq(data, /^\s*cordova\.system\.library\.\d+=(.*)(?:\s|$)/mg)
};
};
StudioBuilder.prototype.extractRealProjectNameFromManifest = function () {
var manifestPath = path.join(this.root, 'app', 'src', 'main', 'AndroidManifest.xml');
var manifestData = fs.readFileSync(manifestPath, 'utf8');
var m = /<manifest[\s\S]*?package\s*=\s*"(.*?)"/i.exec(manifestData);
if (!m) {
throw new CordovaError('Could not find package name in ' + manifestPath);
}
var packageName = m[1];
var lastDotIndex = packageName.lastIndexOf('.');
return packageName.substring(lastDotIndex + 1);
};
// Makes the project buildable, minus the gradle wrapper.
StudioBuilder.prototype.prepBuildFiles = function () {
// Update the version of build.gradle in each dependent library.
var pluginBuildGradle = path.join(this.root, 'cordova', 'lib', 'plugin-build.gradle');
var propertiesObj = this.readProjectProperties();
var subProjects = propertiesObj.libs;
// Check and copy the gradle file into the subproject
// Called by the loop before this function def
var checkAndCopy = function (subProject, root) {
var subProjectGradle = path.join(root, subProject, 'build.gradle');
// This is the future-proof way of checking if a file exists
// This must be synchronous to satisfy a Travis test
try {
fs.accessSync(subProjectGradle, fs.F_OK);
} catch (e) {
shell.cp('-f', pluginBuildGradle, subProjectGradle);
}
};
for (var i = 0; i < subProjects.length; ++i) {
if (subProjects[i] !== 'CordovaLib') {
checkAndCopy(subProjects[i], this.root);
}
}
var name = this.extractRealProjectNameFromManifest();
// Remove the proj.id/name- prefix from projects: https://issues.apache.org/jira/browse/CB-9149
var settingsGradlePaths = subProjects.map(function (p) {
var realDir = p.replace(/[/\\]/g, ':');
var libName = realDir.replace(name + '-', '');
var str = 'include ":' + libName + '"\n';
if (realDir.indexOf(name + '-') !== -1) {
str += 'project(":' + libName + '").projectDir = new File("' + p + '")\n';
}
return str;
});
fs.writeFileSync(path.join(this.root, 'settings.gradle'),
'// GENERATED FILE - DO NOT EDIT\n' +
'include ":"\n' + settingsGradlePaths.join(''));
// Update dependencies within build.gradle.
var buildGradle = fs.readFileSync(path.join(this.root, 'app', 'build.gradle'), 'utf8');
var depsList = '';
var root = this.root;
var insertExclude = function (p) {
var gradlePath = path.join(root, p, 'build.gradle');
var projectGradleFile = fs.readFileSync(gradlePath, 'utf-8');
if (projectGradleFile.indexOf('CordovaLib') !== -1) {
depsList += '{\n exclude module:("CordovaLib")\n }\n';
} else {
depsList += '\n';
}
};
subProjects.forEach(function (p) {
console.log('Subproject Path: ' + p);
var libName = p.replace(/[/\\]/g, ':').replace(name + '-', '');
if (libName !== 'app') {
depsList += ' implementation(project(path: ":' + libName + '"))';
insertExclude(p);
}
});
// For why we do this mapping: https://issues.apache.org/jira/browse/CB-8390
var SYSTEM_LIBRARY_MAPPINGS = [
[/^\/?extras\/android\/support\/(.*)$/, 'com.android.support:support-$1:+'],
[/^\/?google\/google_play_services\/libproject\/google-play-services_lib\/?$/, 'com.google.android.gms:play-services:+']
];
propertiesObj.systemLibs.forEach(function (p) {
var mavenRef;
// It's already in gradle form if it has two ':'s
if (/:.*:/.exec(p)) {
mavenRef = p;
} else {
for (var i = 0; i < SYSTEM_LIBRARY_MAPPINGS.length; ++i) {
var pair = SYSTEM_LIBRARY_MAPPINGS[i];
if (pair[0].exec(p)) {
mavenRef = p.replace(pair[0], pair[1]);
break;
}
}
if (!mavenRef) {
throw new CordovaError('Unsupported system library (does not work with gradle): ' + p);
}
}
depsList += ' compile "' + mavenRef + '"\n';
});
buildGradle = buildGradle.replace(/(SUB-PROJECT DEPENDENCIES START)[\s\S]*(\/\/ SUB-PROJECT DEPENDENCIES END)/, '$1\n' + depsList + ' $2');
var includeList = '';
propertiesObj.gradleIncludes.forEach(function (includePath) {
includeList += 'apply from: "../' + includePath + '"\n';
});
buildGradle = buildGradle.replace(/(PLUGIN GRADLE EXTENSIONS START)[\s\S]*(\/\/ PLUGIN GRADLE EXTENSIONS END)/, '$1\n' + includeList + '$2');
// This needs to be stored in the app gradle, not the root grade
fs.writeFileSync(path.join(this.root, 'app', 'build.gradle'), buildGradle);
};
StudioBuilder.prototype.prepEnv = function (opts) {
var self = this;
return check_reqs.check_gradle()
.then(function (gradlePath) {
return self.runGradleWrapper(gradlePath);
}).then(function () {
return self.prepBuildFiles();
}).then(function () {
// If the gradle distribution URL is set, make sure it points to version we want.
// If it's not set, do nothing, assuming that we're using a future version of gradle that we don't want to mess with.
// For some reason, using ^ and $ don't work. This does the job, though.
var distributionUrlRegex = /distributionUrl.*zip/;
var distributionUrl = process.env['CORDOVA_ANDROID_GRADLE_DISTRIBUTION_URL'] || 'https\\://services.gradle.org/distributions/gradle-4.1-all.zip';
var gradleWrapperPropertiesPath = path.join(self.root, 'gradle', 'wrapper', 'gradle-wrapper.properties');
shell.chmod('u+w', gradleWrapperPropertiesPath);
shell.sed('-i', distributionUrlRegex, 'distributionUrl=' + distributionUrl, gradleWrapperPropertiesPath);
var propertiesFile = opts.buildType + SIGNING_PROPERTIES;
var propertiesFilePath = path.join(self.root, propertiesFile);
if (opts.packageInfo) {
fs.writeFileSync(propertiesFilePath, TEMPLATE + opts.packageInfo.toProperties());
} else if (isAutoGenerated(propertiesFilePath)) {
shell.rm('-f', propertiesFilePath);
}
});
};
/*
* Builds the project with gradle.
* Returns a promise.
*/
StudioBuilder.prototype.build = function (opts) {
var wrapper = path.join(this.root, 'gradlew');
var args = this.getArgs(opts.buildType === 'debug' ? 'debug' : 'release', opts);
return spawn(wrapper, args, {stdio: 'pipe'})
.progress(function (stdio) {
if (stdio.stderr) {
/*
* Workaround for the issue with Java printing some unwanted information to
* stderr instead of stdout.
* This function suppresses 'Picked up _JAVA_OPTIONS' message from being
* printed to stderr. See https://issues.apache.org/jira/browse/CB-9971 for
* explanation.
*/
var suppressThisLine = /^Picked up _JAVA_OPTIONS: /i.test(stdio.stderr.toString());
if (suppressThisLine) {
return;
}
process.stderr.write(stdio.stderr);
} else {
process.stdout.write(stdio.stdout);
}
}).catch(function (error) {
if (error.toString().indexOf('failed to find target with hash string') >= 0) {
return check_reqs.check_android_target(error).then(function () {
// If due to some odd reason - check_android_target succeeds
// we should still fail here.
return Q.reject(error);
});
}
return Q.reject(error);
});
};
StudioBuilder.prototype.clean = function (opts) {
var builder = this;
var wrapper = path.join(this.root, 'gradlew');
var args = builder.getArgs('clean', opts);
return Q().then(function () {
return spawn(wrapper, args, {stdio: 'inherit'});
})
.then(function () {
shell.rm('-rf', path.join(builder.root, 'out'));
['debug', 'release'].forEach(function (config) {
var propertiesFilePath = path.join(builder.root, config + SIGNING_PROPERTIES);
if (isAutoGenerated(propertiesFilePath)) {
shell.rm('-f', propertiesFilePath);
}
});
});
};
module.exports = StudioBuilder;
function isAutoGenerated (file) {
return fs.existsSync(file) && fs.readFileSync(file, 'utf8').indexOf(MARKER) > 0;
}

View File

@ -20,8 +20,8 @@
var CordovaError = require('cordova-common').CordovaError;
var knownBuilders = {
ant: 'AntBuilder',
gradle: 'GradleBuilder',
studio: 'StudioBuilder',
none: 'GenericBuilder'
};
@ -35,7 +35,8 @@ var knownBuilders = {
* @return {Builder} A builder instance for specified build type.
*/
module.exports.getBuilder = function (builderType, projectRoot) {
if (!knownBuilders[builderType]) { throw new CordovaError('Builder ' + builderType + ' is not supported.'); }
if (!knownBuilders[builderType])
throw new CordovaError('Builder ' + builderType + ' is not supported.');
try {
var Builder = require('./' + knownBuilders[builderType]);

View File

@ -21,14 +21,14 @@
/* jshint sub:true */
var shelljs = require('shelljs');
var child_process = require('child_process');
var Q = require('q');
var path = require('path');
var fs = require('fs');
var os = require('os');
var REPO_ROOT = path.join(__dirname, '..', '..', '..', '..');
var PROJECT_ROOT = path.join(__dirname, '..', '..');
var shelljs = require('shelljs'),
child_process = require('child_process'),
Q = require('q'),
path = require('path'),
fs = require('fs'),
os = require('os'),
REPO_ROOT = path.join(__dirname, '..', '..', '..', '..'),
PROJECT_ROOT = path.join(__dirname, '..', '..');
var CordovaError = require('cordova-common').CordovaError;
var superspawn = require('cordova-common').superspawn;
var android_sdk = require('./android_sdk');
@ -53,11 +53,11 @@ function tryCommand (cmd, errMsg, catchStderr) {
}
module.exports.isWindows = function() {
return (os.platform() === 'win32');
return (os.platform() == 'win32');
};
module.exports.isDarwin = function() {
return (os.platform() === 'darwin');
return (os.platform() == 'darwin');
};
// Get valid target from framework/project.properties if run from this repo
@ -84,13 +84,12 @@ module.exports.get_target = function () {
// Returns a promise. Called only by build and clean commands.
module.exports.check_ant = function() {
return superspawn.spawn('ant', ['-version']).then(function (output) {
return superspawn.spawn('ant', ['-version'])
.then(function(output) {
// Parse Ant version from command output
return /version ((?:\d+\.)+(?:\d+))/i.exec(output)[1];
}).catch(function(err) {
if (err) {
throw new CordovaError('Failed to run `ant -version`. Make sure you have `ant` on your $PATH.');
}
});
};
@ -99,14 +98,16 @@ module.exports.get_gradle_wrapper = function () {
var i = 0;
var foundStudio = false;
var program_dir;
// OK, This hack only works on Windows, not on Mac OS or Linux. We will be deleting this eventually!
if (module.exports.isWindows()) {
var result = child_process.spawnSync(path.join(__dirname, 'getASPath.bat'));
// console.log('result.stdout =' + result.stdout.toString());
// console.log('result.stderr =' + result.stderr.toString());
if (result.stderr.toString().length > 0) {
if (module.exports.isDarwin()) {
program_dir = fs.readdirSync('/Applications');
while (i < program_dir.length && !foundStudio) {
if (program_dir[i].startsWith('Android Studio')) {
//TODO: Check for a specific Android Studio version, make sure it's not Canary
androidStudioPath = path.join('/Applications', program_dir[i], 'Contents', 'gradle');
foundStudio = true;
} else { ++i; }
}
} else if (module.exports.isWindows()) {
var androidPath = path.join(process.env['ProgramFiles'], 'Android') + '/';
if (fs.existsSync(androidPath)) {
program_dir = fs.readdirSync(androidPath);
@ -117,17 +118,11 @@ module.exports.get_gradle_wrapper = function () {
} else { ++i; }
}
}
} else {
// console.log('got android studio path from registry');
// remove the (os independent) new line char at the end of stdout
// add gradle to match the above.
androidStudioPath = path.join(result.stdout.toString().split('\r\n')[0], 'gradle');
}
}
if (androidStudioPath !== null && fs.existsSync(androidStudioPath)) {
var dirs = fs.readdirSync(androidStudioPath);
if (dirs[0].split('-')[0] === 'gradle') {
if(dirs[0].split('-')[0] == 'gradle') {
return path.join(androidStudioPath, dirs[0], 'bin', 'gradle');
}
} else {
@ -140,17 +135,17 @@ module.exports.get_gradle_wrapper = function () {
module.exports.check_gradle = function() {
var sdkDir = process.env['ANDROID_HOME'];
var d = Q.defer();
if (!sdkDir) {
if (!sdkDir)
return Q.reject(new CordovaError('Could not find gradle wrapper within Android SDK. Could not find Android SDK directory.\n' +
'Might need to install Android SDK or set up \'ANDROID_HOME\' env variable.'));
}
var gradlePath = module.exports.get_gradle_wrapper();
if (gradlePath.length !== 0) { d.resolve(gradlePath); } else {
if (gradlePath.length !== 0)
d.resolve(gradlePath);
else
d.reject(new CordovaError('Could not find an installed version of Gradle either in Android Studio,\n' +
'or on your system to install the gradle wrapper. Please include gradle \n' +
'in your path, or install Android Studio'));
}
return d.promise;
};
@ -168,14 +163,13 @@ module.exports.check_java = function () {
if (javacPath) {
// OS X has a command for finding JAVA_HOME.
var find_java = '/usr/libexec/java_home';
var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting it manually.';
var default_java_error_msg = 'Failed to find \'JAVA_HOME\' environment variable. Try setting setting it manually.';
if (fs.existsSync(find_java)) {
return superspawn.spawn(find_java).then(function (stdout) {
return superspawn.spawn(find_java)
.then(function(stdout) {
process.env['JAVA_HOME'] = stdout.trim();
}).catch(function(err) {
if (err) {
throw new CordovaError(default_java_error_msg);
}
});
} else {
// See if we can derive it from javac's location.
@ -215,7 +209,8 @@ module.exports.check_java = function () {
}
// We use tryCommand with catchStderr = true, because
// javac writes version info to stderr instead of stdout
return tryCommand('javac -version', msg, true).then(function (output) {
return tryCommand('javac -version', msg, true)
.then(function (output) {
//Let's check for at least Java 8, and keep it future proof so we can support Java 10
var match = /javac ((?:1\.)(?:[8-9]\.)(?:\d+))|((?:1\.)(?:[1-9]\d+\.)(?:\d+))/i.exec(output);
return match && match[1];
@ -270,10 +265,10 @@ module.exports.check_android = function () {
if (androidCmdPath) {
parentDir = path.dirname(androidCmdPath);
grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) === 'tools' || fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
if (path.basename(parentDir) == 'tools' || fs.existsSync(path.join(grandParentDir, 'tools', 'android'))) {
maybeSetAndroidHome(grandParentDir);
} else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
'Detected \'android\' command at ' + parentDir + ' but no \'tools\' directory found near.\n' +
'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools directory.');
}
@ -281,10 +276,10 @@ module.exports.check_android = function () {
if (adbInPath) {
parentDir = path.dirname(adbInPath);
grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) === 'platform-tools') {
if (path.basename(parentDir) == 'platform-tools') {
maybeSetAndroidHome(grandParentDir);
} else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
'Detected \'adb\' command at ' + parentDir + ' but no \'platform-tools\' directory found near.\n' +
'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'platform-tools directory.');
}
@ -292,17 +287,17 @@ module.exports.check_android = function () {
if (avdmanagerInPath) {
parentDir = path.dirname(avdmanagerInPath);
grandParentDir = path.dirname(parentDir);
if (path.basename(parentDir) === 'bin' && path.basename(grandParentDir) === 'tools') {
if (path.basename(parentDir) == 'bin' && path.basename(grandParentDir) == 'tools') {
maybeSetAndroidHome(path.dirname(grandParentDir));
} else {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
'Detected \'avdmanager\' command at ' + parentDir + ' but no \'tools' + path.sep + 'bin\' directory found near.\n' +
'Try reinstall Android SDK or update your PATH to include valid path to SDK' + path.sep + 'tools' + path.sep + 'bin directory.');
}
}
}
if (!process.env['ANDROID_HOME']) {
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting it manually.\n' +
throw new CordovaError('Failed to find \'ANDROID_HOME\' environment variable. Try setting setting it manually.\n' +
'Failed to find \'android\' command in your \'PATH\'. Try update your \'PATH\' to include path to valid SDK directory.');
}
if (!fs.existsSync(process.env['ANDROID_HOME'])) {
@ -342,7 +337,8 @@ module.exports.check_android_target = function (originalError) {
// Google Inc.:Google APIs:20
// Google Inc.:Glass Development Kit Preview:20
var desired_api_level = module.exports.get_target();
return android_sdk.list_targets().then(function (targets) {
return android_sdk.list_targets()
.then(function(targets) {
if (targets.indexOf(desired_api_level) >= 0) {
return targets;
}
@ -362,7 +358,8 @@ module.exports.check_android_target = function (originalError) {
// Returns a promise.
module.exports.run = function() {
return Q.all([this.check_java(), this.check_android()]).then(function (values) {
return Q.all([this.check_java(), this.check_android()])
.then(function(values) {
console.log('ANDROID_HOME=' + process.env['ANDROID_HOME']);
console.log('JAVA_HOME=' + process.env['JAVA_HOME']);
@ -376,6 +373,7 @@ module.exports.run = function () {
});
};
/**
* Object thar represents one of requirements for current platform.
* @param {String} id The unique identifier for this requirements.
@ -389,7 +387,7 @@ var Requirement = function (id, name, version, installed) {
this.name = name;
this.installed = installed || false;
this.metadata = {
version: version
version: version,
};
};
@ -419,13 +417,15 @@ module.exports.check_all = function () {
return checkFns.reduce(function (promise, checkFn, idx) {
// Update each requirement with results
var requirement = requirements[idx];
return promise.then(checkFn).then(function (version) {
return promise.then(checkFn)
.then(function (version) {
requirement.installed = true;
requirement.metadata.version = version;
}, function (err) {
requirement.metadata.reason = err instanceof Error ? err.message : err;
});
}, Q()).then(function () {
}, Q())
.then(function () {
// When chain is completed, return requirements array to upstream API
return requirements;
});

View File

@ -19,8 +19,8 @@
under the License.
*/
var Q = require('q');
var build = require('./build');
var Q = require('q'),
build = require('./build');
var path = require('path');
var Adb = require('./Adb');
var AndroidManifest = require('./AndroidManifest');
@ -33,12 +33,14 @@ var events = require('cordova-common').events;
* @param lookHarder When true, try restarting adb if no devices are found.
*/
module.exports.list = function(lookHarder) {
return Adb.devices().then(function (list) {
return Adb.devices()
.then(function(list) {
if (list.length === 0 && lookHarder) {
// adb kill-server doesn't seem to do the trick.
// Could probably find a x-platform version of killall, but I'm not actually
// sure that this scenario even happens on non-OSX machines.
return spawn('killall', ['adb']).then(function () {
return spawn('killall', ['adb'])
.then(function() {
events.emit('verbose', 'Restarting adb to see if more devices are detected.');
return Adb.devices();
}, function() {
@ -51,7 +53,8 @@ module.exports.list = function (lookHarder) {
};
module.exports.resolveTarget = function(target) {
return this.list(true).then(function (device_list) {
return this.list(true)
.then(function(device_list) {
if (!device_list || !device_list.length) {
return Q.reject(new CordovaError('Failed to deploy to device, no devices found.'));
}
@ -62,7 +65,8 @@ module.exports.resolveTarget = function (target) {
return Q.reject('ERROR: Unable to find target \'' + target + '\'.');
}
return build.detectArchitecture(target).then(function (arch) {
return build.detectArchitecture(target)
.then(function(arch) {
return { target: target, arch: arch, isEmulator: false };
});
});
@ -75,32 +79,36 @@ module.exports.resolveTarget = function (target) {
*/
module.exports.install = function(target, buildResults) {
return Q().then(function() {
if (target && typeof target === 'object') {
if (target && typeof target == 'object') {
return target;
}
return module.exports.resolveTarget(target);
}).then(function(resolvedTarget) {
var apk_path = build.findBestApkForArchitecture(buildResults, resolvedTarget.arch);
var manifest = new AndroidManifest(path.join(__dirname, '../../app/src/main/AndroidManifest.xml'));
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
var pkgName = manifest.getPackageId();
var launchName = pkgName + '/.' + manifest.getActivity().getName();
events.emit('log', 'Using apk: ' + apk_path);
events.emit('log', 'Package name: ' + pkgName);
return Adb.install(resolvedTarget.target, apk_path, {replace: true}).catch(function (error) {
return Adb.install(resolvedTarget.target, apk_path, {replace: true})
.catch(function (error) {
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
// is already installed on device was signed w/different certificate
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
throw error;
events.emit('warn', 'Uninstalling app from device and reinstalling it again because the ' +
'installed app already signed with different key');
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed.
return Adb.uninstall(resolvedTarget.target, pkgName).then(function () {
return Adb.uninstall(resolvedTarget.target, pkgName)
.then(function() {
return Adb.install(resolvedTarget.target, apk_path, {replace: true});
});
}).then(function () {
})
.then(function() {
//unlock screen
return Adb.shell(resolvedTarget.target, 'input keyevent 82');
}).then(function() {

View File

@ -21,7 +21,6 @@
/* jshint sub:true */
var android_versions = require('android-versions');
var retry = require('./retry');
var build = require('./build');
var path = require('path');
@ -56,7 +55,8 @@ function forgivingWhichSync (cmd) {
}
module.exports.list_images_using_avdmanager = function () {
return superspawn.spawn('avdmanager', ['list', 'avd']).then(function (output) {
return superspawn.spawn('avdmanager', ['list', 'avd'])
.then(function(output) {
var response = output.split('\n');
var emulator_list = [];
for (var i = 1; i < response.length; i++) {
@ -116,7 +116,8 @@ module.exports.list_images_using_avdmanager = function () {
};
module.exports.list_images_using_android = function() {
return superspawn.spawn('android', ['list', 'avd']).then(function (output) {
return superspawn.spawn('android', ['list', 'avd'])
.then(function(output) {
var response = output.split('\n');
var emulator_list = [];
for (var i = 1; i < response.length; i++) {
@ -170,7 +171,6 @@ module.exports.list_images_using_android = function () {
}
*/
module.exports.list_images = function() {
return Q.fcall(function () {
if (forgivingWhichSync('avdmanager')) {
return module.exports.list_images_using_avdmanager();
} else if (forgivingWhichSync('android')) {
@ -180,19 +180,6 @@ module.exports.list_images = function () {
throw new CordovaError('Could not find either `android` or `avdmanager` on your $PATH! Are you sure the Android SDK is installed and available?');
});
}
}).then(function (avds) {
// In case we're missing the Android OS version string from the target description, add it.
return avds.map(function (avd) {
if (avd.target && avd.target.indexOf('Android API') > -1 && avd.target.indexOf('API level') < 0) {
var api_level = avd.target.match(/\d+/);
if (api_level) {
var level = android_versions.get(api_level);
avd.target = 'Android ' + level.semver + ' (API level ' + api_level + ')';
}
}
return avd;
});
});
};
/**
@ -201,18 +188,19 @@ module.exports.list_images = function () {
* Returns a promise.
*/
module.exports.best_image = function() {
return this.list_images().then(function (images) {
return this.list_images()
.then(function(images) {
// Just return undefined if there is no images
if (images.length === 0) return;
var closest = 9999;
var best = images[0];
var project_target = parseInt(check_reqs.get_target().replace('android-', ''));
var project_target = check_reqs.get_target().replace('android-', '');
for (var i in images) {
var target = images[i].target;
if (target && target.indexOf('API level') > -1) {
var num = parseInt(target.split('(API level ')[1].replace(')', ''));
if (num === project_target) {
if(target) {
var num = target.split('(API level ')[1].replace(')', '');
if (num == project_target) {
return images[i];
} else if (project_target - num < closest && project_target > num) {
closest = project_target - num;
@ -232,7 +220,8 @@ module.exports.list_started = function () {
// Returns a promise.
// TODO: we should remove this, there's a more robust method under android_sdk.js
module.exports.list_targets = function() {
return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()}).then(function (output) {
return superspawn.spawn('android', ['list', 'targets'], {cwd: os.tmpdir()})
.then(function(output) {
var target_out = output.split('\n');
var targets = [];
for (var i = target_out.length; i >= 0; i--) {
@ -251,7 +240,8 @@ module.exports.list_targets = function () {
module.exports.get_available_port = function () {
var self = this;
return self.list_started().then(function (emulators) {
return self.list_started()
.then(function (emulators) {
for (var p = 5584; p >= 5554; p-=2) {
if (emulators.indexOf('emulator-' + p) === -1) {
events.emit('verbose', 'Found available port: ' + p);
@ -278,7 +268,8 @@ module.exports.start = function (emulator_ID, boot_timeout) {
return Q().then(function() {
if (emulator_ID) return Q(emulator_ID);
return self.best_image().then(function (best) {
return self.best_image()
.then(function(best) {
if (best && best.name) {
events.emit('warn', 'No emulator specified, defaulting to ' + best.name);
return best.name;
@ -291,7 +282,8 @@ module.exports.start = function (emulator_ID, boot_timeout) {
'HINT: For a faster emulator, use an Intel System Image and install the HAXM device driver\n'));
});
}).then(function(emulatorId) {
return self.get_available_port().then(function (port) {
return self.get_available_port()
.then(function (port) {
// Figure out the directory the emulator binary runs in, and set the cwd to that directory.
// Workaround for https://code.google.com/p/android/issues/detail?id=235461
var emulator_dir = path.dirname(shelljs.which('emulator'));
@ -306,15 +298,18 @@ module.exports.start = function (emulator_ID, boot_timeout) {
return self.wait_for_emulator(port);
});
}).then(function(emulatorId) {
if (!emulatorId) { return Q.reject(new CordovaError('Failed to start emulator')); }
if (!emulatorId)
return Q.reject(new CordovaError('Failed to start emulator'));
//wait for emulator to boot up
process.stdout.write('Waiting for emulator to boot (this may take a while)...');
return self.wait_for_boot(emulatorId, boot_timeout).then(function (success) {
return self.wait_for_boot(emulatorId, boot_timeout)
.then(function(success) {
if (success) {
events.emit('log','BOOT COMPLETE');
//unlock screen
return Adb.shell(emulatorId, 'input keyevent 82').then(function () {
return Adb.shell(emulatorId, 'input keyevent 82')
.then(function() {
//return the new emulator id for the started emulators
return emulatorId;
});
@ -334,15 +329,16 @@ module.exports.wait_for_emulator = function (port) {
var self = this;
return Q().then(function() {
var emulator_id = 'emulator-' + port;
return Adb.shell(emulator_id, 'getprop dev.bootcomplete').then(function (output) {
return Adb.shell(emulator_id, 'getprop dev.bootcomplete')
.then(function (output) {
if (output.indexOf('1') >= 0) {
return emulator_id;
}
return self.wait_for_emulator(port);
}, function (error) {
if ((error && error.message &&
(error.message.indexOf('not found') > -1)) ||
(error.message.indexOf('device offline') > -1)) {
if (error && error.message &&
(error.message.indexOf('not found') > -1) ||
error.message.indexOf('device offline') > -1) {
// emulator not yet started, continue waiting
return self.wait_for_emulator(port);
} else {
@ -360,7 +356,8 @@ module.exports.wait_for_emulator = function (port) {
*/
module.exports.wait_for_boot = function(emulator_id, time_remaining) {
var self = this;
return Adb.shell(emulator_id, 'ps').then(function (output) {
return Adb.shell(emulator_id, 'ps')
.then(function(output) {
if (output.match(/android\.process\.acore/)) {
return true;
} else if (time_remaining === 0) {
@ -385,7 +382,8 @@ module.exports.wait_for_boot = function (emulator_id, time_remaining) {
module.exports.create_image = function(name, target) {
console.log('Creating new avd named ' + name);
if (target) {
return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target]).then(null, function (error) {
return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', target])
.then(null, function(error) {
console.error('ERROR : Failed to create emulator image : ');
console.error(' Do you have the latest android targets including ' + target + '?');
console.error(error);
@ -393,7 +391,8 @@ module.exports.create_image = function (name, target) {
} else {
console.log('WARNING : Project target not found, creating avd with a different target but the project may fail to install.');
// TODO: there's a more robust method for finding targets in android_sdk.js
return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]]).then(function () {
return superspawn.spawn('android', ['create', 'avd', '--name', name, '--target', this.list_targets()[0]])
.then(function() {
// TODO: This seems like another error case, even though it always happens.
console.error('ERROR : Unable to create an avd emulator, no targets found.');
console.error('Ensure you have targets available by running the "android" command');
@ -406,7 +405,8 @@ module.exports.create_image = function (name, target) {
};
module.exports.resolveTarget = function(target) {
return this.list_started().then(function (emulator_list) {
return this.list_started()
.then(function(emulator_list) {
if (emulator_list.length < 1) {
return Q.reject('No running Android emulators found, please start an emulator before deploying your project.');
}
@ -417,7 +417,8 @@ module.exports.resolveTarget = function (target) {
return Q.reject('Unable to find target \'' + target + '\'. Failed to deploy to emulator.');
}
return build.detectArchitecture(target).then(function (arch) {
return build.detectArchitecture(target)
.then(function(arch) {
return {target:target, arch:arch, isEmulator:true};
});
});
@ -432,17 +433,12 @@ module.exports.resolveTarget = function (target) {
module.exports.install = function(givenTarget, buildResults) {
var target;
// We need to find the proper path to the Android Manifest
var manifestPath = path.join(__dirname, '..', '..', 'app', 'src', 'main', 'AndroidManifest.xml');
if (buildResults.buildMethod === 'gradle') {
manifestPath = path.join(__dirname, '../../AndroidManifest.xml');
}
var manifest = new AndroidManifest(manifestPath);
var manifest = new AndroidManifest(path.join(__dirname, '../../AndroidManifest.xml'));
var pkgName = manifest.getPackageId();
// resolve the target emulator
return Q().then(function () {
if (givenTarget && typeof givenTarget === 'object') {
if (givenTarget && typeof givenTarget == 'object') {
return givenTarget;
} else {
return module.exports.resolveTarget(givenTarget);
@ -456,7 +452,8 @@ module.exports.install = function (givenTarget, buildResults) {
}).then(function () {
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed.
return Q.when().then(function () {
return Q.when()
.then(function() {
var apk_path = build.findBestApkForArchitecture(buildResults, target.arch);
var execOptions = {
@ -497,23 +494,27 @@ module.exports.install = function (givenTarget, buildResults) {
}
function installPromise () {
return adbInstallWithOptions(target.target, apk_path, execOptions).catch(function (error) {
return adbInstallWithOptions(target.target, apk_path, execOptions)
.catch(function (error) {
// CB-9557 CB-10157 only uninstall and reinstall app if the one that
// is already installed on device was signed w/different certificate
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString())) { throw error; }
if (!/INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES/.test(error.toString()))
throw error;
events.emit('warn', 'Uninstalling app from device and reinstalling it because the ' +
'currently installed app was signed with different key');
// This promise is always resolved, even if 'adb uninstall' fails to uninstall app
// or the app doesn't installed at all, so no error catching needed.
return Adb.uninstall(target.target, pkgName).then(function () {
return Adb.uninstall(target.target, pkgName)
.then(function() {
return adbInstallWithOptions(target.target, apk_path, execOptions);
});
});
}
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise).then(function (output) {
return retry.retryPromise(NUM_INSTALL_RETRIES, installPromise)
.then(function (output) {
events.emit('log', 'INSTALL SUCCESS');
});
});

View File

@ -1,3 +0,0 @@
@ECHO OFF
for /f "tokens=2*" %%a in ('REG QUERY "HKEY_LOCAL_MACHINE\SOFTWARE\Android Studio" /v Path') do set "ASPath=%%~b"
ECHO %ASPath%

View File

@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0install-device"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'install-device' script in 'cordova\lib' folder, aborting...>&2

View File

@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0install-emulator"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'install-emulator' script in 'cordova\lib' folder, aborting...>&2

View File

@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0list-devices"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'list-devices' script in 'cordova\lib' folder, aborting...>&2

View File

@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0list-emulator-images"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'list-emulator-images' script in 'cordova\lib' folder, aborting...>&2

View File

@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0list-started-emulators"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'list-started-emulators' script in 'cordova\lib' folder, aborting...>&2

View File

@ -19,11 +19,11 @@
under the License.
*/
var path = require('path');
var os = require('os');
var Q = require('q');
var child_process = require('child_process');
var ROOT = path.join(__dirname, '..', '..');
var path = require('path'),
os = require('os'),
Q = require('q'),
child_process = require('child_process'),
ROOT = path.join(__dirname, '..', '..');
/*
* Starts running logcat in the shell.

View File

@ -20,10 +20,8 @@
buildscript {
repositories {
mavenCentral()
jcenter()
maven {
url "https://maven.google.com"
}
}
// Switch the Android Gradle plugin version requirement depending on the

View File

@ -1,4 +1,7 @@
/*
*
* Copyright 2013 Anis Kadri
*
* Licensed 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
@ -30,19 +33,8 @@ var handlers = {
var dest = path.join(obj.targetDir, path.basename(obj.src));
// TODO: This code needs to be replaced, since the core plugins need to be re-mapped to a different location in
// a later plugins release. This is for legacy plugins to work with Cordova.
if(options && options.android_studio === true) {
// If a Java file is using the new directory structure, don't penalize it
if (!obj.targetDir.includes('app/src/main')) {
if (obj.src.endsWith('.java')) {
dest = path.join('app/src/main/java', obj.targetDir.substring(4), path.basename(obj.src));
} else if (obj.src.endsWith('.xml')) {
// We are making a huge assumption here that XML files will be going to res/xml or values/xml
dest = path.join('app/src/main', obj.targetDir, path.basename(obj.src));
}
}
}
if (options && options.force) {
@ -79,18 +71,10 @@ var handlers = {
},
'resource-file':{
install:function(obj, plugin, project, options) {
var dest = path.normalize(obj.target);
if (options && options.android_studio === true) {
dest = path.join('app/src/main', dest);
}
copyFile(plugin.dir, obj.src, project.projectDir, dest, !!(options && options.link));
copyFile(plugin.dir, obj.src, project.projectDir, path.normalize(obj.target), !!(options && options.link));
},
uninstall:function(obj, plugin, project, options) {
var dest = path.normalize(obj.target);
if (options && options.android_studio === true) {
dest = path.join('app/src/main', dest);
}
removeFile(project.projectDir, dest);
removeFile(project.projectDir, path.normalize(obj.target));
}
},
'framework': {
@ -111,9 +95,9 @@ var handlers = {
subDir = src;
}
if (obj.type === 'gradleReference') {
if (obj.type == 'gradleReference') {
project.addGradleReference(parentDir, subDir);
} else if (obj.type === 'sys') {
} else if (obj.type == 'sys') {
project.addSystemLibrary(parentDir, subDir);
} else {
project.addSubProject(parentDir, subDir);
@ -141,9 +125,9 @@ var handlers = {
subDir = src;
}
if (obj.type === 'gradleReference') {
if (obj.type == 'gradleReference') {
project.removeGradleReference(parentDir, subDir);
} else if (obj.type === 'sys') {
} else if (obj.type == 'sys') {
project.removeSystemLibrary(parentDir, subDir);
} else {
project.removeSubProject(parentDir, subDir);
@ -237,12 +221,14 @@ function copyFile (plugin_dir, src, project_dir, dest, link) {
// check that src path is inside plugin directory
var real_path = fs.realpathSync(src);
var real_plugin_path = fs.realpathSync(plugin_dir);
if (real_path.indexOf(real_plugin_path) !== 0) { throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"'); }
if (real_path.indexOf(real_plugin_path) !== 0)
throw new CordovaError('File "' + src + '" is located outside the plugin directory "' + plugin_dir + '"');
dest = path.resolve(project_dir, dest);
// check that dest path is located in project directory
if (dest.indexOf(project_dir) !== 0) { throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project'); }
if (dest.indexOf(project_dir) !== 0)
throw new CordovaError('Destination "' + dest + '" for source file "' + src + '" is located outside the project');
shell.mkdir('-p', path.dirname(dest));
if (link) {
@ -258,7 +244,8 @@ function copyFile (plugin_dir, src, project_dir, dest, link) {
// Same as copy file but throws error if target exists
function copyNewFile (plugin_dir, src, project_dir, dest, link) {
var target_path = path.resolve(project_dir, dest);
if (fs.existsSync(target_path)) { throw new CordovaError('"' + target_path + '" already exists!'); }
if (fs.existsSync(target_path))
throw new CordovaError('"' + target_path + '" already exists!');
copyFile(plugin_dir, src, project_dir, dest, !!link);
}
@ -273,7 +260,8 @@ function symlinkFileOrDirTree (src, dest) {
fs.readdirSync(src).forEach(function(entry) {
symlinkFileOrDirTree(path.join(src, entry), path.join(dest, entry));
});
} else {
}
else {
fs.symlinkSync(path.relative(fs.realpathSync(path.dirname(dest)), src), dest);
}
}

View File

@ -16,7 +16,6 @@
specific language governing permissions and limitations
under the License.
*/
/* eslint no-useless-escape: 0 */
var Q = require('q');
var fs = require('fs');
@ -24,7 +23,6 @@ var path = require('path');
var shell = require('shelljs');
var events = require('cordova-common').events;
var AndroidManifest = require('./AndroidManifest');
var checkReqs = require('./check_reqs');
var xmlHelpers = require('cordova-common').xmlHelpers;
var CordovaError = require('cordova-common').CordovaError;
var ConfigParser = require('cordova-common').ConfigParser;
@ -42,14 +40,17 @@ module.exports.prepare = function (cordovaProject, options) {
this._config = updateConfigFilesFrom(cordovaProject.projectConfig, munger, this.locations);
// Update own www dir with project's www assets and plugins' assets and js-files
return Q.when(updateWww(cordovaProject, this.locations)).then(function () {
return Q.when(updateWww(cordovaProject, this.locations))
.then(function () {
// update project according to config.xml changes.
return updateProjectAccordingTo(self._config, self.locations);
}).then(function () {
})
.then(function () {
updateIcons(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
updateSplashes(cordovaProject, path.relative(cordovaProject.root, self.locations.res));
updateFileResources(cordovaProject, path.relative(cordovaProject.root, self.locations.root));
}).then(function () {
})
.then(function () {
events.emit('verbose', 'Prepared android project successfully');
});
};
@ -168,24 +169,17 @@ function cleanWww (projectRoot, locations) {
*/
function updateProjectAccordingTo(platformConfig, locations) {
// Update app name by editing res/values/strings.xml
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
var name = platformConfig.name();
var strings = xmlHelpers.parseElementtreeSync(locations.strings);
strings.find('string[@name="app_name"]').text = name.replace(/\'/g, '\\\'');
var shortName = platformConfig.shortName && platformConfig.shortName();
if (shortName && shortName !== name) {
strings.find('string[@name="launcher_name"]').text = shortName.replace(/\'/g, '\\\'');
}
fs.writeFileSync(locations.strings, strings.write({indent: 4}), 'utf-8');
events.emit('verbose', 'Wrote out android application name "' + name + '" to ' + locations.strings);
// Java packages cannot support dashes
var androidPkgName = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
var pkg = (platformConfig.android_packageName() || platformConfig.packageName()).replace(/-/g, '_');
var manifest = new AndroidManifest(locations.manifest);
var manifestId = manifest.getPackageId();
var orig_pkg = manifest.getPackageId();
manifest.getActivity()
.setOrientation(platformConfig.getPreference('orientation'))
@ -193,14 +187,13 @@ function updateProjectAccordingTo (platformConfig, locations) {
manifest.setVersionName(platformConfig.version())
.setVersionCode(platformConfig.android_versionCode() || default_versionCode(platformConfig.version()))
.setPackageId(androidPkgName)
.setPackageId(pkg)
.setMinSdkVersion(platformConfig.getPreference('android-minSdkVersion', 'android'))
.setMaxSdkVersion(platformConfig.getPreference('android-maxSdkVersion', 'android'))
.setTargetSdkVersion(platformConfig.getPreference('android-targetSdkVersion', 'android'))
.write();
// Java file paths shouldn't be hard coded
var javaPattern = path.join(locations.javaSrc, manifestId.replace(/\./g, '/'), '*.java');
var javaPattern = path.join(locations.root, 'src', orig_pkg.replace(/\./g, '/'), '*.java');
var java_files = shell.ls(javaPattern).filter(function(f) {
return shell.grep(/extends\s+CordovaActivity/g, f);
});
@ -211,16 +204,12 @@ function updateProjectAccordingTo (platformConfig, locations) {
events.emit('log', 'Multiple candidate Java files that extend CordovaActivity found. Guessing at the first one, ' + java_files[0]);
}
var destFile = path.join(locations.root, 'app', 'src', 'main', 'java', androidPkgName.replace(/\./g, '/'), path.basename(java_files[0]));
var destFile = path.join(locations.root, 'src', pkg.replace(/\./g, '/'), path.basename(java_files[0]));
shell.mkdir('-p', path.dirname(destFile));
shell.sed(/package [\w\.]*;/, 'package ' + androidPkgName + ';', java_files[0]).to(destFile);
events.emit('verbose', 'Wrote out Android package name "' + androidPkgName + '" to ' + destFile);
shell.sed(/package [\w\.]*;/, 'package ' + pkg + ';', java_files[0]).to(destFile);
events.emit('verbose', 'Wrote out Android package name "' + pkg + '" to ' + destFile);
var removeOrigPkg = checkReqs.isWindows() || checkReqs.isDarwin() ?
manifestId.toUpperCase() !== androidPkgName.toUpperCase() :
manifestId !== androidPkgName;
if (removeOrigPkg) {
if (orig_pkg !== pkg) {
// If package was name changed we need to remove old java with main activity
shell.rm('-Rf',java_files[0]);
// remove any empty directories
@ -281,7 +270,7 @@ function updateSplashes (cordovaProject, platformResourcesDir) {
if (!resource.density) {
return;
}
if (resource.density === 'mdpi') {
if (resource.density == 'mdpi') {
hadMdpi = true;
}
var targetPath = getImageResourcePath(
@ -406,13 +395,15 @@ function cleanIcons (projectRoot, projectConfig, platformResourcesDir) {
*/
function mapImageResources(rootDir, subDir, type, resourceName) {
var pathMap = {};
shell.ls(path.join(rootDir, subDir, type + '-*')).forEach(function (drawableFolder) {
shell.ls(path.join(rootDir, subDir, type + '-*'))
.forEach(function (drawableFolder) {
var imagePath = path.join(subDir, path.basename(drawableFolder), resourceName);
pathMap[imagePath] = null;
});
return pathMap;
}
function updateFileResources(cordovaProject, platformDir) {
var files = cordovaProject.projectConfig.getFileResources('android');
@ -433,8 +424,9 @@ function updateFileResources (cordovaProject, platformDir) {
resourceMap, { rootDir: cordovaProject.root }, logFileOp);
}
function cleanFileResources(projectRoot, projectConfig, platformDir) {
var files = projectConfig.getFileResources('android', true);
var files = projectConfig.getFileResources('android');
if (files.length > 0) {
events.emit('verbose', 'Cleaning resource files at ' + platformDir);
@ -445,8 +437,7 @@ function cleanFileResources (projectRoot, projectConfig, platformDir) {
});
FileUpdater.updatePaths(
resourceMap, {
rootDir: projectRoot, all: true}, logFileOp);
resourceMap, { rootDir: projectRoot, all: true}, logFileOp);
}
}

View File

@ -21,12 +21,12 @@
/* jshint loopfunc:true */
var path = require('path');
var build = require('./build');
var emulator = require('./emulator');
var device = require('./device');
var Q = require('q');
var events = require('cordova-common').events;
var path = require('path'),
build = require('./build'),
emulator = require('./emulator'),
device = require('./device'),
Q = require('q'),
events = require('cordova-common').events;
function getInstallTarget(runOptions) {
var install_target;
@ -56,10 +56,12 @@ module.exports.run = function (runOptions) {
var self = this;
var install_target = getInstallTarget(runOptions);
return Q().then(function () {
return Q()
.then(function() {
if (!install_target) {
// no target given, deploy to device if available, otherwise use the emulator.
return device.list().then(function (device_list) {
return device.list()
.then(function(device_list) {
if (device_list.length > 0) {
events.emit('warn', 'No target specified, deploying to device \'' + device_list[0] + '\'.');
install_target = device_list[0];
@ -70,30 +72,35 @@ module.exports.run = function (runOptions) {
});
}
}).then(function() {
if (install_target === '--device') {
if (install_target == '--device') {
return device.resolveTarget(null);
} else if (install_target === '--emulator') {
} else if (install_target == '--emulator') {
// Give preference to any already started emulators. Else, start one.
return emulator.list_started().then(function (started) {
return emulator.list_started()
.then(function(started) {
return started && started.length > 0 ? started[0] : emulator.start();
}).then(function(emulatorId) {
return emulator.resolveTarget(emulatorId);
});
}
// They specified a specific device/emulator ID.
return device.list().then(function (devices) {
return device.list()
.then(function(devices) {
if (devices.indexOf(install_target) > -1) {
return device.resolveTarget(install_target);
}
return emulator.list_started().then(function (started_emulators) {
return emulator.list_started()
.then(function(started_emulators) {
if (started_emulators.indexOf(install_target) > -1) {
return emulator.resolveTarget(install_target);
}
return emulator.list_images().then(function (avds) {
return emulator.list_images()
.then(function(avds) {
// if target emulator isn't started, then start it.
for (var avd in avds) {
if (avds[avd].name === install_target) {
return emulator.start(install_target).then(function (emulatorId) {
if (avds[avd].name == install_target) {
return emulator.start(install_target)
.then(function(emulatorId) {
return emulator.resolveTarget(emulatorId);
});
}
@ -107,9 +114,11 @@ module.exports.run = function (runOptions) {
// build results (according to platformApi spec) so they are in different
// format than emulator.install expects.
// TODO: Update emulator/device.install to handle this change
return build.run.call(self, runOptions, resolvedTarget).then(function (buildResults) {
return build.run.call(self, runOptions, resolvedTarget)
.then(function(buildResults) {
if (resolvedTarget.isEmulator) {
return emulator.wait_for_boot(resolvedTarget.target).then(function () {
return emulator.wait_for_boot(resolvedTarget.target)
.then(function () {
return emulator.install(resolvedTarget, buildResults);
});
}

View File

@ -18,7 +18,7 @@
@ECHO OFF
SET script_path="%~dp0start-emulator"
IF EXIST %script_path% (
node %script_path% %*
node "%script_path%" %*
) ELSE (
ECHO.
ECHO ERROR: Could not find 'start-emulator' script in 'cordova\lib' folder, aborting...>&2

View File

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

View File

@ -1,6 +1,5 @@
#Fri Jan 05 03:48:26 EST 2018
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

View File

@ -1,4 +1,4 @@
#!/usr/bin/env bash
#!/usr/bin/env sh
##############################################################################
##
@ -154,11 +154,19 @@ if $cygwin ; then
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
APP_ARGS=$(save "$@")
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
cd "$(dirname "$0")"
fi
exec "$JAVACMD" "$@"

View File

@ -49,7 +49,6 @@ goto fail
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
@ -60,11 +59,6 @@ set _SKIP=2
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line

View File

@ -1,5 +1,5 @@
// Platform: android
// 4450a4cea50616e080a82e8ede9e3d6a1fe3c3ec
// 7ef9f9c03167a4dde4372d869472241b6816fee9
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@ -19,29 +19,31 @@
under the License.
*/
;(function() {
var PLATFORM_VERSION_BUILD_LABEL = '7.0.0';
var PLATFORM_VERSION_BUILD_LABEL = '6.2.3';
// file: src/scripts/require.js
/*jshint -W079 */
/*jshint -W020 */
var require;
var define;
var require,
define;
(function () {
var modules = {};
var modules = {},
// Stack of moduleIds currently being built.
var requireStack = [];
requireStack = [],
// Map of module ID -> index into requireStack of modules currently being built.
var inProgressModules = {};
var SEPARATOR = '.';
inProgressModules = {},
SEPARATOR = ".";
function build(module) {
var factory = module.factory;
var localRequire = function (id) {
var factory = module.factory,
localRequire = function (id) {
var resultantId = id;
//Its a relative path, so lop off the last portion and add the id (minus "./")
if (id.charAt(0) === '.') {
if (id.charAt(0) === ".") {
resultantId = module.id.slice(0, module.id.lastIndexOf(SEPARATOR)) + SEPARATOR + id.slice(2);
}
return require(resultantId);
@ -54,10 +56,10 @@ var define;
require = function (id) {
if (!modules[id]) {
throw 'module ' + id + ' not found';
throw "module " + id + " not found";
} else if (id in inProgressModules) {
var cycle = requireStack.slice(inProgressModules[id]).join('->') + '->' + id;
throw 'Cycle in require graph: ' + cycle;
throw "Cycle in require graph: " + cycle;
}
if (modules[id].factory) {
try {
@ -74,7 +76,7 @@ var define;
define = function (id, factory) {
if (modules[id]) {
throw 'module ' + id + ' already defined';
throw "module " + id + " already defined";
}
modules[id] = {
@ -91,7 +93,7 @@ var define;
})();
//Export for use in node
if (typeof module === 'object' && typeof require === 'function') {
if (typeof module === "object" && typeof require === "function") {
module.exports.require = require;
module.exports.define = define;
}
@ -101,13 +103,15 @@ define("cordova", function(require, exports, module) {
// Workaround for Windows 10 in hosted environment case
// http://www.w3.org/html/wg/drafts/html/master/browsers.html#named-access-on-the-window-object
if (window.cordova && !(window.cordova instanceof HTMLElement)) { // eslint-disable-line no-undef
throw new Error('cordova already defined');
if (window.cordova && !(window.cordova instanceof HTMLElement)) {
throw new Error("cordova already defined");
}
var channel = require('cordova/channel');
var platform = require('cordova/platform');
/**
* Intercept calls to addEventListener + removeEventListener and handle deviceready,
* resume, and pause events.
@ -120,12 +124,12 @@ var m_window_removeEventListener = window.removeEventListener;
/**
* Houses custom event handlers to intercept on document + window event listeners.
*/
var documentEventHandlers = {};
var windowEventHandlers = {};
var documentEventHandlers = {},
windowEventHandlers = {};
document.addEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
if (typeof documentEventHandlers[e] !== 'undefined') {
if (typeof documentEventHandlers[e] != 'undefined') {
documentEventHandlers[e].subscribe(handler);
} else {
m_document_addEventListener.call(document, evt, handler, capture);
@ -134,7 +138,7 @@ document.addEventListener = function (evt, handler, capture) {
window.addEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
if (typeof windowEventHandlers[e] !== 'undefined') {
if (typeof windowEventHandlers[e] != 'undefined') {
windowEventHandlers[e].subscribe(handler);
} else {
m_window_addEventListener.call(window, evt, handler, capture);
@ -144,7 +148,7 @@ window.addEventListener = function (evt, handler, capture) {
document.removeEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
// If unsubscribing from an event that is handled by a plugin
if (typeof documentEventHandlers[e] !== 'undefined') {
if (typeof documentEventHandlers[e] != "undefined") {
documentEventHandlers[e].unsubscribe(handler);
} else {
m_document_removeEventListener.call(document, evt, handler, capture);
@ -154,7 +158,7 @@ document.removeEventListener = function (evt, handler, capture) {
window.removeEventListener = function(evt, handler, capture) {
var e = evt.toLowerCase();
// If unsubscribing from an event that is handled by a plugin
if (typeof windowEventHandlers[e] !== 'undefined') {
if (typeof windowEventHandlers[e] != "undefined") {
windowEventHandlers[e].unsubscribe(handler);
} else {
m_window_removeEventListener.call(window, evt, handler, capture);
@ -174,16 +178,13 @@ function createEvent (type, data) {
return event;
}
/* eslint-disable no-undef */
var cordova = {
define:define,
require:require,
version:PLATFORM_VERSION_BUILD_LABEL,
platformVersion:PLATFORM_VERSION_BUILD_LABEL,
platformId:platform.id,
/* eslint-enable no-undef */
/**
* Methods to add/remove your own addEventListener hijacking on document + window.
*/
@ -217,13 +218,14 @@ var cordova = {
*/
fireDocumentEvent: function(type, data, bNoDetach) {
var evt = createEvent(type, data);
if (typeof documentEventHandlers[type] !== 'undefined') {
if (typeof documentEventHandlers[type] != 'undefined') {
if( bNoDetach ) {
documentEventHandlers[type].fire(evt);
} else {
}
else {
setTimeout(function() {
// Fire deviceready on listeners that were registered before cordova.js was loaded.
if (type === 'deviceready') {
if (type == 'deviceready') {
document.dispatchEvent(evt);
}
documentEventHandlers[type].fire(evt);
@ -235,7 +237,7 @@ var cordova = {
},
fireWindowEvent: function(type, data) {
var evt = createEvent(type,data);
if (typeof windowEventHandlers[type] !== 'undefined') {
if (typeof windowEventHandlers[type] != 'undefined') {
setTimeout(function() {
windowEventHandlers[type].fire(evt);
}, 0);
@ -287,7 +289,7 @@ var cordova = {
try {
var callback = cordova.callbacks[callbackId];
if (callback) {
if (isSuccess && status === cordova.callbackStatus.OK) {
if (isSuccess && status == cordova.callbackStatus.OK) {
callback.success && callback.success.apply(null, args);
} else if (!isSuccess) {
callback.fail && callback.fail.apply(null, args);
@ -304,10 +306,11 @@ var cordova = {
delete cordova.callbacks[callbackId];
}
}
} catch (err) {
var msg = 'Error in ' + (isSuccess ? 'Success' : 'Error') + ' callbackId: ' + callbackId + ' : ' + err;
}
catch (err) {
var msg = "Error in " + (isSuccess ? "Success" : "Error") + " callbackId: " + callbackId + " : " + err;
console && console.log && console.log(msg);
cordova.fireWindowEvent('cordovacallbackerror', { 'message': msg });
cordova.fireWindowEvent("cordovacallbackerror", { 'message': msg });
throw err;
}
},
@ -316,17 +319,18 @@ var cordova = {
try {
func();
} catch(e) {
console.log('Failed to run constructor: ' + e);
console.log("Failed to run constructor: " + e);
}
});
}
};
module.exports = cordova;
});
// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/android/nativeapiprovider.js
// file: /Users/maj/src/cordova-android/cordova-js-src/android/nativeapiprovider.js
define("cordova/android/nativeapiprovider", function(require, exports, module) {
/**
@ -349,7 +353,7 @@ module.exports = {
});
// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/android/promptbasednativeapi.js
// file: /Users/maj/src/cordova-android/cordova-js-src/android/promptbasednativeapi.js
define("cordova/android/promptbasednativeapi", function(require, exports, module) {
/**
@ -398,18 +402,18 @@ function checkArgs (spec, functionName, args, opt_callee) {
var errMsg = null;
var typeName;
for (var i = 0; i < spec.length; ++i) {
var c = spec.charAt(i);
var cUpper = c.toUpperCase();
var arg = args[i];
var c = spec.charAt(i),
cUpper = c.toUpperCase(),
arg = args[i];
// Asterix means allow anything.
if (c === '*') {
if (c == '*') {
continue;
}
typeName = utils.typeName(arg);
if ((arg === null || arg === undefined) && c === cUpper) {
if ((arg === null || arg === undefined) && c == cUpper) {
continue;
}
if (typeName !== typeMap[cUpper]) {
if (typeName != typeMap[cUpper]) {
errMsg = 'Expected ' + typeMap[cUpper];
break;
}
@ -418,7 +422,7 @@ function checkArgs (spec, functionName, args, opt_callee) {
errMsg += ', but got ' + typeName + '.';
errMsg = 'Wrong type for parameter "' + extractParamName(opt_callee || args.callee, i) + '" of ' + functionName + ': ' + errMsg;
// Don't log when running unit tests.
if (typeof jasmine === 'undefined') {
if (typeof jasmine == 'undefined') {
console.error(errMsg);
}
throw TypeError(errMsg);
@ -433,6 +437,7 @@ moduleExports.checkArgs = checkArgs;
moduleExports.getValue = getValue;
moduleExports.enableChecks = true;
});
// file: src/common/base64.js
@ -446,7 +451,7 @@ base64.fromArrayBuffer = function (arrayBuffer) {
};
base64.toArrayBuffer = function(str) {
var decodedStr = typeof atob !== 'undefined' ? atob(str) : Buffer.from(str, 'base64').toString('binary'); // eslint-disable-line no-undef
var decodedStr = typeof atob != 'undefined' ? atob(str) : new Buffer(str,'base64').toString('binary');
var arrayBuffer = new ArrayBuffer(decodedStr.length);
var array = new Uint8Array(arrayBuffer);
for (var i=0, len=decodedStr.length; i < len; i++) {
@ -462,7 +467,7 @@ base64.toArrayBuffer = function (str) {
* platforms tested.
*/
var b64_6bit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
var b64_6bit = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var b64_12bit;
var b64_12bitTable = function() {
@ -478,7 +483,7 @@ var b64_12bitTable = function () {
function uint8ToBase64(rawData) {
var numBytes = rawData.byteLength;
var output = '';
var output="";
var segment;
var table = b64_12bitTable();
for (var i=0;i<numBytes-2;i+=3) {
@ -486,12 +491,12 @@ function uint8ToBase64 (rawData) {
output += table[segment >> 12];
output += table[segment & 0xfff];
}
if (numBytes - i === 2) {
if (numBytes - i == 2) {
segment = (rawData[i] << 16) + (rawData[i+1] << 8);
output += table[segment >> 12];
output += b64_6bit[(segment & 0xfff) >> 6];
output += '=';
} else if (numBytes - i === 1) {
} else if (numBytes - i == 1) {
segment = (rawData[i] << 16);
output += table[segment >> 12];
output += '==';
@ -563,7 +568,7 @@ function include (parent, objects, clobber, merge) {
result = parent[key];
} else {
// Overwrite if not currently defined.
if (typeof parent[key] === 'undefined') {
if (typeof parent[key] == 'undefined') {
assignOrWrapInDeprecateGetter(parent, key, result, obj.deprecated);
} else {
// Set result to what already exists, so we can build children into it if they exist.
@ -622,8 +627,8 @@ exports.replaceHookForTesting = function () {};
// file: src/common/channel.js
define("cordova/channel", function(require, exports, module) {
var utils = require('cordova/utils');
var nextGuid = 1;
var utils = require('cordova/utils'),
nextGuid = 1;
/**
* Custom pub-sub "channel" that can have functions subscribed to it
@ -676,16 +681,16 @@ var Channel = function (type, sticky) {
// Function that is called when the first listener is subscribed, or when
// the last listener is unsubscribed.
this.onHasSubscribersChange = null;
};
var channel = {
},
channel = {
/**
* Calls the provided function only after all of the channels specified
* have been fired. All channels must be sticky channels.
*/
join: function(h, c) {
var len = c.length;
var i = len;
var f = function () {
var len = c.length,
i = len,
f = function() {
if (!(--i)) h();
};
for (var j=0; j<len; j++) {
@ -696,14 +701,13 @@ var channel = {
}
if (!len) h();
},
/* eslint-disable no-return-assign */
create: function(type) {
return channel[type] = new Channel(type, false);
},
createSticky: function(type) {
return channel[type] = new Channel(type, true);
},
/* eslint-enable no-return-assign */
/**
* cordova Channels that must fire before "deviceready" is fired.
*/
@ -739,10 +743,10 @@ var channel = {
};
function checkSubscriptionArgument(argument) {
if (typeof argument !== 'function' && typeof argument.handleEvent !== 'function') {
if (typeof argument !== "function" && typeof argument.handleEvent !== "function") {
throw new Error(
'Must provide a function or an EventListener object ' +
'implementing the handleEvent interface.'
"Must provide a function or an EventListener object " +
"implementing the handleEvent interface."
);
}
}
@ -758,7 +762,7 @@ Channel.prototype.subscribe = function (eventListenerOrFunction, eventListener)
checkSubscriptionArgument(eventListenerOrFunction);
var handleEvent, guid;
if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') {
if (eventListenerOrFunction && typeof eventListenerOrFunction === "object") {
// Received an EventListener object implementing the handleEvent interface
handleEvent = eventListenerOrFunction.handleEvent;
eventListener = eventListenerOrFunction;
@ -767,13 +771,13 @@ Channel.prototype.subscribe = function (eventListenerOrFunction, eventListener)
handleEvent = eventListenerOrFunction;
}
if (this.state === 2) {
if (this.state == 2) {
handleEvent.apply(eventListener || this, this.fireArgs);
return;
}
guid = eventListenerOrFunction.observer_guid;
if (typeof eventListener === 'object') {
if (typeof eventListener === "object") {
handleEvent = utils.close(eventListener, handleEvent);
}
@ -788,7 +792,7 @@ Channel.prototype.subscribe = function (eventListenerOrFunction, eventListener)
if (!this.handlers[guid]) {
this.handlers[guid] = handleEvent;
this.numHandlers++;
if (this.numHandlers === 1) {
if (this.numHandlers == 1) {
this.onHasSubscribersChange && this.onHasSubscribersChange();
}
}
@ -801,7 +805,7 @@ Channel.prototype.unsubscribe = function (eventListenerOrFunction) {
checkSubscriptionArgument(eventListenerOrFunction);
var handleEvent, guid, handler;
if (eventListenerOrFunction && typeof eventListenerOrFunction === 'object') {
if (eventListenerOrFunction && typeof eventListenerOrFunction === "object") {
// Received an EventListener object implementing the handleEvent interface
handleEvent = eventListenerOrFunction.handleEvent;
} else {
@ -824,10 +828,10 @@ Channel.prototype.unsubscribe = function (eventListenerOrFunction) {
* Calls all functions subscribed to this channel.
*/
Channel.prototype.fire = function(e) {
var fail = false; // eslint-disable-line no-unused-vars
var fireArgs = Array.prototype.slice.call(arguments);
var fail = false,
fireArgs = Array.prototype.slice.call(arguments);
// Apply stickiness.
if (this.state === 1) {
if (this.state == 1) {
this.state = 2;
this.fireArgs = fireArgs;
}
@ -841,7 +845,7 @@ Channel.prototype.fire = function (e) {
for (var i = 0; i < toCall.length; ++i) {
toCall[i].apply(this, fireArgs);
}
if (this.state === 2 && this.numHandlers) {
if (this.state == 2 && this.numHandlers) {
this.numHandlers = 0;
this.handlers = {};
this.onHasSubscribersChange && this.onHasSubscribersChange();
@ -849,6 +853,7 @@ Channel.prototype.fire = function (e) {
}
};
// defining them here so they are ready super fast!
// DOM event that is received when the web page is loaded and parsed.
channel.createSticky('onDOMContentLoaded');
@ -881,7 +886,7 @@ module.exports = channel;
});
// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/exec.js
// file: /Users/maj/src/cordova-android/cordova-js-src/exec.js
define("cordova/exec", function(require, exports, module) {
/**
@ -1166,6 +1171,7 @@ module.exports = androidExec;
// file: src/common/exec/proxy.js
define("cordova/exec/proxy", function(require, exports, module) {
// internal map of proxy function
var CommandProxyMap = {};
@ -1173,7 +1179,7 @@ module.exports = {
// example: cordova.commandProxy.add("Accelerometer",{getCurrentAcceleration: function(successCallback, errorCallback, options) {...},...);
add:function(id,proxyObj) {
console.log('adding proxy for ' + id);
console.log("adding proxy for " + id);
CommandProxyMap[id] = proxyObj;
return proxyObj;
},
@ -1190,7 +1196,6 @@ module.exports = {
return ( CommandProxyMap[service] ? CommandProxyMap[service][action] : null );
}
};
});
// file: src/common/init.js
@ -1207,14 +1212,14 @@ var platformInitChannelsArray = [channel.onNativeReady, channel.onPluginsReady];
function logUnfiredChannels(arr) {
for (var i = 0; i < arr.length; ++i) {
if (arr[i].state !== 2) {
if (arr[i].state != 2) {
console.log('Channel not fired: ' + arr[i].type);
}
}
}
window.setTimeout(function() {
if (channel.onDeviceReady.state !== 2) {
if (channel.onDeviceReady.state != 2) {
console.log('deviceready has not fired after 5 seconds.');
logUnfiredChannels(platformInitChannelsArray);
logUnfiredChannels(channel.deviceReadyChannelsArray);
@ -1231,9 +1236,10 @@ function replaceNavigator (origNavigator) {
// Without it, APIs such as getGamepads() break.
if (CordovaNavigator.bind) {
for (var key in origNavigator) {
if (typeof origNavigator[key] === 'function') {
if (typeof origNavigator[key] == 'function') {
newNavigator[key] = origNavigator[key].bind(origNavigator);
} else {
}
else {
(function(k) {
utils.defineGetterSetter(newNavigator,key,function() {
return origNavigator[k];
@ -1256,7 +1262,7 @@ if (!window.console) {
}
if (!window.console.warn) {
window.console.warn = function(msg) {
this.log('warn: ' + msg);
this.log("warn: " + msg);
};
}
@ -1267,7 +1273,7 @@ channel.onActivated = cordova.addDocumentEventHandler('activated');
channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
// Listen for DOMContentLoaded and notify our channel subscribers.
if (document.readyState === 'complete' || document.readyState === 'interactive') {
if (document.readyState == 'complete' || document.readyState == 'interactive') {
channel.onDOMContentLoaded.fire();
} else {
document.addEventListener('DOMContentLoaded', function() {
@ -1317,6 +1323,7 @@ channel.join(function () {
}, platformInitChannelsArray);
});
// file: src/common/init_b.js
@ -1336,14 +1343,14 @@ cordova.exec = require('cordova/exec');
function logUnfiredChannels(arr) {
for (var i = 0; i < arr.length; ++i) {
if (arr[i].state !== 2) {
if (arr[i].state != 2) {
console.log('Channel not fired: ' + arr[i].type);
}
}
}
window.setTimeout(function() {
if (channel.onDeviceReady.state !== 2) {
if (channel.onDeviceReady.state != 2) {
console.log('deviceready has not fired after 5 seconds.');
logUnfiredChannels(platformInitChannelsArray);
logUnfiredChannels(channel.deviceReadyChannelsArray);
@ -1360,9 +1367,10 @@ function replaceNavigator (origNavigator) {
// Without it, APIs such as getGamepads() break.
if (CordovaNavigator.bind) {
for (var key in origNavigator) {
if (typeof origNavigator[key] === 'function') {
if (typeof origNavigator[key] == 'function') {
newNavigator[key] = origNavigator[key].bind(origNavigator);
} else {
}
else {
(function(k) {
utils.defineGetterSetter(newNavigator,key,function() {
return origNavigator[k];
@ -1384,7 +1392,7 @@ if (!window.console) {
}
if (!window.console.warn) {
window.console.warn = function(msg) {
this.log('warn: ' + msg);
this.log("warn: " + msg);
};
}
@ -1395,7 +1403,7 @@ channel.onActivated = cordova.addDocumentEventHandler('activated');
channel.onDeviceReady = cordova.addStickyDocumentEventHandler('deviceready');
// Listen for DOMContentLoaded and notify our channel subscribers.
if (document.readyState === 'complete' || document.readyState === 'interactive') {
if (document.readyState == 'complete' || document.readyState == 'interactive') {
channel.onDOMContentLoaded.fire();
} else {
document.addEventListener('DOMContentLoaded', function() {
@ -1446,10 +1454,10 @@ channel.join(function () {
// file: src/common/modulemapper.js
define("cordova/modulemapper", function(require, exports, module) {
var builder = require('cordova/builder');
var moduleMap = define.moduleMap; // eslint-disable-line no-undef
var symbolList;
var deprecationMap;
var builder = require('cordova/builder'),
moduleMap = define.moduleMap,
symbolList,
deprecationMap;
exports.reset = function() {
symbolList = [];
@ -1489,7 +1497,7 @@ function prepareNamespace (symbolPath, context) {
}
var parts = symbolPath.split('.');
var cur = context;
for (var i = 0, part; part = parts[i]; ++i) { // eslint-disable-line no-cond-assign
for (var i = 0, part; part = parts[i]; ++i) {
cur = cur[part] = cur[part] || {};
}
return cur;
@ -1503,7 +1511,7 @@ exports.mapModules = function (context) {
var moduleName = symbolList[i + 1];
var module = require(moduleName);
// <runs/>
if (strategy === 'r') {
if (strategy == 'r') {
continue;
}
var symbolPath = symbolList[i + 2];
@ -1515,9 +1523,9 @@ exports.mapModules = function (context) {
var parentObj = prepareNamespace(namespace, context);
var target = parentObj[lastName];
if (strategy === 'm' && target) {
if (strategy == 'm' && target) {
builder.recursiveMerge(target, module);
} else if ((strategy === 'd' && !target) || (strategy !== 'd')) {
} else if ((strategy == 'd' && !target) || (strategy != 'd')) {
if (!(symbolPath in origSymbols)) {
origSymbols[symbolPath] = target;
}
@ -1541,14 +1549,15 @@ exports.getOriginalSymbol = function (context, symbolPath) {
exports.reset();
});
// file: src/common/modulemapper_b.js
define("cordova/modulemapper_b", function(require, exports, module) {
var builder = require('cordova/builder');
var symbolList = [];
var deprecationMap;
var builder = require('cordova/builder'),
symbolList = [],
deprecationMap;
exports.reset = function() {
symbolList = [];
@ -1585,7 +1594,7 @@ function prepareNamespace (symbolPath, context) {
}
var parts = symbolPath.split('.');
var cur = context;
for (var i = 0, part; part = parts[i]; ++i) { // eslint-disable-line no-cond-assign
for (var i = 0, part; part = parts[i]; ++i) {
cur = cur[part] = cur[part] || {};
}
return cur;
@ -1599,7 +1608,7 @@ exports.mapModules = function (context) {
var moduleName = symbolList[i + 1];
var module = require(moduleName);
// <runs/>
if (strategy === 'r') {
if (strategy == 'r') {
continue;
}
var symbolPath = symbolList[i + 2];
@ -1611,9 +1620,9 @@ exports.mapModules = function (context) {
var parentObj = prepareNamespace(namespace, context);
var target = parentObj[lastName];
if (strategy === 'm' && target) {
if (strategy == 'm' && target) {
builder.recursiveMerge(target, module);
} else if ((strategy === 'd' && !target) || (strategy !== 'd')) {
} else if ((strategy == 'd' && !target) || (strategy != 'd')) {
if (!(symbolPath in origSymbols)) {
origSymbols[symbolPath] = target;
}
@ -1637,9 +1646,10 @@ exports.getOriginalSymbol = function (context, symbolPath) {
exports.reset();
});
// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/platform.js
// file: /Users/maj/src/cordova-android/cordova-js-src/platform.js
define("cordova/platform", function(require, exports, module) {
// The last resume event that was received that had the result of a plugin call.
@ -1749,7 +1759,7 @@ function onMessageFromNative(msg) {
});
// file: /Users/jbowser/cordova/cordova-android/cordova-js-src/plugin/android/app.js
// file: /Users/maj/src/cordova-android/cordova-js-src/plugin/android/app.js
define("cordova/plugin/android/app", function(require, exports, module) {
var exec = require('cordova/exec');
@ -1846,11 +1856,12 @@ module.exports = {
define("cordova/pluginloader", function(require, exports, module) {
var modulemapper = require('cordova/modulemapper');
var urlutil = require('cordova/urlutil');
// Helper function to inject a <script> tag.
// Exported for testing.
exports.injectScript = function(url, onload, onerror) {
var script = document.createElement('script');
var script = document.createElement("script");
// onload fires even when script fails loads with an error.
script.onload = onload;
// onerror fires for malformed URLs.
@ -1861,11 +1872,11 @@ exports.injectScript = function (url, onload, onerror) {
function injectIfNecessary(id, url, onload, onerror) {
onerror = onerror || onload;
if (id in define.moduleMap) { // eslint-disable-line no-undef
if (id in define.moduleMap) {
onload();
} else {
exports.injectScript(url, function() {
if (id in define.moduleMap) { // eslint-disable-line no-undef
if (id in define.moduleMap) {
onload();
} else {
onerror();
@ -1876,7 +1887,7 @@ function injectIfNecessary (id, url, onload, onerror) {
function onScriptLoadingComplete(moduleList, finishPluginLoading) {
// Loop through all the plugins and then through their clobbers and merges.
for (var i = 0, module; module = moduleList[i]; i++) { // eslint-disable-line no-cond-assign
for (var i = 0, module; module = moduleList[i]; i++) {
if (module.clobbers && module.clobbers.length) {
for (var j = 0; j < module.clobbers.length; j++) {
modulemapper.clobbers(module.id, module.clobbers[j]);
@ -1927,7 +1938,7 @@ function findCordovaPath () {
var term = '/cordova.js';
for (var n = scripts.length-1; n>-1; n--) {
var src = scripts[n].src.replace(/\?.*$/, ''); // Strip any query param (CB-6007).
if (src.indexOf(term) === (src.length - term.length)) {
if (src.indexOf(term) == (src.length - term.length)) {
path = src.substring(0, src.length - term.length) + '/';
break;
}
@ -1945,11 +1956,12 @@ exports.load = function (callback) {
pathPrefix = '';
}
injectIfNecessary('cordova/plugin_list', pathPrefix + 'cordova_plugins.js', function() {
var moduleList = require('cordova/plugin_list');
var moduleList = require("cordova/plugin_list");
handlePluginsObject(pathPrefix, moduleList, callback);
}, callback);
};
});
// file: src/common/pluginloader_b.js
@ -1966,7 +1978,7 @@ function handlePluginsObject (moduleList) {
}
// Loop through all the modules and then through their clobbers and merges.
for (var i = 0, module; module = moduleList[i]; i++) { // eslint-disable-line no-cond-assign
for (var i = 0, module; module = moduleList[i]; i++) {
if (module.clobbers && module.clobbers.length) {
for (var j = 0; j < module.clobbers.length; j++) {
modulemapper.clobbers(module.id, module.clobbers[j]);
@ -1991,17 +2003,19 @@ function handlePluginsObject (moduleList) {
// onDeviceReady is blocked on onPluginsReady. onPluginsReady is fired when there are
// no plugins to load, or they are all done.
exports.load = function(callback) {
var moduleList = require('cordova/plugin_list');
var moduleList = require("cordova/plugin_list");
handlePluginsObject(moduleList);
callback();
};
});
// file: src/common/urlutil.js
define("cordova/urlutil", function(require, exports, module) {
/**
* For already absolute URLs, returns what is passed in.
* For relative URLs, converts them to absolute ones.
@ -2012,6 +2026,7 @@ exports.makeAbsolute = function makeAbsolute (url) {
return anchorEl.href;
};
});
// file: src/common/utils.js
@ -2051,7 +2066,7 @@ utils.arrayIndexOf = function (a, item) {
}
var len = a.length;
for (var i = 0; i < len; ++i) {
if (a[i] === item) {
if (a[i] == item) {
return i;
}
}
@ -2063,10 +2078,10 @@ utils.arrayIndexOf = function (a, item) {
*/
utils.arrayRemove = function(a, item) {
var index = utils.arrayIndexOf(a, item);
if (index !== -1) {
if (index != -1) {
a.splice(index, 1);
}
return index !== -1;
return index != -1;
};
utils.typeName = function(val) {
@ -2077,7 +2092,7 @@ utils.typeName = function (val) {
* Returns an indication of whether the argument is an array or not
*/
utils.isArray = Array.isArray ||
function (a) { return utils.typeName(a) === 'Array'; };
function(a) {return utils.typeName(a) == 'Array';};
/**
* Returns an indication of whether the argument is a Date or not
@ -2090,7 +2105,7 @@ utils.isDate = function (d) {
* Does a deep clone of the object.
*/
utils.clone = function(obj) {
if (!obj || typeof obj === 'function' || utils.isDate(obj) || typeof obj !== 'object') {
if(!obj || typeof obj == 'function' || utils.isDate(obj) || typeof obj != 'object') {
return obj;
}
@ -2109,7 +2124,7 @@ utils.clone = function (obj) {
// https://issues.apache.org/jira/browse/CB-11522 'unknown' type may be returned in
// custom protocol activation case on Windows Phone 8.1 causing "No such interface supported" exception
// on cloning.
if ((!(i in retVal) || retVal[i] !== obj[i]) && typeof obj[i] !== 'undefined' && typeof obj[i] !== 'unknown') { // eslint-disable-line valid-typeof
if((!(i in retVal) || retVal[i] != obj[i]) && typeof obj[i] != 'undefined' && typeof obj[i] != 'unknown') {
retVal[i] = utils.clone(obj[i]);
}
}
@ -2128,11 +2143,11 @@ utils.close = function (context, func, params) {
//------------------------------------------------------------------------------
function UUIDcreatePart(length) {
var uuidpart = '';
var uuidpart = "";
for (var i=0; i<length; i++) {
var uuidchar = parseInt((Math.random() * 256), 10).toString(16);
if (uuidchar.length === 1) {
uuidchar = '0' + uuidchar;
if (uuidchar.length == 1) {
uuidchar = "0" + uuidchar;
}
uuidpart += uuidchar;
}
@ -2150,6 +2165,7 @@ utils.createUUID = function () {
UUIDcreatePart(6);
};
/**
* Extends a child object from a parent object using classical inheritance
* pattern.
@ -2178,6 +2194,10 @@ utils.alert = function (msg) {
}
};
});
window.cordova = require('cordova');

View File

@ -1,5 +1,29 @@
cordova.define('cordova/plugin_list', function(require, exports, module) {
module.exports = [
{
"id": "cordova-plugin-browsertab.BrowserTab",
"file": "plugins/cordova-plugin-browsertab/www/browsertab.js",
"pluginId": "cordova-plugin-browsertab",
"clobbers": [
"cordova.plugins.browsertab"
]
},
{
"id": "cordova-plugin-buildinfo.BuildInfo",
"file": "plugins/cordova-plugin-buildinfo/www/buildinfo.js",
"pluginId": "cordova-plugin-buildinfo",
"clobbers": [
"BuildInfo"
]
},
{
"id": "cordova-plugin-customurlscheme.LaunchMyApp",
"file": "plugins/cordova-plugin-customurlscheme/www/android/LaunchMyApp.js",
"pluginId": "cordova-plugin-customurlscheme",
"clobbers": [
"window.plugins.launchmyapp"
]
},
{
"id": "cordova-plugin-device.device",
"file": "plugins/cordova-plugin-device/www/device.js",
@ -8,6 +32,15 @@ module.exports = [
"device"
]
},
{
"id": "cordova-plugin-inappbrowser.inappbrowser",
"file": "plugins/cordova-plugin-inappbrowser/www/inappbrowser.js",
"pluginId": "cordova-plugin-inappbrowser",
"clobbers": [
"cordova.InAppBrowser.open",
"window.open"
]
},
{
"id": "cordova-plugin-splashscreen.SplashScreen",
"file": "plugins/cordova-plugin-splashscreen/www/splashscreen.js",
@ -24,23 +57,6 @@ module.exports = [
"window.StatusBar"
]
},
{
"id": "ionic-plugin-keyboard.keyboard",
"file": "plugins/ionic-plugin-keyboard/www/android/keyboard.js",
"pluginId": "ionic-plugin-keyboard",
"clobbers": [
"cordova.plugins.Keyboard"
],
"runs": true
},
{
"id": "cordova-plugin-buildinfo.BuildInfo",
"file": "plugins/cordova-plugin-buildinfo/www/buildinfo.js",
"pluginId": "cordova-plugin-buildinfo",
"clobbers": [
"BuildInfo"
]
},
{
"id": "cordova-universal-links-plugin.universalLinks",
"file": "plugins/cordova-universal-links-plugin/www/universal_links.js",
@ -50,46 +66,31 @@ module.exports = [
]
},
{
"id": "cordova-plugin-browsertab.BrowserTab",
"file": "plugins/cordova-plugin-browsertab/www/browsertab.js",
"pluginId": "cordova-plugin-browsertab",
"id": "ionic-plugin-keyboard.keyboard",
"file": "plugins/ionic-plugin-keyboard/www/android/keyboard.js",
"pluginId": "ionic-plugin-keyboard",
"clobbers": [
"cordova.plugins.browsertab"
]
},
{
"id": "cordova-plugin-inappbrowser.inappbrowser",
"file": "plugins/cordova-plugin-inappbrowser/www/inappbrowser.js",
"pluginId": "cordova-plugin-inappbrowser",
"clobbers": [
"cordova.InAppBrowser.open",
"window.open"
]
},
{
"id": "cordova-plugin-customurlscheme.LaunchMyApp",
"file": "plugins/cordova-plugin-customurlscheme/www/android/LaunchMyApp.js",
"pluginId": "cordova-plugin-customurlscheme",
"clobbers": [
"window.plugins.launchmyapp"
]
"cordova.plugins.Keyboard"
],
"runs": true
}
];
module.exports.metadata =
// TOP OF METADATA
{
"cordova-plugin-compat": "1.2.0",
"cordova-plugin-browsertab": "0.2.0",
"cordova-plugin-buildinfo": "2.0.1",
"cordova-plugin-console": "1.1.0",
"cordova-plugin-crosswalk-webview": "2.3.0",
"cordova-plugin-customurlscheme": "4.3.0",
"cordova-plugin-device": "1.1.7",
"cordova-plugin-inappbrowser": "2.0.1",
"cordova-plugin-splashscreen": "4.1.0",
"cordova-plugin-statusbar": "2.4.1",
"cordova-plugin-whitelist": "1.3.3",
"ionic-plugin-keyboard": "2.2.1",
"cordova-plugin-buildinfo": "2.0.1",
"cordova-universal-links-plugin": "1.2.1",
"cordova-plugin-browsertab": "0.2.0",
"cordova-plugin-inappbrowser": "2.0.1",
"cordova-plugin-customurlscheme": "4.3.0"
"ionic-plugin-keyboard": "2.2.1"
};
// BOTTOM OF METADATA
});

View File

@ -1,17 +1,18 @@
# This file was originally created by the Android Tools, but is now
# used by cordova-android to manage the state of the various third party
# libraries used in your application
# This is the Library Module that contains the Cordova Library, this is not
# required when using an AAR
# This is the application project. This is only required for Android Studio Gradle projects
# This file is automatically generated by Android Tools.
# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
#
# This file must be checked in Version Control Systems.
#
# To customize properties used by the Ant build system edit
# "ant.properties", and override values to adapt the script to your
# project structure.
#
# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
#proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
# Project target.
target=android-26
target=android-25
android.library.reference.1=CordovaLib
android.library.reference.2=app
cordova.gradle.include.1=cordova-plugin-crosswalk-webview/dynamicbible-xwalk.gradle
cordova.gradle.include.2=cordova-plugin-buildinfo/dynamicbible-BuildInfo.gradle
cordova.system.library.1=com.android.support:customtabs:23.3.0
cordova.gradle.include.3=cordova-plugin-browsertab/dynamicbible-BrowserTab.gradle
cordova.gradle.include.1=cordova-plugin-browsertab/dynamicbible-BrowserTab.gradle
cordova.gradle.include.2=cordova-plugin-buildinfo/dynamicbible-BuildInfo.gradle
cordova.gradle.include.3=cordova-plugin-crosswalk-webview/dynamicbible-xwalk.gradle

Binary file not shown.

After

Width:  |  Height:  |  Size: 593 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 599 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 328 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 131 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 727 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 744 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 536 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1021 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 681 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,6 @@
<?xml version='1.0' encoding='utf-8'?>
<resources>
<string name="app_name">Dynamic Bible</string>
<string name="launcher_name">@string/app_name</string>
<string name="activity_name">@string/launcher_name</string>
</resources>

View File

@ -0,0 +1,114 @@
<?xml version='1.0' encoding='utf-8'?>
<widget id="walljm.dynamicbible" version="3.0.3" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">
<feature name="BrowserTab">
<param name="android-package" value="com.google.cordova.plugin.browsertab.BrowserTab" />
</feature>
<feature name="BuildInfo">
<param name="android-package" value="org.apache.cordova.buildinfo.BuildInfo" />
</feature>
<feature name="LaunchMyApp">
<param name="android-package" value="nl.xservices.plugins.LaunchMyApp" />
</feature>
<feature name="Device">
<param name="android-package" value="org.apache.cordova.device.Device" />
</feature>
<feature name="InAppBrowser">
<param name="android-package" value="org.apache.cordova.inappbrowser.InAppBrowser" />
</feature>
<feature name="SplashScreen">
<param name="android-package" value="org.apache.cordova.splashscreen.SplashScreen" />
<param name="onload" value="true" />
</feature>
<feature name="StatusBar">
<param name="android-package" value="org.apache.cordova.statusbar.StatusBar" />
<param name="onload" value="true" />
</feature>
<feature name="Whitelist">
<param name="android-package" value="org.apache.cordova.whitelist.WhitelistPlugin" />
<param name="onload" value="true" />
</feature>
<feature name="UniversalLinks">
<param name="android-package" value="com.nordnetab.cordova.ul.UniversalLinksPlugin" />
<param name="onload" value="true" />
</feature>
<feature name="Keyboard">
<param name="android-package" value="io.ionic.keyboard.IonicKeyboard" />
<param name="onload" value="true" />
</feature>
<name>Dynamic Bible</name>
<description>A bible app designed for bible study</description>
<author email="jason@walljm.com" href="http://dynamicbible.com/">Jason Wall</author>
<content src="index.html" />
<access origin="*" />
<allow-intent href="http://*/*" />
<allow-intent href="https://*/*" />
<allow-intent href="tel:*" />
<allow-intent href="sms:*" />
<allow-intent href="mailto:*" />
<allow-intent href="geo:*" />
<universal-links>
<host name="bhgx5.app.goo.gl/XktS" scheme="https" />
<host name="dynamicbible-7c6cf.firebaseapp.com" scheme="https">
<path url="/__/auth/callback" />
</host>
</universal-links>
<allow-intent href="market:*" />
<icon density="ldpi" src="resources\android\icon\drawable-ldpi-icon.png" />
<icon density="mdpi" src="resources\android\icon\drawable-mdpi-icon.png" />
<icon density="hdpi" src="resources\android\icon\drawable-hdpi-icon.png" />
<icon density="xhdpi" src="resources\android\icon\drawable-xhdpi-icon.png" />
<icon density="xxhdpi" src="resources\android\icon\drawable-xxhdpi-icon.png" />
<icon density="xxxhdpi" src="resources\android\icon\drawable-xxxhdpi-icon.png" />
<splash density="land-ldpi" src="resources\android\splash\drawable-land-ldpi-screen.png" />
<splash density="land-mdpi" src="resources\android\splash\drawable-land-mdpi-screen.png" />
<splash density="land-hdpi" src="resources\android\splash\drawable-land-hdpi-screen.png" />
<splash density="land-xhdpi" src="resources\android\splash\drawable-land-xhdpi-screen.png" />
<splash density="land-xxhdpi" src="resources\android\splash\drawable-land-xxhdpi-screen.png" />
<splash density="land-xxxhdpi" src="resources\android\splash\drawable-land-xxxhdpi-screen.png" />
<splash density="port-ldpi" src="resources\android\splash\drawable-port-ldpi-screen.png" />
<splash density="port-mdpi" src="resources\android\splash\drawable-port-mdpi-screen.png" />
<splash density="port-hdpi" src="resources\android\splash\drawable-port-hdpi-screen.png" />
<splash density="port-xhdpi" src="resources\android\splash\drawable-port-xhdpi-screen.png" />
<splash density="port-xxhdpi" src="resources\android\splash\drawable-port-xxhdpi-screen.png" />
<splash density="port-xxxhdpi" src="resources\android\splash\drawable-port-xxxhdpi-screen.png" />
<icon density="ldpi" src="resources/android/icon/drawable-ldpi-icon.png" />
<icon density="mdpi" src="resources/android/icon/drawable-mdpi-icon.png" />
<icon density="hdpi" src="resources/android/icon/drawable-hdpi-icon.png" />
<icon density="xhdpi" src="resources/android/icon/drawable-xhdpi-icon.png" />
<icon density="xxhdpi" src="resources/android/icon/drawable-xxhdpi-icon.png" />
<icon density="xxxhdpi" src="resources/android/icon/drawable-xxxhdpi-icon.png" />
<splash density="land-ldpi" src="resources/android/splash/drawable-land-ldpi-screen.png" />
<splash density="land-mdpi" src="resources/android/splash/drawable-land-mdpi-screen.png" />
<splash density="land-hdpi" src="resources/android/splash/drawable-land-hdpi-screen.png" />
<splash density="land-xhdpi" src="resources/android/splash/drawable-land-xhdpi-screen.png" />
<splash density="land-xxhdpi" src="resources/android/splash/drawable-land-xxhdpi-screen.png" />
<splash density="land-xxxhdpi" src="resources/android/splash/drawable-land-xxxhdpi-screen.png" />
<splash density="port-ldpi" src="resources/android/splash/drawable-port-ldpi-screen.png" />
<splash density="port-mdpi" src="resources/android/splash/drawable-port-mdpi-screen.png" />
<splash density="port-hdpi" src="resources/android/splash/drawable-port-hdpi-screen.png" />
<splash density="port-xhdpi" src="resources/android/splash/drawable-port-xhdpi-screen.png" />
<splash density="port-xxhdpi" src="resources/android/splash/drawable-port-xxhdpi-screen.png" />
<splash density="port-xxxhdpi" src="resources/android/splash/drawable-port-xxxhdpi-screen.png" />
<preference name="loglevel" value="DEBUG" />
<preference name="webView" value="org.crosswalk.engine.XWalkWebViewEngine" />
<preference name="xwalkVersion" value="23+" />
<preference name="xwalkLiteVersion" value="xwalk_core_library_canary:17+" />
<preference name="xwalkCommandLine" value="--disable-pull-to-refresh-effect" />
<preference name="xwalkMode" value="embedded" />
<preference name="xwalkMultipleApk" value="true" />
<preference name="webviewbounce" value="false" />
<preference name="UIWebViewBounce" value="false" />
<preference name="DisallowOverscroll" value="true" />
<preference name="android-minSdkVersion" value="16" />
<preference name="BackupWebStorage" value="none" />
<preference name="SplashMaintainAspectRatio" value="true" />
<preference name="FadeSplashScreenDuration" value="300" />
<preference name="SplashScreen" value="screen" />
<preference name="SplashScreenDelay" value="12000" />
<preference name="ShowSplashScreen" value="true" />
<preference name="AutoHideSplashScreen" value="false" />
<preference name="SplashShowOnlyFirstTime" value="false" />
<preference name="FadeSplashScreen" value="false" />
<preference name="loadUrlTimeoutValue" value="60000" />
<preference name="AndroidLaunchMode" value="singleTask" />
</widget>

View File

@ -1,4 +1,3 @@
// GENERATED FILE - DO NOT EDIT
include ":"
include ":CordovaLib"
include ":app"

View File

@ -0,0 +1,177 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.cordova.plugin.browsertab;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.support.customtabs.CustomTabsIntent;
import android.util.Log;
import java.util.Iterator;
import java.util.List;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Cordova plugin which provides the ability to launch a URL in an
* in-app browser tab. On Android, this means using the custom tabs support
* library, if a supporting browser (e.g. Chrome) is available on the device.
*/
public class BrowserTab extends CordovaPlugin {
public static final int RC_OPEN_URL = 101;
private static final String LOG_TAG = "BrowserTab";
/**
* The service we expect to find on a web browser that indicates it supports custom tabs.
*/
private static final String ACTION_CUSTOM_TABS_CONNECTION =
"android.support.customtabs.action.CustomTabsService";
private boolean mFindCalled = false;
private String mCustomTabsBrowser;
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) {
Log.d(LOG_TAG, "executing " + action);
if ("isAvailable".equals(action)) {
isAvailable(callbackContext);
} else if ("openUrl".equals(action)) {
openUrl(args, callbackContext);
} else if ("close".equals(action)) {
// close is a NOP on Android
return true;
} else {
return false;
}
return true;
}
private void isAvailable(CallbackContext callbackContext) {
String browserPackage = findCustomTabBrowser();
Log.d(LOG_TAG, "browser package: " + browserPackage);
callbackContext.sendPluginResult(new PluginResult(
PluginResult.Status.OK,
browserPackage != null));
}
private void openUrl(JSONArray args, CallbackContext callbackContext) {
if (args.length() < 1) {
Log.d(LOG_TAG, "openUrl: no url argument received");
callbackContext.error("URL argument missing");
return;
}
String urlStr;
try {
urlStr = args.getString(0);
} catch (JSONException e) {
Log.d(LOG_TAG, "openUrl: failed to parse url argument");
callbackContext.error("URL argument is not a string");
return;
}
String customTabsBrowser = findCustomTabBrowser();
if (customTabsBrowser == null) {
Log.d(LOG_TAG, "openUrl: no in app browser tab available");
callbackContext.error("no in app browser tab implementation available");
}
Intent customTabsIntent = new CustomTabsIntent.Builder().build().intent;
customTabsIntent.setData(Uri.parse(urlStr));
customTabsIntent.setPackage(mCustomTabsBrowser);
cordova.getActivity().startActivity(customTabsIntent);
Log.d(LOG_TAG, "in app browser call dispatched");
callbackContext.success();
}
private String findCustomTabBrowser() {
if (mFindCalled) {
return mCustomTabsBrowser;
}
PackageManager pm = cordova.getActivity().getPackageManager();
Intent webIntent = new Intent(
Intent.ACTION_VIEW,
Uri.parse("http://www.example.com"));
List<ResolveInfo> resolvedActivityList =
pm.queryIntentActivities(webIntent, PackageManager.GET_RESOLVED_FILTER);
for (ResolveInfo info : resolvedActivityList) {
if (!isFullBrowser(info)) {
continue;
}
if (hasCustomTabWarmupService(pm, info.activityInfo.packageName)) {
mCustomTabsBrowser = info.activityInfo.packageName;
break;
}
}
mFindCalled = true;
return mCustomTabsBrowser;
}
private boolean isFullBrowser(ResolveInfo resolveInfo) {
// The filter must match ACTION_VIEW, CATEGORY_BROWSEABLE, and at least one scheme,
if (!resolveInfo.filter.hasAction(Intent.ACTION_VIEW)
|| !resolveInfo.filter.hasCategory(Intent.CATEGORY_BROWSABLE)
|| resolveInfo.filter.schemesIterator() == null) {
return false;
}
// The filter must not be restricted to any particular set of authorities
if (resolveInfo.filter.authoritiesIterator() != null) {
return false;
}
// The filter must support both HTTP and HTTPS.
boolean supportsHttp = false;
boolean supportsHttps = false;
Iterator<String> schemeIter = resolveInfo.filter.schemesIterator();
while (schemeIter.hasNext()) {
String scheme = schemeIter.next();
supportsHttp |= "http".equals(scheme);
supportsHttps |= "https".equals(scheme);
if (supportsHttp && supportsHttps) {
return true;
}
}
// at least one of HTTP or HTTPS is not supported
return false;
}
private boolean hasCustomTabWarmupService(PackageManager pm, String packageName) {
Intent serviceIntent = new Intent();
serviceIntent.setAction(ACTION_CUSTOM_TABS_CONNECTION);
serviceIntent.setPackage(packageName);
return (pm.resolveService(serviceIntent, 0) != null);
}
}

View File

@ -0,0 +1,221 @@
package com.nordnetab.cordova.ul;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import com.nordnetab.cordova.ul.js.JSAction;
import com.nordnetab.cordova.ul.model.JSMessage;
import com.nordnetab.cordova.ul.model.ULHost;
import com.nordnetab.cordova.ul.parser.ULConfigXmlParser;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaArgs;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult;
import org.json.JSONException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Created by Nikolay Demyankov on 09.09.15.
* <p/>
* Plugin main class.
* Communicates with the JS side, handles launch intents and so on.
*/
public class UniversalLinksPlugin extends CordovaPlugin {
// list of hosts, defined in config.xml
private List<ULHost> supportedHosts;
// list of subscribers
private Map<String, CallbackContext> subscribers;
// stored message, that is captured on application launch
private JSMessage storedMessage;
// region Public API
@Override
public void initialize(CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
supportedHosts = new ULConfigXmlParser(cordova.getActivity()).parse();
if (subscribers == null) {
subscribers = new HashMap<String, CallbackContext>();
}
handleIntent(cordova.getActivity().getIntent());
}
@Override
public boolean execute(String action, CordovaArgs args, CallbackContext callbackContext) throws JSONException {
boolean isHandled = true;
if (JSAction.SUBSCRIBE.equals(action)) {
subscribeForEvent(args, callbackContext);
} else if (JSAction.UNSUBSCRIBE.equals(action)) {
unsubscribeFromEvent(args);
} else {
isHandled = false;
}
return isHandled;
}
@Override
public void onNewIntent(Intent intent) {
handleIntent(intent);
}
// endregion
// region JavaScript methods
/**
* Add subscriber for the event.
*
* @param arguments arguments, passed from JS side
* @param callbackContext callback to use when event is captured
*/
private void subscribeForEvent(final CordovaArgs arguments, final CallbackContext callbackContext) {
final String eventName = getEventNameFromArguments(arguments);
if (TextUtils.isEmpty(eventName)) {
return;
}
subscribers.put(eventName, callbackContext);
tryToConsumeEvent();
}
/**
* Remove subscriber from the event.
*
* @param arguments arguments, passed from JS side
*/
private void unsubscribeFromEvent(final CordovaArgs arguments) {
if (subscribers.size() == 0) {
return;
}
final String eventName = getEventNameFromArguments(arguments);
if (TextUtils.isEmpty(eventName)) {
return;
}
subscribers.remove(eventName);
}
/**
* Get event name from the cordova arguments.
*
* @param arguments received arguments
* @return event name; <code>null</code> if non is found
*/
private String getEventNameFromArguments(final CordovaArgs arguments) {
String eventName = null;
try {
eventName = arguments.getString(0);
} catch (JSONException e) {
Log.d("UniversalLinks", "Failed to get event name from the JS arguments", e);
}
return eventName;
}
/**
* Try to send event to the subscribers.
*/
private void tryToConsumeEvent() {
if (subscribers.size() == 0 || storedMessage == null) {
return;
}
final String storedEventName = storedMessage.getEventName();
final Set<Map.Entry<String, CallbackContext>> subscribersSet = subscribers.entrySet();
for (Map.Entry<String, CallbackContext> subscriber : subscribersSet) {
final String eventName = subscriber.getKey();
if (eventName.equals(storedEventName)) {
sendMessageToJs(storedMessage, subscriber.getValue());
storedMessage = null;
break;
}
}
}
/**
* Send message to JS side.
*
* @param message message to send
* @param callback to what callback we are sending the message
*/
private void sendMessageToJs(JSMessage message, CallbackContext callback) {
final PluginResult result = new PluginResult(PluginResult.Status.OK, message);
result.setKeepCallback(true);
callback.sendPluginResult(result);
}
// endregion
// region Intent handling
/**
* Handle launch intent.
* If it is an UL intent - then event will be dispatched to the JS side.
*
* @param intent launch intent
*/
private void handleIntent(Intent intent) {
if (intent == null || supportedHosts == null || supportedHosts.size() == 0) {
return;
}
// read intent
String action = intent.getAction();
Uri launchUri = intent.getData();
// if app was not launched by the url - ignore
if (!Intent.ACTION_VIEW.equals(action) || launchUri == null) {
return;
}
// try to find host in the hosts list from the config.xml
ULHost host = findHostByUrl(launchUri);
if (host == null) {
Log.d("UniversalLinks", "Host " + launchUri.getHost() + " is not supported");
return;
}
// store message and try to consume it
storedMessage = new JSMessage(host, launchUri);
tryToConsumeEvent();
}
/**
* Find host entry that matches the launch url.
*
* @param url launch url
* @return host entry; <code>null</code> - if none were found
*/
private ULHost findHostByUrl(Uri url) {
ULHost host = null;
final String launchHost = url.getHost().toLowerCase();
for (ULHost supportedHost : supportedHosts) {
if (supportedHost.getName().equals(launchHost) ||
supportedHost.getName().startsWith("*.") && launchHost.endsWith(supportedHost.getName().substring(1))) {
host = supportedHost;
break;
}
}
return host;
}
// endregion
}

View File

@ -0,0 +1,19 @@
package com.nordnetab.cordova.ul.js;
/**
* Created by Nikolay Demyankov on 09.09.15.
* <p/>
* Class holds list of method names that is called from JS side.
*/
public final class JSAction {
/**
* Subscribe to event.
*/
public static final String SUBSCRIBE = "jsSubscribeForEvent";
/**
* Unsubscribe from event.
*/
public static final String UNSUBSCRIBE = "jsUnsubscribeFromEvent";
}

View File

@ -0,0 +1,193 @@
package com.nordnetab.cordova.ul.model;
import android.net.Uri;
import android.util.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.List;
import java.util.Set;
/**
* Created by Nikolay Demyankov on 10.09.15.
* <p/>
* Model for the message entry, that is send to JS.
*/
public class JSMessage extends JSONObject {
// keys for the message base structure
private static final class JSGeneralKeys {
/**
* Event name
*/
public static final String EVENT = "event";
/**
* Message data block
*/
public static final String DATA = "data";
}
// keys for the message data block
private static final class JSDataKeys {
/**
* Path part of the url
*/
public static final String PATH = "path";
/**
* Scheme of the url
*/
public static final String SCHEME = "scheme";
/**
* Host of the url
*/
public static final String HOST = "host";
/**
* Hash (fragment) from the url - data after '#'
*/
public static final String HASH = "hash";
/**
* Query parameters - data after '?'
*/
public static final String PARAMS = "params";
/**
* Launch url as it is
*/
public static final String ORIGIN = "url";
}
private String eventName;
/**
* Constructor
*
* @param host host entry that corresponds to the launching url
* @param originalUri launch url
*/
public JSMessage(ULHost host, Uri originalUri) {
setEventName(host, originalUri);
setMessageData(host, originalUri);
}
/**
* Getter for event name of this message.
*
* @return event name
*/
public String getEventName() {
return eventName;
}
// region Event name setters
/**
* Set event name for this message entry.
*/
private void setEventName(ULHost host, Uri originalUri) {
eventName = getEventName(host, originalUri);
try {
put(JSGeneralKeys.EVENT, eventName);
} catch (JSONException e) {
Log.d("UniversalLinks", "Failed to set event name", e);
}
}
/**
* Find event name based on the launching url.
* By default, event name from the host object will be used.
* But if we have some path entry in the host and it matches the one from the launch url - his event name will be used.
*/
private String getEventName(ULHost host, Uri originalUri) {
String event = host.getEvent();
final String originPath = originalUri.getPath().toLowerCase();
final List<ULPath> hostPathsList = host.getPaths();
for (ULPath hostPath : hostPathsList) {
final String hostPathUrl = hostPath.getUrl();
if (hostPathUrl == null) {
continue;
}
if (originPath.matches(hostPathUrl)) {
event = hostPath.getEvent();
break;
}
}
return event;
}
// endregion
// region Data block setters
/**
* Fill data block with corresponding information.
*/
private void setMessageData(ULHost host, Uri originalUri) {
final JSONObject dataObject = new JSONObject();
try {
setOriginalUrl(dataObject, originalUri);
setHostData(dataObject, host);
setPathData(dataObject, originalUri);
put(JSGeneralKeys.DATA, dataObject);
} catch (JSONException e) {
Log.d("UniversalLinks", "Failed to set event data", e);
}
}
/**
* Put launch url to the data block
*/
private void setOriginalUrl(JSONObject dataObject, Uri originalUri) throws JSONException {
dataObject.put(JSDataKeys.ORIGIN, originalUri.toString());
}
/**
* Put host name and scheme into data block
*/
private void setHostData(JSONObject dataObject, ULHost host) throws JSONException {
dataObject.put(JSDataKeys.HOST, host.getName());
dataObject.put(JSDataKeys.SCHEME, host.getScheme());
}
/**
* Put path information into data block
*/
private void setPathData(JSONObject dataObject, Uri originalUri) throws JSONException {
dataObject.put(JSDataKeys.HASH, originalUri.getFragment());
dataObject.put(JSDataKeys.PATH, originalUri.getPath());
final JSONObject queryParams = getQueryParamsFromUri(originalUri);
dataObject.put(JSDataKeys.PARAMS, queryParams);
}
/**
* Parse query params.
* For example, if we have link like so: http://somedomain.com/some/path?foo=fooVal&bar=barVal , then
* resulting object will be {foo: fooVal, bar: barVal}.
*
* @return json object
*/
private JSONObject getQueryParamsFromUri(Uri originalUri) throws JSONException, UnsupportedOperationException {
JSONObject queryParams = new JSONObject();
Set<String> keysList = originalUri.getQueryParameterNames();
for (String key : keysList) {
final String value = originalUri.getQueryParameter(key);
queryParams.put(key, value);
}
return queryParams;
}
// endregion
}

View File

@ -0,0 +1,85 @@
package com.nordnetab.cordova.ul.model;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Nikolay Demyankov on 09.09.15.
* <p/>
* Model for <host /> entry, specified in config.xml.
*/
public class ULHost {
// default event name, that is dispatched to JS if none was set to the host or path
private static final String DEFAULT_EVENT = "didLaunchAppFromLink";
// default scheme for the host
private static final String DEFAULT_SCHEME = "http";
private final List<ULPath> paths;
private final String name;
private final String scheme;
private String event;
/**
* Constructor
*
* @param name host name
* @param scheme host scheme
* @param event event that corresponds to this host
*/
public ULHost(final String name, final String scheme, final String event) {
this.name = name.toLowerCase();
this.scheme = (scheme == null) ? DEFAULT_SCHEME : scheme;
this.event = (event == null) ? DEFAULT_EVENT : event;
this.paths = new ArrayList<ULPath>();
}
/**
* Getter for the event name that is sent to JS when user clicks on the link from this host.
* Defined as 'event' attribute.
*
* @return event name
*/
public String getEvent() {
return event;
}
/**
* Setter for event name.
*
* @param event event name
*/
public void setEvent(final String event) {
this.event = event;
}
/**
* Getter for the list of paths, that is set for that host in config.xml.
*
* @return list of hosts
*/
public List<ULPath> getPaths() {
return paths;
}
/**
* Getter for the host name.
* Defined as 'name' attribute.
*
* @return host name
*/
public String getName() {
return name;
}
/**
* Getter for host scheme.
* Defined as 'scheme' attribute.
*
* @return scheme
*/
public String getScheme() {
return scheme;
}
}

View File

@ -0,0 +1,43 @@
package com.nordnetab.cordova.ul.model;
/**
* Created by Nikolay Demyankov on 09.09.15.
* <p/>
* Model for <path /> entry for host in config.xml
*/
public class ULPath {
private final String url;
private final String event;
/**
* Constructor
*
* @param url path url
* @param event event name
*/
public ULPath(final String url, final String event) {
this.url = url.replace("*", "(.*)").toLowerCase();
this.event = event;
}
/**
* Getter for path url.
* Defined as 'url' attribute.
*
* @return path url
*/
public String getUrl() {
return url;
}
/**
* Getter for the event name that is dispatched when application is launched from the link with this path.
* Defined as 'event' attribute.
*
* @return event name
*/
public String getEvent() {
return event;
}
}

View File

@ -0,0 +1,156 @@
package com.nordnetab.cordova.ul.parser;
import android.content.Context;
import android.text.TextUtils;
import com.nordnetab.cordova.ul.model.ULHost;
import com.nordnetab.cordova.ul.model.ULPath;
import org.apache.cordova.ConfigXmlParser;
import org.xmlpull.v1.XmlPullParser;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Nikolay Demyankov on 09.09.15.
* <p/>
* Parser for config.xml. Reads only plugin-specific preferences.
*/
public class ULConfigXmlParser extends ConfigXmlParser {
private final Context context;
private List<ULHost> hostsList;
private boolean isInsideMainTag;
private boolean didParseMainBlock;
private boolean isInsideHostBlock;
private ULHost processedHost;
// region Public API
/**
* Constructor
*
* @param context application context
*/
public ULConfigXmlParser(Context context) {
this.context = context;
}
/**
* Parse config.xml
*
* @return list of hosts, defined in the config file
*/
public List<ULHost> parse() {
resetValuesToDefaultState();
super.parse(context);
return hostsList;
}
// endregion
// region XML processing
@Override
public void handleStartTag(XmlPullParser xml) {
if (didParseMainBlock) {
return;
}
final String name = xml.getName();
if (!isInsideMainTag && XmlTags.MAIN_TAG.equals(name)) {
isInsideMainTag = true;
return;
}
if (!isInsideMainTag) {
return;
}
if (!isInsideHostBlock && XmlTags.HOST_TAG.equals(name)) {
isInsideHostBlock = true;
processHostBlock(xml);
return;
}
if (isInsideHostBlock && XmlTags.PATH_TAG.equals(name)) {
processPathBlock(xml);
}
}
@Override
public void handleEndTag(XmlPullParser xml) {
if (didParseMainBlock) {
return;
}
final String name = xml.getName();
if (isInsideHostBlock && XmlTags.HOST_TAG.equals(name)) {
isInsideHostBlock = false;
hostsList.add(processedHost);
processedHost = null;
return;
}
if (XmlTags.MAIN_TAG.equals(name)) {
isInsideMainTag = false;
didParseMainBlock = true;
}
}
/**
* Parse <host />
*/
private void processHostBlock(XmlPullParser xml) {
final String hostName = xml.getAttributeValue(null, XmlTags.HOST_NAME_ATTRIBUTE);
final String eventName = xml.getAttributeValue(null, XmlTags.HOST_EVENT_ATTRIBUTE);
final String scheme = xml.getAttributeValue(null, XmlTags.HOST_SCHEME_ATTRIBUTE);
processedHost = new ULHost(hostName, scheme, eventName);
}
/**
* Parse <path />
*/
private void processPathBlock(XmlPullParser xml) {
final String url = xml.getAttributeValue(null, XmlTags.PATH_URL_TAG);
String event = xml.getAttributeValue(null, XmlTags.PATH_EVENT_TAG);
// skip wildcard urls
if ("*".equals(url) || ".*".equals(url)) {
// but if path has event name - set it to host
if (!TextUtils.isEmpty(event)) {
processedHost.setEvent(event);
}
return;
}
// if event name is empty - use one from the host
if (TextUtils.isEmpty(event)) {
event = processedHost.getEvent();
}
// create path entry
ULPath path = new ULPath(url, event);
processedHost.getPaths().add(path);
}
// endregion
// region Private API
private void resetValuesToDefaultState() {
hostsList = new ArrayList<ULHost>();
isInsideMainTag = false;
didParseMainBlock = false;
isInsideHostBlock = false;
processedHost = null;
}
// endregion
}

View File

@ -0,0 +1,49 @@
package com.nordnetab.cordova.ul.parser;
/**
* Created by Nikolay Demyankov on 10.09.15.
* <p/>
* XML tags that is used in config.xml to specify plugin preferences.
*/
final class XmlTags {
/**
* Main tag in which we define plugin related stuff
*/
public static final String MAIN_TAG = "universal-links";
/**
* Host main tag
*/
public static final String HOST_TAG = "host";
/**
* Scheme attribute for the host entry
*/
public static final String HOST_SCHEME_ATTRIBUTE = "scheme";
/**
* Name attribute for the host entry
*/
public static final String HOST_NAME_ATTRIBUTE = "name";
/**
* Event attribute for the host entry
*/
public static final String HOST_EVENT_ATTRIBUTE = "event";
/**
* Path main tag
*/
public static final String PATH_TAG = "path";
/**
* Url attribute for the path entry
*/
public static final String PATH_URL_TAG = "url";
/**
* Event attribute for the path entry
*/
public static final String PATH_EVENT_TAG = "event";
}

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