React-Native WebView の戻り処理メソッド

小云云
リリース: 2018-03-01 09:12:56
オリジナル
2448 人が閲覧しました

プロジェクト内の一部のページのコンテンツは頻繁に変更されます。これらのページを解決するために Web ページの使用を検討します。

RN プロジェクトで公開 Web ページを提供し、それが Web コンテンツの場合は、このインターフェイスにジャンプして表示します。

現時点での問題は、Web ページに第 1 レベルのページと第 2 レベルのページがあり、ナビゲーション バーのリターン キー (および Android のリターン キーの処理) を処理するように設計されていることです。 。

この問題の解決策は、RN 公式 Web サイトで見つけることができます。 onNavigationStateChange コールバック メソッドを使用して現在のナビゲーション状態を記録し、前のページに戻るか、この Web ページを終了してアプリの他のインターフェイスに戻るかを決定します。

しかし、Web ページの実装が React である場合、ページがジャンプするときに onNavigationStateChange コールバック メソッドにコールバックがないことがわかります。 ! !なんて太ったんだろう! !

最初は、Web アドレスをコールバックを受信できる Baidu のものに変更しようとしましたが、すべてうまくいきましたが、リンクに変更するとうまくいかなかったので、誰が責任を負うかをバックエンドに転嫁しました。リアクションを間違って書きました。

前回のプロジェクトはタイトで、ソースコードをじっくり見る時間がなかったため、あまり完全ではない解決策を思いつきました。それは、Web ページ上で js を使用してアプリをコールバックするというものです。現在のナビゲーションのステータスを通知します。このソリューションはフレンドリーではありません。

今、ソースコードを読んで本当の理由を見つける時間が少しあります。

この問題の原因と解決策を分析してみましょう。

1. まず、ソースコードの場所を見つけます。

node_modulesreact-nativeReactAndroidsrcmainjavacomfacebookreactviewswebview

no de_modulesreact-nativeLibrariesComponentsWebView

ディレクトリ構造は次のようになります:

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) Callback 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_modulesreact-nativeReactAndroidsrcmainjavacomfacebookreactuimanagerUIManagerModuleConstants.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_modulesreact-nativeLibrariesComponentsWebViewWebView.android.js)

以下のコードでは、Web ページの実装が React であるため、onLoadingStart と onLoadingFinish のみが updateNavigationState を呼び出すことがわかります。たった1ページだけ!したがって、onLoadingStart と onLoadingFinish は 1 回だけ呼び出されます。詳細ページをもう一度クリックしても、新しいページにはジャンプせず、元のページが更新されます。したがって、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(&#39;RCTWebView&#39;, WebView, {  //对应上面JAVA中的 ‘RCTWebView&#39;
 nativeOnly: { messagingEnabled: PropTypes.bool, }, });


 module.exports = WebView;
ログイン後にコピー

2. 解決策

原因が判明したので、解決するのは簡単です

解決策: WebViewをカスタマイズし、doUpdateVisitedHistory処理を追加し、ナビゲーションが変更されるたびにJSに通知します。

1. 下の図のファイルを独自のプロジェクトの Android コード ディレクトリにコピーします

コピーされた Android ディレクトリ:

ReactWebViewManager.java のいくつかの場所を変更する必要があります


TopCanGoBackEvent は、特にナビゲーションの変更を通知するために私が追加したイベントです

TopCanGoBackEvent.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)));
    }
 }
}
ログイン後にコピー

新しい ReactWebViewPage.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);
 }
}
ログイン後にコピー
を作成します

次に、このモジュールを MainApplication に追加します


れーれー

上記は 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 = &#39;webview1&#39;; //此处需要修改名称

 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(&#39;RCTWebView1&#39;, CustomWebView, CustomWebView.extraNativeComponentConfig); //修改名称

module.exports = CustomWebView; //修改名称
ログイン後にコピー

至此就完成自定义WebView模块。也可以解决网页是React实现,不能导航的问题。

以上がReact-Native WebView の戻り処理メソッドの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート