앱 개발을 하다보면 웹뷰(Webview)를 띄워야할 상황이 생깁니다.(지금이 바로 그 순간..) 앱 특성 상 웹보다 한계가 많기 때문인데, 저의 경우에는 게시글의 URL 클릭 시 페이지를 웹뷰로 보여주기 위해 사용하였습니다.
앱 내 웹뷰를 위해 react-native-webview
라이브러리를 사용했습니다.
🔗 npm 링크
웹뷰를 띄우는 방법을 크게 2가지로 나눠 살펴보면,
1️⃣ uri로 웹 연결
import React from 'react';
import { WebView } from 'react-native-webview';
const App = () => {
return (
<Webview
source={{uri: 'https:...중략'}}
/>
);
};
2️⃣ inline HTML 사용
import React from 'react';
import { WebView } from 'react-native-webview';
const App = () => {
return (
<Webview
originWhitelist={['*']}
source={{html: '<h1>Hello world</h1>'}} />
);
};
먼저 게시글 상세화면에 집입했을 때 웹 URL가 있다면 URL를 간략하게 보여주는 UI를 제작했고, UI 컴포넌트를 클릭했을 때 해당 웹 URL을 웹뷰로 보여주는 로직입니다.
(사용한 props
나 메서드
는 주석으로 설명을 적어놨습니다.)
//communityDetailScreen.js
<WebView
ref={wvRef} //웹뷰 컴포넌트의 새로고침이나 navigation 등을 처리하기 위해 ref를 사용
originWhitelist={['*']}
source={{ uri: `${loadWebUrl.trim()}` }} //uri를 사용
style={{ flex: 1 }}
injectedJavaScript={eventScript} //View가 로드될 때 자바스크립트를 웹페이지에 주입
// WebView가 window.postMessage를 call하면 호출
onMessage={(event) => {
handleMessage(event);
}}
...중략
// WebView 로딩이 시작되거나 끝나면 호출
onNavigationStateChange={(navState) => {
...중략
setCanGoback(navState.canGoBack); // 뒤로 갈 수 있는 체크하는 state
setCanGoForward(navState.canGoForward); // 앞으로 갈 수 있는 체크하는 state
setCurrentWebUrl(navState.url); // 현재 url 저장 -> 외부 링크(ex, 사파리)로 사용자가 이동하려고 할 때 필요한 url
}}
// WebView가 시작될 때 호출
onShouldStartLoadWithRequest={(request) => {
...중략
}}
onError={() => {
setIsWebPageError(true);
}}
/>;
웹뷰에 대한 적용이 끝났다면, 이제 웹뷰를 감싸는 UI를 만들어보겠습니다.
<IconBtn
iconName={canGoback ? 'communityBrowserBackActive' : 'communityBrowserBack'}
onPress={() => {
wvRef && wvRef.current.goBack();
}}
/>
<IconBtn
iconName={canGoForward ? 'communityBrowserForwardActive' : 'communityBrowserForward'}
onPress={() => {
wvRef && wvRef.current.goForward();
}}
/>
<IconBtn
iconName={isWebPageError ? 'communityIconDisableBrowserRefresh' : 'communityBrowserRefresh'}
onPress={() => {
wvRef && wvRef.current.reload();
}}
/>
<IconBtn
iconName={isWebPageError ? 'communityIconDisableBrowserExternal' : 'communityBrowserExternalBrowser'}
onPress={async () => {
try {
await Linking.openURL(currentWebUrl);
} catch (e) {
AppUtils.CONSOLE_ERR(e.message);
}
}}
/>
웹뷰를 이용할 경우 (특히 안드로이드에서) Intent
가 동작하지 않는 경우가 있습니다. 대표적으로 많이 사용하는 카카오링크 공유하기 기능을 사용할 때 카카오 JavaScript SDK
에서는Intent
로 카카오 링크를 전송하는데 웹뷰에 이 기능이 구현되어있지 않다면 에러를 내뱉습니다🤮..
npm i react-native-send-intent
yarn add react-native-send-intent
설치 후 안드로이드 세팅을 끝내면 onShouldStartLoadWithRequest
함수에 intent
링크 로직을 추가해주면 됩니다.
const onShouldStartLoadWithRequest = (request) => {
if (event.url.startsWith('http://') || event.url.startsWith('https://') || event.url.startsWith('about:blank')) {
return true;
}
if (Platform.OS === 'android' && request.url.indexOf('intent') !== -1) {
SendIntentAndroid.openChromeIntent(event.url)
.then(isOpened => {
if (!isOpened) {
// console.log('앱 실행 실패')
}
})
.catch(err => {
console.log(err);});
return false;
...중략
최근 앱이지만 웹뷰로 운영되는 서비스가 많이 보입니다. 앱 업데이트 없이 배포 + 앱 반영이 가능하다보니 앱을 사용하는 사용자들의 빈번한 업데이트를 막을 수 있는 큰 장점 때문인 것 같습니다. 그렇지만..웹뷰 또한 한계는 존재하니(웹으로 진입할 때 뜨는 하얀화면 등등)…. 결국 앱과 웹 둘 다 잘하고 싶다는 뜻입니다🥶
그래서 다음에는 웹으로 사이드 프로젝트를 진행 + 페이지를 띄운 후에 앱에서 웹뷰로 사이드 프로젝트를 실행시키는 작업을 진행할 생각입니다. 화이팅!💪
https://www.npmjs.com/package/react-native-webview
https://www.mrlatte.net/code/2020/12/18/react-native-webview-intent