플러터로 웹뷰 세팅하기
Flutter 앱에 WebView 추가 를 읽으면서 정리한 글입니다.
pubspec.yaml에 의존성 추가
아래 명령어로 플러그인을 추가합니다.
flutter pub add webview_flutter flutter pub get
main.dart
에 웹뷰 추가
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; void main() { runApp( const MaterialApp( home: WebViewApp(), ), ); } class WebViewApp extends StatefulWidget { const WebViewApp({Key? key}) : super(key: key); @override State<WebViewApp> createState() => _WebViewAppState(); } class _WebViewAppState extends State<WebViewApp> { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter WebView'), ), body: const WebView( initialUrl: 'https://flutter.dev', ), ); } }
하이브리드 컴포지션 설정
import 'dart:io'; // Add this import. import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; void main() { runApp( const MaterialApp( home: WebViewApp(), ), ); } class WebViewApp extends StatefulWidget { const WebViewApp({Key? key}) : super(key: key); @override State<WebViewApp> createState() => _WebViewAppState(); } class _WebViewAppState extends State<WebViewApp> { // Add from here ... @override void initState() { if (Platform.isAndroid) { WebView.platform = SurfaceAndroidWebView(); } super.initState(); } // ... to here. @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter WebView'), ), body: const WebView( initialUrl: 'https://flutter.dev', ), ); } }
하이브리드 컴포지션이란 네이티브 웹뷰를 플러터 위젯 안에서 보여주는 것을 의미합니다.
페이지 로드 이벤트 수신 대기
import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class WebViewStack extends StatefulWidget { const WebViewStack({Key? key}) : super(key: key); @override State<WebViewStack> createState() => _WebViewStackState(); } class _WebViewStackState extends State<WebViewStack> { var loadingPercentage = 0; @override Widget build(BuildContext context) { return Stack( children: [ WebView( initialUrl: 'https://flutter.dev', onPageStarted: (url) { setState(() { loadingPercentage = 0; }); }, onProgress: (progress) { setState(() { loadingPercentage = progress; }); }, onPageFinished: (url) { setState(() { loadingPercentage = 100; }); }, ), if (loadingPercentage < 100) LinearProgressIndicator( value: loadingPercentage / 100.0, ), ], ); } }
위 코드처럼 웹뷰를 웹뷰스택이라는 Stateful 컴포넌트로 감싸줄 수 있습니다. 그리고 웹뷰스택의 로딩 상태값을 웹뷰의 로딩이벤트에서 조작하는 방식으로 설정하면 웹뷰 가 로드되는 동안 linearProgressIndicator가 움직이는 것을 보여줄 수 있습니다.
WebViewController를 사용하여 작업하기
WebViewStack을 아래와 같이 업데이트합니다.
import 'dart:async'; // Add this import for Completer import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class WebViewStack extends StatefulWidget { const WebViewStack({required this.controller, Key? key}) : super(key: key); // Modify final Completer<WebViewController> controller; // Add this attribute @override State<WebViewStack> createState() => _WebViewStackState(); } class _WebViewStackState extends State<WebViewStack> { var loadingPercentage = 0; @override Widget build(BuildContext context) { return Stack( children: [ WebView( initialUrl: 'https://flutter.dev', // Add from here ... onWebViewCreated: (webViewController) { widget.controller.complete(webViewController); }, // ... to here. onPageStarted: (url) { setState(() { loadingPercentage = 0; }); }, onProgress: (progress) { setState(() { loadingPercentage = progress; }); }, onPageFinished: (url) { setState(() { loadingPercentage = 100; }); }, ), if (loadingPercentage < 100) LinearProgressIndicator( value: loadingPercentage / 100.0, ), ], ); } }
컨트롤러를 추가합니다. 컨트롤러는 Completer
로, 콜백을 Future(Promise) 로 만듭니다.
탐색 컨트롤 만들기
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class NavigationControls extends StatelessWidget { const NavigationControls({required this.controller, Key? key}) : super(key: key); final Completer<WebViewController> controller; @override Widget build(BuildContext context) { return FutureBuilder<WebViewController>( future: controller.future, builder: (context, snapshot) { final WebViewController? controller = snapshot.data; if (snapshot.connectionState != ConnectionState.done || controller == null) { return Row( children: const <Widget>[ Icon(Icons.arrow_back_ios), Icon(Icons.arrow_forward_ios), Icon(Icons.replay), ], ); } return Row( children: <Widget>[ IconButton( icon: const Icon(Icons.arrow_back_ios), onPressed: () async { if (await controller.canGoBack()) { await controller.goBack(); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('No back history item')), ); return; } }, ), IconButton( icon: const Icon(Icons.arrow_forward_ios), onPressed: () async { if (await controller.canGoForward()) { await controller.goForward(); } else { ScaffoldMessenger.of(context).showSnackBar( const SnackBar(content: Text('No forward history item')), ); return; } }, ), IconButton( icon: const Icon(Icons.replay), onPressed: () { controller.reload(); }, ), ], ); }, ); } }
위 코드로 네비게이션 바를 만들 수 있습니다. 컨트롤러를 상속받아서 뒤로/앞으로/새로고침 등을 수행합니다.
import 'dart:async'; // Add this import import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; // Add this import back import 'src/navigation_controls.dart'; // Add this import import 'src/web_view_stack.dart'; void main() { runApp( const MaterialApp( home: WebViewApp(), ), ); } class WebViewApp extends StatefulWidget { const WebViewApp({Key? key}) : super(key: key); @override State<WebViewApp> createState() => _WebViewAppState(); } class _WebViewAppState extends State<WebViewApp> { final controller = Completer<WebViewController>(); // Instantiate the controller @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text('Flutter WebView'), // Add from here ... actions: [ NavigationControls(controller: controller), ], // ... to here. ), body: WebViewStack(controller: controller), // Add the controller argument ); } }
위 코드처럼 메인에서 컨트롤러를 만들고 아래로 전달해줄 수 있습니다.
NavigationDelegate로 탐색 추적
import 'dart:async'; import 'package:flutter/material.dart'; import 'package:webview_flutter/webview_flutter.dart'; class WebViewStack extends StatefulWidget { const WebViewStack({required this.controller, Key? key}) : super(key: key); final Completer<WebViewController> controller; @override State<WebViewStack> createState() => _WebViewStackState(); } class _WebViewStackState extends State<WebViewStack> { var loadingPercentage = 0; @override Widget build(BuildContext context) { return Stack( children: [ WebView( initialUrl: 'https://flutter.dev', onWebViewCreated: (webViewController) { widget.controller.complete(webViewController); }, onPageStarted: (url) { setState(() { loadingPercentage = 0; }); }, onProgress: (progress) { setState(() { loadingPercentage = progress; }); }, onPageFinished: (url) { setState(() { loadingPercentage = 100; }); }, // Add from here ... navigationDelegate: (navigation) { final host = Uri.parse(navigation.url).host; if (host.contains('youtube.com')) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( 'Blocking navigation to $host', ), ), ); return NavigationDecision.prevent; } return NavigationDecision.navigate; }, // ... to here. ), if (loadingPercentage < 100) LinearProgressIndicator( value: loadingPercentage / 100.0, ), ], ); } }
NavigationDelegate
를 이용하여 탐색을 추적하고 차단할 수 있습니다.
'Dev Log' 카테고리의 다른 글
Lighthouse로 성능 개선하기 (0) | 2022.08.30 |
---|---|
gitlab에서 github으로 미러링 과정 중 인증 문제 해결하기 (0) | 2022.08.07 |
온룸 파일 다운로드 관련 이슈와 해결한 방법 (0) | 2022.02.11 |
TypeScript Object, object, {} 비교 (0) | 2021.11.26 |
오픈소스에 기여하는 법 : MDN 문서에 기여하기 (0) | 2021.11.10 |
댓글
이 글 공유하기
다른 글
-
Lighthouse로 성능 개선하기
Lighthouse로 성능 개선하기
2022.08.30 -
gitlab에서 github으로 미러링 과정 중 인증 문제 해결하기
gitlab에서 github으로 미러링 과정 중 인증 문제 해결하기
2022.08.07 -
온룸 파일 다운로드 관련 이슈와 해결한 방법
온룸 파일 다운로드 관련 이슈와 해결한 방법
2022.02.11 -
TypeScript Object, object, {} 비교
TypeScript Object, object, {} 비교
2021.11.26
댓글을 사용할 수 없습니다.