Home » Android » javascript – Debugging WebView in React Native apps

javascript – Debugging WebView in React Native apps

Posted by: admin April 23, 2020 Leave a comment

Questions:

I have a React Native App that uses WebView to render an HTML page from the assets. The page has some javascript that does some processing. The problem is that I cannot see the console.log statements from the web view. I have tried the Chrome Remote Remote Debugging WebViews

Here’s how the code looks like. Note that for Android, I am trying to supply some native props to enable debugging.

import React from 'react';
import Expo from 'expo';
import { WebView } from 'react-native';

export default class App extends React.Component {

  render() {
    const htmlURL = Expo.Asset.fromModule(require('./assets/index.html')).uri;
    return (
      <WebView nativeConfig={{props: {webContentsDebuggingEnabled: true}}}  
      source={{uri: htmlURL}} />
    );
  }
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});

Any ideas around how that might work will be highly appreciated.

How to&Answers:

The easiest way to inspect your WebView in React Native is to just use the Remote JS Debugger. This has the added benefit for working in either iOS or Android, since you’re simply debugging the JavaScript that is running on your application.

In order to see the WebViews, you’ll want to go a step further and use Chrome’s Remote Devices.

DevTools Chrome

If you click on Inspect next to your Document matching the index.html you’re wanting to debug, you can then see all of the logs in the console for that WebView.

enter image description here

I added a <script> inside of index.html in the <header> that just does the following:

console.log('This is showing in the console!')

You can see in the image above, its logging out in the DevTools that is inspecting that WebView.

Answer:

Not sure if it’s relevant for your case, but if you’re also developing for iOS there’s a pretty easy way to do it on a Mac + iOS simulator (or a real device). At the end, a React Native WebView creates a native web-view (UIWebView on iOS, and a WebView on Android), so any debugging method which works for web apps applies here as well.

  1. On your iOS simulator (or device): Open the settings app -> Safari -> Advanced -> Turn Web inspector ON.
  2. Open Safari on your Mac and enable developer mode in: Preferences -> Advanced -> Show developer menu in menu bar (checkbox at the bottom).
  3. In Safari on your mac you will now have the “Develop” menu. Open it and find the Simulator or your connected device. When you hover this menu item you will see the currently loaded page. This works for any page loaded on the device, whether it’s shown in a WebView inside your app or on the system browser.
  4. Once you select the page, you can use the Safari Web Inspector to pretty much do anything: view all loaded resources, network requests, highlight elements, console logs, debug the JS code and more.

Answer:

I propose to unify javascript's console messages (console.log) and logcat of Android into one logcat which can be viewed with [Monitor].(https://developer.android.com/studio/profile/am-basics.html). It can be helpful to have console messages and WebView messages in one place, especially when you have race conditions/timing problems, so you can see the order of events. Monitor also allows you to apply filters, to select which messages you see. iOS users can also fond this helpful.

Here is an example:
enter image description here
See CustomWebViewManager and CustomWebView in React Native for some background on how to customize WebView in React Native (a JavaScript library for building user interfaces. “It is maintained by Facebook, Instagram and a community of individual developers and corporations” wiki ).

Info: WebChromeClient lets you handle Javascript's console.log("message")
{via onConsoleMessage(ConsoleMessage cm)}, alert() and other functions.

Catching JavaScript’s console messages:

//find or get your React Native webView or create a CustomWebView
WebView webView = (WebView) this.findViewById(R.id.webView1);

//by setting a WebClient to catch javascript's console messages:
// and relay them to logcat (view in monitor) or do what you want with them
WebChromeClient webChromeClient = new WebChromeClient() {
        public boolean onConsoleMessage(ConsoleMessage cm) {
            Log.d(TAG, cm.message() + " -- From line "
                    + cm.lineNumber() + " of "
                    + cm.sourceId() );
            return true;
        }
    });

webView.setWebChromeClient(webChromeClient);

The problem with cross platform support is the Virtual Machine and the associated Sandbox.
I think react-native tries to be very pure JavaScript (but fails, JavaScript as a language is pure, the implementations never are, always about compromise). My personal preference for cross platform support is Cordova.

Answer:

You can make use of window.postMessage from inside your WebView and the onMessage prop of the WebView component:

In your html:

...
window.postMessage(stringMessage, '*');
...

In your react native component:

import React from 'react';
import Expo from 'expo';
import { WebView } from 'react-native';

export default class App extends React.Component {
  handleMessage = (event) => {
     console.log(event.nativeEvent.data);
  }
  render() {
    const htmlURL = Expo.Asset.fromModule(require('./assets/index.html')).uri;
    return (
      <WebView nativeConfig={{props: {webContentsDebuggingEnabled: true}}}  
      source={{uri: htmlURL}}
      onMessage={this.handleMessage}
      />
    );
  }
}


const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});