亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > JavaScript > 正文

詳解react-native WebView 返回處理(非回調方法可解決)

2019-11-19 14:17:23
字體:
來源:轉載
供稿:網友

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; //修改名稱

至此就完成自定義WebView模塊。也可以解決網頁是React實現,不能導航的問題。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
午夜精品一区二区三区在线| 亚洲欧美日韩第一区| 久久精品久久久久| 红桃视频成人在线观看| 97精品国产97久久久久久免费| 韩国视频理论视频久久| 国产亚洲精品一区二区| 久久久久久久999精品视频| 91免费的视频在线播放| 69国产精品成人在线播放| 国产97在线观看| 亚洲色图校园春色| 国产精品成人一区二区| 欧美视频在线视频| 国产精品久久久久7777婷婷| 精品国产91久久久久久老师| 亚洲免费av电影| 97婷婷大伊香蕉精品视频| 精品动漫一区二区| 国产黑人绿帽在线第一区| 91香蕉嫩草神马影院在线观看| 91在线播放国产| 久久理论片午夜琪琪电影网| 国产视频自拍一区| 97欧美精品一区二区三区| 国产精品影院在线观看| 日韩av综合中文字幕| 亚洲国产成人精品久久久国产成人一区| 色综合色综合久久综合频道88| 中文字幕亚洲综合| 欧美中文字幕视频在线观看| 国产一区二区三区视频在线观看| 国产91在线视频| 国产不卡视频在线| 国产婷婷色综合av蜜臀av| 国产成人精品久久亚洲高清不卡| 国产精品xxx视频| 久久久伊人欧美| 欧美日韩国产一区二区三区| 亚洲欧美日韩国产成人| 国产精品成人av在线| 欧美高清电影在线看| 欧美性色xo影院| 97成人精品视频在线观看| 亚洲jizzjizz日本少妇| 国产精品网红福利| 成人黄色免费片| 国产亚洲欧美aaaa| 亚洲最新av在线| 国产成人一区二区三区电影| 91免费福利视频| 欧美另类99xxxxx| 日韩中文娱乐网| 在线观看亚洲视频| 亚洲成av人乱码色午夜| 久久乐国产精品| 欧美乱大交xxxxx| 欧美中文字幕视频在线观看| 青青草原一区二区| 欧美成人第一页| 国产日韩欧美影视| 亚洲精品免费一区二区三区| 日本免费久久高清视频| 日韩高清欧美高清| 亚洲精品丝袜日韩| 国内精品美女av在线播放| 92版电视剧仙鹤神针在线观看| 成人免费看片视频| 久久精品亚洲国产| 在线观看国产精品91| 国产精品网站入口| 精品香蕉在线观看视频一| 欧美精品做受xxx性少妇| www.欧美视频| 国产精品av在线| 欧美性高跟鞋xxxxhd| 亚洲性视频网址| 久久免费视频网站| 久久久亚洲精品视频| 日韩成人在线播放| 久久精品这里热有精品| 国产精品成人免费视频| 欧美性感美女h网站在线观看免费| 97在线观看视频| 国产91对白在线播放| 久久影视电视剧免费网站清宫辞电视| 黑人极品videos精品欧美裸| 亚洲va欧美va在线观看| 日韩av免费在线看| 午夜精品久久久久久久久久久久| 国产成人精品av在线| 国产精品精品国产| 97国产成人精品视频| 久久成人亚洲精品| 国产福利精品av综合导导航| 欧美裸身视频免费观看| 欧美日韩中文字幕日韩欧美| 国产精品扒开腿做爽爽爽男男| 一本大道久久加勒比香蕉| 日韩不卡中文字幕| 奇米成人av国产一区二区三区| 亚洲欧洲在线观看| 亚洲精品理论电影| 国产精品成人av在线| 国产欧美日韩高清| 在线日韩精品视频| 欧美成人精品三级在线观看| 亚洲美腿欧美激情另类| 一本色道久久88精品综合| zzijzzij亚洲日本成熟少妇| 日产精品99久久久久久| 亚洲大胆美女视频| 欧美午夜美女看片| 日韩动漫免费观看电视剧高清| 亚洲人成自拍网站| 欧美精品www| 国产精品www| 成人免费看吃奶视频网站| 日韩亚洲欧美中文在线| 成人在线中文字幕| 日韩精品免费一线在线观看| 欧美激情aaaa| 在线精品国产成人综合| 97超碰蝌蚪网人人做人人爽| 国产成人综合av| 亚洲人成在线观看| 亚洲精品久久久久中文字幕欢迎你| 亚洲精品小视频| 欧美极品第一页| 欧美另类69精品久久久久9999| 欧美与黑人午夜性猛交久久久| 成人午夜小视频| 伊人久久久久久久久久久久久| 欧美一级视频在线观看| 91亚洲精品一区二区| 色综合久久悠悠| 日韩一区二区三区在线播放| 91久久久亚洲精品| 91在线精品视频| 欧美成人小视频| 狠狠综合久久av一区二区小说| 亲爱的老师9免费观看全集电视剧| 日韩欧美有码在线| 92裸体在线视频网站| 国产精品日韩在线观看| 精品成人av一区| 97免费在线视频| 国产成人免费av电影| 久久久久久久久91| 欧美亚洲国产精品| 日韩av电影手机在线观看| 午夜精品福利在线观看| 色妞欧美日韩在线| 国内外成人免费激情在线视频网站| 成人免费在线视频网址| 亚洲欧美在线免费观看| 青青精品视频播放| 国产自产女人91一区在线观看| 国产精品男人的天堂| 久久久久久久一区二区| 欧美国产视频日韩| 精品亚洲精品福利线在观看| 欧美成人免费观看| 欧美特级www|