<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
        主站蜘蛛池模板: 国产A∨免费精品视频| 亚洲中文字幕在线无码一区二区| 亚洲啪啪免费视频| 水蜜桃视频在线观看免费播放高清 | 欧洲黑大粗无码免费| 伊伊人成亚洲综合人网7777| 亚洲av永久无码精品秋霞电影秋| 久久久国产精品福利免费| 国产精品亚洲不卡一区二区三区 | 久久精品毛片免费观看| 国产成人亚洲精品狼色在线| 国产成人高清亚洲一区久久| 免费高清小黄站在线观看 | 国产亚洲精品无码拍拍拍色欲| 精品国产亚洲第一区二区三区| 成人人观看的免费毛片| 国产91在线|亚洲| 国产成人A在线观看视频免费 | 亚洲国产精品自产在线播放| 久久亚洲精品无码av| 精品国产免费观看久久久| 亚洲精品无码专区久久| 在线jyzzjyzz免费视频| 亚洲国产一区二区三区在线观看| 妞干网免费视频在线观看| 亚洲色偷偷综合亚洲av78 | 亚洲国产精品成人午夜在线观看| 毛片视频免费观看| 99亚洲乱人伦aⅴ精品| 国产jizzjizz免费看jizz| 色多多A级毛片免费看| 中文字幕亚洲综合久久男男| 中文字字幕在线高清免费电影| 亚洲成在人线av| 亚洲免费一级视频| 亚洲人成网站999久久久综合| 国产免费人成在线视频| 精品熟女少妇aⅴ免费久久| 亚洲第一AAAAA片| 日本免费网址大全在线观看 | 亚洲AV无码第一区二区三区|