
하이브리드 애플리케이션 개발에서 WebView는 웹 콘텐츠와 네이티브 코드의 연결을 담당하는 중요한 역할을 합니다. 특히, iOS와 Android에서 WebView와 네이티브 코드 간의 원활한 통신을 구현하려면 플랫폼별 요구 사항을 충족해야 합니다. 이 글에서는 WebView와 네이티브 통신을 지원하는 TypeScript 기반 인터페이스와 각 플랫폼(iOS, Android, React Native, Flutter)에서의 연동 방법을 설명합니다.
웹뷰와 네이티브 간 통신은 웹 콘텐츠(JavaScript)와 네이티브 코드(Swift, Kotlin/Java 등)가 서로 데이터를 주고받는 과정을 의미합니다. 이를 통해 웹뷰에서 네이티브 기능을 호출하거나, 네이티브 코드에서 웹뷰를 제어할 수 있습니다.
주요 활용 사례:
웹 콘텐츠에서 네이티브 기능 호출 (예: 카메라, 파일 업로드)
네이티브에서 웹뷰의 JavaScript 함수 실행
웹뷰에서 네이티브로 데이터 전달 (예: 사용자 입력 데이터)
네이티브에서 웹 콘텐츠 업데이트
WebView와 네이티브 간 통신은 JavaScript 함수를 통해 이루어집니다. TypeScript를 사용하여 다음과 같은 인터페이스를 설계할 수 있습니다:
interface webViewApp {
foo: () => string;
bar?: () => Promise<void>;
getDeviceInfo?: () => Record<string, any>;
}
declare global {
interface Window {
webView: webViewApp;
webKit?: {
messageHandlers: {
foo: {
postMessage: (message: string) => void;
},
bar?: {
postMessage: (message: string) => void;
};
};
};
}
}
const webViewInterface = {
foo(): string {
if (window.webView && typeof window.webView.foo === 'function') {
return window.webView.foo();
} else if (
window.webKit &&
window.webKit.messageHandlers.foo &&
typeof window.webKit.messageHandlers.foo.postMessage === 'function'
) {
window.webKit.messageHandlers.foo.postMessage('');
return 'Message sent to iOS';
}
throw new Error('No suitable webView interface available for foo method');
},
async bar(): Promise<void> {
if (window.webView && typeof window.webView.bar === 'function') {
await window.webView.bar();
} else if (
window.webKit &&
window.webKit.messageHandlers.bar &&
typeof window.webKit.messageHandlers.bar.postMessage === 'function'
) {
window.webKit.messageHandlers.bar.postMessage('');
} else {
throw new Error('No suitable webView interface available for bar method');
}
},
};
export default webViewInterface;
import WebKit
class ViewController: UIViewController, WKScriptMessageHandler {
override func viewDidLoad() {
let contentController = WKUserContentController()
contentController.add(self, name: "foo") // 메시지 핸들러 추가
let config = WKWebViewConfiguration()
config.userContentController = contentController
let webView = WKWebView(frame: self.view.bounds, configuration: config)
self.view.addSubview(webView)
let url = URL(string: "https://example.com")!
webView.load(URLRequest(url: url))
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
if message.name == "foo" {
print("foo method called from WebView")
}
}
}
import android.webkit.JavascriptInterface
import android.webkit.WebView
import android.webkit.WebViewClient
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val webView = WebView(this).apply {
settings.javaScriptEnabled = true
webViewClient = WebViewClient()
addJavascriptInterface(WebAppInterface(), "webView")
loadUrl("file:///android_asset/index.html")
}
setContentView(webView)
}
inner class WebAppInterface {
@JavascriptInterface
fun foo() {
println("foo method called from WebView")
}
}
}
import React from 'react';
import { WebView } from 'react-native-webview';
const App = () => {
return (
<WebView
source={{ uri: 'https://example.com' }}
onMessage={(event) => {
if (event.nativeEvent.data === 'foo') {
alert('foo method called');
}
}}
/>
);
};
export default App;
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewExample extends StatelessWidget {
@override
Widget build(BuildContext context) {
return WebView(
initialUrl: 'https://example.com',
javascriptMode: JavascriptMode.unrestricted,
javascriptChannels: <JavascriptChannel>{
JavascriptChannel(
name: 'foo',
onMessageReceived: (message) {
print('foo method called from WebView');
},
),
},
);
}
}
WebView와 네이티브 간 통신은 하이브리드 앱 개발에서 필수적입니다. 위에서 설명한 방식으로 통신 인터페이스를 설계하면, iOS, Android, React Native, Flutter 등 다양한 플랫폼에서 일관된 동작을 보장할 수 있습니다. 여러분의 프로젝트에 이 코드를 적용해보세요! 🚀
추가적인 질문이 있다면 댓글로 알려주세요. 😊