美文网首页
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