뚝딱뚝딱 모바일

[Flutter] 앱에서는 WebView, 웹에서는 iframe 구분하기 본문

Flutter 지식

[Flutter] 앱에서는 WebView, 웹에서는 iframe 구분하기

규석 2023. 11. 30. 16:14

안녕하세요!

오늘은 화면 내의 새로운 웹창을 띄울 때, 앱과 웹의 구분을 해보도록 하겠습니다.


그냥 WebView로 만들고, Web으로 실행시키면 되지 않나요?라고 생각하실 수 있습니다.

하지만 Flutter WebView 관련 패키지들은 Web에 대해 지원해주지 않습니다. (생각해 보면 좀 모순 같기도...)

그렇기에, 앱에서는 WebView, 웹에서는 iframe이 뜨도록 분기 처리를 해보도록 하겠습니다.

 

먼저, 파일 두 개를 만들어주겠습니다.

하나는 WebView, 하나는 iframe을 담당할 파일입니다.

이름은 마음대로..!

그리고 각 두개의 파일에 하나의 함수를 만들건대, 이 두 개의 함수들의 이름과, 인자 모두 같은 함수여야 합니다.

함수 오버로딩도 아니고 완전 같은 함수를 만들라고요?

 

네. 이렇게 만드는 이유는 import 때문입니다. iframe을 만들 때 사용할 패키지인 dart:html 패키지가 App 실행 시에는 오류가 나는 패키지이기 때문입니다. 그렇기 때문에 Web으로 실행하였을 때는 WebIFrame 경로로 실행, App으로 실행하였을 때는 AppWebVIew 경로로 실행하여야 합니다.

 

먼저 전 inappwebview 패키지를 사용하였고, 이에 대한 코드는 다른 WebView로도 적용하실 수 있습니다.

AppWebView 파일

Widget getWebView({
  String? src,
  String? id,
  Function(dynamic)? listener,
  WebViewController? controller
}) {
  return WebViewWidget(controller: controller!);
}

반환값이 같아야 하니 Widget으로 하였고, 여기선 controller 인자만 사용하여, WebVIewWidget에 넣어주고 반환하였습니다.

WebIFrame 파일

// 필수 import
import 'dart:html';
import 'dart:ui_web' as ui;

Widget getWebView({
  String? src,
  String? id,
  Function(dynamic)? listener,
  WebViewController? controller
}) {
  IFrameElement iFrame = IFrameElement();
  iFrame.src = src;
  iFrame.id = id!;
  iFrame.style.border = 'none';

  if (listener != null) {
    window.addEventListener('message', listener);
  }

  ui.platformViewRegistry.registerViewFactory(id, (int viewId) => iFrame);

  return HtmlElementView(viewType: id);
}

웹을 해보셨던 분들이라면, 쉽게 이해하실 수 있으실 겁니다. iframe을 먼저 만들어서, 불러올 웹 링크를 src에 넣어주었고, 이 iframe을 구분할 id를 넣어주었습니다.

필요에 따라 웹에서 동작에 따른 response를 넘겨줄 수 있는데, Listener를 추가하여, 받을 수 있도록 하였습니다. 웹에서는 아래 코드로 데이터를 넘겨주도록 합니다.

window.postMessage(data, '*');
or
window.parent.postMessage(data, '*');

 

이제 함수 구성은 끝났습니다. 화면으로 가서 넣어봅시다.

WebViewPage

@override
Widget build(BuildContext context) {
    .
    .  some view
    .
    getWebView(
        src: 'YOUR URL',
        id: 'YOUR ID',
        controller: yourController,
        listener: (value) { print(value.toString); }
    )
    .
    .  some view
    .
);

이렇게 코드를 작성하시고 import를 보시면, AppWebView 파일이나, WebIFrame 파일 둘 중 하나만 import 되어 있을 겁니다.

이제 분기 처리를 해줍시다.

import 'AppWebView.dart'
  if (dart.library.html) 'WebIFrame.dart';

AppWebView 파일로 import를 하는데, 만약 html을 사용한다면, WebIFrame 파일로 import를 해라 이런 뜻입니다.

이를 위해서 함수의 인자와 이름, 반환값까지 같이 맞췄던 것입니다. 조금이라도 달라지면, 다른 함수로 취급받아 새로운 import를 요구하기 때문입니다.

 

웹과 앱 모두 실행시켜보면, 잘 돌아가는 것을 보실 수 있습니다.