@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 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
@@ -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
- webView.addJavascriptInterface(this, "androidBridge");
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
- final String runScript = "window.Capacitor.fromNative(" + data.toString() + ")";
104
- final WebView webView = this.webView;
105
- webView.post(() -> webView.evaluateJavascript(runScript, null));
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, null, ex);
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, null, null);
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(), null);
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-nightly-c3aa3d6c.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": "^4.0.0-beta.1"
26
+ "@capacitor/core": "next"
26
27
  },
27
28
  "publishConfig": {
28
29
  "access": "public"
29
30
  },
30
- "gitHead": "c3aa3d6cbc6dc17d4c580038047ed3a4d8e168a2"
31
+ "gitHead": "434b1a0ff32f513973ef35258032a4df0cb331c1"
31
32
  }