>웹 프론트엔드 >JS 튜토리얼 >반응 네이티브 WebView를 호출하지 않고 반환 처리를 해결하는 방법

반응 네이티브 WebView를 호출하지 않고 반환 처리를 해결하는 방법

php中世界最好的语言
php中世界最好的语言원래의
2018-03-17 13:32:042198검색

이번에는 React-Native WebView를 호출하지 않고 반환 처리를 해결하는 방법을 보여드리겠습니다. 보세요.

1. 서문 프로젝트에는 자주 변경되는 페이지 내용이 있습니다. 이러한 페이지를 해결하려면 웹 페이지를 사용하는 것이 좋습니다.

RN 프로젝트에 공개 웹 페이지를 제공하세요. 웹 콘텐츠인 경우 이 인터페이스로 이동하여 표시하세요.

현재 문제는 웹 페이지에 첫 번째 수준 페이지와 두 번째 수준 페이지가 있으며 탐색 모음의 Return 키(및

Android

의 Return 키)를 처리하도록 설계된다는 것입니다. 이 문제의 해결 방법은 RN 공식 홈페이지에서 확인하실 수 있습니다. onNavigationStateChange 콜백 메소드를 사용하여 현재 탐색 상태를 기록하면 이전 페이지로 돌아갈지, 아니면 이 웹페이지를 종료하고 앱의 다른 인터페이스로 돌아갈지 결정할 수 있습니다.

그러나 웹페이지 구현이 React인 경우에는 페이지가 점프할 때 onNavigationStateChange 콜백 메소드에 콜백이 없다는 것을 알게 될 것입니다! ! ! 얼마나 뚱뚱해! !

처음에는 웹 주소를 콜백을 받을 수 있는 바이두로 바꾸려고 했으나 모든게 잘 돌아가긴 했지만 우리 링크로 바꾸니 안 되서 누구 탓인가 싶어 백엔드에 전가했습니다. React를 잘못 썼습니다.

지난 프로젝트가 빡빡했고 소스 코드를 자세히 살펴볼 시간이 없었기 때문에 웹 페이지에서 js를 사용하여 앱을 다시 호출하는 솔루션이 완성되지 않았습니다. 현재 탐색 상태를 알려줍니다.

이제 소스 코드를 읽고 실제 이유를 알아내는 시간을 조금 갖게 되었습니다.

2. 이유

이 문제의 원인과 해결 방법을 분석해 보겠습니다.

1. 먼저 소스코드의 위치를 ​​찾습니다.

node_modulesreact-nativeReactAndroidsrcmainjavacomfacebookreactviewswebview

node_modulesreact-nativeLibrariesComponentsWebView

디렉토리 구조

는 다음과 같습니다.

2. 구현된 코드 세그먼트(JAVA 측)

RN의 실제 실행 코드는 Native 코드입니다. , 따라서 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 이벤트

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.

( node_modulesreact -nativeLibrariesComponentsWebViewWebView.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. Solution

이제 원인을 찾았으니 해결은 쉽습니다

해결책: 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
   );
  }
}

以上就是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中文网其它相关文章!

推荐阅读:

JS怎样操作改变radio的状态

JS脚本加载后再执行相应回调函数的操作

위 내용은 반응 네이티브 WebView를 호출하지 않고 반환 처리를 해결하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.