서비스에 웹뷰 도입을 미루다 드디어 도입하면서 간단하게 React Native에서 WebView를 설정하고 웹과 소통하는 것에 대해 소개한다. (100% 서비스에 도입된 느낌은 아니지만 tutorial 정도로 정리)
Vite + React 웹 프로젝트 생성
React Native 프로젝트 생성
npx @react-native-community/cli init App
cd App
npm install react-native-webview
cd ios && pod install && cd ..
WEB과 APP이 서로 소통할 때 type, payload 방식으로 메시지를 주고받습니다.
WebView를 컴포넌트화 하기
initialToken이 있다면 앱에서 웹으로 전달handleMessage로 수신// SmartWebView.tsx
// 자세한 WebView 메서드: https://github.com/react-native-webview/react-native-webview/blob/master/docs/Reference.md
import React, { useEffect, useRef } from 'react';
import { KeyboardAvoidingView, Platform, View } from 'react-native';
import { WebView, WebViewMessageEvent } from 'react-native-webview';
interface SmartWebViewProps {
url: string;
initialToken?: string;
onWebMessage?: (type: string, payload: any) => void;
}
export const SmartWebView = ({ url, initialToken, onWebMessage }: SmartWebViewProps) => {
const webviewRef = useRef<WebView>(null);
useEffect(() => {
if (initialToken) {
setTimeout(() => {
webviewRef.current?.postMessage(
JSON.stringify({ type: 'SET_TOKEN', payload: initialToken })
);
}, 1000);
}
}, [initialToken]);
const handleMessage = (event: WebViewMessageEvent) => {
try {
const { type, payload } = JSON.parse(event.nativeEvent.data);
onWebMessage?.(type, payload);
} catch (e) {
console.warn('Invalid message format', e);
}
};
return (
<View style={{ flex: 1 }}>
<KeyboardAvoidingView behavior="padding" style={{ flex: 1 }} keyboardVerticalOffset={Platform.OS === 'ios' ? 0 : -200}>
<WebView
ref={webviewRef}
source={{ uri: url }}
javaScriptEnabled
onMessage={handleMessage}
/>
</KeyboardAvoidingView>
</View>
);
};
import React from 'react';
import { SafeAreaView, Alert } from 'react-native';
import { SmartWebView } from './SmartWebView';
const App = () => {
const handleWebMessage = (type: string, payload: any) => {
if (type === 'HELLO') {
Alert.alert('웹에서 온 메시지', payload);
}
};
return (
<SafeAreaView style={{ flex: 1 }}>
<SmartWebView
url={WEB_URL}
initialToken="mock-access-token-123"
onWebMessage={handleWebMessage}
/>
</SafeAreaView>
);
};
export default App;
import { useEffect, useState } from "react";
declare global {
interface Window {
ReactNativeWebView?: {
postMessage: (message: string) => void;
};
}
}
function App() {
const [accessToken, setAccessToken] = useState<string | null>(null);
useEffect(() => {
const handler = (event: MessageEvent) => {
try {
const message = JSON.parse(event.data);
if (message.type === "SET_TOKEN") {
setAccessToken(message.payload);
}
} catch (e) {
console.warn("[web] JSON parse error:", e);
}
};
window.addEventListener("message", handler);
return () => window.removeEventListener("message", handler);
}, []);
function sendMessageToApp() {
window.ReactNativeWebView?.postMessage(
JSON.stringify({ type: "HELLO", payload: "Hi from Web!" })
);
}
return (
<div>
<h1>Hello from Web</h1>
<p>✅ Access Token: {accessToken}</p>
<button onClick={sendMessageToApp}>앱을 수정해보았습니다!</button> // text를 변경해보았슴당 (앱으로 메시지 보내가 -> 앱을 수정해보았습니다!)
</div>
);
}
export default App;
✅ 앱에서 변경된 웹의 버튼과 웹으로 전달된 initial token을 볼 수 있다.
✅ 웹을 수정해보았습니다! 버튼을 클릭하고 웹에서 앱으로 메시지 수신하여 alert를 띄움.
message 기반 통신은 유연하지만, 플랫폼별로 동작 차이가 있고 WebView로 다루기 어려운 모바일 기능들도 존재.오랜만인데 이제 자주 블로그에 남겨야지...!