일정 작업이 완료되면 실행되는 함수
함수를 정의해두면 바로 실행되지 않고 특정 조건이 성립될 때 실행됨
WebViewController controller = WebViewController()
..setNavigationDelegate(NavigationDelegate(
// ① 로딩 완료 후 실행되는 함수 (콜백)
onPageFinished: (String url){
print(url);
}
))
onPageFinished( )는 웹뷰에서 페이지 로딩이 완료된 뒤에 실행되는 콜백 함수 이다.
이 함수는 첫 번째 매개변수로 로딩된 페이지의 URL을 반환해준다.
페이지 로딩 후 실행하고 싶은 작업이 있다면 함수 내부에 코드를 정의하면 된다.
웹뷰는 프레임워크에 내장된 브라우저를 앱의 네이티브
컴포넌트component에임베딩embedding하는 기능이다.
다시 말해 앱에서 웹 브라우저 기능을 구현해주는 기술이다.
장점
기존에 만든 웹사이트를 손쉽게 활용할 수 있다.
단점
웹뷰는 네이티브 컴포넌트에 비해 속도가 느리고 애니메이션이 부자연스럽다.
웹뷰를 구현할 때 사용할 웹뷰 위젯은 controller 파라미터에 WebViewController 객체를 입력해줘야 한다.
웹뷰 컨트롤러는 웹뷰 위젯을 제어하는데 필요한 기능들을 해준다.

프로젝트 초기화 방법과 권한 및 네이티브 설정 방법을 차례대로 알아보겠다.
모든 프로젝트에서 공통된 사항이므로 확실히 익혀두기 바란다.
pubspec.yaml 파일은 플러터 프로젝트와 관련된 설정을 하는 파일이다.
프로젝트에서 사용할 이미지 및 폰트를 지정하거나 사용할 오픈 소스 프로젝트들을 명시할 때 사용된다.
블로그 웹 앱 프로젝트에서 사용할 webview_flutter 플러그인을 pubspec.yaml 파일에 추가하고 [pub get]을 실행한다.
pubspec.yaml
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.2
webview_flutter: 4.4.1

안드로이드 설정 파일은 android/app/src/main/AndroidManifest.xml이다.
안드로이드 앱에 필요한 각종 권한을 여기서 설정할 수 있다.
AndroidManifest.xml 파일을 열어준다.
웹뷰를 실행할 때 인터넷을 사용해야 하니 인터넷 권한을 추가한다.
android/app/src/main/AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.blog_web_app">
<uses-permission android:name="android.permission.INTERNET" />
... 생략 ...
</manifest>


gradle 이란?
안드로이드의 빌드 툴이다.
android/build.gradle : 프로젝트 파일, 주로 클래스패스나 레포지토리 정보를 입력
android/app/build.gradle : 모듈 파일, 의존성이나 버전 정보 관리
android/app/build.gradle 파일 열기
android.compileSdkVersion 33으로 변경
android.defaultConfig.minSdkVersion 20으로 변경
compileSdkVersion은 앱을 빌드할 때 사용할 SDK 버전이다.
minSdkVersion은 안드로이드 운영체제의 최소 SDK 버전을 설정하는 위치이다.
webview_flutter플러그인을 사용하려면 안드로이드 최소 버전을 20이상으로 설정해야 한다.
이런 네이티브 관련 설정 정보는 보통 각 플러그인의pub.dev페이지에서 확인할 수 있다.
현대 웹사이트는 대부분 HTTPS 프로토콜을 사용하지만 아직 HTTP 프로토콜을 사용하는 웹사이트도 있다.
안드와 iOS에서는 기본적으로 보안때문에 HTTP 가 막혀 있으니 해제하려면 다음 코드를 추가해야 함.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="androis.permission.INTERNET" />
<application
android:label="blog_web_app"
android:name="${applicationName}"
android:icon="@mipmap/ic_launcher"
**android:usesCleartextTraffic="true"**
.
.
.
<application/>
<manifest/>
프로젝트가 커질 수록 폴더와 파일의 정리가 매우 중요하다.
앞으로 모든 프로젝트에서 화면과 관련된 모든 위젯을 screen폴더에 모아두겠다.
블로그 앱 웹을 실행했을 때, 가장 먼저 실행되는 홈 화면 위젯을 만들자
home_screen.dart 파일에 HomeScreen 이라는 StatelessWidget을 생성한다.
import 'package:flutter/material.dart';
class HomeScreen extends StatelessWidget {
// const 생성자.
const HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Text('Home Screen'),
);
}
}
생성자 앞에 const 키워드를 추가하면 const 인스턴스를 생성할 수 있다.
한번 생성된 const 인스턴스 위젯은 재활용되어 하드웨어 리소스를 적게 사용할 수 있다.
import 'package:blog_web_app/screen/home_screen.dart';
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: HomeScreen(),
);
}
}
MaterialApp 위젯은 플러터 앱의 최상위 위젯이며 앱이 처음 실행됐을 때 보여줄 화면을 home 매개변수에 입력할 수 있다.
앱바와 웹뷰로 구성되어있다.
앱바: 제목과 홈 버튼 렌더링하는 역할
웹뷰 : 지정한 URL 의 내용 보여줌
앱바 구현
웹뷰
웹뷰 컨트롤러
홈 버튼

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class HomeScreen extends StatelessWidget {
// const 생성자
HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orange,
title: Text('Code Factory'),
centerTitle: true,
),
body: Text('Home Screen'));
}
}

Appbar 위젯은 일반적으로 Scaffold 위젯의 appBar 매개변수로 넣어준다.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart'; // 1. 웹뷰 플러그인 import
class HomeScreen extends StatelessWidget {
// const 생성자
HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orange,
title: Text('Code Factory'),
centerTitle: true,
),
body: WebViewWidget( // 2. 웹뷰 위젯 추가
controller: webViewController,
));
}
}
웹뷰 위젯은 화면에 웹뷰를 렌더링해주는 역할을 한다.
웹뷰 위젯은 WebViewWidget 을 제어할 수 있는 controller 파라미터를 입력받는다.
웹뷰 컨트롤러는 웹뷰 위젯을 제어하는 역할을 한다.
웹뷰 위젯은 화면에 웹뷰를 렌더링해서 웹 사이트를 보여주는 역할을한다.
웹뷰 컨트롤러의 함수를 실행해서 웹뷰 위젯의 다양한 설정을 제어하고 웹사이트로 이동할 수 있다.
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class HomeScreen extends StatelessWidget {
WebViewController webViewController = WebViewController() // 1. WebViewController 선언
..loadRequest(Uri.parse("https:/blog.codefactory.ai")) // 2. WebViewController의 loadRequest() 함수 실행
..setJavaScriptMode(JavaScriptMode.unrestricted); // 3. JS가 제한 없이 실행될 수 있도록 함
// const 생성자
HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orange,
title: Text('Code Factory'),
centerTitle: true,
),
body: WebViewWidget(
controller: webViewController,
));
}
}
loadRequest() 함수는 웹뷰 위젯의 가장 중요한 함수이다.
loadRequest() 함수는 Uri 객체를 매개변수로 입력받아서 이 입력받은 값을 통해 지정한 사이트로 이동한다.
Uri 객체는 Uri.parse() static 함수가 존재하는데 이 함수에 이동하고싶은 사이트의 URL 을 입력하면 해당 URL이 Uri 객체로 자동 변경된다.

플러터 프로젝트를 실행하는 runApp() 함수는 내부적으로 WidgetsFlutterBinding.ensureInitialized() 함수를 실행하고 있다.
ensureInitialized() 함수는 플러터 프레임워크가 앱을 실행할 준비가 됬는지 확인하는 역할을 한다.
일반적으로 개발자가 직접 이 함수를 실행할 필요는 없지만 StatelessWidget 에서 WebViewController 를 프로퍼티로 직접 인스턴스화 하려면 ensureInitialized() 함수를 직접 실행해줘야 한다.
ensureInitialized() 함수를 직접 실행하지 않고 WebViewController를 정상적으로 인스턴스화 하는 방법은 StatefulWidget 의 initState() 함수에서 진행한다. 이는 나중에 배우겠다.
import 'package:blog_web_app/screen/home_screen.dart';
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized(); // Flutter 프레임워크가 앱을 실행할 준비가 될 때 까지 기다림
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
home: HomeScreen(),
);
}
}
앱바에 홈페이지로 돌아올 수 있는 홈 버튼을 제작해보자
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class HomeScreen extends StatelessWidget {
WebViewController webViewController = WebViewController()
..loadRequest(Uri.parse("https:/blog.codefactory.ai"))
..setJavaScriptMode(JavaScriptMode.unrestricted);
// const 생성자
HomeScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.orange,
title: Text('Code Factory'),
centerTitle: true,
// 1. AppBar에 액션 버튼을 추가하는 매개변수
actions: [
IconButton(
onPressed: () => { // 버튼을 눌렀을 때 실행할 콜백
webViewController // 웹뷰 위젯에서 사이트 전환하기
.loadRequest(Uri.parse('https:/blog.codefactory.ai'))
},
// 홈 버튼 아이콘 스타일 설정
icon: Icon(
Icons.home,
),
)
],
),
body: WebViewWidget(
controller: webViewController,
));
}
}
actions 매개변수에 위젯을 입력하면 AppBar의 우측 끝에서부터 순서대로 위젯이 배치된다. 세팅 버튼이나 필터링 옵션 버튼을 흔히 탑재하는 위치이다.
앱바 오른쪽에 집모양 아이콘이 잘 생겼다. 누르면 홈페이지로 잘 이동한다.
