美文网首页
React Native加载WebView及遇坑总结

React Native加载WebView及遇坑总结

作者: 荒漠现甘泉 | 来源:发表于2019-05-05 10:49 被阅读0次

    前言

    最近几天要做一个React Native简单加载WebView的一个工程,支持加载远程url及本地html。本以为没多大难度,结果因为初学React及React网上靠谱资料少的原因的还是踏了不少坑,特此记录一下。

    创建WebView工程

    在创建React NativeWebView工程之前,我们需要搭建React Native的开发环境,在这我就不细说了,可以参考这篇文章React Native 中文网 - 搭建开发环境。这篇文章很详细,照着步骤走下来基本没啥问题。

    搭好开发环境就可以开始创建工程了。cd到要创建的工程目录,执行以下命令:

    react-native init loadGameReactProject
    

    看到如下打印的日志,就说明已经创建成功了。

    ...
     Run instructions for iOS:
        • cd /Users/hangzhouyuewan/Documents/WorkSpace/Exercise/React/loadGameReactProject && react-native run-ios
        - or -
        • Open ios/loadGameReactProject.xcodeproj in Xcode
        • Hit the Run button
    
      Run instructions for Android:
        • Have an Android emulator running (quickest way to get started), or a device connected.
        • cd /Users/hangzhouyuewan/Documents/WorkSpace/Exercise/React/loadGameReactProject && react-native run-android
        
    

    提示:也可以使用--version参数(注意是两个杠)创建指定版本的项目。例如react-native init MyApp --version 0.44.3。注意版本号必须精确到两个小数点。

    创建好以后可以通过命令cd /Users/hangzhouyuewan/Documents/WorkSpace/Exercise/React/loadGameReactProject && react-native run-ios或者直接在Xcode打开ios/loadGameReactProject.xcodeproj然后运行。

    运行效果如下:

    初始化运行成功截屏.png

    这个是默认的界面,显然不是我想要的,可以在React Native工程目录下,来修改App.js文件来修改界面。

    加载WebView

    通过上面的步骤我已经创建了一个React Native工程。但是内容肯定不是我想要的。需要修改为可以既可以加载本地html,也可以加载远程url的界面。参考了React Native中文网-WebView的介绍。直接将代码粘贴过去。

    import React, { Component } from 'react';
    import { WebView } from 'react-native';
    
    class MyWeb extends Component {
      render() {
        return (
          <WebView
            source={{uri: 'https://github.com/facebook/react-native'}}
            style={{marginTop: 20}}
          />
        );
      }
    }
    

    运行一成功后,刷新界面,结果报错。报错截屏如下:

    加载WebView报错

    百思不得其解。经过仔细比对后,发现是因为将类从模块中导出。这样就没法调用到该MyWeb类,从而导致加载失败。添加导出代码如下。

    export default class MyWeb extends Component {
      render() {
        return (
          <WebView
            source={{uri: 'https://github.com/facebook/react-native'}}
            style={{marginTop: 20}}
          />
        );
      }
    }
    

    这里在class添加了export default,运行一下,界面刷新成功,展示了web页面。exportES6的语法。export可以导出各种类型的变量、常量、类、函数、文件等。这里使用export default导出默认的类。详细介绍可以看这篇文章ES6 模块。还有React Native中文社区的这篇文章React/React Native 的ES5 ES6写法对照表

    WebView加载方式的分类

    WebView既可以通过加载远程url、也可以通过直接嵌入html代码,也可以通过加载本地静态html文件来渲染界面。通过开启设置是否开启useWebKit选项可以使用WKWebView来实现。下面我们分别就这三种加载方式来阐述。

    1.加载远程URL

    加载远程URL像上面示例一样,只需要直接给WebView的属性source赋值url,就能进行加载。如下:

    export default class MyWeb extends Component {
      render() {
        return (
          <WebView
            source={{uri: 'https://github.com/facebook/react-native'}}
            style={{marginTop: 20}}
          />
        );
      }
    }
    

    2.直接嵌入html代码

    直接加载html只需要直接给WebView的属性source赋值url,就能进行加载。如下:

    export default class MyWeb extends Component {
      render() {
        return (
          <WebView
            source={{html: '<h1>Hello World!</h1'}}
            style={{marginTop: 20}}
          />
        );
      }
    }
    

    3.加载本地静态的html文件

    查看文章React Native 中使用 WebView 加载本地 html找到加载本地html的方法。在iOS中要加载一个本地静态的html文件,可以将本地的html放入到和App.js同级目录下,然后通过如下方式加载:

    export default class MyWeb extends Component {
      render() {
        return (
          <WebView
            source={require('./test.html')}
          />
        );
      }
    }
    

    这样运行起来测试一下,发现没问题。但因为我的App是要加载一个H5小游戏,本地html还引用了一些js及资源文件。这时候去加载会发现就加载不了了。

    export default class MyWeb extends Component {
      render() {
        return (
          <WebView
            source={require('./game/index.html')}
          />
        );
      }
    }
    
    game存放目录.png

    运行一下。结果显示黑屏。其实本地html文件已经加载出来了,但是因为html无法加载资源文件,所以导致黑屏了。还得继续想办法,解决本地html加载本地资源的问题。通过搜搜网上的资料,基本上都说这种加载方式在dev环境下是可以加载本地资源的。通过拦截js转换成OCWebView的代码,如下:

    RCTWebView断点.png

    从上面可以发现,js中本地html的加载转换成了localhosturl方式进行加载。所以加载静态html文件是可以的,至于html不能加载本地文件,姑且猜测是因为没有开启本地Web服务的原因。这里有待后续研究如何解决。

    回到上面的话题,既然上面这种方式无法加载引用本地资源的html,我们还得找解决方法来解决这个问题。在ReactNative 打包IOS应用程序这篇文章中提到,当把App发布到AppStore中时,需要将JavaScript和图片等本地资源打包成离线资源,再添加到Xcode中,然后一起发布到App Store中。至于如何添加及实现,且看下章。

    加载引用本地资源的Html方法

    上面提到在App发布到App Store中时,需要将资源打包成离线资源。下面我们就看一下具体的打包步骤。打包离线资源需要使用命令react-native bundle

    一、生成bundle文件

    ios目录下新建bundle目录

    • 1)通过命令行执行命令打包
      进入项目目录,运行以下打包命令。

      react-native bundle --entry-file index.js --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle
      
      • --entry-file,ios或者android入口的js名称。这里是 index.js
      • --platform,平台名称(ios或者android)
      • --dev,设置为false的时候将会对JavaScript进行优化处理。
      • --bundle-output,生成的jsbundle文件的名称,这里是./ios/bundle/index.ios.jsbundle
      • --assets-dest 图片以及其他资源存放的目录,这里放在./ios/bundle目录下。
    • 2)通过脚本打包
      package.json中添加编译命令

      {
        "scripts":{
            "bundle-ios":"node node_modules/react-native/local-cli/cli.js bundle --entry-file index.js  --platform ios --dev false --bundle-output ./ios/bundle/index.ios.jsbundle --assets-dest ./ios/bundle"
        }
      }
      
      

      直接在终端运行npm run bundle-ios�即可生成bundle。

    二、在Xcode中集成

    离线包生成完之后,可以在ios目录下看到一个bundle目录,这个目录就是bundle生成的离线资源。
    需要在Xcode中添加资源到项目中,必须使用Create folder references添加文件夹,否则不起作用。

    • Add Files to "loadGameReactProject"

      添加截屏.png
    • 选择bundle文件,在option中Create folder references

      选择引用.png
    • 这样添加到项目中的文件夹是蓝色的

      添加完成.png

    三、修改AppDelegate.m加载bundle的方式

    AppDelegate.m文件中的- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge方法改为如下实现:

    - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
    {
    //#if DEBUG
    //
    //  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
    //#else
    //  return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
    //#endif
      return [[NSBundle mainBundle] URLForResource:@"bundle/index.ios" withExtension:@"jsbundle"];
    }
    
    • 修改debug状态
      将项目由debug状态改成release状态

    • 选择Generic iOS Device,运行一下。

    • 再选择模拟器或者真机运行,这时发现WebView可以加载起来但是缺显示空白。

      setSource截屏.png
      通过上图我们拦截setSource:方法中的webview加载request方法,打印requestURL,可以知道加载的URL是没有问题的。那问题必然出在加载后回调以及跟js的交互这一块。这时我们只需要将webview的delegate设置为nil就可以了。如下图:
      设置delegate为nil.png
      问题到此就解决了。

      很明显这并不是一个很好的解决方案,后续有待进一步探索解决。

    相关文章

      网友评论

          本文标题:React Native加载WebView及遇坑总结

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