Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] Issue with injectedJavaScriptBeforeContentLoaded #3377

Open
ivankdev opened this issue Apr 3, 2024 · 5 comments
Open

[Android] Issue with injectedJavaScriptBeforeContentLoaded #3377

ivankdev opened this issue Apr 3, 2024 · 5 comments

Comments

@ivankdev
Copy link

ivankdev commented Apr 3, 2024

Integrating webview in my RN app. I need to handle Publitas API by injected javascript code. This is minimal code snippet for repro.

"react-native-webview": "^13.8.4",
import { Alert } from 'react-native'
import WebView from 'react-native-webview'

const publitasInjectedJS = `
  console.log('publitasInjectedJS'); // called always
  
  window.viewerReady = function(api) {
    console.log('viewerReady'); // called sometimes
    // ... doing logic here
  };
  
  true;
`

export const App = () => {
  return (
    <WebView
      injectedJavaScript={publitasInjectedJS} // works well for iOS, never for Android
      injectedJavaScriptBeforeContentLoaded={publitasInjectedJS} // works sometimes for Android
      source={{ uri: 'https://view.publitas.com/delhaize-belgium/2023-w42-fr' }}
      onMessage={() => Alert.alert('postMessage')}
      cacheEnabled={false}
    />
  )
}

So on iOS default injectedJavaScript prop works well and method viewerReady is always called in time.

But on Android side, injectedJavaScript doesn't work at all and injectedJavaScriptBeforeContentLoaded works like in 1 case of 20 page reloads. You can see actually that viewerReady not called at all most of the reloads.

Screenshot 2024-04-03 at 02 05 26 Screenshot 2024-04-03 at 01 35 09


What I also tried is

  onLoad={() => webViewRef.current?.injectJavaScript(publitasInjectedJS)}

but no any visible changes with that approach

Question: Any clues how to make it work for Android properly?

@gronxb
Copy link
Contributor

gronxb commented Apr 3, 2024

you can see this issue: #1099

injectedJavaScriptBeforeContentLoaded is sometimes weird on Android.

injectedJavaScriptObject is an alternate prop for this issue.
https://github.com/react-native-webview/react-native-webview/blob/master/docs/Reference.md#injectedjavascriptobject

see #2960 (comment)

@ivankdev
Copy link
Author

ivankdev commented Apr 3, 2024

you can see this issue: #1099

injectedJavaScriptBeforeContentLoaded is sometimes weird on Android.

injectedJavaScriptObject is an alternate prop for this issue. https://github.com/react-native-webview/react-native-webview/blob/master/docs/Reference.md#injectedjavascriptobject

see #2960 (comment)

@gronxb thanks for answer, but honestly I'm not sure how can passed object help here, when exactly function window.viewerReady not being called. All what I need is get viewerReady called in correct moment, no any data from js needed.

@gronxb
Copy link
Contributor

gronxb commented Apr 4, 2024

Please don't pass the callback of window.viewerReady in React Native. Instead, call window.viewerReady directly in the web, not in React Native, and pass the necessary data to window.viewerReady using injectedJavaScriptObject.

@ivankdev
Copy link
Author

ivankdev commented Apr 4, 2024

@gronxb I cannot change the web part, it's dynamic url shared with mobile team. Anyway seems like I found out some valid workaround, will share in next comment

@ivankdev
Copy link
Author

ivankdev commented Apr 4, 2024

Resolved by adding new prop on native level which handled in onLoadResource callback

   <WebView
      ....
      source={{ uri: params?.url }}
      injectedJavaScript={publitasInjectedJS}
      injectedJavaScriptOnLoadResources={publitasInjectedJS} // android only
    />
diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java
index 6664b6f..6cb9a28 100644
--- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java
+++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebView.java
@@ -46,6 +46,8 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
     String injectedJS;
     protected @Nullable
     String injectedJSBeforeContentLoaded;
+    protected @Nullable
+    String injectedJSOnLoadResources;
     protected static final String JAVASCRIPT_INTERFACE = "ReactNativeWebView";
     protected @Nullable
     RNCWebViewBridge bridge;
@@ -283,6 +285,14 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
         }
     }
 
+    public void callInjectedJavaScriptOnLoadResources() {
+        if (getSettings().getJavaScriptEnabled() &&
+                injectedJSOnLoadResources != null &&
+                !TextUtils.isEmpty(injectedJSOnLoadResources)) {
+            evaluateJavascriptWithFallback("(function() {\n" + injectedJSOnLoadResources + ";\n})();");
+        }
+    }
+
     public void setInjectedJavaScriptObject(String obj) {
         if (getSettings().getJavaScriptEnabled()) {
             RNCWebViewBridge b = createRNCWebViewBridge(this);
diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java
index d59e19c..6e0978b 100644
--- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java
+++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewClient.java
@@ -64,6 +64,14 @@ public class RNCWebViewClient extends WebViewClient {
         }
     }
 
+    @Override
+    public void onLoadResource(WebView webView, String url) {
+        RNCWebView reactWebView = (RNCWebView) webView;
+        reactWebView.callInjectedJavaScriptOnLoadResources();
+
+        super.onLoadResource(webView, url);
+    }
+
     @Override
     public void doUpdateVisitedHistory (WebView webView, String url, boolean isReload) {
       super.doUpdateVisitedHistory(webView, url, isReload);
diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt
index 6a48a81..a52dd98 100644
--- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt
+++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManagerImpl.kt
@@ -488,6 +488,11 @@ class RNCWebViewManagerImpl {
         view.injectedJSBeforeContentLoaded = value
     }
 
+    fun setInjectedJavaScriptOnLoadResources(viewWrapper: RNCWebViewWrapper, injectedJavaScript: String?) {
+        val view = viewWrapper.webView
+        view.injectedJSOnLoadResources = injectedJavaScript
+    }
+
     fun setInjectedJavaScriptForMainFrameOnly(viewWrapper: RNCWebViewWrapper, value: Boolean) {
         val view = viewWrapper.webView
         view.injectedJavaScriptForMainFrameOnly = value
diff --git a/node_modules/react-native-webview/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java
index 5bae4aa..c55fd3c 100644
--- a/node_modules/react-native-webview/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java
+++ b/node_modules/react-native-webview/android/src/newarch/com/reactnativecommunity/webview/RNCWebViewManager.java
@@ -171,6 +171,12 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper>
         mRNCWebViewManagerImpl.setInjectedJavaScriptBeforeContentLoaded(view, value);
     }
 
+    @Override
+    @ReactProp(name = "injectedJavaScriptOnLoadResources")
+    public void setInjectedJavaScriptOnLoadResources(RNCWebViewWrapper view, @Nullable String value) {
+        mRNCWebViewManagerImpl.setInjectedJavaScriptOnLoadResources(view, value);
+    }
+
     @Override
     @ReactProp(name = "injectedJavaScriptForMainFrameOnly")
     public void setInjectedJavaScriptForMainFrameOnly(RNCWebViewWrapper view, boolean value) {
diff --git a/node_modules/react-native-webview/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java
index 709117a..1b2c17b 100644
--- a/node_modules/react-native-webview/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java
+++ b/node_modules/react-native-webview/android/src/oldarch/com/reactnativecommunity/webview/RNCWebViewManager.java
@@ -136,6 +136,11 @@ public class RNCWebViewManager extends ViewGroupManager<RNCWebViewWrapper> {
         mRNCWebViewManagerImpl.setInjectedJavaScriptBeforeContentLoaded(view, value);
     }
 
+    @ReactProp(name = "injectedJavaScriptOnLoadResources")
+    public void setInjectedJavaScriptOnLoadResources(RNCWebViewWrapper view, @Nullable String value) {
+        mRNCWebViewManagerImpl.setInjectedJavaScriptOnLoadResources(view, value);
+    }
+
     @ReactProp(name = "injectedJavaScriptForMainFrameOnly")
     public void setInjectedJavaScriptForMainFrameOnly(RNCWebViewWrapper view, boolean value) {
         mRNCWebViewManagerImpl.setInjectedJavaScriptForMainFrameOnly(view, value);
diff --git a/node_modules/react-native-webview/src/WebViewTypes.ts b/node_modules/react-native-webview/src/WebViewTypes.ts
index 1bc55cb..54e4aa8 100644
--- a/node_modules/react-native-webview/src/WebViewTypes.ts
+++ b/node_modules/react-native-webview/src/WebViewTypes.ts
@@ -1121,6 +1121,13 @@ export interface AndroidWebViewProps extends WebViewSharedProps {
    * @platform android
    */
   allowsProtectedMedia?: boolean;
+
+  /**
+   * Set this to provide JavaScript that will be injected into the web page
+   * when the page resources loaded.
+   * @platform android
+   */
+  injectedJavaScriptOnLoadResources?: string;
 }
 
 export interface WebViewSharedProps extends ViewProps {

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants