Heim >Web-Frontend >js-Tutorial >So lösen Sie die Rückgabeverarbeitung von React-Native WebView, ohne es aufzurufen
Dieses Mal zeige ich Ihnen, wie Sie die Rückgabeverarbeitung von React-Native WebView ohne Aufruf lösen Ein praktischer Fall, werfen wir einen Blick darauf.
1. VorwortEs 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 derzeit besteht darin, dass die Webseite eine Seite der ersten Ebene und eine Seite der zweiten Ebene haben wird, die für die Handhabung der Eingabetaste der Navigationsleiste (sowie für die Verarbeitung der Return-Taste 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 2. Implementiertes Codesegment (JAVA-Seite)Der tatsächlich laufende Code von RN ist nativer Code, also wie der WebView Komponente Einige der Ereignisrückrufe werden tatsächlich durch Rückrufe im nativen Code ausgelöst. Wie folgt
(ReactWebViewManager.java) rn Version 0.47.1
(ReactWebViewManager.java) rn Version 0.43.3, verschiedene Versionen von RN haben Codeanpassungen, also wenn RN Wird aktualisiert, erfordert sorgfältige Regressionstests.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))); } //... }(TopLoadingStartEvent.java) Callback JS Event
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))); } //... }(node_modulesreact-nativeReactAndroidsrcmainjavacomfacebookreactuimanagerUIManagerModuleConstants.java)
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); } }
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 Code-Snippet (JS-Seite)
(node_modulesreact-nativeLibrariesComponentsWebViewWebView.android.js)
Im folgenden Code können Sie sehen Dass nur onLoadingStart und onLoadingFinish updateNavigationState aufrufen, tritt hier auf. Da unsere Webseite in React implementiert ist, gibt es 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('RCTWebView', WebView, { //对应上面JAVA中的 ‘RCTWebView' nativeOnly: { messagingEnabled: PropTypes.bool, }, }); module.exports = WebView;2. Lösung
Nachdem die Ursache gefunden wurde, ist es einfach, sie zu beheben.
Lösung: Passen Sie WebView an und fügen Sie die doUpdateVisitedHistory-Verarbeitung hinzu , benachrichtigen Sie JS jedes Mal, wenn sich die Navigation ändert.
1. Kopieren Sie die Dateien im Bild unten in das Android-Codeverzeichnis in unserem eigenen Projekt
拷贝完后的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 ); } }
以上就是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 = 'webview1'; //此处需要修改名称 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('RCTWebView1', CustomWebView, CustomWebView.extraNativeComponentConfig); //修改名称 module.exports = CustomWebView; //修改名称
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Das obige ist der detaillierte Inhalt vonSo lösen Sie die Rückgabeverarbeitung von React-Native WebView, ohne es aufzurufen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!