Heim  >  Artikel  >  Web-Frontend  >  Behandlung der Rückgabemethode ohne Rückruf über WebView in React-Native

Behandlung der Rückgabemethode ohne Rückruf über WebView in React-Native

亚连
亚连Original
2018-06-04 11:42:092149Durchsuche

In diesem Artikel wird hauptsächlich die detaillierte Erklärung der reaktionsnativen WebView-Rückgabeverarbeitung vorgestellt (kann durch Nicht-Rückrufmethoden gelöst werden). Jetzt teile ich sie mit Ihnen und gebe sie als Referenz.

1. Vorwort

Es gibt einige Seiten im Projekt, die sich häufig ändern. Wir werden erwägen, Webseiten zu verwenden, um diese Seiten zu lösen.

Stellen Sie eine öffentliche Webseite im RN-Projekt bereit. Wenn es sich um Webinhalte handelt, springen Sie zur Anzeige zu dieser Schnittstelle.

Ein Problem zu diesem Zeitpunkt besteht darin, dass die Webseite eine Seite der ersten Ebene und eine Seite der zweiten Ebene haben wird, die für die Handhabung der Return-Taste der Navigationsleiste (und die Handhabung der Rückkehr) ausgelegt sind Schlüssel auf Android).

Die Lösung für dieses Problem finden Sie auf der offiziellen RN-Website. Verwenden Sie einfach die Rückrufmethode onNavigationStateChange, um den aktuellen Navigationsstatus aufzuzeichnen, um zu bestimmen, ob Sie zur vorherigen Seite zurückkehren oder diese Webseite verlassen und zu anderen Schnittstellen der App zurückkehren möchten.

Wenn die Implementierung der Webseite jedoch React ist, tritt ein Problem auf. Wenn die Seite springt, hat die Rückrufmethode onNavigationStateChange keinen Rückruf! ! ! Wie fett! !

Zuerst habe ich versucht, die Webadresse auf die von Baidu zu ändern, die Rückrufe empfangen kann, aber es hat nicht funktioniert, wenn ich sie auf unseren Link geändert habe, also habe ich die Schuld dem gegeben Backend, ich dachte, es sei React. Welcher Teil ist falsch geschrieben.

Da das letzte Projekt knapp war und ich keine Zeit hatte, mir den Quellcode anzusehen, dachte ich über eine nicht sehr vollständige Lösung nach, nämlich die Verwendung von js auf der Webseite, um die App zurückzurufen Informieren Sie sich über den aktuellen Navigationsstatus. Die Anzeige ist unfreundlich.

Jetzt, da ich etwas Zeit hatte, den Quellcode zu lesen, kann ich den wahren Grund verstehen.

2. Gründe

Lassen Sie mich die Ursache dieses Problems und meine Lösung analysieren.

1. Suchen Sie zunächst den Speicherort des Quellcodes.

node_modulesreact-nativeReactAndroidsrcmainjavacomfacebookreactviewswebview

node_modulesreact-nativeLibrariesComponentsWebView

Die Verzeichnisstruktur ist wie folgt:

2. Implementiertes Codesegment (JAVA-Seite)

Der tatsächlich laufende Code von RN ist nativer Code, also tatsächlich einige Ereignisrückrufe wie die WebView-Komponente Sie werden alle durch Rückrufe im nativen Code ausgelöst. Wie folgt

(ReactWebViewManager.java) rn Version 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 Version 0.43.3, RN anders Versionen Es wird Codeanpassungen geben, daher sind bei einem RN-Upgrade sorgfältige Regressionstests erforderlich.

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)

In dieser Datei ist die entsprechende Beziehung definiert

/**
 * 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. Implementiertes Codesegment (JS-Seite)

(node_modulesreact-nativeLibrariesComponentsWebViewWebView.android.js)

Im folgenden Code können Sie sehen, dass nur onLoadingStart und onLoadingFinish updateNavigationState aufrufen. Das Problem tritt hier auf, weil wir die Webseite Die Implementierung ist React und es gibt nur eine Seite! Daher werden onLoadingStart und onLoadingFinish nur einmal aufgerufen. Durch erneutes Klicken auf die Detailseite wird nicht zu einer neuen Seite gesprungen, sondern die Originalseite wird aktualisiert. Es gibt also keinen updateNavigationState-Rückruf.

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. Lösung

Nachdem die Ursache gefunden wurde, ist es einfach, sie zu beheben

Lösung: WebView anpassen, doUpdateVisitedHistory-Verarbeitung hinzufügen und JS jedes Mal benachrichtigen, wenn sich die Navigation ändert.

1. Kopieren Sie die Dateien im Bild unten in das Android-Codeverzeichnis in unserem eigenen Projekt

Das kopierte Android-Verzeichnis:

Es gibt mehrere Stellen, die in ReactWebViewManager.java geändert werden müssen

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 ist ein Ereignis, das ich speziell selbst hinzugefügt habe zum Benachrichtigen von Navigationsänderungen

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

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

Dann fügen Sie dieses Modul in MainApplication hinzu

public class MainApplication extends Application implements ReactApplication {
  @Override
  protected List<ReactPackage> getPackages() {
   return Arrays.<ReactPackage>asList(
     new MainReactPackage(),
     new ReactWebViewPackage()  //WebView
   );
  }
}

Das Obige ist, was auf Android geändert werden muss. Ich habe es nicht auf iOS ausprobiert. Es sollte ganz anders sein.

2. Kopieren Sie die Datei im Bild unten in das JS-Codeverzeichnis in unserem eigenen Projekt und ändern Sie den Namen

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实现,不能导航的问题。

上面是我整理给大家的,希望今后会对大家有帮助。

相关文章:

在vue中如何解决v-for使用报红并出现警告的问题(详细教程)

在Vuejs中如何实现搜索匹配功能方法(详细教程)

在vue.js中利用select下拉框实现绑定和取值方法

Das obige ist der detaillierte Inhalt vonBehandlung der Rückgabemethode ohne Rückruf über WebView in React-Native. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn