不呼叫的情況下怎麼解決react-native WebView的回傳處理
這次給大家帶來不呼叫的情況下怎麼解決react-native WebView的返回處理,不調用的情況下解決react-native WebView的返回處理的注意事項有哪些,下面就是實戰案例,一起來看一下。
1.前言
專案中有些頁面內容是變更比較頻繁的,這些頁面我們會考慮用 網頁 來解決。
在RN專案中提供一個公用的Web頁,如果是網頁內容,就跳到這個介面展示。
此時會有一個問題是,網頁會有一級頁面,二級頁面,這就會設計到導航列返回鍵的處理(以及在Android上返回鍵的處理)。
這個問題,在RN官網就可找到解決方式。就是用 onNavigationStateChange 這個回呼方法記錄目前的導航狀態,從而判斷是回到上一層頁面還是退出這個網頁,回到App的其他介面。
但是,當網頁的實作是React時,就會有問題了,你會發現,當頁面跳轉的時候,onNavigationStateChange這個回呼方法沒有回呼! ! !怎麼肥四! !
一開始嘗試了把網頁地址換成百度的,可以接收回調,一切都運行的很好,可是換成我們的鏈接就不行,所以就把鍋甩給了後台,以為是React哪邊寫的不對。
因為上一個專案時間緊,沒有時間好好去看一下原始碼,就想了一個不是很完善的解決方案,就是網頁用js來回調App告知現在的導航狀態,這樣的解決方式顯示是不友善的。
現在稍微有點時間看了原始碼才知道真正原因。
2.原因
就先分析這個問題的原因和我的解決方式。
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('RCTWebView', WebView, { //对应上面JAVA中的 ‘RCTWebView' 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 = 'webview1'; //此处需要修改名称 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('RCTWebView1', CustomWebView, CustomWebView.extraNativeComponentConfig); //修改名称 module.exports = CustomWebView; //修改名称
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
以上是不呼叫的情況下怎麼解決react-native WebView的回傳處理的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

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

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

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

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

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

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

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

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

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

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

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

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

越來越多的用戶開始升級win11系統,由於每個用戶的使用習慣不同,還是有不少用戶在使用ie11瀏覽器,那麼win11系統用不了ie瀏覽器,該怎麼辦呢? windows11還支援ie11嗎?下面就來看看解決方法。 win11無法使用ie11瀏覽器的解決方法1、先右鍵開始選單,選擇「命令提示字元(管理員)」開啟。 2.開啟之後,直接輸入“Netshwinsockreset”,回車確定。 3.確定之後再輸入「netshadvfirewallreset&rdqu

Cockpit是一個面向Linux伺服器的基於Web的圖形介面。它主要是為了使新用戶/專家用戶更容易管理Linux伺服器。在本文中,我們將討論Cockpit存取模式以及如何從CockpitWebUI切換Cockpit的管理存取。內容主題:駕駛艙進入模式查找當前駕駛艙訪問模式從CockpitWebUI啟用Cockpit的管理訪問從CockpitWebUI禁用Cockpit的管理訪問結論駕駛艙進入模式駕駛艙有兩種訪問模式:受限訪問:這是駕駛艙的默認訪問模式。在這種存取模式下,您無法從駕駛艙Web用戶
