webview_flutterを使ってFlutterアプリ内でWebページを開く
はじめに
FlutterでURLをタップした時にアプリ内でそのURLのWebページを開く方法についてまとめます。この記事では、Flutter公式のプラグインであるwebview_flutterを使用した実装例をメモします。
できるようになること
以下のようにボタンをタップすると指定したURLのWebページをFlutterアプリ内で開きます。
なお、もしFlutterアプリ内でリンクをクリックしたらアプリ外でブラウザを開いてそのWebページを表示したい場合については以下にまとめました。
FlutterでURLをタップしたらブラウザが開いてそこでURL先を表示したい場合があります。この記事では、Flutter公式のプラグインを使用した実装例をメモします。
前提と環境
以降に記載するコードを実行した環境は以下になります。
- iOS 15.5
- Xcode 13.4.1
- Flutter 3.0.5 (Dart 2.17.6)
必要なパッケージ
必要なパッケージは以下になります。
dependencies:
webview_flutter: ^3.0.4
Webページを読み込むウィジェットのコード
冒頭に載せたデモのコードでは、Webページを読み込む部分をウィジェット化し、それを必要な箇所で使っています。 まず先にWebページを読み込むウィジェットのコードを以下に記載します。
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewWidget extends StatefulWidget {
const WebViewWidget({
Key? key,
this.title,
required this.url,
}) : super(key: key);
final String? title;
final String url;
_WebViewWidgetState createState() => _WebViewWidgetState();
}
class _WebViewWidgetState extends State<WebViewWidget> {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
bool _isLoading = false; // ページ読み込み状態
double _downloadProgress = 0.0; // ページ読み込みの進捗値
String _title = '';
String _url = '';
void initState() {
super.initState();
_title = widget.title ?? '';
_url = widget.url;
if (Platform.isAndroid) {
WebView.platform = SurfaceAndroidWebView();
}
}
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
body: Column(
children: [
_isLoading
? LinearProgressIndicator(value: _downloadProgress)
: const SizedBox.shrink(),
Expanded(
child: WebView(
// 表示する初期URLの指定
initialUrl: _url,
// javascriptを有効化. disabled で無効化
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
},
// ページ読み込み中の処理
onProgress: (int progress) {
print('Webサイトを読み込み中です... (進捗 : $progress%)');
setState(() {
_downloadProgress = (progress / 100);
});
},
// ページへの遷移処理開始時の処理
navigationDelegate: (NavigationRequest request) {
// 特定URLへのアクセスは拒否する
if (request.url.startsWith('https://github.com/')) {
print('blocking navigation to $request}');
return NavigationDecision.prevent;
}
print('allowing navigation to $request');
return NavigationDecision.navigate;
},
// ページの読み込み開始時の処理
onPageStarted: (String url) {
print('Page started loading: $url');
setState(() {
_isLoading = true;
});
},
// ページの読み込み完了時の処理
onPageFinished: (String url) async {
print('Page finished loading: $url');
setState(() {
_isLoading = false;
});
// Webページのタイトルを取得
final controller = await _controller.future;
final title = await controller.getTitle();
setState(() {
if (title != null) {
_title = title;
}
});
},
// 水平方向のスワイプ時に戻る、進むを機能させるかのフラグ。iOSでのみ機能する。
gestureNavigationEnabled: true,
// 背景色
backgroundColor: const Color(0x00000000),
// ページ読み込み終了
),
),
],
),
);
}
}
navigationDelegateについて
今回使用しているFlutter公式のプラグインであるwebview_flutter
では、navigationDelegate
にページ遷移する時に遷移先のURLに関連して何かしらの処理を記述できます。例えば、以下のコードでは、https://github.com/
から始まるURLへのアクセスを拒否します。https://github.com/
から始まるURLへのリンクをクリックしても、アクセス拒否の対象であるためページ遷移せず何も起きません。
実際には、特定のURLへのリンクをクリックしたら何かアラートメッセージを出したり、本当に移動するかの確認ダイアログを出したりすると思います。他にもいろいろな使い方ができると思います。
// ページへの遷移処理開始時の処理
navigationDelegate: (NavigationRequest request) {
print('遷移先 : ${request}');
// 特定URLへのアクセスは拒否する
if (request.url.startsWith('https://github.com/')) {
print('$requestへのアクセスをブロック');
return NavigationDecision.prevent;
}
print('$requestへのアクセスを許可');
return NavigationDecision.navigate;
},
上記のNavigationRequest request
は、url (string)
、isForMainFrame (bool)
の値を持ちます。url
は遷移しようとしているURLの文字列です。isForMainFrame
は遷移しようとしているURLがメインフレームであるか、それ以外かの真偽値になります。ここでいうメインフレームとは、WebViewが開いた最初のURL、すなわち上記のコードだとhttps://flutter.dev/
をURLに含むWebページになります。https://flutter.dev
内にあるリンクの内、https://flutter.dev
からはじまるURL以外のWebページへの遷移は全てメインフレームではなく、isForMainFrame
はfalse
になります。
なお、Webページの中で読み込まれるiFrameやlink要素についてもnavigationDelegate
は実行されます。そしてこれらのNavigationRequest request
のisForMainFrame
はfalse
になります。
例えば、以下のようなコードにすると、メインフレーム(上記のデモコードだとhttps://flutter.dev/
を持つURL)以外へのアクセスは一切できなくなります。
// ページへの遷移処理開始時の処理
navigationDelegate: (NavigationRequest request) {
print('遷移先 : ${request}');
// メインフレームでない場合は遷アクセス拒否
if (!request.isForMainFrame) {
return NavigationDecision.prevent;
}
},
これは実際にNavigationRequest request
のisForMainFrame
の値を見て動作確認すると理解しやすいと思います。
Webページを読み込むウィジェットを使う部分のコード
以下が実際に上記のWebページを読み込むウィジェットを使う部分になります。読み込みたいページのURLとタイトルを引数として渡して使用します。
import 'package:flutter/material.dart';
import 'package:url_launcher/link.dart';
...(省略)...
TextButton(
onPressed: () {
Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) => WebViewWidget(
title: "Flutter",
url: "https://flutter.dev",
)
));
},
child: const Text(
'Webサイト表示',
style: TextStyle(fontSize: 12),
),
style: ButtonStyle(
padding: MaterialStateProperty.all(EdgeInsets.zero),
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
),
...(省略)...
まとめ
Flutterアプリ内でWebページを開くための実装についてまとめました。
関連記事
- 公開日:2022/08/30 更新日:2022/08/30
FlutterアプリでAndroid StudioのGenerate Signed Bundle/APKが表示されない時の対処法
FlutterアプリをGoogle Play Storeに公開するためにAndroid Studioを使ってアップロード鍵を生成しようとしたところ、公式ドキュメントに書かれている「Build」→「Generate Signed Bundle/APK」というメニューが見つかりませんでした。この解決法をメモします。
- 公開日:2022/08/14 更新日:2022/08/14
FlutterでURLへのリンクを作成してアプリ外でWebページを開く
FlutterでURLをタップしたらブラウザが開いてそこでURL先を表示したい場合があります。この記事では、Flutter公式のプラグインを使用した実装例をメモします。
- 公開日:2019/12/03 更新日:2019/12/03
Android App Bundleを実機にインストールして試すために使うbundletoolの使い方
Flutterなどで開発したAndroidアプリを自分の手元にある実機にインストールして試したい場合はbundletoolを使用するよう公式ドキュメントに記載されています。ただ、常識であるためなのか詳しい使い方が書かれておらず戸惑ったのでメモしておきます。
- 公開日:2019/12/02 更新日:2019/12/02
Flutterでアプリの復帰やサスペンドを検出して処理を実行する
Flutterで開発したアプリが復帰した時やサスペンドした時を検出して任意の処理を実行するための手順をまとめます。