플러터로 웹뷰 세팅하기
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.30Lighthouse 성능 개선하기 경매정보 검색 앱 '비드'를 만드는 과정에서 Lighthouse를 이용해 성능을 개선해보았습니다. 발단 LightHouse 는 클라이언트 사이드에서 웹 성능을 측정해주는 간편한 도구입니다. 퍼포먼스, 접근성, SEO 등을 평가합니다. 아무런 생각 없이 기능위주의 구현을 했다가 뭔가 느린 것 같아서 측정을 해보니 Performance 31점, TTI 11초라는 참담한 결과를 맞이하였습니다…. 문제 진단 우선 어디가 문제인지 점검하기 위해서 @next/bundle-analyzer를 설치해서 파일 크기를 확인해보았습니다. 일단 const.ts의 파일이 매우 크다는 것을 알 수 있었습니다. 필터가 굉장히 덩치가 큰데, 필터 구조가 복잡하기 때문입니다. 지역, 법… -
gitlab에서 github으로 미러링 과정 중 인증 문제 해결하기
gitlab에서 github으로 미러링 과정 중 인증 문제 해결하기
2022.08.07프로젝트를 깃랩에서 관리하고 배포를 위해 깃허브로 미러링을 시켰습니다. 액세스 토큰을 다시 발급받으면서 토큰이 갱신되었는데, 갱신된 토큰을 다시 입력해도 깃랩에서 계속 오류가 뜨면서 미러링이 안되는 문제가 있었습니다. 해결 방법 Mirroring Repository에 username 뒤에 토큰을 같이 입력해주면 됩니다. https://username:personalacesstoken@gihub.com/repo.git Reference https://forum.gitlab.com/t/authentication-fails-when-trying-to-mirror-gitlab-com-repo-to-github/3137 -
온룸 파일 다운로드 관련 이슈와 해결한 방법
온룸 파일 다운로드 관련 이슈와 해결한 방법
2022.02.11 -
TypeScript Object, object, {} 비교
TypeScript Object, object, {} 비교
2021.11.26
댓글을 사용할 수 없습니다.