React Native: Android WebView returns blank screen for some websites and some devices

Viewed 9307

I've got a working react-native app for quite a few months with a WebView directing to an HTTPS site. This was all working great, but suddenly the WebView start returning a blank page instead of the HTTPS site.

From debugging, I've found out that:

  • This happens only on my device (non of my users have reported this issue)

  • Blank screen is returned for some websites, and for some it renders correctly. (e.g. google.com would render and amazon.com would return a blank screen)

  • From debugging the WebView in chrome inspector it seems like every time a GET call has been made to one of theses sites (e.g. amazon.com) the call gets cancelled after 1 second or so.

  • These sites are called, opened and rendered correctly on my android-chrome browser.

Seems like something in my devices is blocking some websites in WebViews, perhaps a settings, or an app. What could it be?

I'm using LG G4, tried on API version 19 and 23.

3 Answers

Here's what worked for me.

For me it became evident that my certificate was not trusted. In my case this problem could be solved by adding the missing intermediate certificates on the misconfigured server itself. Unfortunately, since I did not have the needed access, I decided to see if it would be possible to implement a workaround.

Here are the details:

  • My path looked like /project_root/android/app/src/main/res/xml/network_security_config.xml after creating the necessary folders.

Here's what the contents of the file looked like:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <trust-anchors>
            <certificates src="@raw/my_ca"/>
        </trust-anchors>
    </domain-config>
</network-security-config>

I replaced "example.com" in the above code sample my problem domain.

  • Next I opened the problem domain in my web browser and downloaded the certificate to my machine.

In Chrome on a Mac you click the lock icon next to the domain, then on "Certificate" and drag the certificate icon to a local directory. This will transfer a DER encoded binary.

In Chrome on Windows you click the lock icon next to the domain, then on "Certificate", then on the "Details" tab and finally "Copy to File" bottom right. Select the DER version when exporting.

  • For the next step I found that I needed to use OpenSSL.

To check if you have it intalled type

openssl version

If that fails you can install it on a Mac with

brew install openssl

For Windows instructions are here: https://slproweb.com/products/Win32OpenSSL.html

  • With OpenSSL ready, in a Terminal/CLI window I converted the file to PEM with
openssl x509 -in downloaded_cert.cer -inform DER -out my_ca.pem -outform PEM
  • I moved the resulting my_ca.pem to /project_root/android/app/src/main/res/raw/my_ca.pem after creating the necessary folders.

  • Finally in /project_root/android/app/src/main/AndroidManifest.xml I added android:networkSecurityConfig="@xml/network_security_config" to the application element similar to this:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>

oh,yeah,It runs successfully.

<View style={{ height: 150, width: 150,overflow:'hidden' }}>
            <WebView
              source={{ uri: 'https://github.com/facebook/react-native' }}
              scalesPageToFit={true}
            />
</View>
Related