From 570e08c51da554911915189938e2c32e08501cdd Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Tue, 16 Mar 2021 20:43:02 -0500 Subject: [PATCH 01/14] Add hook for attaching behavior to native WebView loaded event --- .../main/java/com/getcapacitor/Bridge.java | 26 +++++++++++++++++++ .../java/com/getcapacitor/BridgeFragment.java | 7 +++++ .../com/getcapacitor/BridgeWebViewClient.java | 22 ++++++++++++++++ 3 files changed, 55 insertions(+) diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index 28d470e1a4..c7cbd07bd1 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -120,6 +120,9 @@ public class Bridge { // Any URI that was passed to the app on start private Uri intentUri; + // A list of listeners that trigger when webView is finished loading + private List pageLoadedListeners = new ArrayList<>(); + /** * Create the Bridge with a reference to the main {@link Activity} for the * app, and a reference to the {@link WebView} our app will use. @@ -1107,12 +1110,21 @@ public void setWebViewClient(BridgeWebViewClient client) { this.webViewClient = client; } + List getPageLoadedListeners() { + return pageLoadedListeners; + } + + void setPageLoadedListeners(List pageLoadedListeners) { + this.pageLoadedListeners = pageLoadedListeners; + } + static class Builder { private Bundle instanceState = null; private CapConfig config = null; private List> plugins = new ArrayList<>(); private AppCompatActivity activity; + private final List pageLoadedListeners = new ArrayList<>(); Builder(AppCompatActivity activity) { this.activity = activity; @@ -1146,6 +1158,19 @@ public Builder addPlugins(List> plugins) { return this; } + public Builder addPageLoadedListener(BridgeWebViewClient.PageLoadedListener pageLoadedListener) { + pageLoadedListeners.add(pageLoadedListener); + return this; + } + + public Builder addPageLoadedListeners(List pageLoadedListeners) { + for (BridgeWebViewClient.PageLoadedListener listener : pageLoadedListeners) { + this.addPageLoadedListener(listener); + } + + return this; + } + public Bridge create() { // Cordova initialization ConfigXmlParser parser = new ConfigXmlParser(); @@ -1168,6 +1193,7 @@ public Bridge create() { // Bridge initialization Bridge bridge = new Bridge(activity, webView, plugins, cordovaInterface, pluginManager, preferences, config); bridge.setCordovaWebView(mockWebView); + bridge.setPageLoadedListeners(pageLoadedListeners); if (instanceState != null) { bridge.restoreInstanceState(instanceState); diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java index eadcd39d88..e216bd3eec 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java @@ -28,6 +28,8 @@ public class BridgeFragment extends Fragment { private final List> initialPlugins = new ArrayList<>(); private CapConfig config = null; + private final List pageLoadedListeners = new ArrayList<>(); + public BridgeFragment() { // Required empty public constructor } @@ -55,6 +57,10 @@ public void setConfig(CapConfig config) { this.config = config; } + public void addPageLoadedListener(BridgeWebViewClient.PageLoadedListener pageLoadedListener) { + pageLoadedListeners.add(pageLoadedListener); + } + /** * Load the WebView and create the Bridge */ @@ -73,6 +79,7 @@ protected void load(Bundle savedInstanceState) { .setInstanceState(savedInstanceState) .setPlugins(initialPlugins) .setConfig(config) + .addPageLoadedListeners(pageLoadedListeners) .create(); if (startDir != null) { diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java index 3a0aa2a597..bf00ecee7a 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java @@ -6,8 +6,17 @@ import android.webkit.WebView; import android.webkit.WebViewClient; +import java.util.List; + public class BridgeWebViewClient extends WebViewClient { + /** + * Interface for callbacks when Bridge WebView finishes loading. + */ + public interface PageLoadedListener { + void onPageLoaded(WebView webView); + } + private Bridge bridge; public BridgeWebViewClient(Bridge bridge) { @@ -29,4 +38,17 @@ public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request public boolean shouldOverrideUrlLoading(WebView view, String url) { return bridge.launchIntent(Uri.parse(url)); } + + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + + List pageLoadedListeners = bridge.getPageLoadedListeners(); + + if (pageLoadedListeners != null && view.getProgress() == 100) { + for (PageLoadedListener listener : bridge.getPageLoadedListeners()) { + listener.onPageLoaded(view); + } + } + } } From aa576022ac99c0524db7903f8776281c582082c8 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Tue, 16 Mar 2021 20:46:32 -0500 Subject: [PATCH 02/14] lint... --- .../src/main/java/com/getcapacitor/BridgeWebViewClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java index bf00ecee7a..a05e0c8d13 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java @@ -5,7 +5,6 @@ import android.webkit.WebResourceResponse; import android.webkit.WebView; import android.webkit.WebViewClient; - import java.util.List; public class BridgeWebViewClient extends WebViewClient { From f3984a8d201b43e3ccb43f50204947d334ea795f Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Sun, 28 Mar 2021 13:34:41 -0500 Subject: [PATCH 03/14] bridge fragment awareness and plugin result launcher checks --- .../main/java/com/getcapacitor/Bridge.java | 37 ++++++++++- .../java/com/getcapacitor/BridgeFragment.java | 7 +-- .../main/java/com/getcapacitor/Plugin.java | 63 +++++++++++++------ 3 files changed, 81 insertions(+), 26 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index 28d470e1a4..89846f308d 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -18,6 +18,7 @@ import android.webkit.WebView; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; +import androidx.fragment.app.Fragment; import com.getcapacitor.android.R; import com.getcapacitor.annotation.CapacitorPlugin; import com.getcapacitor.annotation.Permission; @@ -80,6 +81,8 @@ public class Bridge { // A reference to the main activity for the app private final AppCompatActivity context; + // A reference to the containing Fragment if used + private final Fragment fragment; private WebViewLocalServer localServer; private String localUrl; private String appUrl; @@ -136,9 +139,23 @@ public Bridge( PluginManager pluginManager, CordovaPreferences preferences, CapConfig config + ) { + this(context, null, webView, initialPlugins, cordovaInterface, pluginManager, preferences, config); + } + + private Bridge( + AppCompatActivity context, + Fragment fragment, + WebView webView, + List> initialPlugins, + MockCordovaInterfaceImpl cordovaInterface, + PluginManager pluginManager, + CordovaPreferences preferences, + CapConfig config ) { this.app = new App(); this.context = context; + this.fragment = fragment; this.webView = webView; this.webViewClient = new BridgeWebViewClient(this); this.initialPlugins = initialPlugins; @@ -327,6 +344,16 @@ public AppCompatActivity getActivity() { return this.context; } + /** + * Get the fragment for the app, if applicable. This will likely be null unless Capacitor + * is being used embedded in a Native Android app. + * + * @return The fragment containing the Capacitor WebView. + */ + public Fragment getFragment() { + return this.fragment; + } + /** * Get the core WebView under Capacitor's control * @return @@ -1113,11 +1140,17 @@ static class Builder { private CapConfig config = null; private List> plugins = new ArrayList<>(); private AppCompatActivity activity; + private Fragment fragment; Builder(AppCompatActivity activity) { this.activity = activity; } + Builder(Fragment fragment) { + this.activity = (AppCompatActivity) fragment.getActivity(); + this.fragment = fragment; + } + public Builder setInstanceState(Bundle instanceState) { this.instanceState = instanceState; return this; @@ -1159,14 +1192,14 @@ public Bridge create() { cordovaInterface.restoreInstanceState(instanceState); } - WebView webView = activity.findViewById(R.id.webview); + WebView webView = this.fragment != null ? fragment.getView().findViewById(R.id.webview) : activity.findViewById(R.id.webview); MockCordovaWebViewImpl mockWebView = new MockCordovaWebViewImpl(activity.getApplicationContext()); mockWebView.init(cordovaInterface, pluginEntries, preferences, webView); PluginManager pluginManager = mockWebView.getPluginManager(); cordovaInterface.onCordovaInit(pluginManager); // Bridge initialization - Bridge bridge = new Bridge(activity, webView, plugins, cordovaInterface, pluginManager, preferences, config); + Bridge bridge = new Bridge(activity, fragment, webView, plugins, cordovaInterface, pluginManager, preferences, config); bridge.setCordovaWebView(mockWebView); if (instanceState != null) { diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java index eadcd39d88..0f2288fdf8 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java @@ -68,12 +68,7 @@ protected void load(Bundle savedInstanceState) { startDir = getArguments().getString(ARG_START_DIR); } - bridge = - new Bridge.Builder((AppCompatActivity) getActivity()) - .setInstanceState(savedInstanceState) - .setPlugins(initialPlugins) - .setConfig(config) - .create(); + bridge = new Bridge.Builder(this).setInstanceState(savedInstanceState).setPlugins(initialPlugins).setConfig(config).create(); if (startDir != null) { bridge.setServerAssetPath(startDir); diff --git a/android/capacitor/src/main/java/com/getcapacitor/Plugin.java b/android/capacitor/src/main/java/com/getcapacitor/Plugin.java index dc4662ddce..6f55503b32 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Plugin.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Plugin.java @@ -14,6 +14,7 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; +import androidx.lifecycle.Lifecycle; import com.getcapacitor.annotation.ActivityCallback; import com.getcapacitor.annotation.CapacitorPlugin; import com.getcapacitor.annotation.Permission; @@ -111,26 +112,52 @@ void initializeActivityLaunchers() { for (final Method method : pluginClassMethods) { if (method.isAnnotationPresent(ActivityCallback.class)) { // register callbacks annotated with ActivityCallback for activity results - activityLaunchers.put( - method.getName(), - bridge - .getActivity() - .registerForActivityResult( - new ActivityResultContracts.StartActivityForResult(), - result -> triggerActivityCallback(method, result) - ) - ); + ActivityResultLauncher launcher; + + if (bridge.getFragment() != null) { + launcher = + bridge + .getFragment() + .registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> triggerActivityCallback(method, result) + ); + } else { + launcher = + bridge + .getActivity() + .registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> triggerActivityCallback(method, result) + ); + } + + activityLaunchers.put(method.getName(), launcher); } else if (method.isAnnotationPresent(PermissionCallback.class)) { // register callbacks annotated with PermissionCallback for permission results - permissionLaunchers.put( - method.getName(), - bridge - .getActivity() - .registerForActivityResult( - new ActivityResultContracts.RequestMultiplePermissions(), - permissions -> triggerPermissionCallback(method, permissions) - ) - ); + ActivityResultLauncher launcher; + + if (bridge.getFragment() != null) { + launcher = + bridge + .getFragment() + .registerForActivityResult( + new ActivityResultContracts.RequestMultiplePermissions(), + permissions -> triggerPermissionCallback(method, permissions) + ); + } else { + launcher = + bridge + .getActivity() + .registerForActivityResult( + new ActivityResultContracts.RequestMultiplePermissions(), + permissions -> triggerPermissionCallback(method, permissions) + ); + } + + if (!bridge.getActivity().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { + permissionLaunchers.put(method.getName(), launcher); + } } } } From 40f79173b05bc055f9ca66411985d976e256c595 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Sun, 28 Mar 2021 15:31:14 -0500 Subject: [PATCH 04/14] crashfix on fragment load --- .../src/main/java/com/getcapacitor/BridgeFragment.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java index 0f2288fdf8..c38e7d0d0b 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java @@ -7,7 +7,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import androidx.appcompat.app.AppCompatActivity; import androidx.fragment.app.Fragment; import com.getcapacitor.android.R; import java.util.ArrayList; @@ -104,8 +103,8 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa } @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); this.load(savedInstanceState); } From 5b3c5631d70ce900fdaeee48e9782d2f7e166847 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Sun, 28 Mar 2021 15:41:09 -0500 Subject: [PATCH 05/14] removed state check for consistency and comment --- .../src/main/java/com/getcapacitor/BridgeFragment.java | 2 +- android/capacitor/src/main/java/com/getcapacitor/Plugin.java | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java index c38e7d0d0b..ff10eb123d 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java @@ -58,7 +58,7 @@ public void setConfig(CapConfig config) { * Load the WebView and create the Bridge */ protected void load(Bundle savedInstanceState) { - Logger.debug("Starting BridgeActivity"); + Logger.debug("Loading Bridge with BridgeFragment"); Bundle args = getArguments(); String startDir = null; diff --git a/android/capacitor/src/main/java/com/getcapacitor/Plugin.java b/android/capacitor/src/main/java/com/getcapacitor/Plugin.java index 6f55503b32..0d1886605f 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Plugin.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Plugin.java @@ -14,7 +14,6 @@ import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; -import androidx.lifecycle.Lifecycle; import com.getcapacitor.annotation.ActivityCallback; import com.getcapacitor.annotation.CapacitorPlugin; import com.getcapacitor.annotation.Permission; @@ -155,9 +154,7 @@ void initializeActivityLaunchers() { ); } - if (!bridge.getActivity().getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { - permissionLaunchers.put(method.getName(), launcher); - } + permissionLaunchers.put(method.getName(), launcher); } } } From ba0e26f4a66f2dbf6e1a09c879cf5dfee509a090 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Sun, 28 Mar 2021 16:21:13 -0500 Subject: [PATCH 06/14] BridgeChromeClient permission registration fix for fragments --- .../getcapacitor/BridgeWebChromeClient.java | 61 +++++++++++-------- 1 file changed, 37 insertions(+), 24 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java index a1d83974ea..3b6c9cbd11 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java @@ -21,6 +21,7 @@ import android.webkit.WebView; import android.widget.EditText; import androidx.activity.result.ActivityResult; +import androidx.activity.result.ActivityResultCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.core.content.FileProvider; @@ -53,30 +54,42 @@ private interface ActivityResultListener { public BridgeWebChromeClient(Bridge bridge) { this.bridge = bridge; - permissionLauncher = - bridge - .getActivity() - .registerForActivityResult( - new ActivityResultContracts.RequestMultiplePermissions(), - (Map isGranted) -> { - if (permissionListener != null) { - boolean granted = true; - for (Map.Entry permission : isGranted.entrySet()) { - if (!permission.getValue()) granted = false; - } - permissionListener.onPermissionSelect(granted); - } - } - ); - activityLauncher = - bridge - .getActivity() - .registerForActivityResult( - new ActivityResultContracts.StartActivityForResult(), - result -> { - activityListener.onActivityResult(result); - } - ); + + ActivityResultCallback> permissionCallback = (Map isGranted) -> { + if (permissionListener != null) { + boolean granted = true; + for (Map.Entry permission : isGranted.entrySet()) { + if (!permission.getValue()) granted = false; + } + permissionListener.onPermissionSelect(granted); + } + }; + + if (bridge.getFragment() != null) { + permissionLauncher = + bridge + .getFragment() + .registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback); + activityLauncher = + bridge + .getFragment() + .registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> activityListener.onActivityResult(result) + ); + } else { + permissionLauncher = + bridge + .getActivity() + .registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback); + activityLauncher = + bridge + .getActivity() + .registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> activityListener.onActivityResult(result) + ); + } } /** From f5f3af2524b5bf6cbe034c9a892e7f642cd71fb6 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Wed, 31 Mar 2021 10:24:14 -0500 Subject: [PATCH 07/14] changed implementation to extendable abstract class for the WebViewListener --- .../main/java/com/getcapacitor/Bridge.java | 24 +++++++------- .../java/com/getcapacitor/BridgeFragment.java | 8 ++--- .../com/getcapacitor/BridgeWebViewClient.java | 25 ++++++++------- .../com/getcapacitor/WebViewListener.java | 31 +++++++++++++++++++ 4 files changed, 61 insertions(+), 27 deletions(-) create mode 100644 android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index c7cbd07bd1..d1132995f7 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -121,7 +121,7 @@ public class Bridge { private Uri intentUri; // A list of listeners that trigger when webView is finished loading - private List pageLoadedListeners = new ArrayList<>(); + private List webViewListeners = new ArrayList<>(); /** * Create the Bridge with a reference to the main {@link Activity} for the @@ -1110,12 +1110,12 @@ public void setWebViewClient(BridgeWebViewClient client) { this.webViewClient = client; } - List getPageLoadedListeners() { - return pageLoadedListeners; + List getWebViewListeners() { + return webViewListeners; } - void setPageLoadedListeners(List pageLoadedListeners) { - this.pageLoadedListeners = pageLoadedListeners; + void setWebViewListeners(List webViewListeners) { + this.webViewListeners = webViewListeners; } static class Builder { @@ -1124,7 +1124,7 @@ static class Builder { private CapConfig config = null; private List> plugins = new ArrayList<>(); private AppCompatActivity activity; - private final List pageLoadedListeners = new ArrayList<>(); + private final List webViewListeners = new ArrayList<>(); Builder(AppCompatActivity activity) { this.activity = activity; @@ -1158,14 +1158,14 @@ public Builder addPlugins(List> plugins) { return this; } - public Builder addPageLoadedListener(BridgeWebViewClient.PageLoadedListener pageLoadedListener) { - pageLoadedListeners.add(pageLoadedListener); + public Builder addWebViewListener(WebViewListener webViewListener) { + webViewListeners.add(webViewListener); return this; } - public Builder addPageLoadedListeners(List pageLoadedListeners) { - for (BridgeWebViewClient.PageLoadedListener listener : pageLoadedListeners) { - this.addPageLoadedListener(listener); + public Builder addWebViewListeners(List webViewListeners) { + for (WebViewListener listener : webViewListeners) { + this.addWebViewListener(listener); } return this; @@ -1193,7 +1193,7 @@ public Bridge create() { // Bridge initialization Bridge bridge = new Bridge(activity, webView, plugins, cordovaInterface, pluginManager, preferences, config); bridge.setCordovaWebView(mockWebView); - bridge.setPageLoadedListeners(pageLoadedListeners); + bridge.setWebViewListeners(webViewListeners); if (instanceState != null) { bridge.restoreInstanceState(instanceState); diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java index e216bd3eec..4ee951beed 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java @@ -28,7 +28,7 @@ public class BridgeFragment extends Fragment { private final List> initialPlugins = new ArrayList<>(); private CapConfig config = null; - private final List pageLoadedListeners = new ArrayList<>(); + private final List webViewListeners = new ArrayList<>(); public BridgeFragment() { // Required empty public constructor @@ -57,8 +57,8 @@ public void setConfig(CapConfig config) { this.config = config; } - public void addPageLoadedListener(BridgeWebViewClient.PageLoadedListener pageLoadedListener) { - pageLoadedListeners.add(pageLoadedListener); + public void addWebViewListener(WebViewListener webViewListener) { + webViewListeners.add(webViewListener); } /** @@ -79,7 +79,7 @@ protected void load(Bundle savedInstanceState) { .setInstanceState(savedInstanceState) .setPlugins(initialPlugins) .setConfig(config) - .addPageLoadedListeners(pageLoadedListeners) + .addWebViewListeners(webViewListeners) .create(); if (startDir != null) { diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java index a05e0c8d13..80354704e5 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java @@ -1,6 +1,7 @@ package com.getcapacitor; import android.net.Uri; +import android.webkit.WebResourceError; import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; import android.webkit.WebView; @@ -9,13 +10,6 @@ public class BridgeWebViewClient extends WebViewClient { - /** - * Interface for callbacks when Bridge WebView finishes loading. - */ - public interface PageLoadedListener { - void onPageLoaded(WebView webView); - } - private Bridge bridge; public BridgeWebViewClient(Bridge bridge) { @@ -38,15 +32,24 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { return bridge.launchIntent(Uri.parse(url)); } + @Override + public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { + super.onReceivedError(view, request, error); + } + @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); - List pageLoadedListeners = bridge.getPageLoadedListeners(); + List webViewListeners = bridge.getWebViewListeners(); - if (pageLoadedListeners != null && view.getProgress() == 100) { - for (PageLoadedListener listener : bridge.getPageLoadedListeners()) { - listener.onPageLoaded(view); + if (webViewListeners != null && view.getProgress() == 100) { + for (WebViewListener listener : bridge.getWebViewListeners()) { + try { + listener.onPageLoaded(view); + } catch (WebViewListener.NotImplementedException e) { + // Fail quietly when event not used + } } } } diff --git a/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java b/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java new file mode 100644 index 0000000000..ef3d32c3fa --- /dev/null +++ b/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java @@ -0,0 +1,31 @@ +package com.getcapacitor; + +import android.webkit.WebView; + +/** + * Provides callbacks associated with the {@link BridgeWebViewClient} + */ +public abstract class WebViewListener { + + /** + * Callback for page load event. + * + * @param webView The WebView that loaded + */ + public void onPageLoaded(WebView webView) throws NotImplementedException { + throw new NotImplementedException(); + } + + /** + * Callback for page error event. + * + * @param webView + */ + public void onPageError(WebView webView) throws NotImplementedException { + throw new NotImplementedException(); + } + + static class NotImplementedException extends Exception { + // Empty + } +} From 6cb22640d293dc9b0e9dddc7ddb8e28a5d5ca130 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Wed, 31 Mar 2021 10:27:46 -0500 Subject: [PATCH 08/14] Removed onPageError event for now, not used --- .../src/main/java/com/getcapacitor/WebViewListener.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java b/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java index ef3d32c3fa..cb572f3dd6 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java +++ b/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java @@ -16,15 +16,6 @@ public void onPageLoaded(WebView webView) throws NotImplementedException { throw new NotImplementedException(); } - /** - * Callback for page error event. - * - * @param webView - */ - public void onPageError(WebView webView) throws NotImplementedException { - throw new NotImplementedException(); - } - static class NotImplementedException extends Exception { // Empty } From 50a8ff36eb6eab70df663a9b4459bf3e2c8991ee Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Wed, 31 Mar 2021 10:40:38 -0500 Subject: [PATCH 09/14] removed exception from unimplemented webview listeners --- .../main/java/com/getcapacitor/BridgeWebViewClient.java | 6 +----- .../src/main/java/com/getcapacitor/WebViewListener.java | 8 ++------ 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java index 80354704e5..da5cc69b81 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java @@ -45,11 +45,7 @@ public void onPageFinished(WebView view, String url) { if (webViewListeners != null && view.getProgress() == 100) { for (WebViewListener listener : bridge.getWebViewListeners()) { - try { - listener.onPageLoaded(view); - } catch (WebViewListener.NotImplementedException e) { - // Fail quietly when event not used - } + listener.onPageLoaded(view); } } } diff --git a/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java b/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java index cb572f3dd6..88f42efd04 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java +++ b/android/capacitor/src/main/java/com/getcapacitor/WebViewListener.java @@ -12,11 +12,7 @@ public abstract class WebViewListener { * * @param webView The WebView that loaded */ - public void onPageLoaded(WebView webView) throws NotImplementedException { - throw new NotImplementedException(); - } - - static class NotImplementedException extends Exception { - // Empty + public void onPageLoaded(WebView webView) { + // Override me to add behavior to the page loaded event } } From befd1a291c92725533324a22ad92242596736880 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Wed, 31 Mar 2021 10:42:07 -0500 Subject: [PATCH 10/14] removed unused onReceivedError (was testing) --- .../src/main/java/com/getcapacitor/BridgeWebViewClient.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java index da5cc69b81..1afdc1c329 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java @@ -32,11 +32,6 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { return bridge.launchIntent(Uri.parse(url)); } - @Override - public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) { - super.onReceivedError(view, request, error); - } - @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); From de96983c7d3b9faa79e1faa5745bca496c1a47a1 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Wed, 31 Mar 2021 10:50:43 -0500 Subject: [PATCH 11/14] unused import --- .../src/main/java/com/getcapacitor/BridgeWebViewClient.java | 1 - 1 file changed, 1 deletion(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java index 1afdc1c329..a2b81a85e8 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebViewClient.java @@ -1,7 +1,6 @@ package com.getcapacitor; import android.net.Uri; -import android.webkit.WebResourceError; import android.webkit.WebResourceRequest; import android.webkit.WebResourceResponse; import android.webkit.WebView; From fbab7686c45d44c4624d92ab9e56f411eecc0003 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Fri, 2 Apr 2021 09:00:47 -0500 Subject: [PATCH 12/14] public bridge for similar access to Activity --- .../src/main/java/com/getcapacitor/BridgeFragment.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java index 663baaa1c9..f269bd561a 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeFragment.java @@ -56,6 +56,10 @@ public void setConfig(CapConfig config) { this.config = config; } + public Bridge getBridge() { + return bridge; + } + public void addWebViewListener(WebViewListener webViewListener) { webViewListeners.add(webViewListener); } From 9064e382dc206c616104abf5e8bb2e7ba7439d1b Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Fri, 9 Apr 2021 13:30:10 -0500 Subject: [PATCH 13/14] Added bridge helper to reduce code repetition in Plugin.class --- .../main/java/com/getcapacitor/Bridge.java | 23 ++++++++++ .../main/java/com/getcapacitor/Plugin.java | 46 ++++--------------- 2 files changed, 31 insertions(+), 38 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java index 60e64f72a3..a37c193845 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Bridge.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Bridge.java @@ -16,6 +16,10 @@ import android.webkit.ValueCallback; import android.webkit.WebSettings; import android.webkit.WebView; +import androidx.activity.result.ActivityResultCallback; +import androidx.activity.result.ActivityResultLauncher; +import androidx.activity.result.contract.ActivityResultContract; +import androidx.annotation.NonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.core.app.ActivityCompat; import androidx.fragment.app.Fragment; @@ -726,6 +730,25 @@ protected void savePermissionCall(PluginCall call) { } } + /** + * Register an Activity Result Launcher to the containing Fragment or Activity. + * + * @param contract A contract specifying that an activity can be called with an input of + * type I and produce an output of type O. + * @param callback The callback run on Activity Result. + * @return A registered Activity Result Launcher. + */ + public ActivityResultLauncher registerForActivityResult( + @NonNull final ActivityResultContract contract, + @NonNull final ActivityResultCallback callback + ) { + if (fragment != null) { + return fragment.registerForActivityResult(contract, callback); + } else { + return context.registerForActivityResult(contract, callback); + } + } + /** * Build the JSInjector that will be used to inject JS into files served to the app, * to ensure that Capacitor's JS and the JS for all the plugins is loaded each time. diff --git a/android/capacitor/src/main/java/com/getcapacitor/Plugin.java b/android/capacitor/src/main/java/com/getcapacitor/Plugin.java index 0d1886605f..758843699e 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/Plugin.java +++ b/android/capacitor/src/main/java/com/getcapacitor/Plugin.java @@ -111,48 +111,18 @@ void initializeActivityLaunchers() { for (final Method method : pluginClassMethods) { if (method.isAnnotationPresent(ActivityCallback.class)) { // register callbacks annotated with ActivityCallback for activity results - ActivityResultLauncher launcher; - - if (bridge.getFragment() != null) { - launcher = - bridge - .getFragment() - .registerForActivityResult( - new ActivityResultContracts.StartActivityForResult(), - result -> triggerActivityCallback(method, result) - ); - } else { - launcher = - bridge - .getActivity() - .registerForActivityResult( - new ActivityResultContracts.StartActivityForResult(), - result -> triggerActivityCallback(method, result) - ); - } + ActivityResultLauncher launcher = bridge.registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> triggerActivityCallback(method, result) + ); activityLaunchers.put(method.getName(), launcher); } else if (method.isAnnotationPresent(PermissionCallback.class)) { // register callbacks annotated with PermissionCallback for permission results - ActivityResultLauncher launcher; - - if (bridge.getFragment() != null) { - launcher = - bridge - .getFragment() - .registerForActivityResult( - new ActivityResultContracts.RequestMultiplePermissions(), - permissions -> triggerPermissionCallback(method, permissions) - ); - } else { - launcher = - bridge - .getActivity() - .registerForActivityResult( - new ActivityResultContracts.RequestMultiplePermissions(), - permissions -> triggerPermissionCallback(method, permissions) - ); - } + ActivityResultLauncher launcher = bridge.registerForActivityResult( + new ActivityResultContracts.RequestMultiplePermissions(), + permissions -> triggerPermissionCallback(method, permissions) + ); permissionLaunchers.put(method.getName(), launcher); } From 8debb33c7c54c75ca2957d770c757c73eca64900 Mon Sep 17 00:00:00 2001 From: Carl Poole Date: Mon, 12 Apr 2021 08:53:32 -0500 Subject: [PATCH 14/14] Using new Bridge helper for registering activity result launchers --- .../getcapacitor/BridgeWebChromeClient.java | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java index 3b6c9cbd11..01dd8204ff 100644 --- a/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java +++ b/android/capacitor/src/main/java/com/getcapacitor/BridgeWebChromeClient.java @@ -65,31 +65,12 @@ public BridgeWebChromeClient(Bridge bridge) { } }; - if (bridge.getFragment() != null) { - permissionLauncher = - bridge - .getFragment() - .registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback); - activityLauncher = - bridge - .getFragment() - .registerForActivityResult( - new ActivityResultContracts.StartActivityForResult(), - result -> activityListener.onActivityResult(result) - ); - } else { - permissionLauncher = - bridge - .getActivity() - .registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback); - activityLauncher = - bridge - .getActivity() - .registerForActivityResult( - new ActivityResultContracts.StartActivityForResult(), - result -> activityListener.onActivityResult(result) - ); - } + permissionLauncher = bridge.registerForActivityResult(new ActivityResultContracts.RequestMultiplePermissions(), permissionCallback); + activityLauncher = + bridge.registerForActivityResult( + new ActivityResultContracts.StartActivityForResult(), + result -> activityListener.onActivityResult(result) + ); } /**