Blog
ブログ
技術や会社に関する記事を配信しています。
noras AI は、ノラスに関する質問・回答が得意なAIです。ノラスに関連のない質問には、うまく返答しない可能性があります。
noras AI は、ノラスに関する質問・回答が得意なAIです。ノラスに関連のない質問には、うまく返答しない可能性があります。
2025年4月20日


ノラスの創業者。 WEB開発とデザインが得意。 音楽とお祭りが好き。
毎年5月2日〜5月5日のゴールデンウィーク、石川県七尾市では「青柏祭(せいはくさい)」という巨大なお祭りが開催されます。昨年は令和6年能登半島地震の影響で中止となり、今年は2年ぶりの開催。大盛況が予測されています。
そんな青柏祭の巨大曳山行事「でか山」をリアルタイムで追跡するWebアプリ「でか山ウォーク」を開発しました。本記事では、技術選定や開発現場のことについて綴ります。

巨大曳山行事「でか山」は、総重量約10トンにも及ぶ山車を曳き手が力を合わせて動かす壮観なイベントです。しかし、3つの曳山が街中を練り歩くため、どの山車がどこを通っているのか、見物客には追いかけ切れないという課題がありました。
そこで今年は「でか山ウォーク」として、曳山の位置をリアルタイムで可視化するWebアプリを開発。会場にいながらスマホやブラウザで現在位置を把握でき、より快適に祭りを楽しめる体験を提供する運びとなりました。

| サービス | 用途 |
|---|---|
| Firebase Realtime Database | 位置情報テーブルの緯度・経度をリアルタイム更新 |
| Vercel | Reactアプリのデプロイ |
| Google Cloud Monitoring | エラー検知、コストオーバー時のSlack通知 |
| 項目 | 内容 |
|---|---|
| 端末 | スマートフォンレンタル6台(Redmi 12 5G / Xiaomi) |
| アプリ | Kotlinで位置情報を送信する専用アプリを開発 |
| 配布 | Firebase App Distributionで6台の実機に配布(3つのでか山に各1台、予備1台) |
| 技術 | 用途 |
|---|---|
| Vite × React | Webアプリ本体 |
| Google Maps API | 地図表示・マーカー制御 |
スマートフォンのレンタルにはジャパン・エモーション様の法人スマホレンタルサービスを利用しました。迅速かつ丁寧に対応してくださいました。
スマートフォンをGPS機として使うために、AndroidのForeground Serviceを採用しました。
フォアグラウンド サービスを使用しているアプリの例を次に示します。音楽プレーヤーアプリは、フォアグラウンド サービスで音楽を再生します。フィットネスアプリは、ユーザーからの許可を得たうえで、ユーザーのランニングをフォアグラウンド サービスで記録します。
Androidアプリを採用した理由は、ロック時・スリープ時・アプリをスワイプ終了した状態でも、明示的にアプリ内でstopボタンを押すまで途切れることなく位置情報をFirebaseに送信し続けられるためです。iOSではスリープ時やアプリ終了時の挙動がやや異なり、Androidの方が今回の用途には適切と判断しました。短期スマホレンタルの料金が安いのも嬉しいポイントです。
3つのでか山のうち、どれに搭載するかを選んで「位置情報の共有を開始」するだけで完了です。
// Activity.kt
private fun startLocationService(deviceId: String) {
Log.d(TAG, "startLocationService: Starting service with device ID: $deviceId")
val serviceIntent = Intent(this, LocationForegroundService::class.java).apply {
putExtra("DEVICE_ID", deviceId)
}
startForegroundService(serviceIntent)
statusText.text = "位置情報サービスを開始しました($deviceId)"
}
private fun stopLocationService() {
Log.d(TAG, "stopLocationService: Stopping service")
val serviceIntent = Intent(this, LocationForegroundService::class.java)
stopService(serviceIntent)
statusText.text = "位置情報サービスを停止しました"
}
ほぼこれが全てのシンプルなアプリを Firebase App Distribution で配布し、レンタルスマホ6台にインストールしました。

なるべくGoogleマップと同等の操作性を実現したい一方、通信量の膨大化も懸念されるため、慎重に進めました。
初回の位置取得をgetCurrentPositionで行い、その後はwatchPositionで監視し続ける実装としています。これにより、自然な動きの現在地更新を実現できます。
// MyLocation.tsx
// 初回の位置取得
navigator.geolocation.getCurrentPosition(
handlePositionUpdate,
(error) => {
console.error('位置情報の取得に失敗しました:', error);
setGpsNotAvailable(true);
let errorMessage = '正確な現在地が取得できません';
if (error.code === 1) {
errorMessage = '位置情報の使用が許可されていません。ブラウザの設定を確認してください。';
} else if (error.code === 2) {
errorMessage = '位置情報を取得できませんでした。GPSが有効になっているか確認してください。';
}
setLocationError(errorMessage);
toast.error(errorMessage, {
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
});
},
options
);
// 継続して位置を監視
watchId.current = navigator.geolocation.watchPosition(
handlePositionUpdate,
(error) => {
console.error('位置情報の取得に失敗しました:', error);
setGpsNotAvailable(true);
let errorMessage = '正確な現在地が取得できません';
if (error.code === 1) {
errorMessage = '位置情報の使用が許可されていません。ブラウザの設定を確認してください。';
} else if (error.code === 2) {
errorMessage = '位置情報を取得できませんでした。GPSが有効になっているか確認してください。';
} else if (error.code === 3) {
errorMessage = '位置情報の取得がタイムアウトしました。もう一度お試しください。';
}
setLocationError(errorMessage);
toast.error(errorMessage, {
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
});
},
options
);
Googleマップでは数年前から、交通規制や事故渋滞などをユーザーが報告できる機能が搭載されています。同じ発想で、アプリを使用中のユーザーがトイレや駐車場の空き状況を1タップで報告できる機能を実装しました。
「一箇所だけ大混雑」というイベントあるあるを避けるため、各施設のアイコンから「空いてる」「混んでる」を報告できるようにしています。現実的なユースケースと悪意のあるユーザーへの対策として、報告された空き状況は一定時間が経過すると自動的に削除される設計にしました。

実は本件、とある事情で非常にタイトなスケジュールでの開発となりました。
限られた納期と予算の中で、いかにして高パフォーマンスを実現するか。どうすれば青柏祭に一番貢献できるのか。そんな課題を真正面から受け止めると、デベロッパーとしてのプライドが掻き立てられ、案外ワクワクするものでした。毎回これでは身体が持ちませんが。
地方在住エンジニアの苦悩話のようになってしまいましたが、地域の皆様にアプリやWebサービスへの関心を高めていただき、今以上に価値を感じてもらう。そうしてこそ私たちの持つ技術がこの先、能登半島という地域で輝くと信じて、日々開発に取り組んでいます。
無事リリースが完了し、チラシのデザイン・印刷やプレスリリースの配信も終わったところで本記事を書いています。
間違いなく、七尾市が一番盛り上がるタイミングです。震災をきっかけに能登を知ったけど、まだ行ったことがないという方も、ぜひ能登・七尾の青柏祭へお越しください。
