@capacitor/android 4.0.0-nightly-c3aa3d6c.0 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/capacitor/build.gradle +2 -0
- package/capacitor/proguard-rules.pro +26 -0
- package/capacitor/src/main/assets/native-bridge.js +8 -0
- package/capacitor/src/main/java/com/getcapacitor/Bridge.java +102 -3
- package/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +10 -0
- package/capacitor/src/main/java/com/getcapacitor/CapConfig.java +28 -0
- package/capacitor/src/main/java/com/getcapacitor/MessageHandler.java +31 -4
- package/capacitor/src/main/java/com/getcapacitor/PluginCall.java +28 -9
- package/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java +7 -2
- package/package.json +4 -3
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,33 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [4.0.0](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.2...4.0.0) (2022-07-27)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* **android:** Publish proguard-rules.pro on npm ([#5761](https://github.com/ionic-team/capacitor/issues/5761)) ([df77103](https://github.com/ionic-team/capacitor/commit/df77103ca411fa452239099769289eeeea2404d2))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
### Features
|
|
15
|
+
|
|
16
|
+
* **android:** Add android.minWebviewVersion configuration option ([#5768](https://github.com/ionic-team/capacitor/issues/5768)) ([ad83827](https://github.com/ionic-team/capacitor/commit/ad838279e9cd190ce6f1a020a0ac9e3916786324))
|
|
17
|
+
* **android:** Add Optional Data Param for Error Object ([#5719](https://github.com/ionic-team/capacitor/issues/5719)) ([174172b](https://github.com/ionic-team/capacitor/commit/174172b6c64dc9117c48ed0e20c25e0b6c2fb625))
|
|
18
|
+
* **android:** Use addWebMessageListener where available ([#5427](https://github.com/ionic-team/capacitor/issues/5427)) ([c2dfe80](https://github.com/ionic-team/capacitor/commit/c2dfe808446717412b35e82713d123b7a052f264))
|
|
19
|
+
* Add option for custom error page ([#5723](https://github.com/ionic-team/capacitor/issues/5723)) ([e8bdef3](https://github.com/ionic-team/capacitor/commit/e8bdef3b4634e4ad45fa8fc34c7c0ab8dfa383f3))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
# [4.0.0-beta.2](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.1...4.0.0-beta.2) (2022-07-08)
|
|
26
|
+
|
|
27
|
+
**Note:** Version bump only for package @capacitor/android
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
6
33
|
# [4.0.0-beta.1](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.0...4.0.0-beta.1) (2022-06-27)
|
|
7
34
|
|
|
8
35
|
**Note:** Version bump only for package @capacitor/android
|
package/capacitor/build.gradle
CHANGED
|
@@ -4,6 +4,7 @@ ext {
|
|
|
4
4
|
androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.2.0'
|
|
5
5
|
androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.8.0'
|
|
6
6
|
androidxFragmentVersion = project.hasProperty('androidxFragmentVersion') ? rootProject.ext.androidxFragmentVersion : '1.4.1'
|
|
7
|
+
androidxWebkitVersion = project.hasProperty('androidxWebkitVersion') ? rootProject.ext.androidxWebkitVersion : '1.4.0'
|
|
7
8
|
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
|
8
9
|
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3'
|
|
9
10
|
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.4.0'
|
|
@@ -64,6 +65,7 @@ dependencies {
|
|
|
64
65
|
implementation "androidx.activity:activity:$androidxActivityVersion"
|
|
65
66
|
implementation "androidx.fragment:fragment:$androidxFragmentVersion"
|
|
66
67
|
implementation "androidx.coordinatorlayout:coordinatorlayout:$androidxCoordinatorLayoutVersion"
|
|
68
|
+
implementation "androidx.webkit:webkit:$androidxWebkitVersion"
|
|
67
69
|
testImplementation "junit:junit:$junitVersion"
|
|
68
70
|
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
69
71
|
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Add project specific ProGuard rules here.
|
|
2
|
+
# You can control the set of applied configuration files using the
|
|
3
|
+
# proguardFiles setting in build.gradle.
|
|
4
|
+
#
|
|
5
|
+
# For more details, see
|
|
6
|
+
# http://developer.android.com/guide/developing/tools/proguard.html
|
|
7
|
+
|
|
8
|
+
# Rules for Capacitor v3 plugins and annotations
|
|
9
|
+
-keep @com.getcapacitor.annotation.CapacitorPlugin public class * {
|
|
10
|
+
@com.getcapacitor.annotation.PermissionCallback <methods>;
|
|
11
|
+
@com.getcapacitor.annotation.ActivityCallback <methods>;
|
|
12
|
+
@com.getcapacitor.annotation.Permission <methods>;
|
|
13
|
+
@com.getcapacitor.PluginMethod public <methods>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
# Rules for Capacitor v2 plugins and annotations
|
|
17
|
+
# These are deprecated but can still be used with Capacitor for now
|
|
18
|
+
-keep @com.getcapacitor.NativePlugin public class * {
|
|
19
|
+
@com.getcapacitor.PluginMethod public <methods>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
# Rules for Cordova plugins
|
|
23
|
+
-keep public class * extends org.apache.cordova.* {
|
|
24
|
+
public <methods>;
|
|
25
|
+
public <fields>;
|
|
26
|
+
}
|
|
@@ -384,10 +384,18 @@ const nativeBridge = (function (exports) {
|
|
|
384
384
|
}
|
|
385
385
|
return null;
|
|
386
386
|
};
|
|
387
|
+
if (win === null || win === void 0 ? void 0 : win.androidBridge) {
|
|
388
|
+
win.androidBridge.onmessage = function (event) {
|
|
389
|
+
returnResult(JSON.parse(event.data));
|
|
390
|
+
};
|
|
391
|
+
}
|
|
387
392
|
/**
|
|
388
393
|
* Process a response from the native layer.
|
|
389
394
|
*/
|
|
390
395
|
cap.fromNative = result => {
|
|
396
|
+
returnResult(result);
|
|
397
|
+
};
|
|
398
|
+
const returnResult = (result) => {
|
|
391
399
|
var _a, _b;
|
|
392
400
|
if (cap.isLoggingEnabled && result.pluginId !== 'Console') {
|
|
393
401
|
cap.logFromNative(result);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package com.getcapacitor;
|
|
2
2
|
|
|
3
|
+
import android.annotation.SuppressLint;
|
|
3
4
|
import android.app.Activity;
|
|
4
5
|
import android.content.ActivityNotFoundException;
|
|
5
6
|
import android.content.Context;
|
|
@@ -10,6 +11,7 @@ import android.content.pm.PackageInfo;
|
|
|
10
11
|
import android.content.pm.PackageManager;
|
|
11
12
|
import android.content.res.Configuration;
|
|
12
13
|
import android.net.Uri;
|
|
14
|
+
import android.os.Build;
|
|
13
15
|
import android.os.Bundle;
|
|
14
16
|
import android.os.Handler;
|
|
15
17
|
import android.os.HandlerThread;
|
|
@@ -38,9 +40,11 @@ import java.net.URL;
|
|
|
38
40
|
import java.util.ArrayList;
|
|
39
41
|
import java.util.Arrays;
|
|
40
42
|
import java.util.HashMap;
|
|
43
|
+
import java.util.HashSet;
|
|
41
44
|
import java.util.LinkedList;
|
|
42
45
|
import java.util.List;
|
|
43
46
|
import java.util.Map;
|
|
47
|
+
import java.util.Set;
|
|
44
48
|
import org.apache.cordova.ConfigXmlParser;
|
|
45
49
|
import org.apache.cordova.CordovaPreferences;
|
|
46
50
|
import org.apache.cordova.CordovaWebView;
|
|
@@ -73,6 +77,7 @@ public class Bridge {
|
|
|
73
77
|
private static final String BUNDLE_PLUGIN_CALL_BUNDLE_KEY = "capacitorLastPluginCallBundle";
|
|
74
78
|
private static final String LAST_BINARY_VERSION_CODE = "lastBinaryVersionCode";
|
|
75
79
|
private static final String LAST_BINARY_VERSION_NAME = "lastBinaryVersionName";
|
|
80
|
+
private static final String MINIMUM_ANDROID_WEBVIEW_ERROR = "System WebView is not supported";
|
|
76
81
|
|
|
77
82
|
// The name of the directory we use to look for index.html and the rest of our web assets
|
|
78
83
|
public static final String DEFAULT_WEB_ASSET_DIR = "public";
|
|
@@ -80,6 +85,8 @@ public class Bridge {
|
|
|
80
85
|
public static final String CAPACITOR_HTTPS_SCHEME = "https";
|
|
81
86
|
public static final String CAPACITOR_FILE_START = "/_capacitor_file_";
|
|
82
87
|
public static final String CAPACITOR_CONTENT_START = "/_capacitor_content_";
|
|
88
|
+
public static final int DEFAULT_ANDROID_WEBVIEW_VERSION = 60;
|
|
89
|
+
public static final int MINIMUM_ANDROID_WEBVIEW_VERSION = 55;
|
|
83
90
|
|
|
84
91
|
// Loaded Capacitor config
|
|
85
92
|
private CapConfig config;
|
|
@@ -93,6 +100,7 @@ public class Bridge {
|
|
|
93
100
|
private String appUrl;
|
|
94
101
|
private String appUrlConfig;
|
|
95
102
|
private HostMask appAllowNavigationMask;
|
|
103
|
+
private Set<String> allowedOriginRules = new HashSet<String>();
|
|
96
104
|
// A reference to the main WebView for the app
|
|
97
105
|
private final WebView webView;
|
|
98
106
|
public final MockCordovaInterfaceImpl cordovaInterface;
|
|
@@ -182,6 +190,7 @@ public class Bridge {
|
|
|
182
190
|
|
|
183
191
|
// Initialize web view and message handler for it
|
|
184
192
|
this.initWebView();
|
|
193
|
+
this.setAllowedOriginRules();
|
|
185
194
|
this.msgHandler = new MessageHandler(this, webView, pluginManager);
|
|
186
195
|
|
|
187
196
|
// Grab any intent info that our app was launched with
|
|
@@ -194,6 +203,25 @@ public class Bridge {
|
|
|
194
203
|
this.loadWebView();
|
|
195
204
|
}
|
|
196
205
|
|
|
206
|
+
private void setAllowedOriginRules() {
|
|
207
|
+
String[] appAllowNavigationConfig = this.config.getAllowNavigation();
|
|
208
|
+
String authority = this.getHost();
|
|
209
|
+
String scheme = this.getScheme();
|
|
210
|
+
allowedOriginRules.add(scheme + "://" + authority);
|
|
211
|
+
if (this.getServerUrl() != null) {
|
|
212
|
+
allowedOriginRules.add(this.getServerUrl());
|
|
213
|
+
}
|
|
214
|
+
if (appAllowNavigationConfig != null) {
|
|
215
|
+
for (String allowNavigation : appAllowNavigationConfig) {
|
|
216
|
+
if (!allowNavigation.startsWith("http")) {
|
|
217
|
+
allowedOriginRules.add("https://" + allowNavigation);
|
|
218
|
+
} else {
|
|
219
|
+
allowedOriginRules.add(allowNavigation);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
197
225
|
public App getApp() {
|
|
198
226
|
return app;
|
|
199
227
|
}
|
|
@@ -203,14 +231,13 @@ public class Bridge {
|
|
|
203
231
|
String[] appAllowNavigationConfig = this.config.getAllowNavigation();
|
|
204
232
|
|
|
205
233
|
ArrayList<String> authorities = new ArrayList<>();
|
|
234
|
+
|
|
206
235
|
if (appAllowNavigationConfig != null) {
|
|
207
236
|
authorities.addAll(Arrays.asList(appAllowNavigationConfig));
|
|
208
237
|
}
|
|
209
238
|
this.appAllowNavigationMask = HostMask.Parser.parse(appAllowNavigationConfig);
|
|
210
|
-
|
|
211
239
|
String authority = this.getHost();
|
|
212
240
|
authorities.add(authority);
|
|
213
|
-
|
|
214
241
|
String scheme = this.getScheme();
|
|
215
242
|
|
|
216
243
|
localUrl = scheme + "://" + authority;
|
|
@@ -237,7 +264,6 @@ public class Bridge {
|
|
|
237
264
|
if (appUrlPath != null && !appUrlPath.trim().isEmpty()) {
|
|
238
265
|
appUrl += appUrlPath;
|
|
239
266
|
}
|
|
240
|
-
|
|
241
267
|
final boolean html5mode = this.config.isHTML5Mode();
|
|
242
268
|
|
|
243
269
|
// Start the local web server
|
|
@@ -257,10 +283,60 @@ public class Bridge {
|
|
|
257
283
|
setServerBasePath(path);
|
|
258
284
|
}
|
|
259
285
|
}
|
|
286
|
+
|
|
287
|
+
if (!this.isMinimumWebViewInstalled()) {
|
|
288
|
+
String errorUrl = this.getErrorUrl();
|
|
289
|
+
if (errorUrl != null) {
|
|
290
|
+
webView.loadUrl(errorUrl);
|
|
291
|
+
return;
|
|
292
|
+
} else {
|
|
293
|
+
Logger.error(MINIMUM_ANDROID_WEBVIEW_ERROR);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
260
297
|
// Get to work
|
|
261
298
|
webView.loadUrl(appUrl);
|
|
262
299
|
}
|
|
263
300
|
|
|
301
|
+
@SuppressLint("WebViewApiAvailability")
|
|
302
|
+
public boolean isMinimumWebViewInstalled() {
|
|
303
|
+
PackageManager pm = getContext().getPackageManager();
|
|
304
|
+
|
|
305
|
+
// Check getCurrentWebViewPackage() directly if above Android 8
|
|
306
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
|
307
|
+
PackageInfo info = WebView.getCurrentWebViewPackage();
|
|
308
|
+
String majorVersionStr = info.versionName.split("\\.")[0];
|
|
309
|
+
int majorVersion = Integer.parseInt(majorVersionStr);
|
|
310
|
+
return majorVersion >= config.getMinWebViewVersion();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// Otherwise manually check WebView versions
|
|
314
|
+
try {
|
|
315
|
+
String webViewPackage = "com.google.android.webview";
|
|
316
|
+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
317
|
+
webViewPackage = "com.android.chrome";
|
|
318
|
+
}
|
|
319
|
+
PackageInfo info = pm.getPackageInfo(webViewPackage, 0);
|
|
320
|
+
String majorVersionStr = info.versionName.split("\\.")[0];
|
|
321
|
+
int majorVersion = Integer.parseInt(majorVersionStr);
|
|
322
|
+
return majorVersion >= config.getMinWebViewVersion();
|
|
323
|
+
} catch (Exception ex) {
|
|
324
|
+
Logger.warn("Unable to get package info for 'com.google.android.webview'" + ex.toString());
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
try {
|
|
328
|
+
PackageInfo info = pm.getPackageInfo("com.android.webview", 0);
|
|
329
|
+
String majorVersionStr = info.versionName.split("\\.")[0];
|
|
330
|
+
int majorVersion = Integer.parseInt(majorVersionStr);
|
|
331
|
+
return majorVersion >= config.getMinWebViewVersion();
|
|
332
|
+
} catch (Exception ex) {
|
|
333
|
+
Logger.warn("Unable to get package info for 'com.android.webview'" + ex.toString());
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Could not detect any webview, return false
|
|
337
|
+
return false;
|
|
338
|
+
}
|
|
339
|
+
|
|
264
340
|
public boolean launchIntent(Uri url) {
|
|
265
341
|
/*
|
|
266
342
|
* Give plugins the chance to handle the url
|
|
@@ -408,6 +484,25 @@ public class Bridge {
|
|
|
408
484
|
return this.config.getServerUrl();
|
|
409
485
|
}
|
|
410
486
|
|
|
487
|
+
public String getErrorUrl() {
|
|
488
|
+
String errorPath = this.config.getErrorPath();
|
|
489
|
+
|
|
490
|
+
if (errorPath != null && !errorPath.trim().isEmpty()) {
|
|
491
|
+
String authority = this.getHost();
|
|
492
|
+
String scheme = this.getScheme();
|
|
493
|
+
|
|
494
|
+
String localUrl = scheme + "://" + authority;
|
|
495
|
+
|
|
496
|
+
return localUrl + "/" + errorPath;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
return null;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
public String getAppUrl() {
|
|
503
|
+
return appUrl;
|
|
504
|
+
}
|
|
505
|
+
|
|
411
506
|
public CapConfig getConfig() {
|
|
412
507
|
return this.config;
|
|
413
508
|
}
|
|
@@ -1194,6 +1289,10 @@ public class Bridge {
|
|
|
1194
1289
|
return appAllowNavigationMask;
|
|
1195
1290
|
}
|
|
1196
1291
|
|
|
1292
|
+
public Set<String> getAllowedOriginRules() {
|
|
1293
|
+
return allowedOriginRules;
|
|
1294
|
+
}
|
|
1295
|
+
|
|
1197
1296
|
public BridgeWebViewClient getWebViewClient() {
|
|
1198
1297
|
return this.webViewClient;
|
|
1199
1298
|
}
|
|
@@ -56,6 +56,11 @@ public class BridgeWebViewClient extends WebViewClient {
|
|
|
56
56
|
listener.onReceivedError(view);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
|
+
|
|
60
|
+
String errorPath = bridge.getErrorUrl();
|
|
61
|
+
if (errorPath != null && request.isForMainFrame()) {
|
|
62
|
+
view.loadUrl(errorPath);
|
|
63
|
+
}
|
|
59
64
|
}
|
|
60
65
|
|
|
61
66
|
@Override
|
|
@@ -81,5 +86,10 @@ public class BridgeWebViewClient extends WebViewClient {
|
|
|
81
86
|
listener.onReceivedHttpError(view);
|
|
82
87
|
}
|
|
83
88
|
}
|
|
89
|
+
|
|
90
|
+
String errorPath = bridge.getErrorUrl();
|
|
91
|
+
if (errorPath != null && request.isForMainFrame()) {
|
|
92
|
+
view.loadUrl(errorPath);
|
|
93
|
+
}
|
|
84
94
|
}
|
|
85
95
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
package com.getcapacitor;
|
|
2
2
|
|
|
3
3
|
import static com.getcapacitor.Bridge.CAPACITOR_HTTP_SCHEME;
|
|
4
|
+
import static com.getcapacitor.Bridge.DEFAULT_ANDROID_WEBVIEW_VERSION;
|
|
5
|
+
import static com.getcapacitor.Bridge.MINIMUM_ANDROID_WEBVIEW_VERSION;
|
|
4
6
|
import static com.getcapacitor.FileUtils.readFile;
|
|
5
7
|
|
|
6
8
|
import android.content.Context;
|
|
@@ -43,6 +45,8 @@ public class CapConfig {
|
|
|
43
45
|
private boolean webContentsDebuggingEnabled = false;
|
|
44
46
|
private boolean loggingEnabled = true;
|
|
45
47
|
private boolean initialFocus = true;
|
|
48
|
+
private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION;
|
|
49
|
+
private String errorPath;
|
|
46
50
|
|
|
47
51
|
// Embedded
|
|
48
52
|
private String startPath;
|
|
@@ -124,6 +128,8 @@ public class CapConfig {
|
|
|
124
128
|
this.webContentsDebuggingEnabled = builder.webContentsDebuggingEnabled;
|
|
125
129
|
this.loggingEnabled = builder.loggingEnabled;
|
|
126
130
|
this.initialFocus = builder.initialFocus;
|
|
131
|
+
this.minWebViewVersion = builder.minWebViewVersion;
|
|
132
|
+
this.errorPath = builder.errorPath;
|
|
127
133
|
|
|
128
134
|
// Embedded
|
|
129
135
|
this.startPath = builder.startPath;
|
|
@@ -156,6 +162,7 @@ public class CapConfig {
|
|
|
156
162
|
html5mode = JSONUtils.getBoolean(configJSON, "server.html5mode", html5mode);
|
|
157
163
|
serverUrl = JSONUtils.getString(configJSON, "server.url", null);
|
|
158
164
|
hostname = JSONUtils.getString(configJSON, "server.hostname", hostname);
|
|
165
|
+
errorPath = JSONUtils.getString(configJSON, "server.errorPath", null);
|
|
159
166
|
|
|
160
167
|
String configSchema = JSONUtils.getString(configJSON, "server.androidScheme", androidScheme);
|
|
161
168
|
if (this.validateScheme(configSchema)) {
|
|
@@ -177,6 +184,7 @@ public class CapConfig {
|
|
|
177
184
|
"android.allowMixedContent",
|
|
178
185
|
JSONUtils.getBoolean(configJSON, "allowMixedContent", allowMixedContent)
|
|
179
186
|
);
|
|
187
|
+
minWebViewVersion = JSONUtils.getInt(configJSON, "android.minWebViewVersion", DEFAULT_ANDROID_WEBVIEW_VERSION);
|
|
180
188
|
captureInput = JSONUtils.getBoolean(configJSON, "android.captureInput", captureInput);
|
|
181
189
|
webContentsDebuggingEnabled = JSONUtils.getBoolean(configJSON, "android.webContentsDebuggingEnabled", isDebug);
|
|
182
190
|
|
|
@@ -224,6 +232,10 @@ public class CapConfig {
|
|
|
224
232
|
return serverUrl;
|
|
225
233
|
}
|
|
226
234
|
|
|
235
|
+
public String getErrorPath() {
|
|
236
|
+
return errorPath;
|
|
237
|
+
}
|
|
238
|
+
|
|
227
239
|
public String getHostname() {
|
|
228
240
|
return hostname;
|
|
229
241
|
}
|
|
@@ -272,6 +284,15 @@ public class CapConfig {
|
|
|
272
284
|
return initialFocus;
|
|
273
285
|
}
|
|
274
286
|
|
|
287
|
+
public int getMinWebViewVersion() {
|
|
288
|
+
if (minWebViewVersion < MINIMUM_ANDROID_WEBVIEW_VERSION) {
|
|
289
|
+
Logger.warn("Specified minimum webview version is too low, defaulting to " + MINIMUM_ANDROID_WEBVIEW_VERSION);
|
|
290
|
+
return MINIMUM_ANDROID_WEBVIEW_VERSION;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
return minWebViewVersion;
|
|
294
|
+
}
|
|
295
|
+
|
|
275
296
|
public PluginConfig getPluginConfiguration(String pluginId) {
|
|
276
297
|
PluginConfig pluginConfig = pluginsConfiguration.get(pluginId);
|
|
277
298
|
if (pluginConfig == null) {
|
|
@@ -415,6 +436,7 @@ public class CapConfig {
|
|
|
415
436
|
// Server Config Values
|
|
416
437
|
private boolean html5mode = true;
|
|
417
438
|
private String serverUrl;
|
|
439
|
+
private String errorPath;
|
|
418
440
|
private String hostname = "localhost";
|
|
419
441
|
private String androidScheme = CAPACITOR_HTTP_SCHEME;
|
|
420
442
|
private String[] allowNavigation;
|
|
@@ -428,6 +450,7 @@ public class CapConfig {
|
|
|
428
450
|
private Boolean webContentsDebuggingEnabled = null;
|
|
429
451
|
private boolean loggingEnabled = true;
|
|
430
452
|
private boolean initialFocus = false;
|
|
453
|
+
private int minWebViewVersion = DEFAULT_ANDROID_WEBVIEW_VERSION;
|
|
431
454
|
|
|
432
455
|
// Embedded
|
|
433
456
|
private String startPath = null;
|
|
@@ -472,6 +495,11 @@ public class CapConfig {
|
|
|
472
495
|
return this;
|
|
473
496
|
}
|
|
474
497
|
|
|
498
|
+
public Builder setErrorPath(String errorPath) {
|
|
499
|
+
this.errorPath = errorPath;
|
|
500
|
+
return this;
|
|
501
|
+
}
|
|
502
|
+
|
|
475
503
|
public Builder setHostname(String hostname) {
|
|
476
504
|
this.hostname = hostname;
|
|
477
505
|
return this;
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
package com.getcapacitor;
|
|
2
2
|
|
|
3
|
+
import android.net.Uri;
|
|
3
4
|
import android.webkit.JavascriptInterface;
|
|
4
5
|
import android.webkit.WebView;
|
|
6
|
+
import androidx.webkit.JavaScriptReplyProxy;
|
|
7
|
+
import androidx.webkit.WebMessageCompat;
|
|
8
|
+
import androidx.webkit.WebViewCompat;
|
|
9
|
+
import androidx.webkit.WebViewFeature;
|
|
5
10
|
import org.apache.cordova.PluginManager;
|
|
6
11
|
|
|
7
12
|
/**
|
|
@@ -13,13 +18,31 @@ public class MessageHandler {
|
|
|
13
18
|
private Bridge bridge;
|
|
14
19
|
private WebView webView;
|
|
15
20
|
private PluginManager cordovaPluginManager;
|
|
21
|
+
private JavaScriptReplyProxy javaScriptReplyProxy;
|
|
16
22
|
|
|
17
23
|
public MessageHandler(Bridge bridge, WebView webView, PluginManager cordovaPluginManager) {
|
|
18
24
|
this.bridge = bridge;
|
|
19
25
|
this.webView = webView;
|
|
20
26
|
this.cordovaPluginManager = cordovaPluginManager;
|
|
21
27
|
|
|
22
|
-
|
|
28
|
+
WebViewCompat.WebMessageListener capListener = (view, message, sourceOrigin, isMainFrame, replyProxy) -> {
|
|
29
|
+
if (isMainFrame) {
|
|
30
|
+
postMessage(message.getData());
|
|
31
|
+
javaScriptReplyProxy = replyProxy;
|
|
32
|
+
} else {
|
|
33
|
+
Logger.warn("Plugin execution is allowed in Main Frame only");
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER)) {
|
|
38
|
+
try {
|
|
39
|
+
WebViewCompat.addWebMessageListener(webView, "androidBridge", bridge.getAllowedOriginRules(), capListener);
|
|
40
|
+
} catch (Exception ex) {
|
|
41
|
+
webView.addJavascriptInterface(this, "androidBridge");
|
|
42
|
+
}
|
|
43
|
+
} else {
|
|
44
|
+
webView.addJavascriptInterface(this, "androidBridge");
|
|
45
|
+
}
|
|
23
46
|
}
|
|
24
47
|
|
|
25
48
|
/**
|
|
@@ -100,9 +123,13 @@ public class MessageHandler {
|
|
|
100
123
|
|
|
101
124
|
boolean isValidCallbackId = !call.getCallbackId().equals(PluginCall.CALLBACK_ID_DANGLING);
|
|
102
125
|
if (isValidCallbackId) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
126
|
+
if (WebViewFeature.isFeatureSupported(WebViewFeature.WEB_MESSAGE_LISTENER) && javaScriptReplyProxy != null) {
|
|
127
|
+
javaScriptReplyProxy.postMessage(data.toString());
|
|
128
|
+
} else {
|
|
129
|
+
final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")";
|
|
130
|
+
final WebView webView = this.webView;
|
|
131
|
+
webView.post(() -> webView.evaluateJavascript(runScript, null));
|
|
132
|
+
}
|
|
106
133
|
} else {
|
|
107
134
|
bridge.getApp().fireRestoredResult(data);
|
|
108
135
|
}
|
|
@@ -96,7 +96,7 @@ public class PluginCall {
|
|
|
96
96
|
*/
|
|
97
97
|
@Deprecated
|
|
98
98
|
public void error(String msg, Exception ex) {
|
|
99
|
-
reject(msg,
|
|
99
|
+
reject(msg, ex);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
/**
|
|
@@ -114,10 +114,10 @@ public class PluginCall {
|
|
|
114
114
|
*/
|
|
115
115
|
@Deprecated
|
|
116
116
|
public void error(String msg) {
|
|
117
|
-
reject(msg
|
|
117
|
+
reject(msg);
|
|
118
118
|
}
|
|
119
119
|
|
|
120
|
-
public void reject(String msg, String code, Exception ex) {
|
|
120
|
+
public void reject(String msg, String code, Exception ex, JSObject data) {
|
|
121
121
|
PluginResult errorResult = new PluginResult();
|
|
122
122
|
|
|
123
123
|
if (ex != null) {
|
|
@@ -127,23 +127,42 @@ public class PluginCall {
|
|
|
127
127
|
try {
|
|
128
128
|
errorResult.put("message", msg);
|
|
129
129
|
errorResult.put("code", code);
|
|
130
|
+
if (null != data) {
|
|
131
|
+
errorResult.put("data", data);
|
|
132
|
+
}
|
|
130
133
|
} catch (Exception jsonEx) {
|
|
131
|
-
Logger.error(Logger.tags("Plugin"), jsonEx.getMessage(),
|
|
134
|
+
Logger.error(Logger.tags("Plugin"), jsonEx.getMessage(), jsonEx);
|
|
132
135
|
}
|
|
133
136
|
|
|
134
137
|
this.msgHandler.sendResponseMessage(this, null, errorResult);
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
public void reject(String msg, Exception ex, JSObject data) {
|
|
141
|
+
reject(msg, null, ex, data);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public void reject(String msg, String code, JSObject data) {
|
|
145
|
+
reject(msg, code, null, data);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public void reject(String msg, String code, Exception ex) {
|
|
149
|
+
reject(msg, code, ex, null);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public void reject(String msg, JSObject data) {
|
|
153
|
+
reject(msg, null, null, data);
|
|
154
|
+
}
|
|
155
|
+
|
|
137
156
|
public void reject(String msg, Exception ex) {
|
|
138
|
-
reject(msg, null, ex);
|
|
157
|
+
reject(msg, null, ex, null);
|
|
139
158
|
}
|
|
140
159
|
|
|
141
160
|
public void reject(String msg, String code) {
|
|
142
|
-
reject(msg, code, null);
|
|
161
|
+
reject(msg, code, null, null);
|
|
143
162
|
}
|
|
144
163
|
|
|
145
164
|
public void reject(String msg) {
|
|
146
|
-
reject(msg, null, null);
|
|
165
|
+
reject(msg, null, null, null);
|
|
147
166
|
}
|
|
148
167
|
|
|
149
168
|
public void unimplemented() {
|
|
@@ -151,7 +170,7 @@ public class PluginCall {
|
|
|
151
170
|
}
|
|
152
171
|
|
|
153
172
|
public void unimplemented(String msg) {
|
|
154
|
-
reject(msg, "UNIMPLEMENTED", null);
|
|
173
|
+
reject(msg, "UNIMPLEMENTED", null, null);
|
|
155
174
|
}
|
|
156
175
|
|
|
157
176
|
public void unavailable() {
|
|
@@ -159,7 +178,7 @@ public class PluginCall {
|
|
|
159
178
|
}
|
|
160
179
|
|
|
161
180
|
public void unavailable(String msg) {
|
|
162
|
-
reject(msg, "UNAVAILABLE", null);
|
|
181
|
+
reject(msg, "UNAVAILABLE", null, null);
|
|
163
182
|
}
|
|
164
183
|
|
|
165
184
|
public String getPluginId() {
|
|
@@ -172,7 +172,7 @@ public class WebViewLocalServer {
|
|
|
172
172
|
return null;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
if (isLocalFile(loadingUrl) || isMainUrl(loadingUrl) || !isAllowedUrl(loadingUrl)) {
|
|
175
|
+
if (isLocalFile(loadingUrl) || isMainUrl(loadingUrl) || !isAllowedUrl(loadingUrl) || isErrorUrl(loadingUrl)) {
|
|
176
176
|
Logger.debug("Handling local request: " + request.getUrl().toString());
|
|
177
177
|
return handleLocalRequest(request, handler);
|
|
178
178
|
} else {
|
|
@@ -185,6 +185,11 @@ public class WebViewLocalServer {
|
|
|
185
185
|
return path.startsWith(capacitorContentStart) || path.startsWith(capacitorFileStart);
|
|
186
186
|
}
|
|
187
187
|
|
|
188
|
+
private boolean isErrorUrl(Uri uri) {
|
|
189
|
+
String url = uri.toString();
|
|
190
|
+
return url.equals(bridge.getErrorUrl());
|
|
191
|
+
}
|
|
192
|
+
|
|
188
193
|
private boolean isMainUrl(Uri loadingUrl) {
|
|
189
194
|
return (bridge.getServerUrl() == null && loadingUrl.getHost().equalsIgnoreCase(bridge.getHost()));
|
|
190
195
|
}
|
|
@@ -226,7 +231,7 @@ public class WebViewLocalServer {
|
|
|
226
231
|
);
|
|
227
232
|
}
|
|
228
233
|
|
|
229
|
-
if (isLocalFile(request.getUrl())) {
|
|
234
|
+
if (isLocalFile(request.getUrl()) || isErrorUrl(request.getUrl())) {
|
|
230
235
|
InputStream responseStream = new LollipopLazyInputStream(handler, request);
|
|
231
236
|
String mimeType = getMimeType(request.getUrl().getPath(), responseStream);
|
|
232
237
|
int statusCode = getStatusCode(responseStream, handler.getStatusCode());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capacitor/android",
|
|
3
|
-
"version": "4.0.0
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Capacitor: Cross-platform apps with JavaScript and the web",
|
|
5
5
|
"homepage": "https://capacitorjs.com",
|
|
6
6
|
"author": "Ionic Team <hi@ionic.io> (https://ionic.io)",
|
|
@@ -16,16 +16,17 @@
|
|
|
16
16
|
"capacitor/build.gradle",
|
|
17
17
|
"capacitor/lint-baseline.xml",
|
|
18
18
|
"capacitor/lint.xml",
|
|
19
|
+
"capacitor/proguard-rules.pro",
|
|
19
20
|
"capacitor/src/main/"
|
|
20
21
|
],
|
|
21
22
|
"scripts": {
|
|
22
23
|
"verify": "./gradlew clean lint build test -b capacitor/build.gradle"
|
|
23
24
|
},
|
|
24
25
|
"peerDependencies": {
|
|
25
|
-
"@capacitor/core": "
|
|
26
|
+
"@capacitor/core": "next"
|
|
26
27
|
},
|
|
27
28
|
"publishConfig": {
|
|
28
29
|
"access": "public"
|
|
29
30
|
},
|
|
30
|
-
"gitHead": "
|
|
31
|
+
"gitHead": "434b1a0ff32f513973ef35258032a4df0cb331c1"
|
|
31
32
|
}
|