react-native-webview: injectedJavaScript doesnt seem to work on IOS

Bug description: Setup the WebView and try to use the “injectedJavaScript” prop. It works as expected on Android but when on IOS it does nothing.

To Reproduce:

  1. Use this code below as your render method:
render() {
    const runFirst = `
      document.body.style.backgroundColor = 'red';
      setTimeout(function() { window.alert('hi') }, 2000);
      true; // note: this is required, or you'll sometimes get silent failures
    `
    return (
      <View style={{ flex: 1 }}>
        <WebView
          source={{
            uri: 'https://github.com/react-native-community/react-native-webview',
          }}
          injectedJavaScript={runFirst}
        />
      </View>
    )
  }

Expected behavior: Expected to render the github page for react-native-webview with a red background on both platforms.

Screenshots/Videos: Android: Screenshot_1585924185

IOS: Simulator Screen Shot - iPhone 8 - 2020-04-03 at 11 30 34

Environment:

  • OS: IOS
  • OS version: 13.3
  • react-native version: 0.62
  • react-native-webview version: 9.0.2

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 10
  • Comments: 15 (5 by maintainers)

Most upvoted comments

According to the guide, you now must pass a function as the onMessage prop for injected Javascript to work. But, it will work in Android without it anyway.

According to the guide, you now must pass a function as the onMessage prop for injected Javascript to work. But, it will work in Android without it anyway.

I am already using ‘onMessage’. Still it is not working to inject javascript. My WebView something like that: <WebView onLoadEnd={() => { this._setstatus() }} onNavigationStateChange={this.on_navigaton_new} injectedJavaScript={custom_script} onMessage={x => this.onMessageGet(x)} javaScriptEnabled={true} source={{ uri: this.state.url, forceReload: this.state.forceReload }} allowsLinkPsreview={true} incognito={true} domStorageEnabled={true} ref={(ref) => this.myWebView = ref}/>

@PrantikMondal - I had the same issue, the JS didnt inject itself into the webview unless i injected it with the help of ref

export default class App extends Component { render() { const run = ‘document.body.style.backgroundColor = ‘blue’;true;’;

setTimeout(() => {
  this.webref.injectJavaScript(run);
}, 3000);

return (
  <View style={{ flex: 1 }}>
    <WebView
      ref={(r) => (this.webref = r)}
      source={{
        uri: 'https://github.com/react-native-webview/react-native-webview',
      }}
    />
  </View>
);

} }

Thanks @vikbos, good solution for this issue.

Here is my code.

import React, { useRef } from 'react'
import { WebView } from 'react-native-webview'

const INJECTED_JAVASCRIPT = `(function() {
  // your code
})();`

const YourScreen = ({ navigation }) => {
  const webview = useRef(null)
  
  const _handleLoadEnd = () => {
    webview.current.injectJavaScript(INJECTED_JAVASCRIPT)
  }
  
  return (
    <WebView
      javaScriptCanOpenWindowsAutomatically
      onLoadEnd={_handleLoadEnd}
      ref={webview}
      source={{ uri }}/>
  )
}

Don’t add property enableApplePay.

I was able to get this to work with functional components

Without the ref, for some reason injectedJavaScript will not run. With the ref set as webViewRef.current.injectJavaScript(runFirstScript); , injectedJavaScript will run as well.

 ...
 
   const runFirstScript = `
      document.body.style.backgroundColor = 'red';
      setTimeout(function() { window.alert('hi') }, 2000);
      true; // note: this is required, or you'll sometimes get silent failures
    `;

  webViewRef.current.injectJavaScript(runFirstScript);

  return (
    <>
      <WebView
        ref={ref => (webViewRef.current = ref)}
        cacheEnabled={true}
        //  injectedJavaScript={runFirstScript} // other script to run after entire webview has mounted
        javaScriptEnabled
        mixedContentMode={'compatibility'}
        onMessage={event => {
          //    alert(event.nativeEvent.data);
        }}
        originWhitelist={['*']}
        scalesPageToFit
        source={{uri: 'https://example.com'}}
        startInLoadingState={true}
        userAgent="Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.97 Safari/537.36"
      />
    </>
  );```

Could we close this issue now that I’ve created the more specific issue #1311 (which addresses the root cause) to track it instead?

Did not see this issue until just now, but this should be resolved in: https://github.com/react-native-community/react-native-webview/pull/1286

which is now in the latest release!

injectedJavaScriptBeforeContentLoad for Android is implemented in this PR; just need a maintainer to get some time to merge it: https://github.com/react-native-community/react-native-webview/pull/1099

Don’t get too excited though, as it’s a bit broken due to this issue, which may be far harder to solve: https://github.com/react-native-community/react-native-webview/issues/1250

This is not a regression; it’s long been the case that you’ve needed to pass onMessage in order for JS injection to work (and I’ve never liked it). It’s also actually documented, but admittedly hard to find.

Here’s my line-by-line explanation of how to fix it, in case anyone feels like implementing a PR: https://github.com/react-native-community/react-native-webview/issues/1260#issuecomment-607148843