React Native WebView踩坑记

作者: ronniegong | 来源:发表于2016-10-26 14:19 被阅读7166次

    React Native WebView踩坑记

    在使用React Native开发应用时,有些第三方的页面需要在WebView中展示,最初使用WebView展示几个简单的广告推广页时,没有遇到什么问题。随着使用深入,遇到React Native WebView组件的几个问题,一番探索,终于明白了问题点。

    React Native Android WebView body height 100%

    遇到这个问题是在使用0.30版本时,在该版本下有一个外部业务的页面在我们的WebView展示时渲染不出来,表现为页面是一个空白页。

    通过观察日志、断点调试也没有看到什么错误信息提示。

    遇到这种问题,思路是首先搜索官方issues,经过搜索,果然发现已有issue
    https://github.com/facebook/react-native/issues/5211

    下面的讨论中,有人提到了Android端WebView对height 100%的样式不能识别,当页面body设置height 100%时,在WebView中会为页面body设置height 0,因此页面渲染为空白页。

    有了这个提示,打开chrome://inspect开始调试当前WebView,经过审查工具查看样式,发现确实这一页面为body设置了height 100%。幸好WebView允许我们向页面注入js代码,于是可以通过向页面注入下列代码解决

    const jsForInjection = `
      var el = document.getElementsByTagName('body')[0];
      el.style.height = '${Dimensions.get('window').height}px';
    `
    

    跟进React Native release notes发现,在0.32版本,修复了这一缺陷,链接https://github.com/facebook/react-native/commit/1bb1385c7d199a473f76cdec357de2ab4d1d61b6

    React Native Android&iOS WebView view height 100%

    看到前文提到的官方说明,提到已修复这一缺陷还没高兴多久。又遇到了另一个问题。在另一个业务的页面中,使用了比较复杂的布局方式,在页面内容的某一个子区域,又使用了height 100%这种布局。

    这一次不只是Android了,iOS的WebView也不能正确解析这一样式,使用height 100%布局的这一个子区域渲染为空白区域。

    这里没有通用的解决方式了,其他业务如果可以去修改自身的样式布局当然是最好。更实际的解决方案,是发现一例,解决一例。

    以这里遇到的一个页面为例,通过chrome://inspect定位到具体是哪一个区域的问题后,通过注入js,定向的修改这一样式。

    这是一个没有办法的办法了。

     var licaiapp = document.getElementsByClassName('hero-product')[0];
      if(licaiapp){
      licaiapp.style.height = '542px';
      }
    

    React Native Android 私有协议 crash

    在网页中使用js通过私有协议调起外部App,这种方式对大家来说应该不会陌生。

    在Android 0.30版本的使用中,这里没遇到问题,但是升级到0.35版本后,发现在用户没有安装App A时,在WebView加载的页面中,通过私有协议调起App A时,会导致App crash。

    通过查看Android Studio日志,发现下面异常信息

    No Activity found to handle Intent { act=android.intent.action.VIEW dat=investapp://webend-promotion flg=0x10000000 }
    

    根据这一异常信息,查看安装端ReactWebViewManager源码,发现问题的根源在于下面方法

    @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            if (url.startsWith("http://") || url.startsWith("https://")) {
              return false;
            } else {
              Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); 
              intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
              view.getContext().startActivity(intent);   
              return true;   
            }              
        }
    

    React Native 0.31版本开始,在ReactWebViewManager中增加了上述方法,加载私有协议时,通过else中的逻辑调起App。问题是这里代码,在用户未安装这一App,startActivity不能被正确响应时会抛出Exception,而代码的调用处又没有try/catch,因此导致了crash

    给官方提了issue,不过很快被close说觉得不是RN的问题。。。
    https://github.com/facebook/react-native/issues/10499

    看其他issue也有提到这个bug,不再去修改问题了。

    解决办法,基于官方的ReactWebViewManager做下修改吧,然后封装一个自定义WebView出来给JS端调用。

    React Native iOS 私有协议问题

    在iOS模拟器加载一个外部业务的页面时,遇到一个奇怪的问题。业务的页面,首先在WebView里渲染出来,然后又跳去了默认失败界面,如下图所示

    起初一直没理解到底是什么问题,实际上已有issue说的还算明白了
    https://github.com/facebook/react-native/issues/9037

    最初在没理解问题是什么时候,尝试了其他方案,引入了社区的react-native-wkwebview来替代官方的WebView,引入后发现确实解决了问题,页面可以正常渲染,在已安装目标App的手机上,也可以调起App了。

    后来随着对Android端WebView问题的跟进,在加上又看了下上面反馈的issue,意识到这里也是因为WebView加载私有协议失败引起的,不同的是,在iOS端,加载私有协议失败后,进入了失败处理逻辑,跳到了失败提示界面。

    解决方案,iOS端为解决这一问题提供了一个便利的方法,

    onShouldStartLoadWithRequest
    

    可以在这个方法中,根据url的协议头,决定是否真的发起请求,还是调起外部App,代码如下

    
    onShouldStartLoadWithRequest(event){
            if(event.url.startsWith('http://') || event.url.startsWith('https://')) {
                return true;
            }else{
                Linking.canOpenURL(event.url)
                    .then(supported => {
                        if(supported){
                           return Linking.openURL(url);
                        }else{
                            return false;
                        }
                    }).catch(err => {
                        return false;
                })
            }
        }
    

    ReactNative与WebView双向通信

    这个问题当前业务中还没用到,不过目前官方API,仅支持向WebView中注入JS,还不支持从WebView中的页面调用React Native中的方法。

    解决办法,社区已有一个解决方案react-native-webview-bridge

    如果觉得有帮助,可以扫描二维码对我打赏,谢谢

    相关文章

      网友评论

      • 9c2da3dbf779:安卓webview里js无效,遇到过吗
        899445542bb2:添加domStorageEnabled属性
      • 简翦儋箪:为什么我只要一添加这个三方库 我的项目就会报错,报RCTWebViewBrdgeManager.NavigationType 找不到,我是iOS 请问楼主遇到过么
      • 勿问情殇:scalesPageToFit={true}
        这个属性,在ios 中好使,页面可以正常缩放,但是安卓并没有缩放,是怎么回事,楼主遇到过吗?

      本文标题:React Native WebView踩坑记

      本文链接:https://www.haomeiwen.com/subject/mkwduttx.html

      热点阅读