使用 <HTML /> 渲染 iframe 时,Android 在导航回堆栈屏幕时崩溃



当在react-native-screens中启用屏幕,并且屏幕呈现带有iframeHTML元素的<HTML />组件时,应用程序在按下后退按钮返回主屏幕时崩溃。此处为完整复制。

环境

  • React Native:0.61.5
  • react native render html:4.2.2
  • react原生webview:10.3.2
  • react原生屏幕:2.8.0
  • react native render html表桥:0.6.1

故障日志

07-29 17:41:49.173  6901  6901 F crashpad: dlopen: dlopen failed: library "libandroidicu.so" not found: needed by /system/lib/libharfbuzz_ng.so in namespace (default)
--------- beginning of crash
07-29 17:41:49.176  6410  6441 F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x1c in tid 6441 (RenderThread), pid 6410 (com.newmednav)
07-29 17:41:49.340  6904  6904 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
07-29 17:41:49.340  6904  6904 F DEBUG   : Build fingerprint: 'google/sdk_gphone_x86_arm/generic_x86_arm:11/RPB2.200611.009/6625208:userdebug/dev-keys'
07-29 17:41:49.340  6904  6904 F DEBUG   : Revision: '0'
07-29 17:41:49.340  6904  6904 F DEBUG   : ABI: 'x86'
07-29 17:41:49.340  6904  6904 F DEBUG   : Timestamp: 2020-07-29 17:41:49+0545
07-29 17:41:49.340  6904  6904 F DEBUG   : pid: 6410, tid: 6441, name: RenderThread  >>> com.newmednav <<<
07-29 17:41:49.340  6904  6904 F DEBUG   : uid: 10152
07-29 17:41:49.340  6904  6904 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x1c
07-29 17:41:49.340  6904  6904 F DEBUG   : Cause: null pointer dereference
07-29 17:41:49.340  6904  6904 F DEBUG   :     eax efbc2cb0  ebx eed5c69c  ecx eed52a80  edx 00000000
07-29 17:41:49.341  6904  6904 F DEBUG   :     edi d139ae90  esi 00000000
07-29 17:41:49.341  6904  6904 F DEBUG   :     ebp c086ed48  esp c086eb50  eip ee698c1c
07-29 17:41:49.425  6904  6904 F DEBUG   : backtrace:
07-29 17:41:49.425  6904  6904 F DEBUG   :       #00 pc 00247c1c  /system/lib/libhwui.so (android::uirenderer::skiapipeline::GLFunctorDrawable::onDraw(SkCanvas*)+1548) (BuildId: 434a9b68672e1dd2b15599730362463d)
07-29 17:41:49.425  6904  6904 F DEBUG   :       #01 pc 00303a57  /system/lib/libhwui.so (SkDrawable::draw(SkCanvas*, SkMatrix const*)+87) (BuildId: 434a9b68672e1dd2b15599730362463d)
07-29 17:41:49.425  6904  6904 F DEBUG   :       #02 pc 002f4606  /system/lib/libhwui.so (SkBaseDevice::drawDrawable(SkDrawable*, SkMatrix const*, SkCanvas*)+38) (BuildId: 434a9b68672e1dd2b15599730362463d)
07-29 17:41:49.425  6904  6904 F DEBUG   :       #03 pc 00659291  /system/lib/libhwui.so (SkGpuDevice::drawDrawable(SkDrawable*, SkMatrix const*, SkCanvas*)+353) (BuildId: 434a9b68672e1dd2b15599730362463d)
07-29 17:41:49.425  6904  6904 F DEBUG   :       #04 pc 002d9dc0  /system/lib/libhwui.so (SkCanvas::onDrawDrawable(SkDrawable*, SkMatrix const*)+48) (BuildId: 434a9b68672e1dd2b15599730362463d)

这是由react-native-webviewreact-native-screens之间的不兼容引起的,如果使用@react-navigation/*包,则必须依赖于此。

编辑:此后似乎出现了倒退。这里正在追踪它。

固定在react-native-screens@2.12.0

请参阅中的CHANGELOGhttps://github.com/software-mansion/react-native-screens/releases/tag/2.12.0

如果不能升级reat-native屏幕

有3种解决方法:

webview不透明度

const tagsStyles = {
iframe: {
opacity: 0.99
},
// If you are using @native-html/table-plugin
table: {
opacity: 0.99
}
}

在渲染时使用此道具:

return <HTML tagsStyles={tagsStyles} ... />

禁用硬件加速

android/app/src/main/AndroidManifest.xml:中

<activity
android:hardwareAccelerated="false"
/>

禁用本机屏幕从您的App.js文件:

// import {enableScreens} from 'react-native-screens';
// enableScreens();

另一个修复方法是在navigationOptions中禁用反应导航的动画。

static navigationOptions = () => ({
animationEnabled: false,
});

另一个解决方法是在htmlProps内部的webViewProps中添加androidLayerType: 'software',该方法将传递给渲染HTML表,如下所述。

const webViewProps = {
androidLayerType: 'software',
}
const htmlProps = {
WebView,
renderers: {
table: TableRenderer,
},
renderersProps: {
table: {
cssRules,
webViewProps,
computeContainerHeight() {
return null
},
},
},
customHTMLElementModels: {
table: tableModel,
},
}

https://github.com/react-navigation/react-navigation/issues/6960#issuecomment-587418809

更新的解决方案是androidLayerType="软件">,因为androidHardwareAccelerationDisabled现在已被弃用。

例如:-

<AutoHeightWebView
androidHardwareAccelerationDisabled // update here androidLayerType="software"
...
/>

对我来说,这个错误是由社交媒体iframe触发的。应用style = {{ opacity: 0.99 }}是唯一对我有用的东西:

<WebView
useWebKit={true}
scrollEnabled={false}
scalesPageToFit={true}
source={{ html: html }}
javaScriptEnabled={true}
bounces={false}
overScrollMode={'never'}
pagingEnabled={true}
style={{ opacity: 0.99 }} //<---------
/>

来源:https://github.com/react-native-webview/react-native-webview/issues/811

禁用屏幕的导航动画对我很有效。我刚刚为导航器添加了animation: 'none',屏幕选项,如下所示。

const StackNavigator = props => {
return (
<Stack.Navigator  
screenOptions={{
animation: 'none', // <-- Add this.
}}
>
// ...
</Stack.Navigator>
);
};

附言:我还尝试了其他选项,如

  1. WebViewopacity设置为0.99
  2. WebView的父View设置renderToHardwareTextureAndroid={true}
  3. WebViewandroidLayerType属性设置为"software"
  4. 通过设置android:hardwareAccelerated="false"禁用android/app/src/main/AndroidManifest.xml<activity>中的硬件加速

1和2没有用处,3和4虽然有用,但也倾向于只播放音频并显示空白黑屏

因此,我发现为导航器设置animation: 'none',屏幕选项是最有用的这是我使用的iFrame

<iframe 
width="853" 
height="480" 
src="https://www.youtube.com/embed/jbnUQ-o381k" 
title="WAI WAI QUICK PYRO COMEDY CLUB WITH CHAMPIONS | EPI 52 | Bijay Baral, Bhola Raj Sapkota" 
frameborder="0" 
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" 
allowfullscreen
></iframe>

我在这个问题上挣扎了很长时间。问题似乎出在iframe被渲染时,而stack.navigation中的动画仍在进行中。对我来说,最简单的解决方案是阻止iframe渲染,直到导航的动画完成。stack.navigator对此有一个事件。(transitionEnd(。为了实现这一点,你可以简单地做一些这样的事情:

const [finishedTransition, setFinishedTransition] = setState(false)
React.useEffect(() => {
const unsubscribe = navigation.addListener('transitionEnd', (e) => {
setFinishedTransition(true)
});
return unsubscribe;
}, [navigation]);
return(
<>
{finishedTransition ? <Html with iframe/> : null}
</>
)

最新更新