react-native WebView 리 턴 처리(비 리 턴 방법 으로 해결 가능)
프로젝트 중 일부 페이지 의 내용 은 변경 이 비교적 빈번 한데,이 페이지 들 은 우리 가 웹 페이지 로 해결 하 는 것 을 고려 할 것 이다.
RN 프로젝트 에 공용 웹 페이지 를 제공 하고 웹 콘 텐 츠 라면 이 화면 으로 이동 해 보 여 줍 니 다.
이 때 문 제 는 웹 페이지 에 1 급 페이지,2 급 페이지 가 있 는데 이것 은 네 비게 이 션 표시 줄 리 턴 키 의 처리(그리고 안 드 로 이 드 에서 리 턴 키 의 처리)로 설계 된다 는 것 이다.
이 문 제 는 RN 홈 페이지 에서 해결 방법 을 찾 을 수 있다.현재 내 비게 이 션 상 태 를 onNavigation StateChange 라 는 리 셋 방법 으로 기록 하여 이전 페이지 로 돌아 갈 지,이 페이지 를 종료 할 지,App 의 다른 인터페이스 로 돌아 갈 지 판단 하 는 것 입 니 다.
그러나 웹 페이지 의 실현 이 React 일 때 문제 가 생 길 수 있 습 니 다.페이지 가 이동 할 때 onNavigation State Change 라 는 리 셋 방법 이 리 셋 되 지 않 았 음 을 발견 할 수 있 습 니 다!!어떻게 뚱뚱 해!!
처음에 홈 페이지 주 소 를 바 이 두 로 바 꾸 려 고 시 도 했 는데 리 셋 을 받 을 수 있 고 모든 것 이 잘 작 동 되 었 지만 우리 의 링크 로 바 꾸 면 안 되 기 때문에 냄비 를 백 스테이지 에 던 져 서 React 어느 쪽 이 잘못 쓴 줄 알 았 습 니 다.
지난 프로젝트 는 시간 이 촉박 해서 소스 코드 를 잘 볼 시간 이 없어 서 완선 하지 않 은 해결 방안 을 생각 했다.즉,웹 페이지 는 js 로 앱 을 돌려 현재 의 네 비게 이 션 상 태 를 알 리 는 것 이다.이런 해결 방식 은 우호 적 이지 않다.
지금 은 소스 코드 를 보고 나 서 야 진짜 이 유 를 알 수 있 었 다.
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)));
}
//...
}
(TopLoading StartEvent.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_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)
아래 코드 에 서 는 onLoading Start 만 볼 수 있 습 니 다. onLoading Finish 와 호출 됩 니 다. updateNavigation State,문 제 는 바로 여기에 나 타 났 습 니 다.우리 의 웹 페이지 는 React 이기 때문에 한 페이지 밖 에 없습니다!그래서 한 번 만 onLoadingStart 를 호출 합 니 다. onLoading Finish 와자세 한 페이지 를 클릭 하면 새 페이지 로 넘 어가 지 않 고 원래 페이지 를 새로 고침 합 니 다.그래서 updateNavigation State 리 셋 도 없 었 어 요.
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,추가 doUpdateVisited History 처 리 는 내 비게 이 션 이 변 할 때마다 JS 에 알 립 니 다.
1.다음 그림 의 파일 을 우리 프로젝트 의 Android 코드 디 렉 터 리 에 복사 합 니 다.
복사 한 Android 디 렉 터 리:
ReactWebView Manager.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
);
}
}
이상 은 안 드 로 이 드 가 수정 해 야 할 부분 입 니 다.ios 는 시도 해 본 적 이 없습니다.큰 차이 가 있 을 것 입 니 다.같은 이치 입 니 다.2.다음 그림 의 파일 을 우리 프로젝트 의 JS 코드 디 렉 터 리 에 복사 하고 이름 을 수정 합 니 다.
JS 코드 디 렉 터 리:
Custom WebView.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; //
이로써 사용자 정의 WebView 모듈 을 완성 합 니 다.웹 페이지 는 React 구현 으로 내 비게 이 션 이 불가능 한 문제 도 해결 할 수 있다.이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
nginx 에서 사이트 아이콘 표시 설정전단 개발 환경: react:^16.4.1 webpack:^4.16.0 웹 팩 에 favicon. ico 설정 추가: nginx 는 ico 에 대한 지원 을 추가 합 니 다:...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.