Flutter 웹뷰에서 JavaScript 채널 구현하기
문제 상황
사내 어드민 시스템을 Flutter 앱에 웹뷰로 임베딩하는 작업을 진행했다. 웹에서 파일 업로드 시 네이티브 카메라를 호출해야 하는 요구사항이 생겼다. 순수 웹뷰만으로는 불가능해서 JavaScript와 네이티브 간 통신 방법을 찾아봤다.
해결 방법
webview_flutter 패키지(버전 1.0.7)의 JavascriptChannel을 사용했다.
import 'package:webview_flutter/webview_flutter.dart';
class AdminWebView extends StatefulWidget {
@override
_AdminWebViewState createState() => _AdminWebViewState();
}
class _AdminWebViewState extends State<AdminWebView> {
WebViewController _controller;
@override
Widget build(BuildContext context) {
return WebView(
initialUrl: 'https://admin.example.com',
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (controller) {
_controller = controller;
},
javascriptChannels: Set.from([
JavascriptChannel(
name: 'NativeChannel',
onMessageReceived: (JavascriptMessage message) {
_handleNativeCall(message.message);
},
),
]),
);
}
void _handleNativeCall(String action) async {
if (action == 'openCamera') {
final image = await ImagePicker().getImage(source: ImageSource.camera);
if (image != null) {
_controller.evaluateJavascript(
"window.onImageSelected('${image.path}')"
);
}
}
}
}
웹 쪽에서는 다음처럼 호출한다.
function openCamera() {
if (window.NativeChannel) {
window.NativeChannel.postMessage('openCamera');
} else {
// 웹 브라우저에서 실행 시 폴백
document.getElementById('fileInput').click();
}
}
window.onImageSelected = function(path) {
console.log('Image selected:', path);
// 이미지 처리 로직
};
주의사항
javascriptMode를unrestricted로 설정해야 채널이 동작한다.- iOS에서는
Info.plist에 카메라 권한 설정이 필요하다. - 웹 환경에서도 동작하도록 분기 처리를 해뒀다.
재택 근무 중이라 디바이스 테스트가 번거로웠지만, Flutter Hot Reload 덕분에 빠르게 검증할 수 있었다.