首頁 web前端 js教程 react-native WebView 回傳處理方法

react-native WebView 回傳處理方法

Mar 01, 2018 am 09:12 AM
react-native web webview

專案中有些頁面內容是變更比較頻繁的,這些頁面我們會考慮用 網頁 來解決。

在RN專案中提供一個公用的Web頁,如果是網頁內容,就跳到這個介面展示。

此時會有一個問題是,網頁會有一級頁面,二級頁面,這就會設計到導覽列返回鍵的處理(以及在Android上返回鍵的處理)。

這個問題,在RN官網就可找到解決方式。就是用 onNavigationStateChange 這個回呼方法記錄目前的導航狀態,從而判斷是回到上一層頁面還是退出這個網頁,回到App的其他介面。

但是,當網頁的實作是React時,就會有問題了,你會發現,當頁面跳轉的時候,onNavigationStateChange這個回呼方法沒有回呼! ! !怎麼肥四! !

一開始嘗試了把網頁地址換成百度的,可以接收回調,一切都運行的很好,可是換成我們的鏈接就不行,所以就把鍋甩給了後台,以為是React哪邊寫的不對。

因為上一個專案時間緊,沒有時間好好去看一下原始碼,就想了一個不是很完善的解決方案,就是網頁用js來回調App告知現在的導航狀態,這樣的解決方式顯示是不友善的。

現在稍微有點時間看了原始碼才知道真正原因。

下面就分析一下這個問題的原因和我的解決方式。

1.首先,先找出原始碼的位置。

node_modules\react-native\ReactAndroid\src\main\java\com\facebook\react\views\webview

node_modules\react-native\Libraries\Components\WebView

目錄結構是這樣的:

 

#2.實作的程式碼段(JAVA端)

RN的實際運行程式碼都是原生程式碼,所以,像是WebView元件的一些事件回呼,其實都是原生程式碼中的回呼觸發的。如下

(ReactWebViewManager.java) rn版本0.47.1


protected static class ReactWebViewClient extends WebViewClient { //WebViewClient就是我们在写Android原生代码时,监听网页加载情况使用的工具。
   protected static final String REACT_CLASS = "RCTWebView"; //定义的原生组件名,在后面JS中会对应到。

  //...

  @Override
  public void onPageStarted(WebView webView, String url, Bitmap favicon) { //有很多回调方法,此处只举一例
   super.onPageStarted(webView, url, favicon);
   mLastLoadFailed = false;

   dispatchEvent(
     webView,
     new TopLoadingStartEvent(   //自己定义的时间,dispatch后,事件会传给js
       webView.getId(),
       createWebViewEvent(webView, url)));
  }

  //...
 }
登入後複製

(ReactWebViewManager.java) rn版本0.43.3  ,RN不同版本會有程式碼調整,所以RN升級的時候,需要仔細的迴歸測試。


protected static class ReactWebViewClient extends WebViewClient { //WebViewClient就是我们在写Android原生代码时,监听网页加载情况使用的工具。
   protected static final String REACT_CLASS = "RCTWebView"; //定义的原生组件名,在后面JS中会对应到。

  //...

  @Override
  public void onPageStarted(WebView webView, String url, Bitmap favicon) { //有很多回调方法,此处只举一例
   super.onPageStarted(webView, url, favicon);
   mLastLoadFailed = false;

   dispatchEvent(
     webView,
     new TopLoadingStartEvent(   //自己定义的时间,dispatch后,事件会传给js
       webView.getId(),
       createWebViewEvent(webView, url)));
  }

  @Override
  public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload) { //坑在这,这里就是导航有变化的时候会回调在这个版本是有这个处理的,但是不知道在哪个版本删掉了 -.-
   super.doUpdateVisitedHistory(webView, url, isReload);

   dispatchEvent(
     webView,
     new TopLoadingStartEvent(
       webView.getId(),
       createWebViewEvent(webView, url)));
  }

  //...
 }
登入後複製

(TopLoadingStartEvent.java) 回呼JS的Event


public class TopLoadingStartEvent extends Event<TopLoadingStartEvent> {
 public static final String EVENT_NAME = "topLoadingStart";  //对应方法是onLoadingStart, 因为对RN的结构不熟悉,在此处花了很长时间研究是怎么对应的,最后找到了定义对应的文件
 private WritableMap mEventData;

 public TopLoadingStartEvent(int viewId, WritableMap eventData) {
  super(viewId);
  mEventData = eventData;
 }

 @Override
 public String getEventName() {
  return EVENT_NAME;
 }

 @Override
 public boolean canCoalesce() {
  return false;
 }

 @Override
 public short getCoalescingKey() {
  // All events for a given view can be coalesced.
  return 0;
 }

 @Override
 public void dispatch(RCTEventEmitter rctEventEmitter) {
  rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
 }
}
登入後複製

(node_modules\react-native\ReactAndroid\ src\main\java\com\facebook\react\uimanager\UIManagerModuleConstants.java)

這個檔案裡,定義了對應關係


/**
 * Constants exposed to JS from {@link UIManagerModule}.
 */
/* package */ class UIManagerModuleConstants {

 /* package */ static Map getDirectEventTypeConstants() {
  return MapBuilder.builder()
    .put("topContentSizeChange", MapBuilder.of("registrationName", "onContentSizeChange"))
    .put("topLayout", MapBuilder.of("registrationName", "onLayout"))
    .put("topLoadingError", MapBuilder.of("registrationName", "onLoadingError"))
    .put("topLoadingFinish", MapBuilder.of("registrationName", "onLoadingFinish"))
    .put("topLoadingStart", MapBuilder.of("registrationName", "onLoadingStart"))
    .put("topSelectionChange", MapBuilder.of("registrationName", "onSelectionChange"))
    .put("topMessage", MapBuilder.of("registrationName", "onMessage"))
    .build();
 }
}
登入後複製

3.實作的程式碼段(JS端)

(node_modules\react-native\Libraries\Components\WebView\WebView.android.js)

在下面的程式碼中可以看到只有onLoadingStart    和onLoadingFinish 才會呼叫  updateNavigationState ,問題就出現在這裡了,由於我們的網頁實作是React,只有一個頁面啊!所以只會呼叫一次 onLoadingStart  和 onLoadingFinish 。再點選詳情頁並不會跳到新頁面,而是刷新原來的頁面。所以也就沒有 updateNavigationState 回呼了。


class WebView extends React.Component {
 static propTypes = {  //给外部定义的可设置的属性
  ...ViewPropTypes,
  renderError: PropTypes.func,
  renderLoading: PropTypes.func,
  onLoad: PropTypes.func,
  //...
  }

 render() { //绘制页面内容
  //...
  var webView =
   <RCTWebView
    ref={RCT_WEBVIEW_REF}
    key="webViewKey"
    style={webViewStyles}
    source={resolveAssetSource(source)}
    onLoadingStart={this.onLoadingStart}
    onLoadingFinish={this.onLoadingFinish}
    onLoadingError={this.onLoadingError}/>;

  return (
   <View style={styles.container}>
    {webView}
    {otherView}
   </View>
  );
 }

 onLoadingStart = (event) => {
  var onLoadStart = this.props.onLoadStart;
  onLoadStart && onLoadStart(event);
  this.updateNavigationState(event);
 };

 onLoadingFinish = (event) => {
  var {onLoad, onLoadEnd} = this.props;
  onLoad && onLoad(event);
  onLoadEnd && onLoadEnd(event);
  this.setState({
   viewState: WebViewState.IDLE,
  });
  this.updateNavigationState(event);
 };

 updateNavigationState = (event) => {
  if (this.props.onNavigationStateChange) {
   this.props.onNavigationStateChange(event.nativeEvent);
  }
 };
}

var RCTWebView = requireNativeComponent(&#39;RCTWebView&#39;, WebView, {  //对应上面JAVA中的 ‘RCTWebView&#39;
 nativeOnly: { messagingEnabled: PropTypes.bool, }, });


 module.exports = WebView;
登入後複製

2.解決方法

#既然原因找到了,就容易解決了

#解決方式:自訂WebView,新增 doUpdateVisitedHistory 處理,每次導航變更的時候,通知JS。

1. 拷貝下圖中的檔案到我們自己專案中的Android程式碼目錄下

# 完成後的Android目錄:

ReactWebViewManager.java中需要修改幾個地方


public class ReactWebViewManager extends SimpleViewManager<WebView> {
 protected static final String REACT_CLASS = "RCTWebView1"; //此处修改一下名字

 protected static class ReactWebViewClient extends WebViewClient {
    @Override
    public void doUpdateVisitedHistory(WebView webView, String url, boolean isReload) {
      super.doUpdateVisitedHistory(webView, url, isReload);

      dispatchEvent(    //在导航变化的时候,dispatchEvent
          webView,
          new TopCanGoBackEvent(
              webView.getId(),
              createCanGoBackWebViewEvent(webView, url)));
    }
 }
}
登入後複製

TopCanGoBackEvent是我自己新增的一個Event,專門用來通知導航變更

TopCanGoBackEvent.java


public class TopCanGoBackEvent extends Event<TopCanGoBackEvent> {

 public static final String EVENT_NAME = "topChange"; 
 private WritableMap mEventData;

 public TopCanGoBackEvent(int viewId, WritableMap eventData) {
  super(viewId);
  mEventData = eventData;
 }

 @Override
 public String getEventName() {
  return EVENT_NAME;
 }

 @Override
 public boolean canCoalesce() {
  return false;
 }

 @Override
 public short getCoalescingKey() {
  // All events for a given view can be coalesced.
  return 0;
 }

 @Override
 public void dispatch(RCTEventEmitter rctEventEmitter) {
  rctEventEmitter.receiveEvent(getViewTag(), getEventName(), mEventData);
 }
}
登入後複製

新建ReactWebViewPage.java


public class ReactWebViewPackage implements ReactPackage {

  @Override
  public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {

    return Collections.emptyList();
  }

  @Override
  public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
    return Arrays.<ViewManager>asList(
        new ReactWebViewManager()
    );
  }
}
登入後複製

然後在MainApplication中加上這個模組


public class MainApplication extends Application implements ReactApplication {
  @Override
  protected List<ReactPackage> getPackages() {
   return Arrays.<ReactPackage>asList(
     new MainReactPackage(),
     new ReactWebViewPackage()  //WebView
   );
  }
}
登入後複製

以上就是Android需要修改的地方,ios我沒有嘗試過,應該大差不差同一個道理。

2. 拷貝下圖中的檔案到我們自己專案中的JS程式碼目錄下,並修改一下名字

JS程式碼目錄:

CustomWebView.android.js 有幾個地方需要修改。


/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @providesModule CustomWebView  //此处需要修改名称
 */

var RCT_WEBVIEW_REF = &#39;webview1&#39;; //此处需要修改名称

 render() {
  var webView =
   <NativeWebView
    onLoadingStart={this.onLoadingStart}
    onLoadingFinish={this.onLoadingFinish}
    onLoadingError={this.onLoadingError}
    onChange={this.onChange} //添加方法
   />;

  return (
   <View style={styles.container}>
    {webView}
    {otherView}
   </View>
  );
 }

 onChange = (event) => {  //添加方法
  this.updateNavigationState(event);
 };
}

var RCTWebView = requireNativeComponent(&#39;RCTWebView1&#39;, CustomWebView, CustomWebView.extraNativeComponentConfig); //修改名称

module.exports = CustomWebView; //修改名称
登入後複製

至此就完成自定义WebView模块。也可以解决网页是React实现,不能导航的问题。

以上是react-native WebView 回傳處理方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

如何使用python+Flask實作日誌在web網頁即時更新顯示 如何使用python+Flask實作日誌在web網頁即時更新顯示 May 17, 2023 am 11:07 AM

一、日誌輸出到檔案使用模組:logging可以產生自訂等級日誌,可以輸出日誌到指定路徑日誌等級:debug(偵錯日誌)=5){clearTimeout(time)//如果連續10次取得的都是空日誌清除定時任務}return}if(data.log_type==2){//如果取得到新日誌for(i=0;i

使用Java 13中的新的JavaFX WebView元件來顯示網頁內容 使用Java 13中的新的JavaFX WebView元件來顯示網頁內容 Aug 01, 2023 pm 01:09 PM

使用Java13中的新的JavaFXWebView元件來顯示網頁內容隨著Java的不斷發展,JavaFX已成為建立跨平台圖形介面的主要工具之一。 JavaFX提供了豐富的圖形庫和元件,讓開發者能夠輕鬆地創建各種各樣的使用者介面。其中,JavaFXWebView元件是一個非常有用的元件,它允許我們在JavaFX應用程式中顯示網頁內容。在Java13中,J

Nginx的Web伺服器caddy怎麼使用 Nginx的Web伺服器caddy怎麼使用 May 30, 2023 pm 12:19 PM

Caddy簡介Caddy是一款功能強大,擴展性高的Web伺服器,目前在Github上已有38K+Star。 Caddy採用Go語言編寫,可用於靜態資源託管和反向代理。 Caddy具有以下主要特性:比較Nginx複雜的配置,其獨創的Caddyfile配置非常簡單;可以透過其提供的AdminAPI實現動態修改配置;預設支援自動化HTTPS配置,能自動申請HTTPS憑證並進行配置;能夠擴展到數以萬計的站點;可以在任意地方執行,沒有額外的依賴;採用Go語言編寫,內存安全更有保證。安裝首先我們直接在CentO

如何使用Golang實作網頁應用程式的表單驗證 如何使用Golang實作網頁應用程式的表單驗證 Jun 24, 2023 am 09:08 AM

表單驗證是Web應用程式開發中非常重要的環節,它能夠在提交表單資料之前對資料進行有效性檢查,避免應用程式出現安全漏洞和資料錯誤。使用Golang可以輕鬆實現網頁應用程式的表單驗證,本文將介紹如何使用Golang來實作網頁應用程式的表單驗證。一、表單驗證的基本要素在介紹如何實作表單驗證之前,我們需要知道表單驗證的基本要素是什麼。表單元素:表單元素是指

Java API 開發中使用 Jetty7 進行 Web 伺服器處理 Java API 開發中使用 Jetty7 進行 Web 伺服器處理 Jun 18, 2023 am 10:42 AM

JavaAPI開發中使用Jetty7進行Web伺服器處理隨著互聯網的發展,Web伺服器已經成為了應用程式開發的核心部分,同時也是許多企業所關注的焦點。為了滿足日益增長的業務需求,許多開發人員選擇使用Jetty進行Web伺服器開發,其靈活性和可擴展性受到了廣泛的認可。本文將介紹如何在JavaAPI開發中使用Jetty7進行We

怎麼設定nginx保證frps伺服器與web共用80埠 怎麼設定nginx保證frps伺服器與web共用80埠 Jun 03, 2023 am 08:19 AM

首先你會有個疑惑,frp是什麼呢?簡單的說frp就是內網穿透工具,配置客戶端以後,可以透過伺服器來存取內部網路。現在我的伺服器,已經用nginx做站了,80端口只有一個,那如果frp的服務端也想使用80端口,那該怎麼辦呢?經過查詢,這個是可以實現的,就是利用nginx的反向代理來實現。補充一下:frps就是伺服器端(server),frpc就是客戶端(client)。第一步:修改伺服器中nginx.conf設定檔在nginx.conf中http{}裡加入以下參數,server{listen80

Web 端即時防擋臉彈幕(基於機器學習) Web 端即時防擋臉彈幕(基於機器學習) Jun 10, 2023 pm 01:03 PM

防擋臉彈幕,即大量彈幕飄過,但不會遮擋視訊畫面中的人物,看起來像是從人物背後飄過去的。機器學習已經火了好幾年了,但很多人都不知道瀏覽器中也能運行這些能力;本文介紹在視頻彈幕方面的實踐優化過程,文末列舉了一些本方案可適用的場景,期望能開啟一些腦洞。 mediapipeDemo(https://google.github.io/mediapipe/)展示主流防擋臉彈幕實現原理點播up上傳視訊伺服器後台計算提取視訊畫面中的人像區域,轉換成svg儲存用戶端播放視訊的同時,從伺服器下載svg與彈幕合成,人像

web標準是什麼東西 web標準是什麼東西 Oct 18, 2023 pm 05:24 PM

Web標準是一組由W3C和其他相關組織制定的規範和指南,它包括HTML、CSS、JavaScript、DOM、Web可訪問性和性能優化等方面的標準化,透過遵循這些標準,可以提高頁面的兼容性、可訪問性、可維護性和效能。 Web標準的目標是使Web內容能夠在不同的平台、瀏覽器和裝置上一致地展示和交互,提供更好的使用者體驗和開發效率。

See all articles