【Flutter】WebViewで問い合わせを実装する【コピペでOK】

技術メモ

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

 

 

グーグルフォームを作成する

まずはグーグルフォームを作成します。

グーグルフォームを使うメリットは以下の通りです。

 

・簡単にフォームを作成できる
・ユーザーからのお問い合わせを一元的に管理できる

 

五分もかからずフォームを作成できるので、メイン機能の開発に労力を割くことができます。

 

下のリンクから、フォームを作成します。

Google フォーム - アンケートを作成、分析できる無料サービス
自分でアンケートを作成するだけでなく、他のユーザーとも同時に共同で作成できます。また、デザイン性の高いさまざまな既製テーマから選択したり、独自のテーマを作成したりすることも可能です。しかも、Google フォーム内で結果を分析できる、Google の無料サービスです。

 

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

※フォームのURLの末尾は /viewformになっています。

 

WebViewプラグインをインストールする

WebViewを実装するために、 webview_flutter をプロジェクトに導入します。

webview_flutter | Flutter Package
A Flutter plugin that provides a WebView widget on Android and iOS.

 

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のonPageStartedonPageFinishedにそれぞれsetStateを指定し、indexを変更できるようにします。

 

インターネットに接続されていない場合の処理を記載する

インターネットに接続されていない場合、プログレスインジケーターが延々と回り続けます。

そこでインターネットに接続されていないことを表示する処理を追加します。

 

 

FutureBuilderを利用して、インターネットの接続状況を確認してWidgetを出し分けます。

FutureBuilderを利用することで、非同期でWidgetを生成することが可能です。

 

futureに指定したcheckメソッドでインターネットの接続状況を確認して、その結果に応じてbuilderに指定したWidgetを生成します。

 

これで問い合わせをWebViewで実装することができました。

お疲れ様でした!

 

今回の実装でリリースしたアプリ

先日、爆速ToDoメモをリリースしました。

「アプリ起動後、即記録」をコンセプトにFlutterで開発したTodoメモアプリです。

 

爆速ToDoメモアプリ

 

爆速ToDoメモ - アプリを開いて2秒で記録!!

 

 

ぜひインストールして触ってみてください!

https://apps.apple.com/jp/app/rapid-superfast-to-do-list/id1511398926

 

アプリ開発初心者がFlutterでアプリをリリースした際の苦しみを語りました。

 

業務未経験からポートフォリオなしでWebエンジニアに転職した際の経験談を語りました。

これからエンジニアへの転職を考えている人はぜひ読んでみてください。

技術メモ
スポンサーリンク
スポンサーリンク
のすけをフォローする
やばブロ!

コメント