Flutterで動的にOGPを変えられるようにした話
はじめに
こちらのブログはFlutterでできています。スタックに関してはこちらをご覧ください!
https://idonuntius.com/blogs/introduction_flutter_blog
今回はブログ詳細ページをページ毎にOGPを変えられるようにしたので、その実装方法を紹介できればと思います。
前提
- Flutter × Firebase Hostingを使用しています
- 今回の実装はこちらのサイトを参考に実装しています(というかほぼこちらの実装ですmm)
- こちらのブログはデータベースなどはなく内部でJSONで管理しています
firebase.jsonの編集
firebase.jsonの rewrites を使っていきます。
source にはブログ詳細ページのそれぞれのpathを記載。
destination には次で説明する各ブログ詳細ページ用のHTMLを記載。
{
"hosting": {
"public": "build/web",
// ~~~~~
"rewrites": [
// ↓↓↓ 追加
{
"source": "/blogs/introduction_flutter_blog",
"destination": "/html/introduction_flutter_blog.html"
},
{
"source": "/blogs/first_commit",
"destination": "/html/first_commit.html"
},
// ↑↑↑ 追加
{
"source": "**",
"destination": "/index.html"
}
]
}
}
各ブログ詳細ページのHTMLを作成
/web ディレクトリに html ディレクトリを作成し各HTMLを追加します。
og:image に関しては /web ディレクトリに images ディレクトリを作成し、そこに画像を入れています。
/web/html/first_commit.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" type="image/png" href="./../favicon.png" />
<title>First commit</title>
<meta name="description" content="ブログ始めました">
<meta property="og:title" content="First commit">
<meta property="og:description" content="ブログ始めました">
<meta property="og:image" content="https://idonuntius.com/images/first_commit.png" />
<meta property="og:type" content="article">
<meta property="og:site_name" content="idonun.blog">
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@idonuntius">
<meta name="twitter:title" content="First commit">
<meta name="twitter:description" content="ブログ始めました">
</head>
<body>
<script type="text/javascript">window.location = "/blogs/first_commit_";</script>
</body>
</html>
重要なのが <script type='text/javascript'>window.location = '/blogs/first_commit_';</script> です。
こうすことで /blogs/first_commit とURLを打っても /blogs/first_commit_ にリダイレクトされます。 _を最後につけることで、ループすることを防いでいます。
Flutter web側の対応
pathが /blogs/${slug}_なURLが返ってくるため、Flutter web側でそれに対応していく必要があります。
自身のブログではgo_router + go_router_builderを使用しているため、そのライブラリでの実装方法を記載していきます。
go_routerにはredirectがあります。URLが叩かれるとGoRouterクラスのredirectが反応します。
/blogs/${slug}_が叩かれた際もここが呼ばれるので、最後の_を削除して返すようにします。
final goRouter = GoRouter(
routes: $appRoutes,
redirect: (context, state) {
if (state.fullPath == '/${BlogDetailRoute.path}') {
final value = state.pathParameters['slug'];
if (value != null && value.isNotEmpty && value.substring(value.length - 1, value.length) == '_') {
return '/blogs/${value.substring(0, value.length - 1)}';
}
}
return null;
},
errorBuilder: (context, state) => ErrorScreenRoute().build(context, state),
);
// ~~~
class BlogDetailRoute extends GoRouteData {
const BlogDetailRoute({required this.slug});
static const path = 'blogs/:slug';
final String slug;
@override
Widget build(BuildContext context, GoRouterState state) {
return BlogDetailScreen(slug: slug);
}
}
結果
X(旧Twitter) でURLを入力したところ、問題なく表示されました!!

最後に
OGPの情報がちゃんと表示されました。実際はブログ投稿時にいちいち firebase.json やHTMLの作成しているのは辛いので、コマンドを叩けば生成されるようにしています。
しかしまだ画像だけは自動化できていないので、どこかでできたらと思っています。