상세 컨텐츠

본문 제목

[Flutter] Webview 라이브러리 - webview_flutter

플러터/라이브러리

by 감자 바보 2025. 1. 3. 12:39

본문

반응형

공식 문서 : https://pub.dev/packages/webview_flutter

 

flutter에서 webview_flutter 라이브러리는 애플리케이션 내에서 웹 콘텐츠를 표시할 수 있도록 도와주는 공식 패키지입니다. 이를 통해 웹 페이지, 로컬 HTML 파일, 또는 웹 기반 애플리케이션을 Flutter 앱 내에 통합할 수 있습니다. **webview_flutter**는 다양한 플랫폼(안드로이드, iOS)에서 일관된 웹뷰 경험을 제공하며, 웹 페이지와의 상호작용을 가능하게 합니다.


📘 목차

  1. webview_flutter 소개
  2. 설치 및 설정
  3. 기본 사용법
  4. 고급 기능
  5. 보안 고려 사항
  6. 문제 해결 및 자주 발생하는 문제
  7. Best Practices (최고의 사용 방법)
  8. 추가 리소스

📘 1. webview_flutter 소개

  • *webview_flutter*는 Flutter 애플리케이션 내에서 웹 콘텐츠를 표시할 수 있는 웹뷰(WebView)를 제공하는 공식 패키지입니다. 이 패키지를 사용하면 사용자가 앱 내에서 직접 웹 페이지를 탐색할 수 있으며, 웹 기반 기능을 앱에 통합할 수 있습니다.

주요 특징:

  • 플랫폼 지원: 안드로이드 및 iOS에서 지원됩니다.
  • JavaScript 지원: JavaScript 실행 및 상호작용이 가능합니다.
  • 로컬 HTML 파일 로드: 앱 내에 포함된 로컬 HTML 파일을 로드할 수 있습니다.
  • Flutter와 웹뷰 간 통신: JavaScript와 Flutter 간의 양방향 통신을 지원합니다.
  • 커스터마이즈 가능: 웹뷰의 다양한 속성을 설정하여 맞춤형 웹 경험을 제공할 수 있습니다.

📘 2. 설치 및 설정

🔍 1️⃣ pubspec.yaml에 패키지 추가

먼저, 프로젝트의 pubspec.yaml 파일에 webview_flutter 패키지를 추가해야 합니다. 최신 버전을 사용하도록 권장합니다.

ependencies:
  flutter:
    sdk: flutter
  webview_flutter: ^4.0.7  # 최신 버전 확인 후 적용

패키지를 추가한 후, 터미널에서 다음 명령어를 실행하여 패키지를 설치합니다.

flutter pub get

🔍 2️⃣ 안드로이드 설정

안드로이드에서 웹뷰를 사용하려면 몇 가지 추가 설정이 필요합니다.

  1. AndroidManifest.xml 수정
    
        
    
        
            
        
    
    
    
  2. android/app/src/main/AndroidManifest.xml 파일을 열고, 인터넷 권한을 추가합니다.
  3. Android Gradle 설정
    android {
        defaultConfig {
            applicationId "com.example.your_app"
            minSdkVersion 19
            targetSdkVersion 33
            // 기타 설정
        }
    }
    
    
  4. 최소 SDK 버전이 19 이상인지 확인합니다. android/app/build.gradle 파일에서 minSdkVersion을 확인하고 필요 시 수정합니다.

🔍 3️⃣ iOS 설정

iOS에서도 웹뷰를 사용하려면 몇 가지 설정이 필요합니다.

  1. Info.plist 수정
    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSAllowsArbitraryLoads</key>
        <true/>
    </dict>
    
    
    주의: NSAllowsArbitraryLoads를 true로 설정하면 모든 HTTP 요청이 허용되므로, 보안에 민감한 앱에서는 특정 도메인만 허용하도록 설정하는 것이 좋습니다.
  2. ios/Runner/Info.plist 파일을 열고, App Transport Security Settings를 추가하여 HTTP 요청을 허용하거나, 특정 도메인에 대한 예외를 설정할 수 있습니다.
  3. WKWebView 설정 (선택 사항)
  4. 기본적으로 **webview_flutter**는 WKWebView를 사용합니다. 필요에 따라 추가 설정을 할 수 있습니다.

📘 3. 기본 사용법

  • *webview_flutter*를 사용하여 간단한 웹뷰를 구현하는 방법을 소개합니다.

🔍 1️⃣ 간단한 웹뷰 예제

아래는 Flutter 애플리케이션 내에 웹뷰를 삽입하여 웹 페이지를 로드하는 기본 예제입니다.

main.dart:

import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'WebView Flutter Example',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const WebViewExample(),
    );
  }
}

class WebViewExample extends StatefulWidget {
  const WebViewExample({super.key});

  @override
  State createState() => _WebViewExampleState();
}

class _WebViewExampleState extends State {
  late final WebViewController _controller;

  @override
  void initState() {
    super.initState();

    // 초기화 시점에 WebViewController 설정
    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted) // JavaScript 허용
      ..setBackgroundColor(const Color(0x00000000)) // 배경색 설정
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageStarted: (String url) {
            print('페이지 로딩 시작: $url');
          },
          onPageFinished: (String url) {
            print('페이지 로딩 완료: $url');
          },
          onWebResourceError: (WebResourceError error) {
            print('웹 리소스 오류: ${error.description}');
          },
        ),
      )
      ..loadRequest(Uri.parse('<https://flutter.dev>'));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('WebView Example'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: () {
              _controller.reload(); // 페이지 새로고침
            },
          ),
        ],
      ),
      body: WebViewWidget(controller: _controller),
    );
  }
}

설명:

  1. WebViewController 초기화:
    • WebViewController를 사용하여 웹뷰의 동작을 제어합니다.
    • setJavaScriptMode(JavaScriptMode.unrestricted): JavaScript 실행을 허용합니다.
    • setNavigationDelegate: 웹뷰의 내비게이션 이벤트를 처리할 수 있는 델리게이트를 설정합니다.
    • loadRequest: 로드할 웹 페이지의 URL을 지정합니다.
  2. WebViewWidget:
    • WebViewWidget을 사용하여 웹뷰를 화면에 표시합니다. controller를 전달하여 웹뷰를 제어합니다.
  3. AppBar:
    • 페이지 상단에 새로고침 버튼을 추가하여 웹페이지를 새로고침할 수 있습니다.

📘 4. 고급 기능

🔍 1️⃣ JavaScript 실행

웹뷰 내에서 JavaScript를 실행할 수 있습니다. 예를 들어, 특정 함수를 호출하거나 웹 페이지와 상호작용할 수 있습니다.

예제: JavaScript 코드 실행

// 버튼을 눌러 JavaScript 실행
ElevatedButton(
  onPressed: () {
    _controller.runJavaScript('alert("Hello from Flutter!");');
  },
  child: const Text('JavaScript 실행'),
),

결과: 웹 페이지 내에서 "Hello from Flutter!"라는 경고창이 표시됩니다.

🔍 2️⃣ 웹 페이지 로딩 상태 관리

웹뷰의 로딩 상태를 관리하여 사용자에게 로딩 스피너 등을 표시할 수 있습니다.

예제: 로딩 인디케이터 추가

class _WebViewExampleState extends State {
  late final WebViewController _controller;
  bool _isLoading = true; // 로딩 상태 변수

  @override
  void initState() {
    super.initState();

    _controller = WebViewController()
      ..setJavaScriptMode(JavaScriptMode.unrestricted)
      ..setBackgroundColor(const Color(0x00000000))
      ..setNavigationDelegate(
        NavigationDelegate(
          onPageStarted: (String url) {
            setState(() {
              _isLoading = true;
            });
          },
          onPageFinished: (String url) {
            setState(() {
              _isLoading = false;
            });
          },
          onWebResourceError: (WebResourceError error) {
            setState(() {
              _isLoading = false;
            });
            print('웹 리소스 오류: ${error.description}');
          },
        ),
      )
      ..loadRequest(Uri.parse('<https://flutter.dev>'));
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('WebView Example'),
        actions: [
          IconButton(
            icon: const Icon(Icons.refresh),
            onPressed: () {
              _controller.reload();
            },
          ),
        ],
      ),
      body: Stack(
        children: [
          WebViewWidget(controller: _controller),
          if (_isLoading)
            const Center(
              child: CircularProgressIndicator(),
            ),
        ],
      ),
    );
  }
}

설명:

  • _isLoading 변수: 웹 페이지 로딩 상태를 추적합니다.
  • onPageStarted: 페이지 로딩 시작 시 _isLoading을 true로 설정하여 로딩 인디케이터를 표시합니다.
  • onPageFinished 및 onWebResourceError: 페이지 로딩 완료 또는 오류 발생 시 _isLoading을 false로 설정하여 로딩 인디케이터를 숨깁니다.
  • Stack 위젯: 웹뷰와 로딩 인디케이터를 겹쳐서 표시합니다.

🔍 3️⃣ 웹뷰와 Flutter 간의 통신

웹뷰 내의 JavaScript와 Flutter 코드 간에 상호작용할 수 있습니다. 이를 통해 양방향 통신이 가능합니다.

예제: JavaScript에서 Flutter로 메시지 보내기

  1. Flutter 측 설정:
  2. @override void initState() { super.initState(); _controller = WebViewController() ..setJavaScriptMode(JavaScriptMode.unrestricted) ..setBackgroundColor(const Color(0x00000000)) ..addJavaScriptChannel( 'FlutterChannel', onMessageReceived: (JavaScriptMessage message) { // JavaScript에서 보낸 메시지 처리 print('JavaScript로부터 메시지 수신: ${message.message}'); }, ) ..setNavigationDelegate( NavigationDelegate( onPageStarted: (String url) { setState(() { _isLoading = true; }); }, onPageFinished: (String url) { setState(() { _isLoading = false; }); }, onWebResourceError: (WebResourceError error) { setState(() { _isLoading = false; }); print('웹 리소스 오류: ${error.description}'); }, ), ) ..loadRequest(Uri.parse('<https://your-web-page.com>')); }
  3. 웹 페이지 JavaScript 코드:
    <!DOCTYPE html>
    <html>
    <head>
      <title>Flutter WebView Communication</title>
      <script type="text/javascript">
        function sendMessageToFlutter() {
          FlutterChannel.postMessage('Hello from JavaScript!');
        }
      </script>
    </head>
    <body>
      <h1>Flutter WebView Communication</h1>
      <button onclick="sendMessageToFlutter()">Send Message to Flutter</button>
    </body>
    </html>
    
    
  4. 웹 페이지 내에서 Flutter로 메시지를 보내려면, FlutterChannel.postMessage를 사용합니다.

설명:

  • JavaScriptChannel 추가: addJavaScriptChannel을 사용하여 Flutter와 JavaScript 간의 통신 채널을 설정합니다.
  • JavaScript에서 메시지 보내기: 웹 페이지 내에서 FlutterChannel.postMessage를 호출하여 Flutter로 메시지를 보냅니다.
  • Flutter에서 메시지 수신: Flutter의 onMessageReceived 콜백에서 메시지를 처리합니다.

📘 5. 보안 고려 사항

웹뷰를 사용할 때 보안은 매우 중요한 요소입니다. 다음은 웹뷰 사용 시 고려해야 할 주요 보안 사항입니다:

🔍 1️⃣ JavaScript 실행 제한

JavaScript 실행을 완전히 허용할 경우, 악의적인 스크립트가 실행될 수 있으므로 신뢰할 수 없는 콘텐츠를 로드할 때는 주의가 필요합니다.

예시: JavaScript 실행 제한

_controller = WebViewController()
  ..setJavaScriptMode(JavaScriptMode.disabled) // JavaScript 비활성화
  ..loadRequest(Uri.parse('<https://secure-website.com>'));

🔍 2️⃣ HTTPS 사용 권장

민감한 데이터를 다루는 경우, 항상 HTTPS를 통해 안전하게 데이터를 전송하도록 합니다.

🔍 3️⃣ 외부 콘텐츠 로드 제한

앱 내에서 로드할 수 있는 콘텐츠의 출처를 제한하여, 신뢰할 수 없는 도메인에서의 콘텐츠 로드를 방지합니다.

예시: URL 필터링

_controller.setNavigationDelegate(
  NavigationDelegate(
    onNavigationRequest: (NavigationRequest request) {
      if (request.url.startsWith('<https://trusted-domain.com>')) {
        return NavigationDecision.navigate;
      } else {
        return NavigationDecision.prevent;
      }
    },
  ),
);

🔍 4️⃣ 사용자 인증 정보 보호

웹뷰 내에서 로그인 정보나 인증 토큰을 다루는 경우, 해당 정보가 안전하게 처리되도록 주의합니다.


📘 6. 문제 해결 및 자주 발생하는 문제

🔍 1️⃣ 웹뷰가 로드되지 않음

  • 원인: 인터넷 권한이 설정되지 않았거나, 잘못된 URL을 로드하려는 경우
  • 해결 방법:
    • 안드로이드와 iOS 설정에서 인터넷 권한이 제대로 설정되었는지 확인합니다.
    • 로드하려는 URL이 올바르고, 웹 서버가 정상적으로 작동하는지 확인합니다.

🔍 2️⃣ JavaScript 실행이 되지 않음

  • 원인: JavaScript 모드가 비활성화되어 있거나, JavaScript 코드에 오류가 있는 경우
  • 해결 방법:
    • JavaScriptMode.unrestricted로 설정되어 있는지 확인합니다.
    • 웹 페이지의 JavaScript 코드에 오류가 없는지 확인합니다.

🔍 3️⃣ 웹뷰와 Flutter 간 통신이 되지 않음

  • 원인: JavaScriptChannel이 제대로 설정되지 않았거나, JavaScript 코드에서 올바르게 메시지를 보내지 않은 경우
  • 해결 방법:
    • addJavaScriptChannel을 통해 채널이 제대로 추가되었는지 확인합니다.
    • JavaScript 코드에서 postMessage를 올바르게 호출했는지 확인합니다.

🔍 4️⃣ 웹뷰 내에서 네비게이션 컨트롤이 작동하지 않음

  • 원인: NavigationDelegate가 올바르게 설정되지 않았거나, 특정 네비게이션 요청이 제한된 경우
  • 해결 방법:
    • NavigationDelegate의 콜백 함수가 올바르게 구현되었는지 확인합니다.
    • 필요한 경우 특정 네비게이션 요청을 허용하도록 설정합니다.

📘 7. Best Practices (최고의 사용 방법)

🔍 1️⃣ 최소한의 권한 부여

웹뷰를 사용할 때 필요한 최소한의 권한만 부여하여 보안 위험을 줄입니다. 예를 들어, 인터넷 권한 외에 추가적인 권한이 필요하지 않다면 요청하지 않습니다.

🔍 2️⃣ 신뢰할 수 있는 콘텐츠만 로드

웹뷰에서 로드하는 콘텐츠는 신뢰할 수 있는 출처에서만 로드하도록 제한합니다. 이를 통해 악의적인 스크립트 실행을 방지할 수 있습니다.

🔍 3️⃣ 사용자 입력 검증

웹뷰 내에서 사용자로부터 입력받은 데이터를 처리할 때는 항상 입력을 검증하고, 필요한 경우 이스케이프 처리를 합니다.

🔍 4️⃣ 보안 업데이트 유지

webview_flutter 패키지와 Flutter SDK를 최신 버전으로 유지하여 보안 패치를 적용받도록 합니다.

🔍 5️⃣ 웹뷰의 상태 관리

웹뷰의 상태(로딩 상태, 오류 상태 등)를 적절히 관리하여 사용자에게 명확한 피드백을 제공합니다.

🔍 6️⃣ 성능 최적화

웹뷰 내에서 불필요한 리소스를 로드하지 않도록 최적화하고, 필요한 경우 캐싱을 활용하여 성능을 향상시킵니다.

728x90
반응형

관련글 더보기