Flutter WebにフォームをSpearlyを使って埋め込んでみる
Flutter Advent Calendar 2021 の12日目の記事です。
Flutter WebでLPやコーポレートサイト的なものを作りたいときに役に立つ内容として書きました。
概要
今年は何度かFlutter Webに関して記事を書いてきました。製品版として利用するにはまだまだ難点があるものの、PoCに利用するには必要最低限の機能が整っているかと思います。
以前にSpearly CMSを利用してコンテンツのDBを外部に委託しつつ、Webサイトの構築を行いましたが、今回はお問い合わせやアンケートなどのフォームをSpearly Formを利用して埋め込んでみたいと思います。
なお、これによって以下の技術だけで面倒なデータ管理をすることなくお知らせ機能やお問い合わせ機能をもったWebサイトをほぼ無料で構築することが可能です。
- Flutter Web
- Firebase Hosting
- Spearly CMS/Form
なぜSpearlyなのか
ヘッドレスCMSと言えば microCMS が有名だとは思うのですが、microCMSの場合
- 個人プランからチームプランに切り替えることができない
- フォーム機能を利用する場合、HTML部分を自作したり、通知のために他サービスとの連携する必要がある
という点が自分の用途とは合わないかなと思って見送りました。
Spearlyに関しては基本は無料で、複数人で利用する際に問い合わせて切り替え作業を行う必要があるようです。
個人で使う分には、2.の要素が気にならなければmicroCMSでも同じ内容は実現できるかと思います。
(試したわけではないので、本当にできるかは分かりません)
Spearlyの準備
前回とほぼ同じですが、今回は「フォーム」の機能を利用します。
- こちらの公式ドキュメントに沿って、「実行許可ドメインを設定をしよう」の項目まで完了させます。
- 「フォーム機能を使ってみよう」の項目から進行して、「フォームの埋め込みプレビューと、回答の確認をしよう」まで終わらせます。
Spearlyの組み込み
今回もお手軽なjsタグを貼り付けて埋め込む方法で実装します。
Flutter WebはDartをJavaScriptにコンパイルしてSPAっぽくなっており、そこにiframeでフォームを埋め込む形になります。
なお、会員向けページに詳細はあるのですが、apiからフォームを利用する方法もあるようです。
assets/form.html の設定
ここで利用する「form.html」のbodyタグの中身は「埋め込みプレビュー機能」を使って、任意のHTMLに整えてから添付するのがおすすめです。
(ファイル名は便宜上form.htmlにしているだけなので、何でもOKです)
<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の設定
画像を読み込む際に設定する方法と一緒です。
flutter:
assets:
- assets/form.html
main.dartの設定
今回はプロジェクト内のHTMLを参照していますが、Googleフォームやformrunを利用する場合には外部URLを ui.platformViewRegistry.registerViewFactory
の src
に設置してあげれば問題なく動作します。
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を貼ってあるので興味のある人はカスタマイズしてご利用ください。
実際に作成したフォーム
送信されたデータはSpearly Form内のページから閲覧したり、CSVとしてダウンロードしたりできるようです。
また、フォームが送信されたときにもメールで通知したりWebhookを利用したりできます。
動作するフォームはこちらです。
細々と特殊なことをしているので、参考記事も合わせて貼っておきます。
課題
緊急で困ってはいませんが課題としては以下のようなものがあります。
- フォームのデザインをFlutter経由で行えるようにしたい
- フォーム送信が行われたときに画面をうまく更新するようにしたい
- static_micro_cms のようにFlutter Package化したい(前にテスト的に作ったものを更新しないと…)
それぞれボリュームが多い作業なので、進展がありしだいスクラップか記事で共有したいと思っています!
最後まで読んでいただいてありがとうございました!
Discussion