5

It seems WebView plays a similar role of web workers for react-native.

I am trying to offload heavy data fetch to a WebView but it seems very painful and could not find a fetch example with WebView.

So I have below JavaScript code with which I am trying to call the API.

When using the exact same code from a regular react-native class, the JSON response is perfectly fetched and parsed.

But when the same JavaScript code is injected into a WebView with injectJavaScript method, the Content-Type value causes the problem. (When I remove it, I see from the backend that the call is made but I can not get the JSON data at the frontend - WebView side-.)

It seems it is related to cors even though the API backend allows all cross-origin requests.

As a result, my questions are:

  1. What is a proper way to use fetch with WebView in react-native?
  2. Why the behaviour is different between react-native and WebView?
var l_headers = {
   Accept: 'application/json',
   'Content-Type': 'application/json'
};
var l_init = {
    method: "POST",
    headers: l_headers,
    body: {}
};
fetch("http://172.20.10.12:8000/test", l_init).then(function (response) {
    return response.json();
}).then(function (responseJson) {
    alert('API called: ' + JSON.stringify(responseJson));
});

PS: One final handicap, please note that I am also using EXPO and not able to eject because of its benefits. That is why I can not use react-native-community's react-native-webview as of today. (It seems in future this will be adapted for EXPO).

Mehmet Kaplan
  • 1,723
  • 2
  • 20
  • 43

1 Answers1

5

Update
Following code snippet, I am fetching JSON through POST fetch and once fetched the response gets shown inside alert. Here is a working Snack Expo Link.

  injectjs() {
    let jsCode = `const bodyData = JSON.stringify({
      title: 'foo',
      body: 'bar',
      userId: 1
    });
    fetch('https://jsonplaceholder.typicode.com/posts', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
      },
      body: bodyData,
    }).then(response => response.text()).then(valueText => {
      alert(JSON.stringify(valueText));
    });`;
    return jsCode;
  }

  render() {
    return (
      <View style={styles.container}>
       <WebView
          ref={webview => { this.webview = webview; }}
          source={{
            uri: "https://www.google.com"
            }}
            injectedJavaScript={this.injectjs()}
            javaScriptEnabled = {true}
            style={styles.webview}
          />
      </View>
    );
  }

Old Answer
I usually use postMessage in ReactNative WebView when I need to communicate between HTML and react native code.

  • HTML code to send message to react native
    postMessage(JSON.stringify(yourJson), '*');
  • Receive message from react native

    document.addEventListener('message',(event) => {
    eval(event, data)
    }, false)

  • React Native WebView
    <WebView
           ref={webview => { this.webview = webview; }}
           source={anySource}
           injectedJavaScript={script}
           javaScriptEnabled = {true}
           onMessage={this.onMessage}
           onNavigationStateChange = {this.handleNavigation}
         />
  • Receive message

    onMessage = (e) => {
     let { data } = e.nativeEvent; // data you will receive from html
    }

  • To post message
    this.webview.postMessage('YourMessage')

If postMessage doesn't work in expo you can use onShouldStartLoadWithRequest / onNavigationStateChange method instead.

    handleNavigation = (event) => {
        const url = event.url;
        const sections = url.split('#');
        if(sections.length > 1 && sections[1].indexOf('message=') != -1) {
           const message = sections[1[.replace('message=', '');
           //Do any action with message
           return;
        }
        //Other navigation actions
      }
Jerin
  • 3,657
  • 3
  • 20
  • 45
  • Thanks for the answer Jerin but unfortunately this is not the question. The question is about using ‘’’fetch’’’ method with POST and headers in WebView. – Mehmet Kaplan Feb 27 '19 at 05:56
  • I updated answer with a hack which basically loads the response as local HTML instead. – Jerin Feb 28 '19 at 07:06
  • I appreciate the effort. Problem seems not in the formation of the WebView. I pasted the whole class here: https://www.codepile.net/pile/R5ZAKA2v . The problem seems WebView can not make fetch call at all. In order to give a clue, if I change the baseUrl with "uri" then the response html is rendered. But this is plain page get. What I need is to POST my data and get JSON response. – Mehmet Kaplan Feb 28 '19 at 12:53
  • @MehmetKaplan I updated the answer to meet your requirement of using a POST fetch through an injectedJavaScript inside webview. I based in on the code snippet that you shared also attaching a working snack expo link. – Jerin Mar 01 '19 at 11:17
  • the answer is convincing that it definitely works. Thank you very much. It seems my problem is at backend. Even though my ExpressJS application is enabled by app.use(cors()); app.options('*', cors()); app.all('/test', (req, res) => rh.testConnection(req, res)); It still does not accept the request hence does nothing. – Mehmet Kaplan Mar 02 '19 at 12:22
  • 1
    And final quote, the connection problem is also solved. It seems WebView does not allow insecure resources if the url was secure. As stated here https://stackoverflow.com/questions/32456848/ios9-does-not-load-insecure-resources-from-a-secure-page-ssl-https . In order to resolve I removed the https URI and placed a dummy html. Thanks again, I think this can be closed now. – Mehmet Kaplan Mar 02 '19 at 14:18
  • Glad you solved it @MehmetKaplan . Also sorry for the confusion earlier. In my rush, I didn't realize that `injectedJavaScript` method was what you were looking for in particular. – Jerin Mar 02 '19 at 15:12
  • @Jerin, In my code the json code show in alert, but my question is how can I get this result in my class variable ? – Pankaj Sonava Dec 24 '20 at 13:41
  • @PankajSonava I didn't get your question. Instead of alert you can replace it with your code updation code. – Jerin Feb 07 '21 at 17:29