React Native加載WebView及遇坑總結(jié)

前言

最近幾天要做一個React Native簡單加載WebView的一個工程,支持加載遠(yuǎn)程url及本地html。本以為沒多大難度,結(jié)果因為初學(xué)React及React網(wǎng)上靠譜資料少的原因的還是踏了不少坑,特此記錄一下。

創(chuàng)建WebView工程

在創(chuàng)建React NativeWebView工程之前,我們需要搭建React Native的開發(fā)環(huán)境,在這我就不細(xì)說了,可以參考這篇文章React Native 中文網(wǎng) - 搭建開發(fā)環(huán)境。這篇文章很詳細(xì),照著步驟走下來基本沒啥問題。

搭好開發(fā)環(huán)境就可以開始創(chuàng)建工程了。cd到要創(chuàng)建的工程目錄,執(zhí)行以下命令:

react-native init loadGameReactProject

看到如下打印的日志,就說明已經(jīng)創(chuàng)建成功了。

...
 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參數(shù)(注意是兩個杠)創(chuàng)建指定版本的項目。例如react-native init MyApp --version 0.44.3。注意版本號必須精確到兩個小數(shù)點。

創(chuàng)建好以后可以通過命令cd /Users/hangzhouyuewan/Documents/WorkSpace/Exercise/React/loadGameReactProject && react-native run-ios或者直接在Xcode打開ios/loadGameReactProject.xcodeproj然后運行。

運行效果如下:

初始化運行成功截屏.png

這個是默認(rèn)的界面,顯然不是我想要的,可以在React Native工程目錄下,來修改App.js文件來修改界面。

加載WebView

通過上面的步驟我已經(jīng)創(chuàng)建了一個React Native工程。但是內(nèi)容肯定不是我想要的。需要修改為可以既可以加載本地html,也可以加載遠(yuǎn)程url的界面。參考了React Native中文網(wǎng)-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}}
      />
    );
  }
}

運行一成功后,刷新界面,結(jié)果報錯。報錯截屏如下:

加載WebView報錯

百思不得其解。經(jīng)過仔細(xì)比對后,發(fā)現(xiàn)是因為將類從模塊中導(dǎo)出。這樣就沒法調(diào)用到該MyWeb類,從而導(dǎo)致加載失敗。添加導(dǎo)出代碼如下。

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可以導(dǎo)出各種類型的變量、常量、類、函數(shù)、文件等。這里使用export default導(dǎo)出默認(rèn)的類。詳細(xì)介紹可以看這篇文章ES6 模塊。還有React Native中文社區(qū)的這篇文章React/React Native 的ES5 ES6寫法對照表

WebView加載方式的分類

WebView既可以通過加載遠(yuǎn)程url、也可以通過直接嵌入html代碼,也可以通過加載本地靜態(tài)html文件來渲染界面。通過開啟設(shè)置是否開啟useWebKit選項可以使用WKWebView來實現(xiàn)。下面我們分別就這三種加載方式來闡述。

1.加載遠(yuǎn)程URL

加載遠(yuǎn)程URL像上面示例一樣,只需要直接給WebView的屬性source賦值url,就能進(jìn)行加載。如下:

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,就能進(jìn)行加載。如下:

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

3.加載本地靜態(tài)的html文件

查看文章React Native 中使用 WebView 加載本地 html找到加載本地html的方法。在iOS中要加載一個本地靜態(tài)的html文件,可以將本地的html放入到和App.js同級目錄下,然后通過如下方式加載:

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

這樣運行起來測試一下,發(fā)現(xiàn)沒問題。但因為我的App是要加載一個H5小游戲,本地html還引用了一些js及資源文件。這時候去加載會發(fā)現(xiàn)就加載不了了。

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

運行一下。結(jié)果顯示黑屏。其實本地html文件已經(jīng)加載出來了,但是因為html無法加載資源文件,所以導(dǎo)致黑屏了。還得繼續(xù)想辦法,解決本地html加載本地資源的問題。通過搜搜網(wǎng)上的資料,基本上都說這種加載方式在dev環(huán)境下是可以加載本地資源的。通過攔截js轉(zhuǎn)換成OCWebView的代碼,如下:

RCTWebView斷點.png

從上面可以發(fā)現(xiàn),js中本地html的加載轉(zhuǎn)換成了localhosturl方式進(jìn)行加載。所以加載靜態(tài)html文件是可以的,至于html不能加載本地文件,姑且猜測是因為沒有開啟本地Web服務(wù)的原因。這里有待后續(xù)研究如何解決。

回到上面的話題,既然上面這種方式無法加載引用本地資源的html,我們還得找解決方法來解決這個問題。在ReactNative 打包IOS應(yīng)用程序這篇文章中提到,當(dāng)把App發(fā)布到AppStore中時,需要將JavaScript和圖片等本地資源打包成離線資源,再添加到Xcode中,然后一起發(fā)布到App Store中。至于如何添加及實現(xiàn),且看下章。

加載引用本地資源的Html方法

上面提到在App發(fā)布到App Store中時,需要將資源打包成離線資源。下面我們就看一下具體的打包步驟。打包離線資源需要使用命令react-native bundle

一、生成bundle文件

ios目錄下新建bundle目錄

  • 1)通過命令行執(zhí)行命令打包
    進(jìn)入項目目錄,運行以下打包命令。

    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,設(shè)置為false的時候?qū)?code>JavaScript進(jìn)行優(yōu)化處理。
    • --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
  • 這樣添加到項目中的文件夾是藍(lán)色的

    添加完成.png

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

AppDelegate.m文件中的- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge方法改為如下實現(xiàn):

- (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狀態(tài)
    將項目由debug狀態(tài)改成release狀態(tài)

  • 選擇Generic iOS Device,運行一下。

  • 再選擇模擬器或者真機運行,這時發(fā)現(xiàn)WebView可以加載起來但是缺顯示空白。

    setSource截屏.png

    通過上圖我們攔截setSource:方法中的webview加載request方法,打印requestURL,可以知道加載的URL是沒有問題的。那問題必然出在加載后回調(diào)以及跟js的交互這一塊。這時我們只需要將webview的delegate設(shè)置為nil就可以了。如下圖:
    設(shè)置delegate為nil.png

    問題到此就解決了。

    很明顯這并不是一個很好的解決方案,后續(xù)有待進(jìn)一步探索解決。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。