WebViewという機能を使用することで、ネイティブアプリ内でWebページを表示することができます。
WebViewを使用することでアプリから外部のWebブラウザに飛ばさずに済むので、ユーザー体験が向上するメリットがあります。
また、既存のWebページを流用できるので、アプリ開発コストを下げることができます。
特に個人開発でアプリをリリースする場合は少しでも開発コストを下げることが重要なので、主要機能ではない箇所をWebViewで実装するのはアリです。
今回はFlutterアプリにWebViewを使用して、問い合わせ機能を実装していきます。
問い合わせフォームはグーグルフォームを利用します。
実装後はこのようになります。

コードはコピペできるように、なるべくまるごと掲載していきます。
それではいきましょう!
開発環境
- MacBook Pro (macOS Catalina バージョン10.15.4)
- Flutter 1.12.13+hotfix.5 channel stable
- Dart 2.7.0

グーグルフォームを作成する
まずはグーグルフォームを作成します。
グーグルフォームを使うメリットは以下の通りです。
・ユーザーからのお問い合わせを一元的に管理できる
五分もかからずフォームを作成できるので、メイン機能の開発に労力を割くことができます。
下のリンクから、フォームを作成します。

フォーム作成後、右上の目のマーク(プレビュー)をクリックして立ち上がったページのURLをコピーします。
※フォームのURLの末尾は /viewformになっています。

WebViewプラグインをインストールする
WebViewを実装するために、 webview_flutter をプロジェクトに導入します。

WebViewページを作成する
完成コードはこちらです。
import 'dart:async';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:rapid_todo/loading.dart';
import 'package:rapid_todo/localization/localized_constants.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebViewPage extends StatefulWidget {
@override
_WebViewPageState createState() => _WebViewPageState();
}
class _WebViewPageState extends State {
final Completer _controller =
Completer();
var connectionStatus;
num position = 1;
final key = UniqueKey();
doneLoading(String A) {
setState(() {
position = 0;
});
}
startLoading(String A) {
setState(() {
position = 1;
});
}
// インターネット接続チェック
Future check() async {
try {
final result = await InternetAddress.lookup('google.com');
if (result.isNotEmpty && result[0].rawAddress.isNotEmpty) {
connectionStatus = true;
}
} on SocketException catch (_) {
connectionStatus = false;
}
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: check(), // Future or nullを取得
builder: (BuildContext context, AsyncSnapshot snapshot) {
return Scaffold(
appBar: AppBar(
title: Text('不具合を報告'),
),
body: connectionStatus == true
? IndexedStack(
index: position,
children: [
WebView(
initialUrl: 'グーグルフォームのURL',
javascriptMode: JavascriptMode.unrestricted, // JavaScriptを有効化
onWebViewCreated:
(WebViewController webViewController) {
_controller.complete(webViewController);
},
key: key,
onPageFinished: doneLoading, // indexを0にしてWebViewを表示
onPageStarted: startLoading, // indexを1にしてプログレスインジケーターを表示
),
// プログレスインジケーターを表示
Container(
child: Center(
child: CircularProgressIndicator(backgroundColor: Colors.blue),
),
),
],
)
// インターネットに接続されていない場合の処理
: SafeArea(
child: Center(
child: Column(
children: [
Padding(
padding: EdgeInsets.only(
top: 120,
bottom: 20,
),
child: Container(),
),
Padding(
padding: EdgeInsets.only(
bottom: 20,
),
child: Text(
'インターネットに接続されていません',
),
),
],
),
),
),
);
});
}
}
実装ポイント
WebViewを実装するに当たってのポイントを解説します。
WebViewでページを表示
initialUrl に先ほど作成したグーグルフォームのURLを指定します。
また javascriptMode に JavascriptMode.unrestricted を指定してJavaScriptを有効にしてください(デフォルトでは無効になっているので注意)
インターネット接続中にプログレスインジケーターを表示する
インターネット接続中に画面が真っ白だとUX的に良くないため、プログレスインジケーターを表示しています。
プログレスインジケーターとは通信中に表示されるクルクル回る画像です。

IndexedStack を使ってインターネット接続中にはプログレスインジケーターを表示し、接続が完了したらWebViewでグーグルフォームのページを表示するようにします。
IndexedStackを使うことでindexプロパティに番号を渡すだけで、childrenに指定したWidgetから表示するものを選択できます。
WebViewのonPageStartedとonPageFinishedにそれぞれsetStateを指定し、indexを変更できるようにします。
インターネットに接続されていない場合の処理を記載する
インターネットに接続されていない場合、プログレスインジケーターが延々と回り続けます。
そこでインターネットに接続されていないことを表示する処理を追加します。

FutureBuilderを利用して、インターネットの接続状況を確認してWidgetを出し分けます。
FutureBuilderを利用することで、非同期でWidgetを生成することが可能です。
futureに指定したcheckメソッドでインターネットの接続状況を確認して、その結果に応じてbuilderに指定したWidgetを生成します。
これで問い合わせをWebViewで実装することができました。
お疲れ様でした!
今回の実装でリリースしたアプリ
先日、爆速ToDoメモをリリースしました。
「アプリ起動後、即記録」をコンセプトにFlutterで開発したTodoメモアプリです。
爆速ToDoメモ - アプリを開いて2秒で記録!!


ぜひインストールして触ってみてください!
アプリ開発初心者がFlutterでアプリをリリースした際の苦しみを語りました。
業務未経験からポートフォリオなしでWebエンジニアに転職した際の経験談を語りました。
これからエンジニアへの転職を考えている人はぜひ読んでみてください。






コメント