반응형
Overview
- 플러터를 이용하여 웹 페이지를 표시하고, 웹 문서를 이용하여 화면 표시가 가능하도록 합니다.
포스팅을 보기 전에...
이 글은 webview_flutter 패키지를 통해 안드로이드 가상 에뮬레이터로 웹 페이지를 표시하는 것을 목표로 합니다.
또한 포스팅에서 설명하는 소스 코드는 웹뷰 패키지가 4.0 이상의 버전으로 작성하였습니다.
3.0 버전으로 작성된 웹뷰 코드와 많이 다를 수 있습니다.
이 포스팅에서의 웹 뷰 구현은 WebView가 아닌 WebViewWidget을 사용하며, 컨트롤러를 이용합니다.
WebView는 Deprecated 되어서 이후 버전에서는 사용이 어려울 수 있습니다.
포스팅에서의 환경
- Flutter Version : 3.11.0-6.0.pre.108
- webview_flutter: ^4.2.0
- webview_flutter_android: ^3.7.0
- webview_flutter_wkwebview: ^3.4.3
- Android Emulator : Pixel_3a_API_33_x86_64
예시 - webview_flutter 3.0에서의 웹 뷰 구현 코드
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('WebView Example'),
),
body: WebView(
initialUrl : 'https://luvris2.tistory.com/',
),
);
}
예시 - webview_flutter 4.0 이상, 이 포스팅에서의 다루는 코드
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('WebView Example'),
),
body: WebViewWidget(
controller: _controller,
),
);
}
}
웹 뷰 설정
프로젝트에 웹 뷰 패키지 추가
- 터미널에서 아래의 명령어 입력
- 웹뷰 사용시 접속하는 디바이스가 안드로이드일지 iOS일지 모르므로 디바이스에 따라 보여줄 웹뷰 설정을 위함
- 현재 웹뷰는 모바일 기기에서만 작동합니다. 윈도우나 크롬으로 디버그하면 에러화면이 나옵니다.
flutter pub add webview_flutter
flutter pub add webview_flutter_android
flutter pub add webview_flutter_wkwebview
Android SDK 버전 설정
- 이 포스팅은 안드로이드 에뮬레이터를 기준으로 포스팅하였습니다.
- Android Emulator : Pixel_3a_API_33_x86_64
- 안드로이드에서 웹 뷰 컴파일시 33 이상의 API 버전이 필요합니다.
- 그렇지 않으면 아래와 같이 에러 출력됩니다.
- (프로젝트 디렉토리에서) android - app - build.gradle 파일 열기
- android 안의 'compileSdkVersion' 부분을 33 로 수정
- defaultConfig 안의 'minSdkVersion' 부분을 19 로 수정
- compileSdkVersion : 컴파일 시 사용되는 버전, 최신 기능 사용을 위해 가능한 최신 버전 사용 권장
- minSdkVersion : 앱 구동 최소 버전, 가능한 많은 기기에서 설치를 위해 가능한 낮은 버전으로 선택
구문
webview_flutter 공식 문서에 따르면 웹뷰는 컨트롤러를 이용하여 웹 페이지를 표시하고,
컨트롤러를 인스턴스화하여 웹뷰에 제공하는 형태의 코드를 제공합니다.
사실 샘플 코드를 보고 실행이 되지 않아 한참을 해맸습니다...
설명이 부실한건지 내가 멍청한 건지... 후자겠죠... ㅠㅠㅠ
웹 뷰 컨트롤러 인스턴스화
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
// Update loading bar.
},
onPageStarted: (String url) {},
onPageFinished: (String url) {},
onWebResourceError: (WebResourceError error) {},
onNavigationRequest: (NavigationRequest request) {
if (request.url.startsWith('https://www.youtube.com/')) {
return NavigationDecision.prevent;
}
return NavigationDecision.navigate;
},
),
)
..loadRequest(Uri.parse('https://flutter.dev'));
컨트롤러를 웹 뷰 위젯으로 전달
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Flutter Simple Example')),
body: WebViewWidget(controller: controller),
);
}
코딩 (기능 구현)
웹 뷰 사용을 위한 패키지 임포트
- 웹 뷰를 표시할 webview_flutter 패키지
- 안드로이드용 웹 뷰 패키지 : webview_flutter_android
- iOS용 웹 뷰 패키지 : webview_flutter_wkwebview
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
// Import for Android features.
import 'package:webview_flutter_android/webview_flutter_android.dart';
// Import for iOS features.
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
웹 뷰 위젯 구현
- 웹 뷰를 보여주려면 'WebViewWidget' 위젯을 이용하여야 합니다.
- 페이지 표시는 컨트롤러를 통해 제공합니다.
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('WebView Example'),
),
// 웹 뷰
body: WebViewWidget(
controller: _controller,
),
);
}
컨트롤러 생성
- 웹뷰 컨트롤러 인스턴스를 생성합니다.
- late : 변수를 액세스 하기 전에 값이 할당됨을 나타냄, 초기 값을 미리 제공하지 않는 변수 선언
- final : 나주엥 값이 할당되고 초기화 후 재할당 할 수 없는 변수 선언
// 웹뷰 컨트롤러 인스턴스 생성
late final WebViewController _controller;
- 컨트롤러를 생성하기 위해 initState 를 이용하여 앱 실행시 컨트롤러를 생성해줍니다.
- 아래의 코드들은 모두 initState에서 작성하기 때문에 아래의 코드에선 '}' 기호를 사용하여 initState를 닫지 않습니다.
@override
initState() {
super.initState();
- 가장 먼저 컨트롤러가 어떤 환경의 기기에서 실행되는지 확인합니다.
// 플랫폼별 웹 뷰 컨트롤러 생성에 필요한 매개변수
late final PlatformWebViewControllerCreationParams params;
// 디바이스가 iOS일 경우
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
params = WebKitWebViewControllerCreationParams(
allowsInlineMediaPlayback: true,
mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
);
}
// 디바이스가 Android일 경우
else if (WebViewPlatform.instance is AndroidWebViewPlatform) {
params = const PlatformWebViewControllerCreationParams();
}
- 실행된 환경에 맞는 컨트롤러를 생성합니다.
// 플랫폼에 맞는 컨트롤러 생성
final WebViewController controller =
WebViewController.fromPlatformCreationParams(params);
if (controller.platform is AndroidWebViewController) {
AndroidWebViewController.enableDebugging(true);
(controller.platform as AndroidWebViewController)
.setMediaPlaybackRequiresUserGesture(false);
}
- 컨트롤러를 설정합니다.
- 참고 : onNavigationRequest에서 웹 페이지 접근 금지, 표시 처리를 할 수 있습니다.
- 그러나 아무리 테스트해봐도 prevent 한 웹페이지가 접속이 됩니다. 알아본 결과 loadRequest가 먼저 실행되어서 prevent 설정이 무시된다고는 하는데 자세히는 모르겠습니다. 알고 계신분 알려주세요...
// 컨트롤러 설정
controller
// 웹뷰에서 자바스크립트 코드 실행 여부 : 제한없이 사용
..setJavaScriptMode(JavaScriptMode.unrestricted)
// 웹 뷰 배경색 설정 : 투명 배경
..setBackgroundColor(const Color(0x00000000))
// 웹 뷰 이벤트 및 요청을 처리할 대리자 설정
..setNavigationDelegate(
NavigationDelegate(
// 페이지 로딩 진행률 표시
onProgress: (int progress) {
// Update loading bar.
print('Update loading bar : $progress');
},
// 새 페이지가 로드 될 때 실행되는 코드
onPageStarted: (String url) {
print('onPageStarted : $url');
},
// 페이지 로드가 완료 될 때 실행되는 코드
onPageFinished: (String url) {
print('onPageFinished : $url');
},
// 웹 리소스 로드 오류 시 실행 되는 코드
onWebResourceError: (WebResourceError error) {
print('WebResourceError : $error');
},
// 내비게이션 요청 시 실행되는 코드
// 요청된 URL을 기반으로 표시를 허용할지 금지할지 결정
onNavigationRequest: (NavigationRequest request) {
// url이 유튜브일 경우 : 웹 페이지 표시 금지
if (request.url.startsWith('https://www.youtube.com/')) {
return NavigationDecision.prevent;
}
// url이 유튜브가 아닐 경우 : 웹 페이지 표시
return NavigationDecision.navigate;
},
),
)
// 보여줄 페이지 URL
..loadRequest(Uri.parse('https://luvris2.tistory.com/'));
- 생성한 컨트롤러를 웹뷰 컨트롤러 인스턴스에 저장합니다.
- 저장 후 iniState 의 함수를 닫습니다.
_controller = controller;
}
전체 소스 코드
- main.dart
더보기
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
// Import for Android features.
import 'package:webview_flutter_android/webview_flutter_android.dart';
// Import for iOS features.
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';
void main() => runApp(const MaterialApp(home: MyWebView()));
class MyWebView extends StatefulWidget {
const MyWebView({super.key});
@override
State<MyWebView> createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
late final WebViewController _controller;
@override
initState() {
super.initState();
// 플랫폼별 웹 뷰 컨트롤러 생성에 필요한 매개변수
late final PlatformWebViewControllerCreationParams params;
// 디바이스가 iOS일 경우
if (WebViewPlatform.instance is WebKitWebViewPlatform) {
params = WebKitWebViewControllerCreationParams(
allowsInlineMediaPlayback: true,
mediaTypesRequiringUserAction: const <PlaybackMediaTypes>{},
);
}
// 디바이스가 Android일 경우
else if (WebViewPlatform.instance is AndroidWebViewPlatform) {
params = const PlatformWebViewControllerCreationParams();
}
// 플랫폼에 맞는 컨트롤러 생성
final WebViewController controller =
WebViewController.fromPlatformCreationParams(params);
if (controller.platform is AndroidWebViewController) {
AndroidWebViewController.enableDebugging(true);
(controller.platform as AndroidWebViewController)
.setMediaPlaybackRequiresUserGesture(false);
}
// 컨트롤러 설정
controller
// 웹뷰에서 자바스크립트 코드 실행 여부 : 제한없이 사용
..setJavaScriptMode(JavaScriptMode.unrestricted)
// 웹 뷰 배경색 설정 : 투명 배경
..setBackgroundColor(const Color(0x00000000))
// 웹 뷰 이벤트 및 요청을 처리할 대리자 설정
..setNavigationDelegate(
NavigationDelegate(
// 페이지 로딩 진행률 표시
onProgress: (int progress) {
// Update loading bar.
print('Update loading bar : $progress');
},
// 새 페이지가 로드 될 때 실행되는 코드
onPageStarted: (String url) {
print('onPageStarted : $url');
},
// 페이지 로드가 완료 될 때 실행되는 코드
onPageFinished: (String url) {
print('onPageFinished : $url');
},
// 웹 리소스 로드 오류 시 실행 되는 코드
onWebResourceError: (WebResourceError error) {
print('WebResourceError : $error');
},
// 내비게이션 요청 시 실행되는 코드
// 요청된 URL을 기반으로 표시를 허용할지 금지할지 결정
onNavigationRequest: (NavigationRequest request) {
// url이 유튜브일 경우 : 웹 페이지 표시 금지
if (request.url.startsWith('https://www.youtube.com/')) {
return NavigationDecision.prevent;
}
// url이 유튜브가 아닐 경우 : 웹 페이지 표시
return NavigationDecision.navigate;
},
),
)
// 보여줄 페이지 URL
..loadRequest(Uri.parse('https://luvris2.tistory.com/'));
_controller = controller;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('WebView Example'),
),
body: WebViewWidget(
controller: _controller,
),
);
}
}
앱 실행
- 앱 실행 화면
- 콘솔 화면
- 컨트롤러 설정 시 내비게이션 대리자를 통한 정보를 콘솔에 표시한 화면
코드 간소화
- 코드가 너무 길어서 사용하기 불편하다면 모든 설정을 생략하고 간소화하여 웹페이지를 표시할 수 있습니다.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() => runApp(const MaterialApp(home: MyWebView()));
class MyWebView extends StatefulWidget {
const MyWebView({super.key});
@override
State<MyWebView> createState() => _MyWebViewState();
}
class _MyWebViewState extends State<MyWebView> {
// 웹뷰 컨트롤러 인스턴스 생성
late final WebViewController _controller;
@override
initState() {
super.initState();
// 보여줄 페이지 URL
_controller = WebViewController()
..loadRequest(Uri.parse('https://luvris2.tistory.com/'));
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('WebView Example'),
),
body: WebViewWidget(
controller: _controller,
),
);
}
}
- 실행 화면
참고
- flutter - pub.dev - package - webview_flutter
- flutter - webview_flutter package - documentation - webview_flutter - WebViewController class
- flutter - webview_flutter package - documentation - webview_flutter - NavigationDelegate class
반응형