3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ReactNativeアプリにて、WebView+ReactNavigationを利用するとクラッシュする問題の回避策

Posted at

概要

2022/9時点で、特定のAndorid(確認したのは、Android9)において、WebViewをマウントした画面から、ReactNavigationを使った画面遷移を行うとクラッシュする問題がある。
(navigationの遷移アニメーション機能と WebViewのレンダリング機能が競合している?)

本記事は、試行錯誤した結果動いた方法と失敗した方法をまとめた備忘録です。

環境

  • ReactNative : v.0.69.3
  • react-native-webview : v.11.23.0
  • ReactNavigation : v.5.9.8

参考

ベースとなるコード

例として、ボタンをクリックすると、StackNavigatorによってDetailPageに飛ぶ画面を作成。
画面はWebViewコンポーネントをマウントしていることとする。

const WebViewSample: React.VFC<Props> = (props) => {
  const param: string = props.param;
  // ボタンタップで別ページに遷移
  const goNextPage = useCallback(() => {
    navigation.navigate("DetailPage", {param});
    }
  }, [param]);
  // WebViewコンポーネントをマウント
  return (
    <View>
      <MyButton onClick={goNextPage}/>
      <WebView
        source={hoge}
        ...
      />
    </View>
  )
}

結論

ReactNavigationのhookを利用し、画面にフォーカスされた時 or 外れた時に、WebViewコンポーネントをアンマウントすることで回避。
→ フォーカスON/OFFの判定には、ReactNavigationのuseFocusEffectを利用する。

また、遷移先画面から「戻る」場合、再度WebViewコンポーネントをマウントするとクラッシュする。
そこで、「戻る」場合は、一定時間待ち合わせてからマウントすることで回避。待ち合わせには、setTimeoutを利用するため、副作用hookを活用する。(なぜ副作用hookを使うか?などは、他の方々の記事参照のこと。本記事では割愛)

import { useFocusEffect } from "@react-navigation/native";

const WebViewSample: React.VFC<Props> = (props) => {
  const param: string = props.param;
  const [isShow, setIsShow] = useState<boolean>(false);

  useFocusEffect(
    useCallback(() => {
      //focus後、1秒後にWebViewをマウント
      const timeout = setTimeout(() => {
        setIsShow(true);
      }, 1000);
      // focusが外れた際は、WebViewコンポーネントをunmountする
      return () => {
        clearTimeout(timeout);
        setIsShow(false);
      };
    }, [])
  );

  // ボタンタップで別ページに遷移
  const goNextPage = useCallback(() => {
    navigation.navigate("DetailPage", {param});
    }
  }, [param]);
  // WebViewコンポーネントをマウント
  return (
    <View>
      <MyButton onClick={goNextPage}/>
      // isShowフラグによってmount or unmount制御
      {isShow && <WebView
        source={hoge}
        ...
      />
      }
    </View>
  )
}

試行錯誤したものたち

WebViewのstyleで回避してみる

Webviewのstyleとして、opacity: 0.99, overlay: "hidden"を指定

<WebView style={opacity: 0.99, overlay: "hidden"}>
  source={hoge}
  ...
</WebView>

→ クラッシュは直らず。また画面崩れも発生したので見送り

WebViewのpropsに androidLayerType="software"指定

<WebView>
  androidLayerType="software"
  source={hoge}
  ...
</WebView>

→ WebView自体表示されなくなったので見送り

Manifestにて、hardwareacceleratedをオフにする

// AndroidManifest.xml
    <application android:hardwareAccelerated="true" ...>

→ WebView自体表示されなくなったので見送り

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?