question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Android: Vanilla android error page shown, despite setting renderError()

See original GitHub issue

Bug description:

When using WebView with Android, there is a basic Android error page shown, alongside the content returned by renderError.

class WebView extends React.Component<WebViewProps> {
  webViewRef = null;
  reload = () => {
    if (this.webViewRef) {
      this.webViewRef.reload();
    }
  };
  render() {
    const { source } = this.props;
    return (
      <RNWebView
        ref={webView => (this.webViewRef = webView)}
        source={{ uri: 'blablabla_not_a_real_domain' }}
        dataDetectorTypes="none"
        useWebKit
        renderLoading={() => (
          <CenteredBlock>
            <ActivityIndicator />
          </CenteredBlock>
        )}
        renderError={(error, code, description) => {
          let errorMessage;
          if (Platform.OS === 'ios') {
            errorMessage = description;
          } else {
            errorMessage = 'Something went wrong whilst loading this content.';
          }
          return (
            <CenteredBlock>
              <CenteredRow>
                <WarningIcon width={32} height={32} />
              </CenteredRow>
              <Body centered>
                {errorMessage}
              </Body>
              <CenteredRow>
                <TextLink title="Retry" onPress={this.reload} />
              </CenteredRow>
            </CenteredBlock>
          );
        }}
        startInLoadingState
      />
    );
  }
}

To Reproduce:

Expected behavior:

Render only the content returned by the renderError prop.

Screenshots/Videos:

image

Environment:

  • OS: MacOS / Android
  • OS version: Mojave / Nexus_5X_API_28_x86
  • react-native version: 0.58.6
  • react-native-webview version: 5.8.1

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:18

github_iconTop GitHub Comments

6reactions
cjpetecommented, May 11, 2019

Do you think it should return errorMessage without the vanilla android error page??

I don’t want this to be in the UI:

image

I would have expected that supplying a renderError prop would be a way to totally override any UI shown when there is an error.

5reactions
PrijalBistacommented, Oct 30, 2020

WorkAround For Now:

This issue still persists and Ive spent 1-2 days trying to find a decent solution. As mentioned above the only way to solve this for now (work around solution) is by sort of overlaying a loader during that short time period when android’s default error page is shown. The workaround that i have figured out is based of all the previous comments above. I am leaving it here in case others come looking for a good enough workaround to this: Create a loader (with absoluteFill because we need to overlap webview with this loader):

//components/loader.js
import * as React from 'react';
import { View, StyleSheet, ActivityIndicator } from 'react-native';

export default function Loader() {
  return (
    <View style={[StyleSheet.absoluteFill, styles.container]}>
      <ActivityIndicator size="large" color="#8ec641" />
    </View>
  );
}

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

Create a error page (also with absoluteFil as mentioned by @woodpav on previous comment in this thread here ). Here’s a simple error page:

//components/error.js
import * as React from 'react';
import { Text, View, StyleSheet, Image, Button } from 'react-native';

export default function Error({retryHandler}) {
  return (
    <View style={[StyleSheet.absoluteFill, styles.container]}>
      <Text style={styles.paragraph}>
        Ops! Something went wrong while loading content.
      </Text>
      <Button title="Retry" onPress = {() => {retryHandler()}} />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: 'white',
    alignItems: 'center',
    justifyContent: 'center',
    padding: 24,
  },
  paragraph: {
    margin: 24,
    fontSize: 16,
    color: 'red',
    opacity: 0.5,
    textAlign: 'center',
  }
});

Now the actual trick on hiding the screen very similar to @dorw123 in previous comment in this thread here We will use webview’s onLoadStart to show loader, and onLoadEnd to hide loader but the idea is use setTimeout to hide the loader after some amount of time. i.e For this we use a _loading state where we add our webview and use it to show hide loader. Here’s how i did it:

// App.js

import * as React from 'react';
import { View, Platform } from 'react-native';
import { WebView } from 'react-native-webview';
//
import Error from './components/Error';
import Loader from './components/Loader';

export default class App extends React.Component {
  constructor() {
    super();
  }

  state = {
    _loading: false,
  }

  webView = {
    canGoBack: false,
    ref: null,
  }

  _retry() {
    if(this.webView.ref) {
      this.webView.ref.reload();
    }
  }

  render() {
      let {  _loading } = this.state;
      return (
        <View style={{ flex:1 }}>
          <WebView
              source={{ uri: 'https://github.com' }}
 
             style={{ marginTop: 0 }}

              // set _loading state to true when loading starts
              onLoadStart = { () => {this.setState({_loading:true})} }

              onLoadEnd={(syntheticEvent) => {
                  // update component to be aware of loading status
                  const { nativeEvent } = syntheticEvent;
                  this.isLoading = nativeEvent.loading;
                  
                  // since this issue arise on android only. delay only on android platform
                  if(Platform.OS === 'android') {
                    // delay loader to hide default android webpage not available screen
                    setTimeout(() => {
                      this.setState({_loading:false})
                    }, 150);
                  } else {
                    this.setState({_loading:false})
                  }
              }}

              renderError={
                (errorName) => <Error retryHandler = {this._retry.bind(this)}/>
              }

              ref={(webView) => { this.webView.ref = webView; }}
            />
          {_loading && <Loader/> }
        </View>
      );
  }
}

Feel free to copy and test it out for yourselves. This workaround works for now and u can change the 150 on setTimeout() to any preferable value if u like. If there’s any issue regarding this solution please let me know. 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

Remove android default error page on react native webview
My solutions is Alert function import React, { Component } from 'react'; import { Alert } from 'react-native'; import { View, Spinner }...
Read more >
Android WebView Example Tutorial - DigitalOcean
Android WebView is used to display HTML in an android app. We can use android WebView to load HTML page into android app....
Read more >
Scala Enterprise Update Notes - ENT - Scala Docs
This page covers the Release and Update Notes for all releases in the Scala Enterprise 10 Series and 11 Series. The label "(Notable)"...
Read more >
How to fix rendering problem in Android Studio - Quora
Hence the UI render produces error rendering the new UI elements classes. Just clean your project by Build -> clean project. Then again...
Read more >
How to Solve Android's 13 Most Common Error Messages
Testing is a crucial part of Android development, allowing you to iron out all ... In the window that appears, click Show Advanced...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found