🚀

Flutter WebにフォームをSpearlyを使って埋め込んでみる

2021/12/12に公開

Flutter Advent Calendar 2021 の12日目の記事です。

https://qiita.com/advent-calendar/2021/flutter

Flutter WebでLPやコーポレートサイト的なものを作りたいときに役に立つ内容として書きました。

概要

今年は何度かFlutter Webに関して記事を書いてきました。製品版として利用するにはまだまだ難点があるものの、PoCに利用するには必要最低限の機能が整っているかと思います。

以前にSpearly CMSを利用してコンテンツのDBを外部に委託しつつ、Webサイトの構築を行いましたが、今回はお問い合わせやアンケートなどのフォームをSpearly Formを利用して埋め込んでみたいと思います。

https://zenn.dev/qst/articles/e97b005c536cccc69006

https://news.spearly.com/release/c-dlbnPZJO1tc7y9K8Tk4s

なお、これによって以下の技術だけで面倒なデータ管理をすることなくお知らせ機能やお問い合わせ機能をもったWebサイトをほぼ無料で構築することが可能です。

  • Flutter Web
  • Firebase Hosting
  • Spearly CMS/Form

なぜSpearlyなのか

ヘッドレスCMSと言えば microCMS が有名だとは思うのですが、microCMSの場合

  1. 個人プランからチームプランに切り替えることができない
  2. フォーム機能を利用する場合、HTML部分を自作したり、通知のために他サービスとの連携する必要がある

という点が自分の用途とは合わないかなと思って見送りました。
Spearlyに関しては基本は無料で、複数人で利用する際に問い合わせて切り替え作業を行う必要があるようです。

https://www.spearly.com/home

個人で使う分には、2.の要素が気にならなければmicroCMSでも同じ内容は実現できるかと思います。
(試したわけではないので、本当にできるかは分かりません)

Spearlyの準備

前回とほぼ同じですが、今回は「フォーム」の機能を利用します。

  1. こちらの公式ドキュメントに沿って、「実行許可ドメインを設定をしよう」の項目まで完了させます。
  2. フォーム機能を使ってみよう」の項目から進行して、「フォームの埋め込みプレビューと、回答の確認をしよう」まで終わらせます。

https://docs.spearly.com/tutorial/c-IfPNWbxdAVY2Q7JRqoh8

Spearlyの組み込み

今回もお手軽なjsタグを貼り付けて埋め込む方法で実装します。
Flutter WebはDartをJavaScriptにコンパイルしてSPAっぽくなっており、そこにiframeでフォームを埋め込む形になります。
なお、会員向けページに詳細はあるのですが、apiからフォームを利用する方法もあるようです。

assets/form.html の設定

ここで利用する「form.html」のbodyタグの中身は「埋め込みプレビュー機能」を使って、任意のHTMLに整えてから添付するのがおすすめです。
(ファイル名は便宜上form.htmlにしているだけなので、何でもOKです)

assets/form.html
<head>
    <!-- ここに貼るタグは公式ドキュメントを見てください -->
    <script src="https://static.spearly.com/js/v2/spearly-cms.browser.js" defer></script>
    <script>window.addEventListener('DOMContentLoaded',()=>{const t=document.querySelectorAll(':not(:defined)');for(const e of t) {e.style.visibility="hidden";}; window.spearly.config.AUTH_KEY="sample"},{once:true})</script>
    <!-- デザインが気になる人はここでデザインをあててください -->
</head>
<body>
<!-- ここに貼るタグは公式ドキュメントを見てください -->
<spearly-form
  data-api-key='sample'
  data-form-id='f-sample'>
  <h1>{%= form_title %}</h1>
  <p>{%= form_description %}</p>
 <div>

  <h3>{%= form_label_name %}</h3>

  <p>{%= form_description_name %}</p>

  {%= form_name %}

 </div>
 <button type="submit">送信</button>
</spearly-form>
</body>

pubspec.yamlの設定

画像を読み込む際に設定する方法と一緒です。

pubspec.yaml
flutter:
  assets:
    - assets/form.html

main.dartの設定

今回はプロジェクト内のHTMLを参照していますが、Googleフォームやformrunを利用する場合には外部URLを ui.platformViewRegistry.registerViewFactorysrc に設置してあげれば問題なく動作します。

main.dart
import 'dart:html' as html;
import 'dart:ui' as ui;

import 'package:flutter/material.dart';

class HomePage extends StatelessWidget {
  final String _viewId = 'spearly-form';

  
  Widget build(BuildContext context) {

    // ignore: undefined_prefixed_name
    ui.platformViewRegistry.registerViewFactory(
        _viewId,
        (int id) => html.IFrameElement()
          ..width = MediaQuery.of(context).size.width.toString()
          ..height = MediaQuery.of(context).size.height.toString()
          // Googleフォームやformrunの場合にはここを外部URLに変更します
          ..src = 'assets/form.html'
          ..style.border = 'none');

    return Scaffold(
      appBar: AppBar(
        title: Text(
          'Spearly Form Sample' 
        ),
      ),
      // iframeのサイズはこのSizedboxで調整します
      body: SizedBox(
        width: 500,
        height: 800,
        child: HtmlElementView(
          viewType: _viewId,
        ),
      ),
    );
  }
}

ビルド&デプロイ

僕の場合、デプロイ先にはFirebase Hostingを利用しているのですが、頻繁に利用しているので、GitHub Actionsで自動デプロイされるようにしています。

今回のテーマとは直接関係ないので割愛しますが、リンク先に「Flutter Web + Firebase Hosting」の場合のActionsのYAMLを貼ってあるので興味のある人はカスタマイズしてご利用ください。

https://zenn.dev/qst/scraps/4a8c65a928c80b

実際に作成したフォーム

Flutter WebとSpearly Formで作成したフォーム

送信されたデータはSpearly Form内のページから閲覧したり、CSVとしてダウンロードしたりできるようです。
また、フォームが送信されたときにもメールで通知したりWebhookを利用したりできます。

通知周りの設定

動作するフォームはこちらです。
細々と特殊なことをしているので、参考記事も合わせて貼っておきます。

https://lp.hhg-exe.jp/

https://zenn.dev/qst/articles/c11c37a3531ce5476de7

課題

緊急で困ってはいませんが課題としては以下のようなものがあります。

  1. フォームのデザインをFlutter経由で行えるようにしたい
  2. フォーム送信が行われたときに画面をうまく更新するようにしたい
  3. static_micro_cms のようにFlutter Package化したい(前にテスト的に作ったものを更新しないと…)

それぞれボリュームが多い作業なので、進展がありしだいスクラップか記事で共有したいと思っています!

最後まで読んでいただいてありがとうございました!

Discussion