【Flutter/Dart】WebViewの実装方法!WebViewControllerの使い方

【Flutter/Dart】WebViewの実装方法!WebViewControllerの使い方

この記事からわかること

  • Flutter/DartWebView実装させる方法
  • webview_flutterパッケージ使い方
  • NavigationDelegateとは?

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

環境

FlutterでWebViewを実装する方法

FlutterでWebサイトをアプリ内から表示できるWebViewを実装する方法はいくつか存在します。

どちらもアプリ内からWebサイトを表示することが可能ですが、webview_flutterでは表示しているWebViewのサイズやUIをコントロール可能ですが、url_launcherでは「In-App Browser」という仕組みでWebサイトが表示されるため、自動でフルスクリーンかつ周りの装飾も既存のものになります。

【Flutter/Dart】URLをブラウザ起動で開く方法!url_launcherパッケージの使い方

url_launcherの実装は以下の記事を参考にしてください。

webview_flutterの使い方

webview_flutterパッケージはデフォルトではこのパッケージを組み込まれていないのでflutter pub add webview_flutterコマンドを実行して導入しておく必要があります。

$ flutter pub add webview_flutter

これでimport文を追加することで機能が利用できるようになります。

import 'package:webview_flutter/webview_flutter.dart';

プラットフォーム固有のWebViewの持つ機能を利用したい場合はそれぞて別パッケージになっているので別途導入する必要があります。

// Android : webview_flutter_android
import 'package:webview_flutter_android/webview_flutter_android.dart';
// iOS/macOS : webview_flutter_wkwebview
import 'package:webview_flutter_wkwebview/webview_flutter_wkwebview.dart';

WebView Widgetの実装

実際にWebViewを実装してみます。WebViewScreenという外部から呼び出して使えるカスタムWebView Widgetを実装してみました。「GitHub」に掲載しているので参考にしてください。

/// WebView
class WebViewScreen extends StatefulWidget {
  // 対象URL
  final String url;

  const WebViewScreen({super.key, required this.url});

  @override
  State<WebViewScreen> createState() => _WebViewScreenState();
}

class _WebViewScreenState extends State<WebViewScreen> {
  late final WebViewController _controller;

  @override
  void initState() {
    super.initState();
    _controller =
        WebViewController()
           // JavaScript有効にする
          ..setJavaScriptMode(JavaScriptMode.unrestricted)
          // 初期描画対象のURLを指定
          ..loadRequest(Uri.parse(widget.url));
  }

  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      // WebView表示エリア
      child: SafeArea(child: WebViewWidget(controller: _controller)),
    );
  }
}

ここからは細かく実装のポイントを確認していきます。

WebViewController

WebViewControllerWebViewの設定や操作を行うためのコントローラークラスです。以下の実装ではinitStateWebViewControllerを初期化し設定を行なっています。loadRequestメソッドで表示したいURLを指定します。

@override
void initState() {
  super.initState();
  _controller =
      WebViewController()
        // JavaScript有効にする
        ..setJavaScriptMode(JavaScriptMode.unrestricted)
        // 初期描画対象のURLを指定
        ..loadRequest(Uri.parse(widget.url));
}

JavaScriptの有効/無効setJavaScriptModeで指定します。JavaScriptMode.unrestricted制限なし(=有効)JavaScriptMode.disabled無効にできます。

WebViewWidget

実際にWebView UIを構築しているのはWebViewWidgetです。これは特に変わったことはなく引数にWebViewControllerを指定することでWebViewが表示されるようになります。

// WebView表示エリア
child: SafeArea(child: WebViewWidget(controller: _controller)),

進む / 戻る / リロード

WebViewでWebページを表示中の「進む / 戻る / リロード」などの操作WebViewControllerから行うことが可能です。「進む / 戻る」は呼び出す際にawaitが必要になります。

進む

await _controller.goForward();

戻る

await _controller.goBack();

戻る

_controller.reload();

さらに「進む / 戻る」はcanGoForward/canGoBackメソッドを使用して有効化どうかを識別できます。これをsetNavigationDelegateに仕込んでおくことでページ読み込み完了後に進む / 戻るボタンの活性状態を更新するといった仕組みを実装することも可能です。

bool canGoBack = false;
bool canGoForward = false;

@override
void initState() {
  super.initState();
  _controller = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..loadRequest(Uri.parse(widget.url))
    ..setNavigationDelegate(
      NavigationDelegate(
        // ページ読み込み完了後に進む / 戻るボタンの状態を更新
        onPageFinished: (_) => _updateNavigationState(),
      ),
    );
}

/// 進む / 戻るボタンの状態を更新
Future<void> _updateNavigationState() async {
  final back = await _controller.canGoBack();
  final forward = await _controller.canGoForward();
  setState(() {
    canGoBack = back;
    canGoForward = forward;
  });
}

NavigationDelegate

NavigationDelegateを使用することで以下のようなことが実装できるようになります。

使用方法はWebViewControllerの初期セットアップ時にsetNavigationDelegateメソッドの引数にNavigationDelegate型を指定します。例えば特定のドメインだけブロックしたい場合はonNavigationRequestからNavigationRequest型でリクエスト情報を参照できるのでULRをチェックし遷移をブロックしたい場合NavigationDecision.preventを、遷移を許可したい場合NavigationDecision.navigateを返せばハンドリングできます。

@override
void initState() {
  super.initState();
  _controller = WebViewController()
    ..setJavaScriptMode(JavaScriptMode.unrestricted)
    ..loadRequest(Uri.parse(widget.url));
    ..setNavigationDelegate(
      NavigationDelegate(
        onNavigationRequest: (NavigationRequest request) {
          if (request.url.contains("appdev-room.com")) {
            // 特定のURLへの遷移をブロック
            return NavigationDecision.prevent;
          }
          // 他のURLは許可
          return NavigationDecision.navigate;
        },
      ),
    )
}

定義を確認してみると他にもいろいろなイベントを取得することが可能です。


NavigationDelegate({
  // ナビゲーション制御
  FutureOr<NavigationDecision> Function(NavigationRequest request)? onNavigationRequest, 
  // ページ読み込み開始
  void Function(String url)? onPageStarted, 
  // ページ読み込み完了
  void Function(String url)? onPageFinished, 
  // 読み込み進捗
  void Function(int progress)? onProgress, 
  // リソースエラー
  void Function(WebResourceError error)? onWebResourceError, 
  // URL変更時の処理
  void Function(UrlChange change)? onUrlChange, 
  // HTTP認証要求
  void Function(HttpAuthRequest request)? onHttpAuthRequest, 
  // HTTPエラー発生時
  void Function(HttpResponseError error)? onHttpError, 
})

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index