@capacitor/android 4.0.0-alpha.1 → 4.0.0-beta.1

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.
Files changed (23) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/capacitor/build.gradle +7 -7
  3. package/capacitor/src/main/java/com/getcapacitor/AppUUID.java +65 -0
  4. package/capacitor/src/main/java/com/getcapacitor/Bridge.java +45 -10
  5. package/capacitor/src/main/java/com/getcapacitor/BridgeActivity.java +11 -54
  6. package/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java +4 -5
  7. package/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +1 -0
  8. package/capacitor/src/main/java/com/getcapacitor/CapConfig.java +37 -2
  9. package/capacitor/src/main/java/com/getcapacitor/CapacitorWebView.java +1 -0
  10. package/capacitor/src/main/java/com/getcapacitor/FileUtils.java +6 -1
  11. package/capacitor/src/main/java/com/getcapacitor/JSExport.java +1 -1
  12. package/capacitor/src/main/java/com/getcapacitor/Plugin.java +16 -10
  13. package/capacitor/src/main/java/com/getcapacitor/PluginHandle.java +4 -0
  14. package/capacitor/src/main/java/com/getcapacitor/ProcessedRoute.java +28 -0
  15. package/capacitor/src/main/java/com/getcapacitor/RouteProcessor.java +8 -0
  16. package/capacitor/src/main/java/com/getcapacitor/WebViewLocalServer.java +20 -3
  17. package/capacitor/src/main/java/com/getcapacitor/cordova/CapacitorCordovaCookieManager.java +1 -2
  18. package/capacitor/src/main/java/com/getcapacitor/cordova/MockCordovaWebViewImpl.java +5 -0
  19. package/capacitor/src/main/res/values/colors.xml +4 -4
  20. package/capacitor/src/main/res/values/strings.xml +0 -5
  21. package/capacitor/src/main/res/values/styles.xml +0 -9
  22. package/package.json +3 -3
  23. package/capacitor/src/main/res/drawable/ic_transparent.xml +0 -12
package/CHANGELOG.md CHANGED
@@ -3,6 +3,84 @@
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-beta.1](https://github.com/ionic-team/capacitor/compare/4.0.0-beta.0...4.0.0-beta.1) (2022-06-27)
7
+
8
+ **Note:** Version bump only for package @capacitor/android
9
+
10
+
11
+
12
+
13
+
14
+ # [4.0.0-beta.0](https://github.com/ionic-team/capacitor/compare/3.6.0...4.0.0-beta.0) (2022-06-17)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * **android:** make removeAllListeners return a promise ([#5527](https://github.com/ionic-team/capacitor/issues/5527)) ([6f4d858](https://github.com/ionic-team/capacitor/commit/6f4d858ea879d97109c0c7da2d664d04806adc2a))
20
+ * **android:** prevent app from loading if server.url is invalid ([d4a0dea](https://github.com/ionic-team/capacitor/commit/d4a0deaa37eda4476f0be030e266c2c1260fc6e8))
21
+
22
+
23
+ ### Features
24
+
25
+ * **android:** don't allow server.androidScheme to be set to schemes handled by WebView ([01285ba](https://github.com/ionic-team/capacitor/commit/01285ba253d602b08a41240ad2ccf370730d51a3))
26
+ * **android:** set default targetSDK to 31 ([#5442](https://github.com/ionic-team/capacitor/issues/5442)) ([4442459](https://github.com/ionic-team/capacitor/commit/4442459b24cdbac25cb1e4de11583d22c21452b3))
27
+ * **android:** set default targetSDK to 32 ([#5611](https://github.com/ionic-team/capacitor/issues/5611)) ([416b966](https://github.com/ionic-team/capacitor/commit/416b9662fbf6233d23216c0c0441862603c3a723))
28
+ * **android:** Upgrade gradle to 7.4 ([#5445](https://github.com/ionic-team/capacitor/issues/5445)) ([28eaf18](https://github.com/ionic-team/capacitor/commit/28eaf1851fa7a912917dbb40c68fb4dd583d08ad))
29
+ * **android:** Use java 11 ([#5552](https://github.com/ionic-team/capacitor/issues/5552)) ([e47959f](https://github.com/ionic-team/capacitor/commit/e47959fcbd6a89b97b1275a5814fdb4e7ce30672))
30
+
31
+
32
+
33
+
34
+
35
+ # [3.6.0](https://github.com/ionic-team/capacitor/compare/3.5.1...3.6.0) (2022-06-17)
36
+
37
+
38
+ ### Features
39
+
40
+ * **android:** update support for Portals for Capacitor to include Live Updates ([#5660](https://github.com/ionic-team/capacitor/issues/5660)) ([62f0a5e](https://github.com/ionic-team/capacitor/commit/62f0a5eaa40776aad79dbf8f8c0900037d3cc97e))
41
+ * **iOS, Android:** add AppUUID Lib for plugins ([#5690](https://github.com/ionic-team/capacitor/issues/5690)) ([05e76cf](https://github.com/ionic-team/capacitor/commit/05e76cf526a44e07fa75f9482fa2223a13918638))
42
+
43
+
44
+
45
+ # [4.0.0-alpha.2](https://github.com/ionic-team/capacitor/compare/3.4.1...4.0.0-alpha.2) (2022-05-12)
46
+
47
+
48
+ ### Bug Fixes
49
+
50
+ * **android:** make removeAllListeners return a promise ([#5527](https://github.com/ionic-team/capacitor/issues/5527)) ([6f4d858](https://github.com/ionic-team/capacitor/commit/6f4d858ea879d97109c0c7da2d664d04806adc2a))
51
+ * **android:** prevent app from loading if server.url is invalid ([d4a0dea](https://github.com/ionic-team/capacitor/commit/d4a0deaa37eda4476f0be030e266c2c1260fc6e8))
52
+
53
+
54
+ ### Features
55
+
56
+ * **android:** don't allow server.androidScheme to be set to schemes handled by WebView ([01285ba](https://github.com/ionic-team/capacitor/commit/01285ba253d602b08a41240ad2ccf370730d51a3))
57
+ * **android:** set default targetSDK to 31 ([#5442](https://github.com/ionic-team/capacitor/issues/5442)) ([4442459](https://github.com/ionic-team/capacitor/commit/4442459b24cdbac25cb1e4de11583d22c21452b3))
58
+ * **android:** Upgrade gradle to 7.4 ([#5445](https://github.com/ionic-team/capacitor/issues/5445)) ([28eaf18](https://github.com/ionic-team/capacitor/commit/28eaf1851fa7a912917dbb40c68fb4dd583d08ad))
59
+ * **android:** Use java 11 ([#5552](https://github.com/ionic-team/capacitor/issues/5552)) ([e47959f](https://github.com/ionic-team/capacitor/commit/e47959fcbd6a89b97b1275a5814fdb4e7ce30672))
60
+
61
+
62
+
63
+
64
+ ## [3.5.1](https://github.com/ionic-team/capacitor/compare/3.5.0...3.5.1) (2022-05-04)
65
+
66
+
67
+ ### Bug Fixes
68
+
69
+ * **android:** move initialFocus on webview into config ([#5579](https://github.com/ionic-team/capacitor/issues/5579)) ([8b4e861](https://github.com/ionic-team/capacitor/commit/8b4e861514b0fbe08e9296f49c280234f54742e1))
70
+
71
+
72
+
73
+
74
+
75
+ # [3.5.0](https://github.com/ionic-team/capacitor/compare/3.4.3...3.5.0) (2022-04-22)
76
+
77
+
78
+ ### Features
79
+
80
+ * **android:** Add overridable routing for WebViewLocalServer ([#5553](https://github.com/ionic-team/capacitor/issues/5553)) ([3bb288e](https://github.com/ionic-team/capacitor/commit/3bb288e848c5c0e49c1e58c0782e0b1ffd7b1f31))
81
+
82
+
83
+
6
84
  # [4.0.0-alpha.1](https://github.com/ionic-team/capacitor/compare/3.4.1...4.0.0-alpha.1) (2022-03-25)
7
85
 
8
86
 
@@ -13,6 +91,18 @@ See [Conventional Commits](https://conventionalcommits.org) for commit guideline
13
91
 
14
92
 
15
93
 
94
+ ## [3.4.3](https://github.com/ionic-team/capacitor/compare/3.4.2...3.4.3) (2022-03-04)
95
+
96
+ **Note:** Version bump only for package @capacitor/android
97
+
98
+
99
+
100
+
101
+
102
+ ## [3.4.2](https://github.com/ionic-team/capacitor/compare/3.4.1...3.4.2) (2022-03-03)
103
+
104
+ **Note:** Version bump only for package @capacitor/android
105
+
16
106
 
17
107
 
18
108
  ## [3.4.1](https://github.com/ionic-team/capacitor/compare/3.4.0...3.4.1) (2022-02-09)
@@ -1,8 +1,8 @@
1
1
  ext {
2
2
  androidxActivityVersion = project.hasProperty('androidxActivityVersion') ? rootProject.ext.androidxActivityVersion : '1.4.0'
3
- androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.1'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.4.2'
4
4
  androidxCoordinatorLayoutVersion = project.hasProperty('androidxCoordinatorLayoutVersion') ? rootProject.ext.androidxCoordinatorLayoutVersion : '1.2.0'
5
- androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.7.0'
5
+ androidxCoreVersion = project.hasProperty('androidxCoreVersion') ? rootProject.ext.androidxCoreVersion : '1.8.0'
6
6
  androidxFragmentVersion = project.hasProperty('androidxFragmentVersion') ? rootProject.ext.androidxFragmentVersion : '1.4.1'
7
7
  junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
8
8
  androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.3'
@@ -17,7 +17,7 @@ buildscript {
17
17
  mavenCentral()
18
18
  }
19
19
  dependencies {
20
- classpath 'com.android.tools.build:gradle:7.1.1'
20
+ classpath 'com.android.tools.build:gradle:7.2.1'
21
21
  }
22
22
  }
23
23
 
@@ -26,10 +26,10 @@ tasks.withType(Javadoc).all { enabled = false }
26
26
  apply plugin: 'com.android.library'
27
27
 
28
28
  android {
29
- compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 31
29
+ compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 32
30
30
  defaultConfig {
31
31
  minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 22
32
- targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 31
32
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 32
33
33
  versionCode 1
34
34
  versionName "1.0"
35
35
  consumerProguardFiles 'proguard-rules.pro'
@@ -47,8 +47,8 @@ android {
47
47
  warningsAsErrors true
48
48
  }
49
49
  compileOptions {
50
- sourceCompatibility JavaVersion.VERSION_1_8
51
- targetCompatibility JavaVersion.VERSION_1_8
50
+ sourceCompatibility JavaVersion.VERSION_11
51
+ targetCompatibility JavaVersion.VERSION_11
52
52
  }
53
53
  }
54
54
 
@@ -0,0 +1,65 @@
1
+ package com.getcapacitor;
2
+
3
+ import android.content.Context;
4
+ import android.content.SharedPreferences;
5
+ import androidx.appcompat.app.AppCompatActivity;
6
+ import java.nio.charset.StandardCharsets;
7
+ import java.security.MessageDigest;
8
+ import java.security.NoSuchAlgorithmException;
9
+ import java.util.Objects;
10
+ import java.util.UUID;
11
+
12
+ public final class AppUUID {
13
+
14
+ private static final String KEY = "CapacitorAppUUID";
15
+
16
+ public static String getAppUUID(AppCompatActivity activity) throws Exception {
17
+ assertAppUUID(activity);
18
+ return readUUID(activity);
19
+ }
20
+
21
+ public static void regenerateAppUUID(AppCompatActivity activity) throws Exception {
22
+ try {
23
+ String uuid = generateUUID();
24
+ writeUUID(activity, uuid);
25
+ } catch (NoSuchAlgorithmException ex) {
26
+ throw new Exception("Capacitor App UUID could not be generated.");
27
+ }
28
+ }
29
+
30
+ private static void assertAppUUID(AppCompatActivity activity) throws Exception {
31
+ String uuid = readUUID(activity);
32
+ if (uuid.equals("")) {
33
+ regenerateAppUUID(activity);
34
+ }
35
+ }
36
+
37
+ private static String generateUUID() throws NoSuchAlgorithmException {
38
+ MessageDigest salt = MessageDigest.getInstance("SHA-256");
39
+ salt.update(UUID.randomUUID().toString().getBytes(StandardCharsets.UTF_8));
40
+ return bytesToHex(salt.digest());
41
+ }
42
+
43
+ private static String readUUID(AppCompatActivity activity) {
44
+ SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
45
+ return sharedPref.getString(KEY, "");
46
+ }
47
+
48
+ private static void writeUUID(AppCompatActivity activity, String uuid) {
49
+ SharedPreferences sharedPref = activity.getPreferences(Context.MODE_PRIVATE);
50
+ SharedPreferences.Editor editor = sharedPref.edit();
51
+ editor.putString(KEY, uuid);
52
+ editor.apply();
53
+ }
54
+
55
+ private static String bytesToHex(byte[] bytes) {
56
+ byte[] HEX_ARRAY = "0123456789ABCDEF".getBytes(StandardCharsets.US_ASCII);
57
+ byte[] hexChars = new byte[bytes.length * 2];
58
+ for (int j = 0; j < bytes.length; j++) {
59
+ int v = bytes[j] & 0xFF;
60
+ hexChars[j * 2] = HEX_ARRAY[v >>> 4];
61
+ hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F];
62
+ }
63
+ return new String(hexChars, StandardCharsets.UTF_8);
64
+ }
65
+ }
@@ -22,6 +22,7 @@ import androidx.activity.result.contract.ActivityResultContract;
22
22
  import androidx.annotation.NonNull;
23
23
  import androidx.appcompat.app.AppCompatActivity;
24
24
  import androidx.core.app.ActivityCompat;
25
+ import androidx.core.content.pm.PackageInfoCompat;
25
26
  import androidx.fragment.app.Fragment;
26
27
  import com.getcapacitor.android.R;
27
28
  import com.getcapacitor.annotation.CapacitorPlugin;
@@ -130,6 +131,9 @@ public class Bridge {
130
131
  // A list of listeners that trigger when webView events occur
131
132
  private List<WebViewListener> webViewListeners = new ArrayList<>();
132
133
 
134
+ // An interface to manipulate route resolving
135
+ private RouteProcessor routeProcessor;
136
+
133
137
  /**
134
138
  * Create the Bridge with a reference to the main {@link Activity} for the
135
139
  * app, and a reference to the {@link WebView} our app will use.
@@ -215,7 +219,10 @@ public class Bridge {
215
219
  try {
216
220
  URL appUrlObject = new URL(appUrlConfig);
217
221
  authorities.add(appUrlObject.getAuthority());
218
- } catch (Exception ex) {}
222
+ } catch (Exception ex) {
223
+ Logger.error("Provided server url is invalid: " + ex.getMessage());
224
+ return;
225
+ }
219
226
  localUrl = appUrlConfig;
220
227
  appUrl = appUrlConfig;
221
228
  } else {
@@ -290,7 +297,7 @@ public class Bridge {
290
297
 
291
298
  try {
292
299
  PackageInfo pInfo = getContext().getPackageManager().getPackageInfo(getContext().getPackageName(), 0);
293
- versionCode = Integer.toString(pInfo.versionCode);
300
+ versionCode = Integer.toString((int) PackageInfoCompat.getLongVersionCode(pInfo));
294
301
  versionName = pInfo.versionName;
295
302
  } catch (Exception ex) {
296
303
  Logger.error("Unable to get package info", ex);
@@ -418,7 +425,6 @@ public class Bridge {
418
425
  settings.setDomStorageEnabled(true);
419
426
  settings.setGeolocationEnabled(true);
420
427
  settings.setDatabaseEnabled(true);
421
- settings.setAppCacheEnabled(true);
422
428
  settings.setMediaPlaybackRequiresUserGesture(false);
423
429
  settings.setJavaScriptCanOpenWindowsAutomatically(true);
424
430
  if (this.config.isMixedContentAllowed()) {
@@ -444,7 +450,10 @@ public class Bridge {
444
450
  Logger.debug("WebView background color not applied");
445
451
  }
446
452
 
447
- webView.requestFocusFromTouch();
453
+ if (config.isInitialFocus()) {
454
+ webView.requestFocusFromTouch();
455
+ }
456
+
448
457
  WebView.setWebContentsDebuggingEnabled(this.config.isWebContentsDebuggingEnabled());
449
458
  }
450
459
 
@@ -469,6 +478,17 @@ public class Bridge {
469
478
  }
470
479
  }
471
480
 
481
+ @SuppressWarnings("deprecation")
482
+ private String getLegacyPluginName(Class<? extends Plugin> pluginClass) {
483
+ NativePlugin legacyPluginAnnotation = pluginClass.getAnnotation(NativePlugin.class);
484
+ if (legacyPluginAnnotation == null) {
485
+ Logger.error("Plugin doesn't have the @CapacitorPlugin annotation. Please add it");
486
+ return null;
487
+ }
488
+
489
+ return legacyPluginAnnotation.name();
490
+ }
491
+
472
492
  /**
473
493
  * Register a plugin class
474
494
  * @param pluginClass a class inheriting from Plugin
@@ -478,14 +498,10 @@ public class Bridge {
478
498
 
479
499
  CapacitorPlugin pluginAnnotation = pluginClass.getAnnotation(CapacitorPlugin.class);
480
500
  if (pluginAnnotation == null) {
481
- NativePlugin legacyPluginAnnotation = pluginClass.getAnnotation(NativePlugin.class);
482
-
483
- if (legacyPluginAnnotation == null) {
484
- Logger.error("Plugin doesn't have the @CapacitorPlugin annotation. Please add it");
501
+ pluginName = this.getLegacyPluginName(pluginClass);
502
+ if (pluginName == null) {
485
503
  return;
486
504
  }
487
-
488
- pluginName = legacyPluginAnnotation.name();
489
505
  } else {
490
506
  pluginName = pluginAnnotation.name();
491
507
  }
@@ -524,6 +540,7 @@ public class Bridge {
524
540
  * @return
525
541
  */
526
542
  @Deprecated
543
+ @SuppressWarnings("deprecation")
527
544
  public PluginHandle getPluginWithRequestCode(int requestCode) {
528
545
  for (PluginHandle handle : this.plugins.values()) {
529
546
  int[] requestCodes;
@@ -839,6 +856,7 @@ public class Bridge {
839
856
  }
840
857
 
841
858
  @Deprecated
859
+ @SuppressWarnings("deprecation")
842
860
  public void startActivityForPluginWithResult(PluginCall call, Intent intent, int requestCode) {
843
861
  Logger.debug("Starting activity for result");
844
862
 
@@ -856,6 +874,7 @@ public class Bridge {
856
874
  * @param grantResults the set of granted/denied permissions
857
875
  * @return true if permission code was handled by a plugin explicitly, false if not
858
876
  */
877
+ @SuppressWarnings("deprecation")
859
878
  boolean onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
860
879
  PluginHandle plugin = getPluginWithRequestCode(requestCode);
861
880
 
@@ -995,6 +1014,7 @@ public class Bridge {
995
1014
  * @param resultCode
996
1015
  * @param data
997
1016
  */
1017
+ @SuppressWarnings("deprecation")
998
1018
  boolean onActivityResult(int requestCode, int resultCode, Intent data) {
999
1019
  PluginHandle plugin = getPluginWithRequestCode(requestCode);
1000
1020
 
@@ -1190,6 +1210,14 @@ public class Bridge {
1190
1210
  this.webViewListeners = webViewListeners;
1191
1211
  }
1192
1212
 
1213
+ RouteProcessor getRouteProcessor() {
1214
+ return routeProcessor;
1215
+ }
1216
+
1217
+ void setRouteProcessor(RouteProcessor routeProcessor) {
1218
+ this.routeProcessor = routeProcessor;
1219
+ }
1220
+
1193
1221
  /**
1194
1222
  * Add a listener that the WebViewClient can trigger on certain events.
1195
1223
  * @param webViewListener A {@link WebViewListener} to add.
@@ -1213,6 +1241,7 @@ public class Bridge {
1213
1241
  private List<Class<? extends Plugin>> plugins = new ArrayList<>();
1214
1242
  private AppCompatActivity activity;
1215
1243
  private Fragment fragment;
1244
+ private RouteProcessor routeProcessor;
1216
1245
  private final List<WebViewListener> webViewListeners = new ArrayList<>();
1217
1246
 
1218
1247
  public Builder(AppCompatActivity activity) {
@@ -1265,6 +1294,11 @@ public class Bridge {
1265
1294
  return this;
1266
1295
  }
1267
1296
 
1297
+ public Builder setRouteProcessor(RouteProcessor routeProcessor) {
1298
+ this.routeProcessor = routeProcessor;
1299
+ return this;
1300
+ }
1301
+
1268
1302
  public Bridge create() {
1269
1303
  // Cordova initialization
1270
1304
  ConfigXmlParser parser = new ConfigXmlParser();
@@ -1288,6 +1322,7 @@ public class Bridge {
1288
1322
  Bridge bridge = new Bridge(activity, fragment, webView, plugins, cordovaInterface, pluginManager, preferences, config);
1289
1323
  bridge.setCordovaWebView(mockWebView);
1290
1324
  bridge.setWebViewListeners(webViewListeners);
1325
+ bridge.setRouteProcessor(routeProcessor);
1291
1326
 
1292
1327
  if (instanceState != null) {
1293
1328
  bridge.restoreInstanceState(instanceState);
@@ -12,11 +12,11 @@ public class BridgeActivity extends AppCompatActivity {
12
12
 
13
13
  protected Bridge bridge;
14
14
  protected boolean keepRunning = true;
15
- private CapConfig config;
15
+ protected CapConfig config;
16
16
 
17
- private int activityDepth = 0;
18
- private List<Class<? extends Plugin>> initialPlugins = new ArrayList<>();
19
- private final Bridge.Builder bridgeBuilder = new Bridge.Builder(this);
17
+ protected int activityDepth = 0;
18
+ protected List<Class<? extends Plugin>> initialPlugins = new ArrayList<>();
19
+ protected final Bridge.Builder bridgeBuilder = new Bridge.Builder(this);
20
20
 
21
21
  @Override
22
22
  protected void onCreate(Bundle savedInstanceState) {
@@ -26,47 +26,18 @@ public class BridgeActivity extends AppCompatActivity {
26
26
  setTheme(getResources().getIdentifier("AppTheme_NoActionBar", "style", getPackageName()));
27
27
  setTheme(R.style.AppTheme_NoActionBar);
28
28
  setContentView(R.layout.bridge_layout_main);
29
- }
30
-
31
- /**
32
- * Initializes the Capacitor Bridge with the Activity.
33
- * @deprecated It is preferred not to call this method. If it is not called, the bridge is
34
- * initialized automatically. If you need to add additional plugins during initialization,
35
- * use {@link #registerPlugin(Class)} or {@link #registerPlugins(List)}.
36
- *
37
- * @param plugins A list of plugins to initialize with Capacitor
38
- */
39
- @Deprecated
40
- protected void init(Bundle savedInstanceState, List<Class<? extends Plugin>> plugins) {
41
- this.init(savedInstanceState, plugins, null);
42
- }
43
-
44
- /**
45
- * Initializes the Capacitor Bridge with the Activity.
46
- * @deprecated It is preferred not to call this method. If it is not called, the bridge is
47
- * initialized automatically. If you need to add additional plugins during initialization,
48
- * use {@link #registerPlugin(Class)} or {@link #registerPlugins(List)}.
49
- *
50
- * @param plugins A list of plugins to initialize with Capacitor
51
- * @param config An instance of a Capacitor Configuration to use. If null, will load from file
52
- */
53
- @Deprecated
54
- protected void init(Bundle savedInstanceState, List<Class<? extends Plugin>> plugins, CapConfig config) {
55
- this.initialPlugins = plugins;
56
- this.config = config;
29
+ PluginManager loader = new PluginManager(getAssets());
57
30
 
58
- this.load();
59
- }
31
+ try {
32
+ bridgeBuilder.addPlugins(loader.loadPluginClasses());
33
+ } catch (PluginLoadException ex) {
34
+ Logger.error("Error loading plugins.", ex);
35
+ }
60
36
 
61
- /**
62
- * @deprecated This method should not be called manually.
63
- */
64
- @Deprecated
65
- protected void load(Bundle savedInstanceState) {
66
37
  this.load();
67
38
  }
68
39
 
69
- private void load() {
40
+ protected void load() {
70
41
  Logger.debug("Starting BridgeActivity");
71
42
 
72
43
  bridge = bridgeBuilder.addPlugins(initialPlugins).setConfig(config).create();
@@ -96,20 +67,6 @@ public class BridgeActivity extends AppCompatActivity {
96
67
  @Override
97
68
  public void onStart() {
98
69
  super.onStart();
99
-
100
- // Preferred behavior: init() was not called, so we construct the bridge with auto-loaded plugins.
101
- if (bridge == null) {
102
- PluginManager loader = new PluginManager(getAssets());
103
-
104
- try {
105
- bridgeBuilder.addPlugins(loader.loadPluginClasses());
106
- } catch (PluginLoadException ex) {
107
- Logger.error("Error loading plugins.", ex);
108
- }
109
-
110
- this.load();
111
- }
112
-
113
70
  activityDepth++;
114
71
  this.bridge.onStart();
115
72
  Logger.debug("App started");
@@ -147,7 +147,6 @@ public class BridgeWebChromeClient extends WebChromeClient {
147
147
  AlertDialog.Builder builder = new AlertDialog.Builder(view.getContext());
148
148
  builder
149
149
  .setMessage(message)
150
- .setTitle("Alert")
151
150
  .setPositiveButton(
152
151
  "OK",
153
152
  (dialog, buttonIndex) -> {
@@ -187,7 +186,6 @@ public class BridgeWebChromeClient extends WebChromeClient {
187
186
 
188
187
  builder
189
188
  .setMessage(message)
190
- .setTitle("Confirm")
191
189
  .setPositiveButton(
192
190
  "OK",
193
191
  (dialog, buttonIndex) -> {
@@ -236,7 +234,6 @@ public class BridgeWebChromeClient extends WebChromeClient {
236
234
 
237
235
  builder
238
236
  .setMessage(message)
239
- .setTitle("Prompt")
240
237
  .setView(input)
241
238
  .setPositiveButton(
242
239
  "OK",
@@ -286,8 +283,10 @@ public class BridgeWebChromeClient extends WebChromeClient {
286
283
  callback.invoke(origin, true, false);
287
284
  } else {
288
285
  final String[] coarsePermission = { Manifest.permission.ACCESS_COARSE_LOCATION };
289
- // TODO replace with Build.VERSION_CODES.S once we target SDK 31
290
- if (Build.VERSION.SDK_INT >= 31 && PermissionHelper.hasPermissions(bridge.getContext(), coarsePermission)) {
286
+ if (
287
+ Build.VERSION.SDK_INT >= Build.VERSION_CODES.S &&
288
+ PermissionHelper.hasPermissions(bridge.getContext(), coarsePermission)
289
+ ) {
291
290
  callback.invoke(origin, true, false);
292
291
  } else {
293
292
  callback.invoke(origin, false, false);
@@ -28,6 +28,7 @@ public class BridgeWebViewClient extends WebViewClient {
28
28
  return bridge.launchIntent(url);
29
29
  }
30
30
 
31
+ @Deprecated
31
32
  @Override
32
33
  public boolean shouldOverrideUrlLoading(WebView view, String url) {
33
34
  return bridge.launchIntent(Uri.parse(url));
@@ -9,8 +9,10 @@ import android.content.res.AssetManager;
9
9
  import androidx.annotation.Nullable;
10
10
  import com.getcapacitor.util.JSONUtils;
11
11
  import java.io.IOException;
12
+ import java.util.Arrays;
12
13
  import java.util.HashMap;
13
14
  import java.util.Iterator;
15
+ import java.util.List;
14
16
  import java.util.Locale;
15
17
  import java.util.Map;
16
18
  import org.json.JSONException;
@@ -40,6 +42,7 @@ public class CapConfig {
40
42
  private boolean captureInput = false;
41
43
  private boolean webContentsDebuggingEnabled = false;
42
44
  private boolean loggingEnabled = true;
45
+ private boolean initialFocus = true;
43
46
 
44
47
  // Embedded
45
48
  private String startPath;
@@ -105,7 +108,11 @@ public class CapConfig {
105
108
  this.html5mode = builder.html5mode;
106
109
  this.serverUrl = builder.serverUrl;
107
110
  this.hostname = builder.hostname;
108
- this.androidScheme = builder.androidScheme;
111
+
112
+ if (this.validateScheme(builder.androidScheme)) {
113
+ this.androidScheme = builder.androidScheme;
114
+ }
115
+
109
116
  this.allowNavigation = builder.allowNavigation;
110
117
 
111
118
  // Android Config
@@ -116,6 +123,7 @@ public class CapConfig {
116
123
  this.captureInput = builder.captureInput;
117
124
  this.webContentsDebuggingEnabled = builder.webContentsDebuggingEnabled;
118
125
  this.loggingEnabled = builder.loggingEnabled;
126
+ this.initialFocus = builder.initialFocus;
119
127
 
120
128
  // Embedded
121
129
  this.startPath = builder.startPath;
@@ -148,7 +156,12 @@ public class CapConfig {
148
156
  html5mode = JSONUtils.getBoolean(configJSON, "server.html5mode", html5mode);
149
157
  serverUrl = JSONUtils.getString(configJSON, "server.url", null);
150
158
  hostname = JSONUtils.getString(configJSON, "server.hostname", hostname);
151
- androidScheme = JSONUtils.getString(configJSON, "server.androidScheme", androidScheme);
159
+
160
+ String configSchema = JSONUtils.getString(configJSON, "server.androidScheme", androidScheme);
161
+ if (this.validateScheme(configSchema)) {
162
+ androidScheme = configSchema;
163
+ }
164
+
152
165
  allowNavigation = JSONUtils.getArray(configJSON, "server.allowNavigation", null);
153
166
 
154
167
  // Android
@@ -187,10 +200,22 @@ public class CapConfig {
187
200
  loggingEnabled = isDebug;
188
201
  }
189
202
 
203
+ initialFocus = JSONUtils.getBoolean(configJSON, "android.initialFocus", initialFocus);
204
+
190
205
  // Plugins
191
206
  pluginsConfiguration = deserializePluginsConfig(JSONUtils.getObject(configJSON, "plugins"));
192
207
  }
193
208
 
209
+ private boolean validateScheme(String scheme) {
210
+ List<String> invalidSchemes = Arrays.asList("file", "ftp", "ftps", "ws", "wss", "about", "blob", "data");
211
+ if (invalidSchemes.contains(scheme)) {
212
+ Logger.warn(scheme + " is not an allowed scheme. Defaulting to http.");
213
+ return false;
214
+ }
215
+
216
+ return true;
217
+ }
218
+
194
219
  public boolean isHTML5Mode() {
195
220
  return html5mode;
196
221
  }
@@ -243,6 +268,10 @@ public class CapConfig {
243
268
  return loggingEnabled;
244
269
  }
245
270
 
271
+ public boolean isInitialFocus() {
272
+ return initialFocus;
273
+ }
274
+
246
275
  public PluginConfig getPluginConfiguration(String pluginId) {
247
276
  PluginConfig pluginConfig = pluginsConfiguration.get(pluginId);
248
277
  if (pluginConfig == null) {
@@ -398,6 +427,7 @@ public class CapConfig {
398
427
  private boolean captureInput = false;
399
428
  private Boolean webContentsDebuggingEnabled = null;
400
429
  private boolean loggingEnabled = true;
430
+ private boolean initialFocus = false;
401
431
 
402
432
  // Embedded
403
433
  private String startPath = null;
@@ -496,5 +526,10 @@ public class CapConfig {
496
526
  this.loggingEnabled = enabled;
497
527
  return this;
498
528
  }
529
+
530
+ public Builder setInitialFocus(boolean focus) {
531
+ this.initialFocus = focus;
532
+ return this;
533
+ }
499
534
  }
500
535
  }
@@ -30,6 +30,7 @@ public class CapacitorWebView extends WebView {
30
30
  }
31
31
 
32
32
  @Override
33
+ @SuppressWarnings("deprecation")
33
34
  public boolean dispatchKeyEvent(KeyEvent event) {
34
35
  if (event.getAction() == KeyEvent.ACTION_MULTIPLE) {
35
36
  evaluateJavascript("document.activeElement.value = document.activeElement.value + '" + event.getCharacters() + "';", null);
@@ -77,7 +77,7 @@ public class FileUtils {
77
77
  final String type = split[0];
78
78
 
79
79
  if ("primary".equalsIgnoreCase(type)) {
80
- return Environment.getExternalStorageDirectory() + "/" + split[1];
80
+ return legacyPrimaryPath(split[1]);
81
81
  } else {
82
82
  final int splitIndex = docId.indexOf(':', 1);
83
83
  final String tag = docId.substring(0, splitIndex);
@@ -136,6 +136,11 @@ public class FileUtils {
136
136
  return null;
137
137
  }
138
138
 
139
+ @SuppressWarnings("deprecation")
140
+ private static String legacyPrimaryPath(String pathPart) {
141
+ return Environment.getExternalStorageDirectory() + "/" + pathPart;
142
+ }
143
+
139
144
  /**
140
145
  * Read a plaintext file.
141
146
  *
@@ -94,7 +94,7 @@ public class JSExport {
94
94
  return readFile(context.getAssets(), path);
95
95
  }
96
96
  } catch (IOException ex) {
97
- Logger.error("Unable to read file at path " + path);
97
+ Logger.warn("Unable to read file at path " + path);
98
98
  }
99
99
  return builder.toString();
100
100
  }
@@ -745,9 +745,10 @@ public class Plugin {
745
745
  * @param call
746
746
  */
747
747
  @SuppressWarnings("unused")
748
- @PluginMethod(returnType = PluginMethod.RETURN_NONE)
748
+ @PluginMethod(returnType = PluginMethod.RETURN_PROMISE)
749
749
  public void removeAllListeners(PluginCall call) {
750
750
  eventListeners.clear();
751
+ call.resolve();
751
752
  }
752
753
 
753
754
  /**
@@ -788,15 +789,7 @@ public class Plugin {
788
789
  public void requestPermissions(PluginCall call) {
789
790
  CapacitorPlugin annotation = handle.getPluginAnnotation();
790
791
  if (annotation == null) {
791
- // handle permission requests for plugins defined with @NativePlugin (prior to 3.0.0)
792
- NativePlugin legacyAnnotation = this.handle.getLegacyPluginAnnotation();
793
- String[] perms = legacyAnnotation.permissions();
794
- if (perms.length > 0) {
795
- saveCall(call);
796
- pluginRequestPermissions(perms, legacyAnnotation.permissionRequestCode());
797
- } else {
798
- call.resolve();
799
- }
792
+ handleLegacyPermission(call);
800
793
  } else {
801
794
  // handle permission requests for plugins defined with @CapacitorPlugin (since 3.0.0)
802
795
  String[] permAliases = null;
@@ -862,6 +855,19 @@ public class Plugin {
862
855
  }
863
856
  }
864
857
 
858
+ @SuppressWarnings("deprecation")
859
+ private void handleLegacyPermission(PluginCall call) {
860
+ // handle permission requests for plugins defined with @NativePlugin (prior to 3.0.0)
861
+ NativePlugin legacyAnnotation = this.handle.getLegacyPluginAnnotation();
862
+ String[] perms = legacyAnnotation.permissions();
863
+ if (perms.length > 0) {
864
+ saveCall(call);
865
+ pluginRequestPermissions(perms, legacyAnnotation.permissionRequestCode());
866
+ } else {
867
+ call.resolve();
868
+ }
869
+ }
870
+
865
871
  /**
866
872
  * Handle request permissions result. A plugin using the deprecated {@link NativePlugin}
867
873
  * should override this to handle the result, or this method will handle the result
@@ -20,11 +20,14 @@ public class PluginHandle {
20
20
 
21
21
  private final String pluginId;
22
22
 
23
+ @SuppressWarnings("deprecation")
23
24
  private NativePlugin legacyPluginAnnotation;
25
+
24
26
  private CapacitorPlugin pluginAnnotation;
25
27
 
26
28
  private Plugin instance;
27
29
 
30
+ @SuppressWarnings("deprecation")
28
31
  public PluginHandle(Bridge bridge, Class<? extends Plugin> pluginClass) throws InvalidPluginException, PluginLoadException {
29
32
  this.bridge = bridge;
30
33
  this.pluginClass = pluginClass;
@@ -67,6 +70,7 @@ public class PluginHandle {
67
70
  return this.pluginId;
68
71
  }
69
72
 
73
+ @SuppressWarnings("deprecation")
70
74
  public NativePlugin getLegacyPluginAnnotation() {
71
75
  return this.legacyPluginAnnotation;
72
76
  }
@@ -0,0 +1,28 @@
1
+ package com.getcapacitor;
2
+
3
+ /**
4
+ * An data class used in conjunction with RouteProcessor.
5
+ *
6
+ * @see com.getcapacitor.RouteProcessor
7
+ */
8
+ public class ProcessedRoute {
9
+
10
+ private String path;
11
+ private boolean isAsset;
12
+
13
+ public String getPath() {
14
+ return path;
15
+ }
16
+
17
+ public void setPath(String path) {
18
+ this.path = path;
19
+ }
20
+
21
+ public boolean isAsset() {
22
+ return isAsset;
23
+ }
24
+
25
+ public void setAsset(boolean asset) {
26
+ isAsset = asset;
27
+ }
28
+ }
@@ -0,0 +1,8 @@
1
+ package com.getcapacitor;
2
+
3
+ /**
4
+ * An interface used in the processing of routes
5
+ */
6
+ public interface RouteProcessor {
7
+ ProcessedRoute process(String basePath, String path);
8
+ }
@@ -24,7 +24,6 @@ import android.webkit.WebResourceResponse;
24
24
  import java.io.IOException;
25
25
  import java.io.InputStream;
26
26
  import java.net.HttpURLConnection;
27
- import java.net.SocketTimeoutException;
28
27
  import java.net.URL;
29
28
  import java.net.URLConnection;
30
29
  import java.nio.charset.StandardCharsets;
@@ -256,6 +255,12 @@ public class WebViewLocalServer {
256
255
  InputStream responseStream;
257
256
  try {
258
257
  String startPath = this.basePath + "/index.html";
258
+ if (bridge.getRouteProcessor() != null) {
259
+ ProcessedRoute processedRoute = bridge.getRouteProcessor().process(this.basePath, "/index.html");
260
+ startPath = processedRoute.getPath();
261
+ isAsset = processedRoute.isAsset();
262
+ }
263
+
259
264
  if (isAsset) {
260
265
  responseStream = protocolHandler.openAsset(startPath);
261
266
  } else {
@@ -467,13 +472,25 @@ public class WebViewLocalServer {
467
472
  public InputStream handle(Uri url) {
468
473
  InputStream stream = null;
469
474
  String path = url.getPath();
475
+
476
+ // Pass path to routeProcessor if present
477
+ RouteProcessor routeProcessor = bridge.getRouteProcessor();
478
+ if (routeProcessor != null) {
479
+ ProcessedRoute processedRoute = bridge.getRouteProcessor().process("", path);
480
+ path = processedRoute.getPath();
481
+ isAsset = processedRoute.isAsset();
482
+ }
483
+
470
484
  try {
471
485
  if (path.startsWith(capacitorContentStart)) {
472
486
  stream = protocolHandler.openContentUrl(url);
473
- } else if (path.startsWith(capacitorFileStart) || !isAsset) {
474
- if (!path.startsWith(capacitorFileStart)) {
487
+ } else if (path.startsWith(capacitorFileStart)) {
488
+ stream = protocolHandler.openFile(path);
489
+ } else if (!isAsset) {
490
+ if (routeProcessor == null) {
475
491
  path = basePath + url.getPath();
476
492
  }
493
+
477
494
  stream = protocolHandler.openFile(path);
478
495
  } else {
479
496
  stream = protocolHandler.openAsset(assetPath + path);
@@ -12,7 +12,6 @@ class CapacitorCordovaCookieManager implements ICordovaCookieManager {
12
12
  public CapacitorCordovaCookieManager(WebView webview) {
13
13
  webView = webview;
14
14
  cookieManager = CookieManager.getInstance();
15
- CookieManager.setAcceptFileSchemeCookies(true);
16
15
  cookieManager.setAcceptThirdPartyCookies(webView, true);
17
16
  }
18
17
 
@@ -33,7 +32,7 @@ class CapacitorCordovaCookieManager implements ICordovaCookieManager {
33
32
 
34
33
  @Override
35
34
  public void clearCookies() {
36
- cookieManager.removeAllCookie();
35
+ cookieManager.removeAllCookies(null);
37
36
  }
38
37
 
39
38
  @Override
@@ -112,6 +112,7 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
112
112
  @Override
113
113
  public void clearCache() {}
114
114
 
115
+ @Deprecated
115
116
  @Override
116
117
  public void clearCache(boolean b) {}
117
118
 
@@ -181,6 +182,7 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
181
182
  this.pluginManager.onDestroy();
182
183
  }
183
184
 
185
+ @Deprecated
184
186
  @Override
185
187
  public void sendJavascript(String statememt) {
186
188
  nativeToJsMessageQueue.addJavaScript(statememt);
@@ -198,14 +200,17 @@ public class MockCordovaWebViewImpl implements CordovaWebView {
198
200
  @Override
199
201
  public void showWebPage(String url, boolean openExternal, boolean clearHistory, Map<String, Object> params) {}
200
202
 
203
+ @Deprecated
201
204
  @Override
202
205
  public boolean isCustomViewShowing() {
203
206
  return false;
204
207
  }
205
208
 
209
+ @Deprecated
206
210
  @Override
207
211
  public void showCustomView(View view, WebChromeClient.CustomViewCallback callback) {}
208
212
 
213
+ @Deprecated
209
214
  @Override
210
215
  public void hideCustomView() {}
211
216
 
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
- <resources>
3
- <color name="colorPrimary">#3F51B5</color>
4
- <color name="colorPrimaryDark">#303F9F</color>
5
- <color name="colorAccent">#FF4081</color>
2
+ <resources xmlns:tools="http://schemas.android.com/tools">
3
+ <color tools:ignore="UnusedResources" name="colorPrimary">#3F51B5</color>
4
+ <color tools:ignore="UnusedResources" name="colorPrimaryDark">#303F9F</color>
5
+ <color tools:ignore="UnusedResources" name="colorAccent">#FF4081</color>
6
6
  </resources>
@@ -1,7 +1,2 @@
1
1
  <resources>
2
- <string name="app_name">CapacitorAndroid</string>
3
- <string name="ok">OK</string>
4
- <string name="picture">Picture</string>
5
- <string name="request_permission">Allow this app to take pictures</string>
6
- <string name="camera_error">Unable to use camera</string>
7
2
  </resources>
@@ -1,13 +1,4 @@
1
1
  <resources>
2
-
3
- <!-- Base application theme. -->
4
- <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
5
- <!-- Customize your theme here. -->
6
- <item name="colorPrimary">@color/colorPrimary</item>
7
- <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
8
- <item name="colorAccent">@color/colorAccent</item>
9
- </style>
10
-
11
2
  <style name="AppTheme.NoActionBar" parent="Theme.AppCompat.NoActionBar">
12
3
  <item name="windowActionBar">false</item>
13
4
  <item name="windowNoTitle">true</item>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capacitor/android",
3
- "version": "4.0.0-alpha.1",
3
+ "version": "4.0.0-beta.1",
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)",
@@ -22,10 +22,10 @@
22
22
  "verify": "./gradlew clean lint build test -b capacitor/build.gradle"
23
23
  },
24
24
  "peerDependencies": {
25
- "@capacitor/core": "^3.4.0"
25
+ "@capacitor/core": "next"
26
26
  },
27
27
  "publishConfig": {
28
28
  "access": "public"
29
29
  },
30
- "gitHead": "7faec09fd724a0af7436f3d30c83856b7bb5ce51"
30
+ "gitHead": "8520516c0883cb11df3b0097ac793290235c27de"
31
31
  }
@@ -1,12 +0,0 @@
1
- <?xml version="1.0" encoding="utf-8"?>
2
- <vector xmlns:android="http://schemas.android.com/apk/res/android"
3
- android:width="16dp"
4
- android:height="16dp"
5
- android:viewportHeight="108"
6
- android:viewportWidth="108">
7
-
8
- <path
9
- android:width="1dp"
10
- android:color="@android:color/transparent" />
11
-
12
- </vector>