개요
Web View
모바일 앱을 사용하다가 웹 사이트에 접근해야할 때가 있다.
이럴 때 기본 브라우저를 통해 이동하는 로직을 짜도 되지만, 이렇게 되면 사용자들이 서비스(앱)에서 쉽게 이탈하게 된다.
이런 이탈을 방지하기 위해 앱 자체에 웹 뷰를 놓기도 하고, 좀 더 편의성을 높이기 위해 앱 자체에서 웹 뷰를 배치하기도 한다.
Flutter에는 이 웹 뷰가 위젯의 형태로 되어있어서 위젯을 도입하는 방식으로 쉽게 적용할 수 있다.
문제점
Dependency에 flutter_webview를 넣는 것으로 웹 뷰를 쉽게 도입할 수 있는데, 문제는 참고할 만한 정보가 굉장히 적다.
Flutter 공식에서 제공하는 튜토리얼의 최종 업데이트는 2022년 1월 25일인데, webview_flutter의 업데이트는 2023년 5월 23일에 4.2.1버전으로 이루어졌다. ▼
업데이트 자체는 큰 문제가 아닐 수도 있다.
iOS가 업데이트 되었다고 사용성 면에서 큰 차이가 나지 않고, 새로운 기능만 추가가 되는 것을 생각해보면 어쩌면 그리 심각한 문제가 아닐 수 있다.
하지만 2022년 12월 17일에 배포된 4.0.0부터는 사용성에 차이가 생겼다.
더 이상 WebView()
로 위젯을 사용하지 않고, WebViewWidget()
으로 호출하는 것부터 controller에서 대부분의 것들을 처리하는 것이 차이점이다.
하지만 튜토리얼은 그 이전 버전인 3.x.x 버전을 기준으로 소개를 하고 있기에 사용 방식에서의 차이가 있어 튜토리얼을 통해 사용방법을 익히는 것이 불가능해졌다.
요즘 블로그들이 이해하기 쉽게 정리가 잘 된 편이라 블로그의 힘을 빌리려고 했지만, 대부분의 글들이 3.x.x 버전을 기준으로 설명을 해놓았기에 도움이 되지 않았다.
해결
그래서 이를 해결하기 위해 공식 문서와 해외의 최신 프로젝트들을 찾아서 webview를 적용했다.
그리고 어떻게 쉽게 해결했는지 글로 정리해놓기로 했다.
WebViewWidget (4.2.1 기준) 사용
WebViewWidget()
웹 뷰를 도입하기 위해서는 WebViewWidget()
을 사용해야한다.
3.x.x 버전과 4.x.x 버전의 가장 큰 차이점이다.
WebViewWidget()
자체를 사용하는 것은 어렵지 않다.
아래와 같이 WebViewWidget()을 호출하고 그 안에 controller를 넣어주면 된다. ▼
class WebPagePractice extends StatelessWidget {
const WebPagePractice({super.key});
@override
Widget build(BuildContext context) {
WebPageViewController webPageViewController = WebPageViewController();
return Scaffold(
body: WebViewWidget(
controller: webPageViewController.controller,
),
);
}
}
WebViewController()
그렇다면 문제는 controller다.
WebViewWidget()
자체의 이용은 호출 한 번으로 끝나지만, 이를 이용하기 위해 controller를 만들어야 한다.
WebViewController
클래스가 있기에 클래스 내용을 채우면 된다.
필자는 나중에 다른 기능도 더 넣기 위해 해당 controller를 WebPageViewController
로 한 번 더 감쌌다. ▼
class WebPageViewController {
var controller = WebViewController()
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
debugPrint('WebView is loading (progress : $progress%)');
},
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://noguen.tistory.com/'));
}
코드를 하나씩 확인해보자.
var controller = WebViewController()
기본적으로 WebViewController라는 클래스가 webview_flutter 패키지에 정의가 되어있다.
우리가 해야할 일은 이 클래스 인스턴스를 만들고, 내용을 채우는 것이다.
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
debugPrint('WebView is loading (progress : $progress%)');
},
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://noguen.tistory.com/'));
채울 내용은 총 3가지로, setBackgroundColor
, setNavigationDelegate
, loadRequest
이다.
이 중에서 필수로 채워야 하는 건 setNavigationDelegate
, loadRequest
이다.
이들은 .. 연산자로 호출되며, .. 연산자의 의미는 한 클래스 인스턴스에서 연속적으로 다음 내용들을 수행하겠다는 의미이다.
setBackgroundColor
웹 뷰 바탕 화면 색상을 정해주는 메소드이다.
로딩 되기 전에는 바탕 화면을 보여주긴 하나 짧은 시간 보여주기 때문에 디테일을 살릴게 아니라면 굳이 설정하지 않아도 된다.
setNavigationDelegate
Delegate 패턴?
Delegate 패턴이 뭔지 모른다면 아래의 글을 읽고 오시는걸 추천합니다.
웹 페이지와 관련된 것들을 대신 다뤄주는 Delegate 클래스다.
NavigationDelegate(
onProgress: (int progress) {
debugPrint('WebView is loading (progress : $progress%)');
},
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
로딩 요청을 시작하는 부분이다.
..loadRequest(Uri.parse('원하는 url'));
웹뷰의 목적인 ‘원하는 사이트 보여주기’ 를 수행하게 해주는 메소드다.
예제 코드 전문
class WebPageViewController {
var controller = WebViewController()
..setBackgroundColor(const Color(0x00000000))
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
debugPrint('WebView is loading (progress : $progress%)');
},
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('원하는 url'));
}
class WebViewPage {
const WebViewPage({super.key});
@override
Widget build(BuildContext context) {
var controller = WebPageViewController();
return Scaffold(
appBar: AppBar(),
body: SafeArea(
child: WebViewWidget(
controller: controller,
),
),
);
}
}
'Develop > Flutter' 카테고리의 다른 글
[Flutter] Const를 사용해야하는 이유 (2) | 2024.02.14 |
---|---|
[Flutter][Widget] FloatingActionButton 위젯 (0) | 2024.02.12 |
[Flutter] FutureBuilder로 비동기 화면 그리기 (feat.GetX) (0) | 2024.02.01 |
[Flutter] Dart의 Single Quote와 Double Quote (0) | 2024.01.31 |
[Flutter] 파이어베이스 이메일 인증에서 생긴 문제 (0) | 2024.01.23 |