7단계 블로그 웹 앱

송기영·2023년 12월 11일
0

플러터

목록 보기
9/25

7.1. 사전지식

7.1.1. 콜백 함수

일정 작업이 완료되면 실행되는 함수이며, 특정 조건이 성립될 때 실행되기 때문에 이름이 콜백 함수이다. 예를 들어 유저가 화면에 터치 했을 때 실행할 함수나 웹 뷰의 로딩이 완료됏을 때 실행항 콜백 함수는 다음과 같다.

WebView(
	initialUrl: "https://blog.codefactory.ai",
	javascriptMode: JavascriptMode.unrestricted,
	onPageFinished: (String url) {
			print(url);
	},
)

7.1.2. 웹뷰 위젯

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

속성설명
initalUrl처음 실행할 웹사이트의 주소입니다.
javascriptMode웹뷰에서 자바스크립트 실행을 허용할지 여부를 결정할 수 있다.
onWebViewCreated웹뷰 위젯이 생성되면 실행할 콜백 함수이다.(뒤로가기, 앞으로가기, 새로운 URL 실행하기 등 기능을 조작할 수 있다)
onPageStarted웹뷰가 처음 생성되거나 페이지를 이동했을 때 웹페이지가 로딩되기 시작하면 실행할 콜백 함수이다.
onPageFinished웹페이지 로딩이 끝나면 실행된다.
onProgress웹페이지가 로딩 중일 때 지속적으로 실행되며 페이지의 로딩이 끝날 때 까지 실행된다. 매개변수에 int값으로 페이지 로딩 상태를 0부터 100사이의 숫자로 제공해준다.

7.1.3. 안드로이드와 iOS 네이티브 설정

각 네이티브 플랫폼으로 코드가 컴파일되므로 최소한의 네이티브 설정은 필요하다. 인터넷 접근권한, 카메라, 사진첩, 푸쉬 권한 등 보안에 민감한 사항이나 하드웨어에 접근할 때도 네이티브 설정을 해야한다.

네이티브 설저이 필요한 경우는 일반적으로 해당 플러그인의 pub.dev 소개 페이지에서 확인할 수 있다.

7.2. 사전 준비

  • 프로젝트 이름: blog_web_app
  • 네이티브 언어: 코틀린, 스위프트

7.2.1. pubspec.yaml 설정하기

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

# webview_flutter 설치하기
dependencies:
  cupertino_icons: ^1.0.6
  flutter:
    sdk: flutter
  webview_flutter: ^4.4.2

주요 pub 명령어

명령어설명
flutter pub getpubspec.yaml 파일에 등록한 플ㄹ그인들을 내려받습니다.
flutter pub add [플러그인 이름]pubspec.yaml에 플러그인을 추가합니다.
flutter pub upgradepubspec.yaml에 등록된 플러그인들을 모두 최신 버전으로 업데이트 합니다.
flutter pub run현재 프로젝트를 실행합니다.

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

웹뷰를 사용하기 위해서는 몇 가지 네이티브 설정이 필요하다. 인터넷 사용 권한을 추가하고 https 프로토콜뿐만 아니라 http 프로토콜도 이용할 수 있도록 수정해야한다.

안드로이드 설정

android/app/src/main/AndroidManifest.xml 파일에서 각종 권한을 설정할 수 있다.

  1. 아래와 같이 인터넷 권한을 추가해준다.

    <!-- android/app/src/main/AndroidManifest.xml -->
    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-permission android:name="android.permission.INTERNET" />
        <!-- 생략 -->
    </manifest>
  1. 안드로이드와 IOS는 기본적으로 http 웹사이트를 사용할 수 없도록 설정되어있는데 이를 허용해주려면 아래코드를 추가해주면 된다.

    <manifest xmlns:android="http://schemas.android.com/apk/res/android">
        <uses-permission android:name="android.permission.INTERNET"/ >
        <application
            android:label="blog_web_app"
            android:name="${applicationName}"
            android:icon="@mipmap/ic_launcher"
            android:usesCleartextTraffic="true" // 추가
            >
            <!-- 생략 --!>
        </application>
    </manifest>

자주 사용하는 안드로이드 권한 코드

코드설명
INTERNET인터넷 사용 권한
CAMERA카메라 사용 권한
WRITE_EXTERNAL_STORAGE앱 외부에 파일을 저장할 수 있는 권한
READ_EXTERNAL_STORAGE앱 외부의 파일을 읽을 수 있는 권한
VIBRATE진동을 일으킬 수 있는 권한
ACCESS_FINE_LOCATIONGPS와 네트워크를 모두 사용해서 정확한 현재 위치 정보를 가져올 수있는 권한
ACCESS_COARSE_LOCATION네트워크만 사용해서 대략적인 위치 정보를 가져올 수 있는 권한
ACCESS_BACKGROUND_LOCATION앱이 배경에 있을 때 위치 정보를 얻을 수 있는 권한
BILLING인앱 결제를 할 수 있는 권한
CALL_PHONE전화기 앱을 사용하지 않고 전화를 할 수 있는 권한
NETWORK_STATE네트워크 상태를 가져올 수 있는 권한
RECORD_AUDIO음성 녹음 할 수 있는 권한
  1. android/app/build.gradle 파일은 안드로이드의 빌드 툴인 그레이들 설정파일이다.

    android/build.gradle과 android/app/build.gradle은 서로 다른 파일이니 유의해야한다.

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

    android/app/build.gradle : 모듈 파일이며 의존성이나 버전 정보를 관리한다. ****

    아래와 같이 변경해준다.

    android {
    		// 생략
        compileSdk 32
    
        defaultConfig {
    				// 생략
            minSdkVersion 20 
        }
    }

    compileSdk는 앱을 빌드할 때 사용할 SDK 버전이다.

    minSdkVersion은 안드로이드 운영체제의 최소 SDK 버전을 설정할 수 있는 위치이다.

    웹뷰를 사용하기 위해서는 최소 20이상으로 설정해야 한다.

IOS 설정

ios/Runner/Info.plist파일은 IOS의 런타임을 설정하는 파일이다. 권한 요청을 할 때 보여줄 메시지를 정의할때 사용하기도 한다.

<key>NSAppleMusicUsageDescription</key>
<string>음악을 재생하는 권한이 필요합니다.</string>
  1. http 프로토콜을 사용하는 설정을 추가한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<!-- 생략 -->
	<key>NSAppTransportSecurity</key>
	<dict>
		<key>NSAllowsLocalNetworking</key>
		<true/>
		<key>NSAllowsArbitraryLoadsInWebContent</key>
		<true/>
	</dict>
</dict>
</plist>

Info.plist에 자주 추가하게 되는 키값

키값설명
NSCalendarsUsageDescription달력 사용 권한 메시지
NSCameraUsageDescription카메라 사용 권한 메시지
NSContactsUsageDescription연락처 사용 권한 메시지
NSLocationUsageDescription위치 정보 사용 권한 메시지
NSPhotoLibraryUsageDescription사진 접근 권한 메시지
NSFacelDUsageDescriptionFaceID 사용 권한 메시지
NSMicrophoneUsageDescription마이크 사용 권한 메시지
NSMotionUsageDescriptionAccelerometer 사용 권한 메시지
NSSiriUsageDescriptionsiri 사용 권한 메시지

7.2.3. 프로젝트 초기화 하기

폴더와 파일 정리가 중요하기 때문에 화면관 관련된 모든 위젯을 screen 폴더에 모아서 관린한다.

  • home_screen.dart
// lib/screen/home_screen.dart

import "package:flutter/material.dart";

class HomeScreen extends StatelessWidget {
  // const 생성자
  const HomeScreen({Key? key}) : super(key: key);
  
  Widget build(BuildContext context) {
    return (Scaffold(
      body: Text("Home Screen"),
    ));
  }
}
  • main.dart
import 'package:blog_web_app/screen/home_screen.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MaterialApp(
    home: HomeScreen(),
  ));
}

💡Tips: import할때 경로 “package:[프로젝트 이름]/[lib 폴더로부터의 위치]/파일명.dart” 단 private로 선언된 속성들은 불러오기에 제외된다.

7.3. 레이아웃 구상 및 구현

앱바와 웹뷰로 이루어져 있음

7.3.1. 앱바 구현하기

import "package:flutter/material.dart";

class HomeScreen extends StatelessWidget {
  const HomeScreen({Key? key}) : super(key: key);
  
  Widget build(BuildContext context) {
    return (Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.orange,
        title: Text(
          "Code Factory",
          style: TextStyle(color: Colors.white),
        ),
        centerTitle: true,
      ),
      body: Text("Home Screen"),
    ));
  }
}

7.3.2. 웹뷰 구현하기

책에서는 WebView() 사용해서 처리했지만 webview_flutter 버전이 많이 변경됨에 따라 아래 코드처럼 구현하면 정상적으로 보임을 확인할 수 있다.

나는 webview_flutter 4.4.2버전을 설치해 적용했다.

import "package:flutter/material.dart";

import "package:webview_flutter/webview_flutter.dart";

class HomeScreen extends StatelessWidget {
  // const 생성자
  const HomeScreen({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return (Scaffold(
        appBar: AppBar(
          backgroundColor: Colors.orange,
          title: Text(
            "Code Factory",
            style: TextStyle(color: Colors.white),
          ),
          centerTitle: true,
        ),
        body: WebViewWidget(controller: controller)));
  }
}

WebViewController controller = WebViewController()
  ..setJavaScriptMode(JavaScriptMode.unrestricted)
  ..setBackgroundColor(const Color(0x00000000))
  ..setNavigationDelegate(NavigationDelegate(
      onProgress: (int progress) {
        // Update loading Bar
      },
      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://blog.codefactory.ai/"));

7.3.3. 웹뷰 컨트롤러 설정하기

홈 아이콘을 눌렀을 때 웹뷰 화면을 변경하려면 위젯 제어 기능이 필요하다. 플러터는 위젯을 코드로 제어하는 기능을 제공한다.

import "package:flutter/material.dart";

import "package:webview_flutter/webview_flutter.dart";

class HomeScreen extends StatelessWidget {
  // const 생성자
  HomeScreen({Key? key}) : super(key: key);

  WebViewController controller = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..setBackgroundColor(const Color(0x00000000))
    ..setNavigationDelegate(NavigationDelegate(
        onProgress: (int progress) {
          // Update loading Bar
        },
        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://blog.codefactory.ai/"));

  
  Widget build(BuildContext context) {
    return (Scaffold(
        appBar: AppBar(
            backgroundColor: Colors.orange,
            title: Text(
              "Code Factory",
              style: TextStyle(color: Colors.white),
            ),
            centerTitle: true,
            actions: [
              IconButton(
                  onPressed: () {
                    controller.goBack();
                  },
                  icon: Icon(
                    Icons.arrow_back,
                    color: Colors.white,
                  )),
              IconButton(
                  onPressed: () {
                    if (controller != null) {
                      controller!.loadRequest(
                          Uri.parse("https://blog.codefactory.ai/"));
                    }
                  },
                  icon: Icon(
                    Icons.home,
                    color: Colors.white,
                  )),
              IconButton(
                  onPressed: () {
                    controller.goForward();
                  },
                  icon: Icon(
                    Icons.arrow_forward,
                    color: Colors.white,
                  )),
            ]),
        body: WebViewWidget(controller: controller)));
  }
}

💡Tips: 현재 flutter_webview 4.0부터 Webview사용은 더 이상 사용하지 않는다고 한다. 따라서 WebviewController를 만들고 WebviewWidget 매개변수에 넣어줘야한다.

profile
업무하면서 쌓인 노하우를 정리하는 블로그🚀 풀스택 개발자를 지향하고 있습니다👻

0개의 댓글