티스토리 뷰
728x90
반응형
프로젝트를 진행하면서 React Native WebView를 적용해야하는 일이 있어서 정리를 하면서 적용을 해 보았습니다.
웹뷰는 적용은 Android 및 ios를 같이 진행하겠습니다.
또한 참고 하시는 분들은 각자의 프로젝트 마다 구조가 다르니 중요한 컴포넌트와 프로세스만 정리를 하겠습니다.
Step 01 - WebView로 이동할 스택을 정하자!
- 저는 아래 사진에 있는 공지사항 클릭 시 웹뷰로 보내는 프로세스 입니다.
- Stack 코드를 보시면 StackNavigation안에 Stack.Screen을 정의하고 있습니다.
- Stack 코드의 36번 라인의 isCanBack은 뒤로 갈 수 있는지 판별하는 변수입니다.
- Stack 코드의 38번 라인의 if문은 웹뷰 상태에서 뒤로갈 곳이 있으면 이전 페이지로 돌아가게되며 그것이 아니라면 어플로 돌아오게 됩니다.
참고 * 9번 라인의 LogBox.ignoreLogs는 웹뷰의 경고처리를 나오지 안도록 해주는 역할 입니다.
https://stackoverflow.com/questions/60954742/how-to-pass-parent-function-to-child-screen-in-react-navigation-5
- 아래 js는 위에 사진에 보이는 공지사항 버튼 입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<Button
title={"공지사항"}
iconname={faMegaphone}
onPress={() =>
navigation.navigate("CommonStack", {
screen: "Board",
params: {
isCanBack: null,
},
})
}
activeOpacity={0.8}
/>
|
cs |
- 아래 js는 공지사항의 Stack 구조입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
import React from "react";
import { createStackNavigator } from "@react-navigation/stack";
import { Button, LogBox } from "react-native";
import Board from "../screens/board/index";
const Stack = createStackNavigator();
LogBox.ignoreLogs([
"Non-serializable values were found in the navigation state",
]);
export default function CommonStack() {
return (
<Stack.Navigator
initialRouteName="Home"
screenOptions={{
gestureEnabled: false,
headerShown: true,
cardStyle: { backgroundColor: "transparent" },
headerBackTitleVisible: false,
headerTintColor: "#414141",
headerStyle: {
borderBottomWidth: 1,
borderBottomColor: "#F0F0F0",
elevation: 0, //for android
shadowOpacity: 0, // for ios
},
}}
>
<Stack.Screen
name="Board"
options={(navigation) => ({
title: "공지사항",
headerLeft: (props) => {
// Android 및 ios에서 뒤로가기 클릭시 보내는 파라미터
const isCanBack = navigation.route.params.isCanBack;
if (isCanBack) {
return (
<Button
{...props}
title="Back"
color="#00cc00"
onPress={isCanBack.onPress}
/>
);
}
return <Button title="Back" color="red" {...props} />;
},
})}
component={Board}
/>
</Stack.Navigator>
);
}
|
cs |
Step 02 - ios, Android를 구분해주자!
- 위의 Stack에서 선언해 놓은 Board 컴포넌트입니다.
- 해당 Board 컴포넌트는 ios 및 Android에 따라서 보여주는 웹뷰의 형태가 달라집니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
import React from "react";
import { StyleSheet, View, Platform } from "react-native";
import IosPlatform from "../platform/iosPlatform";
import AndroidPlatform from "../platform/androidPlatform";
export default function Board() {
const url = "https://kdg-is.tistory.com/";
return (
<View style={styles.root}>
<View style={styles.browser}>
{Platform.OS === "ios" ? (
<IosPlatform url={url} />
) : (
<AndroidPlatform url={url} />
)}
</View>
</View>
);
}
const styles = StyleSheet.create({
browser: {
flex: 1,
flexDirection: "row",
},
root: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
display: "flex",
},
});
|
cs |
Step 03 - ios 웹뷰작업 해주자!
- IosPlatform 컴포넌트는 Board 컴포넌트로 url를 받아서 경로를 지정해줍니다.
- 다른 코드들도 있지만 우리가 봐야할 코드는 WebView의 onNavigationStateChange 입니다.
- onNavigationStateChange란?
- 웹뷰 로딩이 시작되거나 끝나면 호출하는 함수입니다. navState로 url이 변경되었는지 감지 할 수 있습니다.
- 16번 라인의 onNavigationStateChange 함수
- 인자로 navState를 받아서 navState속에 있는 canGoBack이라는 변수를 가져옵니다.
- 해당 19번 라인의 if ~ else문이 Stack.Screen의 Board에서 중요하게 사용하고 있는 isCanBack의 변수를 설정하는 곳입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
import React, { useState } from "react";
import { useNavigation } from "@react-navigation/core";
import { StyleSheet, View, ActivityIndicator } from "react-native";
import { WebView } from "react-native-webview";
const INJECTED_JAVASCRIPT = `(function() {
AsyncStorage.setItem("memberCode", 1);
AsyncStorage.setItem("isApp", true);
})();`;
export default function IosPlatform({ url }) {
const navigation = useNavigation();
const [browserRef, setBrowserRef] = useState(null);
const onNavigationStateChange = (navState) => {
const { canGoBack } = navState;
if (canGoBack) {
navigation.setParams({
isCanBack: {
title: "",
onPress: () => browserRef.goBack(),
},
});
} else {
navigation.setParams({
isCanBack: null,
});
}
};
return (
<View style={styles.root}>
<View style={styles.browserContainer}>
<WebView
ref={(ref) => {
setBrowserRef(ref);
}}
source={{
uri: url,
}}
startInLoadingState
originWhitelist={["*"]}
renderLoading={() => (
<View style={{ flex: 1, alignItems: "center" }}>
<ActivityIndicator size="large" />
</View>
)}
allowsBackForwardNavigationGestures
onNavigationStateChange={(navState) =>
onNavigationStateChange(navState)
}
injectedJavaScript={INJECTED_JAVASCRIPT}
onMessage={(event) => {}}
/>
</View>
</View>
);
}
const styles = StyleSheet.create({
root: {
flex: 1,
},
browserContainer: {
flex: 2,
},
});
|
cs |
ios 결과 화면
Step 04 - Android 웹뷰작업 해주자!
- 안드로이드는 기본적으로 아래에 뒤로가기 버튼도 있지만 ios처럼 상단에 뒤로가기 버튼도 만들어 주었습니다.
- AndroidPlatform 컴포넌트도 ios 컴포넌트처럼 봐야할 코드는 WebView의 onNavigationStateChange 입니다.
- 58번 라인에서 하드웨어적인 뒤로가기 처리와 소프트적인 뒤로가기 처리를 해주고 있습니다.
- backPress 함수는 ios 컴포넌트와 마찬가지로 동작 방식은 동일합니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
|
import React, { useRef, useState } from "react";
import { BackHandler } from "react-native";
import { useNavigation } from "@react-navigation/core";
import { useFocusEffect } from "@react-navigation/native";
import { WebView } from "react-native-webview";
const INJECTED_JAVASCRIPT = `(function() {
AsyncStorage.setItem("memberCode", 1);
AsyncStorage.setItem("isApp", true);
})();`;
export default function AndroidPlatform({ url }) {
const navigation = useNavigation();
const webview = useRef(null);
const [canGoBack, SetCanGoBack] = useState(false);
// 안드로이드의 하드웨어적인 뒤로가기 설정
useFocusEffect(
React.useCallback(() => {
const onBackPress = () => {
if (webview.current && canGoBack) {
webview.current.goBack();
return true;
} else {
return false;
}
};
BackHandler.addEventListener("hardwareBackPress", onBackPress);
return () =>
BackHandler.removeEventListener("hardwareBackPress", onBackPress);
}, [canGoBack])
);
// 안드로이드의 소프트웨어적인 뒤로가기 설정
const backPress = (navState) => {
const { canGoBack } = navState;
if (canGoBack) {
navigation.setParams({
isCanBack: {
title: "",
onPress: () => webview.current.goBack(),
},
});
} else {
navigation.setParams({
isCanBack: null,
});
}
};
return (
<WebView
source={{
uri: url,
}}
ref={webview}
onNavigationStateChange={(navState) => {
SetCanGoBack(navState.canGoBack) + backPress(navState);
}}
injectedJavaScript={INJECTED_JAVASCRIPT}
onMessage={(event) => {}}
/>
);
}
|
cs |
Android 결과 화면
참고 사이트)
https://www.reactnativeschool.com/integrating-react-navigation-back-button-with-a-webview
* 궁금하신 내용이 있으면 댓글을 달아주시면 답변드리겠습니다!
728x90
반응형
'React Native' 카테고리의 다른 글
expo - google map mapView의 getMapBoundaries사용 방법 (0) | 2021.09.10 |
---|---|
React Native Expo - Android 구글맵 연동 중 에러 (0) | 2021.09.07 |
React - prisma connectOrCreate사용 방법 (0) | 2021.05.14 |
React - apollo-server-express를 이용한 파일 업로드 방법 (0) | 2021.05.12 |
React - node - 12 이상에서 파일 업로드 버그 (0) | 2021.05.12 |
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
TAG
- spring boot 엑셀 다운로드
- java ThreadLocal
- spring boot excel download oom
- spring boot redisson 분산락 구현
- pipe and filter architecture
- 공간 기반 아키텍처
- @ControllerAdvice
- 레이어드 아키텍처란
- transactional outbox pattern spring boot
- service based architecture
- spring boot redisson sorted set
- space based architecture
- polling publisher spring boot
- java userThread와 DaemonThread
- redis 대기열 구현
- redis sorted set으로 대기열 구현
- 람다 표현식
- spring boot redis 대기열 구현
- spring boot excel download paging
- pipeline architecture
- spring boot redisson destributed lock
- 자바 백엔드 개발자 추천 도서
- 서비스 기반 아키텍처
- JDK Dynamic Proxy와 CGLIB의 차이
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- microkernel architecture
- transactional outbox pattern
- spring boot poi excel download
- redis sorted set
- 트랜잭셔널 아웃박스 패턴 스프링부트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
글 보관함