React Native WebView踩坑记

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

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 141,930评论 1 299
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 60,888评论 1 255
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 93,606评论 0 211
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 40,848评论 0 175
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 48,544评论 1 253
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 38,671评论 1 173
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 30,312评论 2 267
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,112评论 0 165
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 28,899评论 6 229
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 32,451评论 0 213
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,221评论 2 213
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 30,541评论 1 225
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 24,196评论 0 31
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,079评论 2 213
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 31,448评论 3 204
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,597评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 25,969评论 0 164
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 33,451评论 2 230
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 33,523评论 2 229

推荐阅读更多精彩内容