Flutter 로 하이브리드 앱을 만들 일이 생겼습니다.

제목 그대로 플러터로 하이브리드 앱을 만들어야 하는 상황에 놓였습니다. 그래서 Flutter에서는 어떻게 웹뷰를 띄우는지 알아보았고, 그것을 공유하고자 합니다. 그리고 웹뷰를 정상적으로 띄웠더라도 특정 조치를 취하지 않으면 뒤로가기 버튼이 동작하지 않고 앱이 꺼져버립니다. 이것은 또 어떻게 해결할 수 있는지도 확인해보겠습니다.

플러터로 어떻게 웹뷰를 만들까

패키치 설치

Flutter에서는 웹뷰를 띄울 때 `webview_flutter`라는 package를 이용합니다. 

사용을 위해 미리 pub get 해줍니다. 글을 쓰는 시점에서는 ^2.0.12버젼입니다.

 

클래스 작성

package를 설치했다면 이제 WebViewExample 이라는 이름으로 클래스를 만들어줍니다.

Stateful widget으로 만들고, 아래와 같이 만들어줍니다.

(아래의 _goback 메서드는 지금 신경쓰지 않아도 됩니다.)

 

import 'dart:async';
import 'dart:io';

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

class WebViewExample extends StatefulWidget {
  @override
  WebViewExampleState createState() => WebViewExampleState();
}

class WebViewExampleState extends State<WebViewExample> {
  WebViewController? _webViewController;

  @override
  void initState() {
    super.initState();
    // Enable hybrid composition.
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () => _goBack(context),
      child: Scaffold(
        body: WebView(
          initialUrl: 'http://192.168.0.104:8080/',
          javascriptMode: JavascriptMode.unrestricted,
        ),
      ),
    );
  }

  Future<bool> _goBack(BuildContext context) async {
    if (_webViewController == null) {
      return true;
    }
    if (await _webViewController!.canGoBack()) {
      _webViewController!.goBack();
      return Future.value(false);
    } else {
      return Future.value(true);
    }
  }
}

 

위 코드에서 주목해야 할 부분은 initialUrl과 그 밑의 javascriptMode 입니다.

initialUrl은 최초 진입점이 될 부분이고, 

javascriptMode는 아래에서 예시로 들고 있듯이 자바스크립트를 사용할 건지 여부를 결정합니다.

참고로 initialUrl이 https:// 가 아니라 http:// 로 시작한다면

더보기

안드로이드의 경우 android/src/main/AndroidManifest.xml을 아래와 같이 수정합니다.

...
	<application
    	...
        android:usesCleartextTraffic="true">
    	...

iOS의 경우 info.plist에 allowArbitraryLoads를 허용해야 합니다.(링크:https://comxp.tistory.com/353)

 

 

 

 

뒤로가기 기능은 어떻게 추가할까

 

여기까지 잘 따라했다면 웹뷰를 적용하는 법에 대해서는 다들 아셨을 것입니다.

이제 뒤로가기 기능을 추가해봅시다. 

코드를 다음과 같이 일치시켜줍니다. _completerHandler가 추가됐네요.

 

import 'dart:async';
import 'dart:io';

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

class WebViewExample extends StatefulWidget {
  @override
  WebViewExampleState createState() => WebViewExampleState();
}

class WebViewExampleState extends State<WebViewExample> {
  WebViewController? _webViewController;
  final Completer<WebViewController> _completerController =
      Completer<WebViewController>();

  @override
  void initState() {
    super.initState();
    // Enable hybrid composition.
    if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
  }

  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () => _goBack(context),
      child: Scaffold(
        body: WebView(
          onWebViewCreated: (WebViewController webViewController) {
            _completerController.future
                .then((value) => _webViewController = value);
            _completerController.complete(webViewController);
          },
          initialUrl: 'http://192.168.0.104:8080/',
          javascriptMode: JavascriptMode.unrestricted,
        ),
      ),
    );
  }

  Future<bool> _goBack(BuildContext context) async {
    if (_webViewController == null) {
      return true;
    }
    if (await _webViewController!.canGoBack()) {
      _webViewController!.goBack();
      return Future.value(false);
    } else {
      return Future.value(true);
    }
  }
}

 

위 코드에서 뒤로가기 버튼이 동작하는 원리는 이렇습니다. 

웹뷰가 생성되고, completer에 의해 webViewController까지 생성이 되면,

onWillPop에 연결되어 있는 _goBack 함수가 동작할 준비를 마칩니다.

go_back함수는 webviewController의 canGoBack() 메서드를 호출하는데,

이 함수는 히스토리상에 뒤로 갈 페이지가 남아있으면 true, 아니면 false를 반환합니다.

 

onWillPop메서드는 true를 반환하는 경우 화면이 pop됩니다. 즉, 내가 보고 있는 화면 자체가 사라진다는 겁니다. 그렇기 때문에 뒤로가기 버튼을 눌렀을 때 history상 돌아갈 곳이 남아있다면 onWillPop에 false를 전달해야 하고, 없다면 true를 전달하여 홈화면으로 돌아가게 만드는 것입니다.

 

iOS의 경우 할 것이 아직 하나 남았습니다.

 

안드로이드의 경우 뒤로가기 버튼이 있지만 iOS 앱의 경우 뒤로가기 버튼이 없기 때문에 Floating Button을 추가하여 뒤로가기를 실행할 수 있어야 합니다. 웹뷰를 만드는 쪽에서 뒤로가기 버튼을 만든다면 그것 또한 방법이 될 수 있겠네요 !

 

 

Reference

canGoBack: https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewController/canGoBack.html

 

canGoBack method - WebViewController class - webview_flutter library - Dart API

Future canGoBack() Checks whether there's a back history item. Note that this operation is asynchronous, and it is possible that the "canGoBack" state has changed by the time the future completed. Implementation Future canGoBack() { return _webViewPlatform

pub.dev

completer: https://api.flutter.dev/flutter/dart-async/Completer-class.html

willPopScope: https://api.flutter.dev/flutter/widgets/WillPopScope-class.html

webViewController: https://pub.dev/documentation/webview_flutter/latest/webview_flutter/WebViewController-class.html

전체 코드 참조: https://kangtaejin.github.io/flutter/flutter-webview/

webview_flutter: https://pub.dev/packages/webview_flutter

 

  • 네이버 블러그 공유하기
  • 네이버 밴드에 공유하기
  • 페이스북 공유하기
  • 카카오스토리 공유하기
// custom