つい影響されて…
本当このサイトに影響されてここ作ったからね https://taittsuu.com/home ガチのツイ廃というかタイッツー廃
掲示板機能の分離 ├─ Thread/Reply → 独立したboardアプリへ移行 ├─ 匿名投稿の「名前#トリップ」機能を実装 └─ URL・テンプレート参照を全て更新 収益化の仕組み ├─ AffiliateProductにcustom_html対応(バナー広告の直接埋め込み) ├─ show_in_feedフラグで、フィード内広告の対象を制御 └─ 10投稿ごとに自動で広告を挿入
Zのコミュニティサイトを、Androidアプリとしても使えるようにしました! Google Play正式リリース前のβテストとして、まずはフォロワーの皆さんに先行配布します。 📱ダウンロード: https://community.tokeisanheaven.uk/static/downloads/app-release-signed.apk ※Google Play以外からのインストールになるため、警告出るよ
このコミュニティサイトは、Djangoというフレームワークを使って1から作りました。今回から10回に分けて、その開発の記録を書いていきます。 まず最初に決めたのは「どんな見た目のサイトにするか」でした。ただの掲示板ではなく、投稿・タグ・いいねがある、Twitterのタイムラインに近い見た目を目指しました。文字だけがずらっと並ぶ無機質なページではなく、誰かの日常が流れているような、温かみのある画面にしたいと考えていました。 配色は、サイト名の「Heaven Portal」に合わせて、ラベンダーがかった白背景に、空色と後光のような金色をアクセントカラーにしています。見出しには明朝体、本文にはゴシック体を使い分けて、柔らかい雰囲気を意識しました。フォントの組み合わせひとつで、サイト全体の印象がかなり変わるので、ここは何度か試行錯誤しました。 投稿一覧のカードデザインは、影を薄くつけて浮かび上がるようにし、投稿者のアイコン・本文・タグ・いいねボタンを1つのカードにまとめています。長い投稿は500文字を超えると自動で折りたたまれ、「続きを読む」で全文表示できるようにしました。 サイドバーには「新着記事」「アクセス数順」「いいね順」を表示し、どのページからでも人気の投稿にたどり着けるようにしています。こうしたデザインの細部は、一度作って終わりではなく、実際に使ってみて感じた「なんとなく使いにくいな」を、都度直していく繰り返しでした。 投稿作成画面についても、最初は文字数の上限をかなり短く設定していたのですが、実際に運用してみると窮屈に感じることが多く、後から思い切って上限を広げました。見た目の美しさと使いやすさは、頭の中で考えているだけでは分からず、実際に自分で触ってみて初めて気づくことが多いというのが、ここまでの一番の学びです。 次回は、投稿とタグの仕組みについて書きます。
今回は、サイトの中心的な機能である「投稿」と「タグ」について書きます。 投稿機能では、タイトル・本文・画像・タグをまとめて登録できます。画像のファイル名は、そのまま保存すると日本語や特殊文字が原因でエラーになることがあったため、ランダムな文字列に変換してから保存する仕組みにしました。実際、開発の途中で特定の画像だけアップロードに失敗する不具合が起きて、原因を探ったところ、日本語混じりのファイル名がストレージ側で受け付けられていなかったことが分かり、この対策を入れることになりました。 タグは投稿作成時にカンマ区切りで入力するだけで、自動的に新しいタグとして登録されます。日本語のタグ名にも対応していて、タグごとの一覧ページも自動で生成されます。ここでも一度、日本語タグのページだけ表示されないという不具合があり、URLの設定を見直して直しました。 タグの入力欄については、テンプレート側で参照している項目名がずれていたせいで、しばらくの間タグが正しく保存されないという不具合が続いていたこともありました。地道に原因を切り分けていく作業も、開発の醍醐味のひとつだと感じています。 さらに、投稿の一覧では、長い投稿を最初から全文表示すると画面が間延びしてしまうため、500文字を超える投稿は自動的に途中で折りたたみ、「続きを読む」ボタンで全文を展開できるようにしました。タイムライン全体の見やすさを保ちながら、長文もしっかり書けるようにする、両立が難しいポイントでした。 次回は、匿名投稿もできる掲示板機能について書きます。
今回は、匿名でも書き込める掲示板機能について書きます。 掲示板は、2ちゃんねる風の匿名投稿ができる仕組みにしました。名前を入力しなければ「名無し」として投稿でき、「名前#秘密の文字列」の形式で入力すると、その文字列をもとにした「トリップ」という短い符号が名前の後ろに付きます。同じ文字列を使い続ける限り、名乗らなくても同一人物だと分かる、昔ながらの仕組みです。 この掲示板機能は、もともと投稿機能と同じアプリの中に間借りする形で作っていたのですが、役割が大きく異なるため、途中で独立したアプリとして切り出しました。切り出す際には、データベースのテーブルを新しく作り直す形をとり、幸い当時はまだ利用者がいなかったため、データ移行の心配なく進めることができました。 また、同じ人が連続で投稿しすぎないように、投稿後30秒間は再投稿できない制限も入れています。荒らし対策として、匿名投稿者のIPアドレスも記録するようにしました。 掲示板を独立させる作業の中で、テンプレート内のリンク先の指定がひとつだけ古いままになっていて、レス投稿ボタンを押すとエラーになる不具合も起きました。こうした「移行時のうっかり漏れ」は、実際に手を動かしてみないと気づきにくいものだと実感しました。 トリップの仕組みは、入力された秘密の文字列をそのまま保存するのではなく、ハッシュ関数という一方向の変換をかけてから短く切り出して保存しています。これにより、元の文字列が漏れる心配をせずに「同じ人らしさ」だけを示せるようになっています。昔からある掲示板文化の知恵を、実際に自分で実装してみると、その巧妙さに感心させられます。 次回は、SNSアカウントでログインできる仕組みについて書きます。
このサイトを、Androidアプリとしても配布できるようにしました。今回は、PWA(Progressive Web App)として作っていたサイトを、TWA(Trusted Web Activity)という仕組みでAndroidアプリ化した手順を、実際につまずいた点も含めて書いていきます。 ■ そもそもTWAとは TWAは、既存のWebサイトを、ほぼコードを書かずにAndroidアプリとして包める、Google公式の仕組みです。アプリ内でChromeのエンジンをそのまま使い、通常のブラウザのようなアドレスバーを表示せずにサイトを表示できます。ネイティブアプリを1から書く必要がなく、今あるDjangoサイトの資産をそのまま活かせるのが最大の利点です。 前提として、TWA化する前にサイト自体をPWA化しておく必要があります。具体的には、アプリ名やアイコンを定義する「manifest.json」というファイルと、オフライン対応やプッシュ通知を担う「Service Worker」というJavaScriptファイルの2つを用意しました。 ■ Bubblewrapでのプロジェクト生成 TWA化には、Googleが提供する「Bubblewrap」というコマンドラインツールを使いました。Node.js製のツールで、事前にNode.jsとnpmが入っている環境なら、次のコマンドでインストールできます。 npm install -g @bubblewrap/cli 初期化コマンド(bubblewrap init)を実行すると、対話形式で、サイトのmanifest.jsonを読み込みながら、アプリ名・パッケージ名・テーマカラー・アイコン画像などを順番に質問されます。ここで注意したいのが、JDKとAndroid SDKのダウンロードです。まだ入っていない場合、Bubblewrap自身が自動でダウンロード・インストールしてくれますが、あわせて1GB近い容量とそれなりの時間がかかります。 ■ 署名鍵の扱いには要注意 初期化の最後に、アプリの署名に使う鍵(キーストア)を新規作成する場面がありました。ここで設定するパスワードと鍵ファイルは、今後そのアプリを更新するたびにずっと使い続ける、非常に重要なものです。紛失すると、二度と同じアプリとして更新できなくなり、最悪の場合は新しいアプリとして登録し直すしかなくなります。生成直後に、必ず安全な場所へバックアップしておくことを強くおすすめします。 初期化が終わったら、以下のコマンドでビルドします。 bubblewrap build これで、テスト用のAPKファイルと、Google Play提出用のAABファイルの両方が生成されます。 ■ サイトとアプリの信頼関係を証明する TWAでアドレスバーを完全に非表示にするには、「このアプリとこのサイトは同じ運営者が管理している」ことを証明する必要があります。これには「Digital Asset Links」という仕組みを使います。 bubblewrap fingerprint generateAssetLinks というコマンドで、署名鍵から自動的に証明用のJSONファイルが作られます。これを、サイトの「/.well-known/assetlinks.json」という決まった場所に設置する必要がありました。Djangoでは、robots.txtやads.txtと同じ要領で、TemplateViewを使って配信するようにしています。 最初、このJSONファイルの中身が空の配列になってしまう不具合に遭遇しました。原因は、鍵のフィンガープリント(証明書の指紋のようなもの)が、プロジェクトの設定ファイルにまだ登録されていなかったためでした。 keytool -list -v -keystore android.keystore -alias android というコマンドで鍵からフィンガープリントを取得し、 bubblewrap fingerprint add [取得した値] で明示的に登録し直すことで解決しました。 ■ 実機での動作確認 生成したAPKファイルを実際のAndroid端末にインストールしてみると、無事にアドレスバーのない、通常のアプリと同じ見た目で起動できました。Google Play以外からインストールする形になるため、初回だけ「提供元不明のアプリ」という警告が出ますが、設定から許可すればすぐにインストールできます。 ■ 今後について まずはこのAPKファイルを、SNSのフォロワー向けにβ版として直接配布する形にしました。Google Playへの正式リリースには開発者登録(登録料が必要)と審査が必要になるため、身内での反応を見てから、落ち着いて進めていく予定です。 なお、iPhone(iOS)には、AndroidのAPKのような形の自由な野良配布の仕組みが存在しません。iOSでは、Safariの「ホーム画面に追加」機能を使ったPWAとしての利用を案内する形に留めています。 今回、Webサイトとネイティブアプリの境界にある技術に触れてみて、Webの資産をそのままモバイルアプリの入り口として活かせる仕組みの便利さを実感しました。