<span id="mktg5"></span>

<i id="mktg5"><meter id="mktg5"></meter></i>

        <label id="mktg5"><meter id="mktg5"></meter></label>
        最新文章專題視頻專題問答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
        主站蜘蛛池模板: 在线涩涩免费观看国产精品| 亚洲精品在线视频| 日韩av无码免费播放| 亚洲精品乱码久久久久蜜桃| 蜜芽亚洲av无码精品色午夜| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 免费国产成人18在线观看| 亚洲国产精品久久人人爱| 四虎影视在线永久免费看黄| 久久久久国产免费| 亚洲中文字幕无码亚洲成A人片| 亚洲精品无码不卡在线播HE| 免费看AV毛片一区二区三区| 亚洲精品在线免费看| 国产国产人免费人成成免视频 | 日韩免费高清一级毛片| 久久亚洲精品国产亚洲老地址| 亚洲国产精品福利片在线观看| 免费a级毛片在线观看| 成年男女免费视频网站| 一级成人a做片免费| 亚洲色大情网站www| 精品日韩99亚洲的在线发布 | 一区二区三区免费电影| 在线亚洲高清揄拍自拍一品区| 亚洲AV日韩AV天堂久久| 国产亚洲人成网站在线观看| 国产片免费福利片永久| 毛片免费在线视频| 国产乱子精品免费视观看片| 久久精品乱子伦免费| 国产永久免费高清在线| 精品国产免费一区二区三区| 黄色a三级三级三级免费看| 亚洲国产精品成人AV在线| 精品国产成人亚洲午夜福利| 亚洲国产夜色在线观看| 久久亚洲精品中文字幕无码 | 免费观看91视频| 最新亚洲成av人免费看| 女人隐私秘视频黄www免费|