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

injectedJavaScript doesnt seem to work on IOS #1291

Closed
TylerNRobertson opened this issue Apr 3, 2020 · 15 comments
Closed

injectedJavaScript doesnt seem to work on IOS #1291

TylerNRobertson opened this issue Apr 3, 2020 · 15 comments

Comments

@TylerNRobertson
Copy link

TylerNRobertson commented Apr 3, 2020

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
@tdcook
Copy link

tdcook commented Apr 4, 2020

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.

@TylerNRobertson
Copy link
Author

@tdcook that seems to have fixed the IOS issue but now the main issue is Android & IOS can only access whats injected at seperate times. window.onload works for IOS to try and get the values but when put into android it only returns undefined. "injectedJavaScriptBeforeContentLoad" seems like a requirement almost for both platforms, is there a way to simulate this since its not built in?

@shirakaba
Copy link
Contributor

shirakaba commented Apr 8, 2020

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: #1260 (comment)

@shirakaba
Copy link
Contributor

shirakaba commented Apr 8, 2020

injectedJavaScriptBeforeContentLoad for Android is implemented in this PR; just need a maintainer to get some time to merge it: #1099

Don’t get too excited though, as it’s a bit broken due to this issue, which may be far harder to solve: #1250

@songxiaoliang
Copy link

@shirakaba thanks, Looking forward to the merger and normal use of this module

@SRandazzo
Copy link
Contributor

Did not see this issue until just now, but this should be resolved in: #1286

which is now in the latest release!

@swallville
Copy link

Someone could provide a minor gist or working example to simply change the background color?

@shirakaba
Copy link
Contributor

@swallville that's already documented here in the "Communicating between JS and Native" guide, which is linked off to by the API docs for injectedJavascript.

@shirakaba
Copy link
Contributor

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

@github-actions
Copy link

github-actions bot commented Jun 9, 2020

Hello 👋, this issue has been opened for more than 2 months with no activity on it. If the issue is still here, please keep in mind that we need community support and help to fix it! Just comment something like still searching for solutions and if you found one, please open a pull request! You have 7 days until this gets closed automatically

@PrantikMondal
Copy link

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}/>

@vikbos
Copy link

vikbos commented Nov 11, 2021

@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>
);

}
}

@geiz
Copy link

geiz commented Nov 29, 2021

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"
      />
    </>
  );```

@aaronetto
Copy link

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.

@ujanggmisbah
Copy link

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"
      />
    </>
  );```

thank you very much this code is running fine in my app

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