[Flutter] ์›น๋ทฐ(WebView)

์ฐŒ๋‹ˆ์›”๋“œยท2024๋…„ 2์›” 27์ผ
0

๐Ÿ“š ์ฑ…ย ์Šคํ„ฐ๋””

๋ชฉ๋ก ๋ณด๊ธฐ
8/11
post-thumbnail

๐Ÿ“ ๊ฐœ๋… ์ •๋ฆฌ

WebViewWidget

  • ์›น ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์œ„์ ฏ
  • URL์„ ์ถ”๊ฐ€ํ•ด์คŒ์œผ๋กœ์จ ์›ํ•˜๋Š” ์›น์‚ฌ์ดํŠธ๋ฅผ ์•ฑ์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅ

WebViewController

  • ์›น๋ทฐ ์œ„์ ฏ์„ ์ œ์–ดํ•˜๋Š”๋ฐ ํ•„์š”ํ•œ ๊ธฐ๋Šฅ ์ œ๊ณต

๐Ÿ”Œ ์‚ฌ์ „ ์ค€๋น„

webview_flutter

pubspec.yaml ์„ค์ •ํ•˜๊ธฐ

pubspec.yaml ํŒŒ์ผ์€ ํ”Œ๋Ÿฌํ„ฐ ํ”„๋กœ์ ํŠธ์™€ ๊ด€๋ จ๋œ ์„ค์ •์„ ํ•˜๋Š” ํŒŒ์ผ์ด๋‹ค.

  1. webview_flutter ํ”Œ๋Ÿฌ๊ทธ์ธ์„ pubspec.yaml ํŒŒ์ผ์— ์ถ”๊ฐ€ํ•˜๊ณ  [pub get]์„ ์‹คํ–‰ํ•œ๋‹ค.
dependencies:
  flutter:
    sdk: flutter

  cupertino_icons: ^1.0.2
  webview_flutter: ^4.7.0

๐Ÿ’ก flutter pub get์€ pubspec.yaml ํŒŒ์ผ์— ๋“ฑ๋กํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ๋“ค์„ ๋‚ด๋ ค๋ฐ›๋Š” ๋ช…๋ น์–ด๋‹ค.

๊ถŒํ•œ ๋ฐ ๋„ค์ดํ‹ฐ๋ธŒ ์„ค์ •ํ•˜๊ธฐ

๐Ÿค– ์•ˆ๋“œ๋กœ์ด๋“œ

์•ˆ๋“œ๋กœ์ด๋“œ ์„ค์ • ํŒŒ์ผ์€ android/app/src/main/AndroidManifest.xml ์ด๋‹ค.

  1. AndroidManifest.xml ํŒŒ์ผ์— ์›น๋ทฐ๋ฅผ ์‹คํ–‰ํ•  ๋•Œ ์ธํ„ฐ๋„ท์„ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‹ˆ ์ธํ„ฐ๋„ท ๊ถŒํ•œ์„ ์ถ”๊ฐ€ํ•œ๋‹ค.
<uses-permission android:name="android.permission.INTERNET" />
  1. android/app/build.gradel ํŒŒ์ผ์„ ์—ด์–ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋ณ€๊ฒฝํ•œ๋‹ค.
android {
	compileSdkVersion 33 โฌ…๏ธ
    ----- ์ƒ๋žต -----
    defaultConfig {
        applicationId "com.example.blog_web_app"
        minSdkVersion 20 โฌ…๏ธ
        targetSdkVersion flutter.targetSdkVersion
        versionCode flutterVersionCode.toInteger()
        versionName flutterVersionName
    }
    ----- ์ƒ๋žต -----
}
  • minSdkVersion : ์•ˆ๋“œ๋กœ์ด๋“œ ์šด์˜์ฒด์ œ์˜ ์ตœ์†Œ SDK ๋ฒ„์ „์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋Š” ์œ„์น˜
  • compileSdkVersion : ์•ฑ์„ ๋นŒ๋“œํ•  ๋•Œ ์‚ฌ์šฉํ•  SDK ๋ฒ„์ „

๐Ÿ’ก android/app/build.gradel ํŒŒ์ผ์€ ์˜์กด์„ฑ์ด๋‚˜ ๋ฒ„์ „ ์ •๋ณด๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค.

  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 >

๋งŒ์•ฝ, http ํ”„๋กœํ† ์ฝœ์„ ํ—ˆ์šฉํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋ฉด ํ•ด๋‹น ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค.

๐ŸŽ iOS

  1. ios/Runner/Info.plist ํŒŒ์ผ์— 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>

๐Ÿ’ก ios/Runner/Info.plist ํŒŒ์ผ์€ iOS ์•ฑ์˜ ๋Ÿฐํƒ€์ž„์„ ์„ค์ •ํ•˜๋Š” ํŒŒ์ผ์ด๋‹ค.

๐Ÿ–ฅ๏ธ ๊ตฌํ˜„

AppBar

AppBar ์œ„์ ฏ์€ ์ผ๋ฐ˜์ ์œผ๋กœ Scaffold ์œ„์ ฏ์˜ appBar ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ๋„ฃ์–ด์ค€๋‹ค.

import 'package:flutter/material.dart';

class HomeScreen extends StatelessWidget {
  WebViewController controller = WebViewController();

  HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.orange,
        title: Text('jjinheeWorld'),
        centerTitle: true,
      ),
      body: Text('Home Screen'),
    );
  }
}

WebViewWidget

WebViewWidget์€ ํ™”๋ฉด์— ์›น๋ทฐ๋ฅผ ๋ Œ๋”๋งํ•ด์ฃผ๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

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

class HomeScreen extends StatelessWidget {
  WebViewController controller = WebViewController();

  HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.orange,
        title: Text('jjinheeWorld'),
        centerTitle: true,
      ),
      body: WebViewWidget(
        controller: controller,
      ),
    );
  }
}

WebViewController

WebViewController๋Š” ์›น๋ทฐ ์œ„์ ฏ์„ ์ œ์–ดํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค.

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

class HomeScreen extends StatelessWidget {
   WebViewController controller = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..loadRequest(Uri.parse('https://velog.io/@jjinnyit/posts'));

  HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.orange,
        title: Text('jjinheeWorld'),
        centerTitle: true,
      ),
      body: WebViewWidget(
        controller: controller,
      ),
    );
  }
}
  • loadRequest() : Uri ๊ฐ์ฒด๋ฅผ ๋งค๊ฐœ๋ณ€์ˆ˜๋กœ ์ž…๋ ฅ๋ฐ›์œผ๋ฉฐ ์ด ์ž…๋ ฅ๋ฐ›์€ ๊ฐ’์„ ํ†ตํ•ด ์ง€์ •ํ•œ ์‚ฌ์ดํŠธ๋กœ ์ด๋™

main.dart ํŒŒ์ผ ์ˆ˜์ •ํ•˜๊ธฐ

StatelessWidget์—์„œ WebViewController๋ฅผ ํ”„๋กœํผํ‹ฐ๋กœ ์ง์ ‘ ์ธ์Šคํ„ด์Šคํ™”ํ•˜๋ ค๋ฉด WidgetsFlutterBinding.ensureInitialized() ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ์‹คํ–‰ํ•ด์ฃผ๋Š” ์ž‘์—…์„ ํ•ด์•ผ ํ•œ๋‹ค.

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:blog_web_app/screen/home_screen.dart';

void main() {
  // Flutter ํ”„๋ ˆ์ž„์›Œํฌ๊ฐ€ ์•ฑ์„ ์‹คํ–‰ํ•  ์ค€๋น„๊ฐ€ ๋  ๋•Œ๊นŒ์ง€ ๊ธฐ๋‹ค๋ฆผ
  WidgetsFlutterBinding.ensureInitialized();

  runApp(
    MaterialApp(
      home: HomeScreen(),
    ),
  );
}

ํ™ˆ ๋ฒ„ํŠผ ๊ตฌํ˜„ํ•˜๊ธฐ

์–ด๋–ค ํŽ˜์ด์ง€์—์„œ๋“  ์ฐŒ๋‹ˆ์›”๋“œ์˜ ๋ฒจ๋กœ๊ทธ ํ™ˆํŽ˜์ด์ง€๋กœ ๋Œ์•„์˜ฌ ์ˆ˜ ์žˆ๋Š” ํ™ˆ ๋ฒ„ํŠผ์„ ๋งŒ๋“ค์–ด๋ณด์ž.

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

class HomeScreen extends StatelessWidget {
   WebViewController controller = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..loadRequest(Uri.parse('https://velog.io/@jjinnyit/posts'));

  HomeScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.orange,
        title: Text('jjinheeWorld'),
        centerTitle: true,
        actions: [
          IconButton(
            onPressed: () {
              controller.loadRequest(Uri.parse('https://velog.io/@jjinnyit/posts'));
            },
            icon: Icon(
              Icons.home
            ),
          ),
        ],
      ),
      body: WebViewWidget(
        controller: controller,
      ),
    );
  }
}

๐Ÿ‘€ ์ฐธ๊ณ 

์ด ๊ธ€์€ ๊ณจ๋“ ๋ž˜๋น— ใ€Š์ฝ”๋“œํŒฉํ† ๋ฆฌ์˜ ํ”Œ๋Ÿฌํ„ฐ ํ”„๋กœ๊ทธ๋ž˜๋ฐใ€‹์˜ ์Šคํ„ฐ๋”” ๋‚ด์šฉ ์ž…๋‹ˆ๋‹ค.

0๊ฐœ์˜ ๋Œ“๊ธ€