🚀 Flutter WebView로 기존 웹사이트를 앱으로 만들기

Flutter는 Google에서 개발한 강력한 크로스 플랫폼 프레임워크입니다. 잘 만들어진 웹사이트가 이미 있으신가요? 이번 글에서는 Flutter의 웹뷰(WebView)를 활용해 단 몇 줄의 코드로 기존 웹사이트에 새로운 생명을 불어넣어 멋진 모바일 앱으로 탈바꿈시키는 방법을 알아보겠습니다.

1. 웹뷰(WebView)란?

**웹뷰(WebView)**는 앱 안에 내장된 작은 브라우저라고 생각하면 쉽습니다. 앱의 네이티브 UI 안에 웹 콘텐츠를 자연스럽게 표시해주는 기능이죠.

장점 (Pros)

  • 높은 재사용성: 이미 완벽하게 작동하는 웹사이트가 있다면, 그 기능을 그대로 가져와 앱으로 만들 수 있습니다.
  • 간편한 기능 구현: 특히 결제 기능(PG)처럼 웹으로 이미 구현된 복잡한 모듈을 네이티브 코드로 다시 개발할 필요 없이 바로 연동할 수 있어 개발 시간을 획기적으로 단축합니다.
  • 빠른 업데이트: 웹 페이지만 수정하면 앱 심사 없이도 콘텐츠를 변경하거나 업데이트할 수 있습니다.

단점 (Cons)

  • 성능: 네이티브 컴포넌트보다 다소 느릴 수 있으며, 복잡한 애니메이션은 부자연스러워 보일 수 있습니다.

이러한 장단점을 고려했을 때, 웹뷰는 기존 웹 자산을 활용해 빠르게 앱을 출시하거나, 특정 기능(콘텐츠 표시, 결제 등)을 앱에 간편하게 통합할 때 매우 효과적인 선택입니다.


2. 프로젝트 설정

본격적인 코딩에 앞서, Flutter 프로젝트가 웹뷰를 사용할 수 있도록 몇 가지 준비가 필요합니다.

웹뷰 플러그인 추가

터미널을 열고 프로젝트 최상위 폴더에서 아래 명령어를 실행해 webview_flutter 플러그인을 추가합니다. 이 명령어는 가장 최신 버전의 플러그인을 설치하고, pubspec.yaml 파일에 자동으로 의존성을 등록해 줍니다.

flutter pub add webview_flutter

네이티브 권한 설정

웹뷰가 인터넷에 접속하려면 각 플랫폼(Android, iOS)에 인터넷 사용 권한을 명시적으로 부여해야 합니다.

Android 설정

  1. android/app/src/main/AndroidManifest.xml 파일을 엽니다.
  2. <manifest> 태그 안에 아래와 같이 인터넷 권한(INTERNET)을 추가합니다.
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
    <uses-permission android:name="android.permission.INTERNET" />

    <application ...>
        ...
    </application>
</manifest>

iOS 설정

  1. ios/Runner/Info.plist 파일을 엽니다.
  2. <dict> 태그 안에 아래 코드를 추가하여 HTTP 통신 및 웹 콘텐츠 로드를 허용합니다.
<dict>
    ...
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    ...
</dict>

iOS 권한 요청 메시지: 만약 앱이 카메라, 위치 정보 등 추가적인 권한을 필요로 한다면, Info.plist에 사용자가 이해할 수 있는 권한 요청 사유를 반드시 명시해야 합니다.

<key>NSCameraUsageDescription</key>
<string>사진 첨부를 위해 카메라 사용 권한이 필요합니다.</string>

3. 핵심 코드 구현

이제 모든 준비가 끝났습니다. 실제 코드를 작성해 웹사이트를 앱 화면에 띄워보겠습니다. 가독성을 위해 화면 관련 파일은 lib/screen 폴더를 만들어 관리하겠습니다.

home_screen.dart : 웹뷰 화면 만들기

lib/screen/home_screen.dart 파일을 생성하고 아래 코드를 작성합니다. 이 파일은 실제 웹뷰가 표시될 화면을 담당합니다.

// lib/screen/home_screen.dart
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

// 블로그 URL
final Uri blogUri = Uri.parse('https://blog.codefactory.ai');

class HomeScreen extends StatelessWidget {
  // WebViewController를 생성합니다.
  final WebViewController controller = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted) // 자바스크립트 사용을 허용합니다.
    ..loadRequest(blogUri); // 초기 페이지를 로드합니다.

  HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.orange,
        title: const Text('Code Factory'),
        centerTitle: true,
        actions: [
          // 홈 버튼
          IconButton(
            onPressed: () {
              controller.loadRequest(blogUri); // 컨트롤러를 통해 홈으로 이동
            },
            icon: const Icon(Icons.home),
          ),
          // 뒤로 가기 버튼
          IconButton(
            onPressed: () {
              controller.goBack(); // 컨트롤러를 통해 뒤로 가기
            },
            icon: const Icon(Icons.arrow_back),
          ),
          // 앞으로 가기 버튼
          IconButton(
            onPressed: () {
              controller.goForward(); // 컨트롤러를 통해 앞으로 가기
            },
            icon: const Icon(Icons.arrow_forward),
          ),
        ],
      ),
      // WebViewWidget에 컨트롤러를 연결하여 웹뷰를 화면에 표시합니다.
      body: WebViewWidget(
        controller: controller,
      ),
    );
  }
}

코드 해설:

  1. WebViewController: 웹뷰의 핵심 두뇌입니다. 페이지를 로드(loadRequest)하고, 자바스크립트 사용을 설정(setJavaScriptMode)하며, 뒤로/앞으로 가기(goBackgoForward) 등 웹뷰의 모든 동작을 제어합니다.
  2. WebViewWidget: 화면에 웹뷰를 그려주는 위젯입니다. controller 속성에 위에서 생성한 컨트롤러를 연결해주기만 하면 됩니다.
  3. AppBar의 actions: 앱 바에 홈, 뒤로 가기, 앞으로 가기 버튼을 추가하고, 각 버튼을 눌렀을 때 WebViewController의 해당 함수를 호출하여 웹뷰를 제어합니다.

main.dart : 앱 시작점 설정

마지막으로 lib/main.dart 파일을 수정하여 앱이 시작될 때 우리가 만든 HomeScreen을 첫 화면으로 보여주도록 설정합니다.

// lib/main.dart
import 'package:blog_web_app/screen/home_screen.dart'; // 우리가 만든 HomeScreen을 임포트
import 'package:flutter/material.dart';

void main() {
  // main 함수에서 비동기 작업을 수행할 때 반드시 추가해야 하는 코드
  WidgetsFlutterBinding.ensureInitialized();

  runApp(
    MaterialApp(
      debugShowCheckedModeBanner: false, // 디버그 배너 제거
      home: HomeScreen(), // 앱의 첫 화면으로 HomeScreen을 지정
    ),
  );
}

코드 해설:

  • WidgetsFlutterBinding.ensureInitialized(): 이 코드는 Flutter 엔진이 위젯을 그릴 준비가 완료되었는지 확인하는 역할을 합니다. runApp()이 실행되기 전에 웹뷰 컨트롤러 초기화와 같은 작업이 필요할 수 있으므로, main 함수 상단에 추가해주는 것이 안전합니다.

이제 앱을 실행하면, 지정한 웹사이트가 아름다운 앱 화면 안에서 완벽하게 동작하는 것을 확인하실 수 있습니다.


4. 부록: 주요 명령어 및 권한 목록

주요 flutter pub 명령어

  • flutter pub add [플러그인 이름]: 특정 플러그인을 프로젝트에 추가하고 자동으로 다운로드합니다. (권장)
  • flutter pub getpubspec.yaml 파일에 수동으로 추가한 플러그인들을 다운로드합니다.
  • flutter pub upgrade: 프로젝트의 모든 플러그인을 최신 버전으로 업데이트합니다.

자주 사용되는 Android 권한 (AndroidManifest.xml)

  • CAMERA: 카메라 사용
  • ACCESS_FINE_LOCATION: 정확한 위치 정보 접근
  • RECORD_AUDIO: 오디오 녹음
  • WRITE_EXTERNAL_STORAGE: 외부 저장소 쓰기

자주 사용되는 iOS 권한 키 (Info.plist)

  • NSCameraUsageDescription: 카메라 사용 권한 요청 메시지
  • NSLocationWhenInUseUsageDescription: 앱 사용 중 위치 정보 접근 권한 요청 메시지
  • NSPhotoLibraryUsageDescription: 사진 앨범 접근 권한 요청 메시지
  • NSMicrophoneUsageDescription: 마이크 사용 권한 요청 메시지

실행화면

flutter-webapp-thumb

참고

https://heavenly.tistory.com/entry/Flutter-기술-탐구-앱-개발-실전-로그

#Flutter #플러터 #WebView #웹뷰 #WebApp #웹앱 #webview_flutter #FlutterTutorial #모바일앱개발 #CrossPlatform #크로스플랫폼 #Dart #다트 #Android #iOS #플러터강의 #앱개발 #코딩

“We should be better for our children.” 👍

댓글 남기기