블로그 웹 앱 만들기(콜백함수와 웹뷰 위젯)

잠만보·2024년 8월 3일

사전지식

콜백 함수

일정 작업이 완료되면 실행되는 함수
함수를 정의해두면 바로 실행되지 않고 특정 조건이 성립될 때 실행됨

WebViewController controller = WebViewController()
  ..setNavigationDelegate(NavigationDelegate(
  // ① 로딩 완료 후 실행되는 함수 (콜백)
    onPageFinished: (String url){
      print(url);
    }
))

onPageFinished( )는 웹뷰에서 페이지 로딩이 완료된 뒤에 실행되는 콜백 함수 이다.

이 함수는 첫 번째 매개변수로 로딩된 페이지의 URL을 반환해준다.

페이지 로딩 후 실행하고 싶은 작업이 있다면 함수 내부에 코드를 정의하면 된다.

웹뷰 위젯

웹뷰는 프레임워크에 내장된 브라우저를 앱의 네이티브 컴포넌트component임베딩embedding하는 기능이다.
다시 말해 앱에서 웹 브라우저 기능을 구현해주는 기술이다.

장점
기존에 만든 웹사이트를 손쉽게 활용할 수 있다.

단점
웹뷰는 네이티브 컴포넌트에 비해 속도가 느리고 애니메이션이 부자연스럽다.

웹뷰를 구현할 때 사용할 웹뷰 위젯은 controller 파라미터에 WebViewController 객체를 입력해줘야 한다.
웹뷰 컨트롤러는 웹뷰 위젯을 제어하는데 필요한 기능들을 해준다.

웹뷰 컨트롤러에서 흔히 사용하는 함수들

프로젝트 사전 준비

프로젝트 초기화 방법과 권한 및 네이티브 설정 방법을 차례대로 알아보겠다.
모든 프로젝트에서 공통된 사항이므로 확실히 익혀두기 바란다.

1. pubspec.yaml 설정하기

pubspec.yaml 파일은 플러터 프로젝트와 관련된 설정을 하는 파일이다.
프로젝트에서 사용할 이미지폰트를 지정하거나 사용할 오픈 소스 프로젝트들을 명시할 때 사용된다.

블로그 웹 앱 프로젝트에서 사용할 webview_flutter 플러그인을 pubspec.yaml 파일에 추가하고 [pub get]을 실행한다.

pubspec.yaml

dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
webview_flutter: 4.4.1

주요 pub 명령어

2. 권한 및 네이티브 설정하기

안드로이드 설정

안드로이드 설정 파일은 android/app/src/main/AndroidManifest.xml이다.
안드로이드 앱에 필요한 각종 권한을 여기서 설정할 수 있다.

  1. AndroidManifest.xml 파일을 열어준다.

  2. 웹뷰를 실행할 때 인터넷을 사용해야 하니 인터넷 권한을 추가한다.

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 설정

gradle 이란?
안드로이드의 빌드 툴이다.

android/build.gradle : 프로젝트 파일, 주로 클래스패스나 레포지토리 정보를 입력

android/app/build.gradle : 모듈 파일, 의존성이나 버전 정보 관리

  1. android/app/build.gradle 파일 열기

  2. android.compileSdkVersion 33으로 변경
    android.defaultConfig.minSdkVersion 20으로 변경

compileSdkVersion 은 앱을 빌드할 때 사용할 SDK 버전이다.
minSdkVersion 은 안드로이드 운영체제의 최소 SDK 버전을 설정하는 위치이다.

webview_flutter 플러그인을 사용하려면 안드로이드 최소 버전을 20이상으로 설정해야 한다.
이런 네이티브 관련 설정 정보는 보통 각 플러그인의 pub.dev 페이지에서 확인할 수 있다.

HTTP 설정

현대 웹사이트는 대부분 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/>

3. 프로젝트 초기화하기

프로젝트가 커질 수록 폴더와 파일의 정리가 매우 중요하다.

앞으로 모든 프로젝트에서 화면과 관련된 모든 위젯을 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 인스턴스 위젯은 재활용되어 하드웨어 리소스를 적게 사용할 수 있다.

main.dart 에서 HomeScreen 불러오기

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 의 내용 보여줌

구현하기 단계

  1. 앱바 구현

  2. 웹뷰

  3. 웹뷰 컨트롤러

  4. 홈 버튼

앱바 구현하기

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 객체로 자동 변경된다.

main.dart 파일 수정하기.

플러터 프로젝트를 실행하는 runApp() 함수는 내부적으로 WidgetsFlutterBinding.ensureInitialized() 함수를 실행하고 있다.

ensureInitialized() 함수는 플러터 프레임워크가 앱을 실행할 준비가 됬는지 확인하는 역할을 한다.

일반적으로 개발자가 직접 이 함수를 실행할 필요는 없지만 StatelessWidget 에서 WebViewController 를 프로퍼티로 직접 인스턴스화 하려면 ensureInitialized() 함수를 직접 실행해줘야 한다.

ensureInitialized() 함수를 직접 실행하지 않고 WebViewController를 정상적으로 인스턴스화 하는 방법은 StatefulWidgetinitState() 함수에서 진행한다. 이는 나중에 배우겠다.

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의 우측 끝에서부터 순서대로 위젯이 배치된다. 세팅 버튼이나 필터링 옵션 버튼을 흔히 탑재하는 위치이다.

앱바 오른쪽에 집모양 아이콘이 잘 생겼다. 누르면 홈페이지로 잘 이동한다.

profile
아프지 말자 - (잘못된 정보, 수정 사항 있으면 언제든지 알려주시면 감사하겠습니다!)

0개의 댓글