在React Native WebView上删除Android默认错误页面

时间:2019-04-03 07:51:14

标签: android react-native android-webview

我在React Native中使用的是Webview,并且想要在发生某些错误(例如,没有互联网连接)时显示自定义错误消息。

我的代码:

<WebView 
  renderError={() => (
    <MissingConnection />
  )}
  other params....
/>

加载网页时出错,一秒钟之内,Webview就会显示默认的android错误,例如: enter image description here 然后我的MissingConnection组件会弹出,隐藏Web视图。

有没有办法完全删除默认的android错误屏幕?它只闪烁一秒钟,结果感觉确实不对。

3 个答案:

答案 0 :(得分:1)

首先:您做对了

我最近发现了同样的问题,并做了一些调查。问题不在于您的代码,React Native或react-native-webview

这只是Android WebView的默认行为。许多Java开发人员都遇到相同的问题,例如SO上相关线程的示例:

webview error while loading a page without internet

Prevent WebView from displaying "web page not available"

Android WebView onReceivedError()

通常可以解决的建议是:

  • 在尝试加载任何内容之前检查Internet连接(防止失败)

  • 快速删除错误内容,并在onReceivedError中显示您自己的内容(该内容基本上映射到renderError中的react-native-webview方法)。有时会像Java here一样加载本地URL。

  • 请确保有一个覆盖层,以防万一没有错误。 react-native-webview反之,在出现错误时显示覆盖。但是活动指示器覆盖图是一个很好的例子,它表示直到加载完成或遇到错误。

据我所知,除了这些令人失望的方式外,我们无能为力,因为我宁愿不与系统抗争。

编辑:Android的Firefox Focus与快速替换错误处理程序中的内容相同。

这是在Java的源代码中完成的:

https://github.com/mozilla-mobile/focus-android/blob/c789362b9c331b2036755a8398e3770be43b50b8/app/src/main/java/org/mozilla/focus/webview/FocusWebViewClient.java#L330

https://github.com/mozilla-mobile/focus-android/blob/63339d2d9a5d132bf4a1fffc4c46c0ce393abe87/app/src/main/java/org/mozilla/focus/webview/ErrorPage.java#L126

所以我认为我们在一起很好!

编辑2 :我很好奇,如果在真正的Android设备上未处于调试模式时,此显示是否确实可见。我的有根据的猜测是该代码的执行速度更快,并且根本不可见。顺便说一下,此页面可能仅显示404(未找到)错误,如果您使用硬编码的URL和您自己的服务器,则不太可能出现。

编辑3 :可见本机错误页面 在发布模式下的真实设备上运行。防止这种闪烁的唯一方法是创建一个覆盖图。我打开了一个与另一个错误相关的问题,该错误在https://github.com/react-native-community/react-native-webview/issues/474#issuecomment-487022106react-native-webview处也解决了。

答案 1 :(得分:1)

我的解决方案是警报功能

import React, { Component } from 'react';
import { Alert } from 'react-native';
import { View, Spinner } from 'native-base';
import { WebView } from 'react-native-webview';

export default class ExampleScreen extends Component {

  displaySpinner() {
    return (
      <View style={{ flex: 1 }}>
        <Spinner color="blue" />
      </View>
    );
  }

  displayError() {
    Alert.alert(
      "no_internet",
      "require_internet_connection",
      [
        { text: 'OK', onPress: () => this.props.navigation.goBack() },
      ],
      { cancelable: false });
  }

  render() {
    return (
      <WebView onError={() => this.displayError()}
        startInLoadingState={true}
        renderLoading={() => {
          return this.displaySpinner();
        }}
        source={{ uri: 'https://example.com' }} />
    );
  }
};

enter image description here

答案 2 :(得分:0)

实际上,就我而言,这种解决方案很奏效

import React, { useEffect, useRef } from 'react';
import { StyleSheet, View, BackHandler } from 'react-native';
import { colors, variables } from 'utils/theme';
import { WebView } from 'react-native-webview';
import { Button, Spinner, Text } from 'components';
import { fa } from 'utils/constants/locales';

const uri = YOUR_WEB_PAGE_URL

const Loading = () => {
  return (
    <View style={styles.loadingWrapper}>
      <Spinner />
      <Text style={styles.loading}>{fa.proEducation.loading}</Text>
    </View>
  );
};
const Error = ({ reload }) => {
  return (
    <View style={styles.loadingWrapper}>
      <Button
        style={styles.retry}
        label={fa.proEducation.retry}
        primary
        onPress={reload}
      />
    </View>
  );
};

const ProEducation = () => {
  const webview = useRef(null);
  const canGoBackRef = useRef(false);
  const onAndroidBackPress = () => {
    if (canGoBackRef.current && webview.current) {
      webview.current.goBack();
      return true;
    }
    return false;
  };
  useEffect(() => {
    BackHandler.addEventListener('hardwareBackPress', onAndroidBackPress);
    return () => {
      BackHandler.removeEventListener('hardwareBackPress', onAndroidBackPress);
    };
  }, []);
  const onNavigationStateChange = ({ canGoBack }) => {
    canGoBackRef.current = canGoBack;
  };
  const reload = () => webview.current.reload();

  return (
    <View style={styles.wrapper}>
      <WebView
        ref={webview}
        source={{ uri }}
        style={styles.webView}
        onNavigationStateChange={onNavigationStateChange}
        javaScriptEnabled
        domStorageEnabled
        renderLoading={() => <Loading />}
        renderError={() => <Error reload={reload} />}
        startInLoadingState
      />
    </View>
  );
};

const styles = StyleSheet.create({
  loading: {
    color: colors.lightBlack,
    fontSize: 15,
    marginTop: 8,
    textAlign: 'center',
  },
  loadingWrapper: {
    backgroundColor: colors.white,
    bottom: 0,
    flex: 1,
    justifyContent: 'center',
    left: 0,
    marginBottom: 'auto',
    marginLeft: 'auto',
    marginRight: 'auto',
    marginTop: 'auto',
    position: 'absolute',
    right: 0,
    top: 0,
  },
  retry: {
    alignSelf: 'center',
    paddingHorizontal: variables.gutter,
    paddingVertical: variables.gutter / 2,
  },
  webView: {
    flex: 1,
  },
  wrapper: {
    backgroundColor: colors.bg,
    flex: 1,
  },
});

export default ProEducation;