• <fieldset id="8imwq"><menu id="8imwq"></menu></fieldset>
  • <bdo id="8imwq"><input id="8imwq"></input></bdo>
    最新文章專題視頻專題問答1問答10問答100問答1000問答2000關鍵字專題1關鍵字專題50關鍵字專題500關鍵字專題1500TAG最新視頻文章推薦1 推薦3 推薦5 推薦7 推薦9 推薦11 推薦13 推薦15 推薦17 推薦19 推薦21 推薦23 推薦25 推薦27 推薦29 推薦31 推薦33 推薦35 推薦37視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關鍵字專題關鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
    問答文章1 問答文章501 問答文章1001 問答文章1501 問答文章2001 問答文章2501 問答文章3001 問答文章3501 問答文章4001 問答文章4501 問答文章5001 問答文章5501 問答文章6001 問答文章6501 問答文章7001 問答文章7501 問答文章8001 問答文章8501 問答文章9001 問答文章9501
    當前位置: 首頁 - 科技 - 知識百科 - 正文

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

    來源:懂視網 責編:小采 時間:2020-11-27 22:18:37
    文檔

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

    詳解react-native WebView 返回處理(非回調方法可解決):1.前言 項目中有些頁面內容是變更比較頻繁的,這些頁面我們會考慮用 網頁 來解決。 在RN項目中提供一個公用的Web頁,如果是網頁內容,就跳轉到這個界面展示。 此時會有一個問題是,網頁會有一級頁面,二級頁面,這就會設計到導航欄返回鍵的處理(以及在And
    推薦度:
    導讀詳解react-native WebView 返回處理(非回調方法可解決):1.前言 項目中有些頁面內容是變更比較頻繁的,這些頁面我們會考慮用 網頁 來解決。 在RN項目中提供一個公用的Web頁,如果是網頁內容,就跳轉到這個界面展示。 此時會有一個問題是,網頁會有一級頁面,二級頁面,這就會設計到導航欄返回鍵的處理(以及在And

    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
     );
     }
    }

    聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

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

    詳解react-native WebView 返回處理(非回調方法可解決):1.前言 項目中有些頁面內容是變更比較頻繁的,這些頁面我們會考慮用 網頁 來解決。 在RN項目中提供一個公用的Web頁,如果是網頁內容,就跳轉到這個界面展示。 此時會有一個問題是,網頁會有一級頁面,二級頁面,這就會設計到導航欄返回鍵的處理(以及在And
    推薦度:
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top
    主站蜘蛛池模板: 久久99精品国产99久久| 好湿好大硬得深一点动态图91精品福利一区二区 | 国产精品一区12p| 99精品视频在线观看| 亚洲欧美日韩久久精品第一区| 国产精品视频不卡| 日本精品在线视频| 国产精品成人免费福利| 精品视频一区二区三三区四区| 亚洲人成电影网站国产精品| 久久精品亚洲福利| 国产亚洲精品成人a v小说| 99热精品毛片全部国产无缓冲| 精品一区二区久久久久久久网站| 精品无码国产一区二区三区51安 | 99精品全国免费观看视频..| 蜜芽亚洲av无码精品色午夜| 日韩精品无码久久一区二区三| 国产精品无码免费播放| 香蕉国产精品频视| 国产精品你懂得| 55夜色66夜色国产精品视频| 久久99久久99精品免视看动漫| 亚洲国产精品无码成人片久久| 日本精品一区二区三区在线视频一 | 亚洲精品亚洲人成人网| 无码精品第一页| 无码国产亚洲日韩国精品视频一区二区三区 | 精品久久人妻av中文字幕| 亚洲国产精品一区二区成人片国内 | 国产精品久久99| 国产精品美女久久久| 久久精品国产只有精品2020| 精品国产福利久久久| 四虎成人www国产精品| 中文字幕一区二区精品区| 国产99久久久国产精品~~牛 | 国产成人精品视频2021| 国产高清一级毛片精品| 国产伦精品一区二区三区视频猫咪 | 久久亚洲精品人成综合网|