Bluetoothで地球の裏側まで ─ すれ違いアプリKontaの中身

きっかけ お酒を飲みながら友達と「こういうアプリあったら面白いよね」みたいな話をすることってあると思うんですが、今回はなぜか本当に作ることになりました。流れはあんまり覚えていません。 元々はもっと大きいアプリを作ろうとしていて、その機能の一つにBluetoothを使う想定がありました。その話をしているときに「Kontaみたいなアプリがあってもいいよね」という感じになって、じゃあとりあえずこっちから作るか、と。 (Kontaという名前の由来については、また今度書きます笑) それでBluetoothについて調べていたら、だんだん妄想がふくらんできました。 アプリを入れた人が増えれば増えるほど、その人たちが中継機になって、いつか地球の裏側の人とも繋がるんじゃないか。 日本にいるAさんと、ブラジルにいるBさん。この2人は直接は知り合いません。でも間にいる人たちが少しずつメッセージを運んでくれれば、いつかは届くんじゃないかなと。会話には出てこない人たちが橋になるイメージです。 サーバーもいらないし、通信キャリアもいらない。人がいればそれでネットワークになる、みたいなことを考えていました。 結果としては、まだ全然そこまで行っていません。作ったのは、目の前ですれ違った人と1対1で話すだけのアプリ(Konta)です。サーバーは使っていないので圏外でも動きますが、届く範囲は十数メートルくらいです。 どんなアプリか Konta というアプリです。紹介ページはこちらです。 https://konta.world/ やることはシンプルで、 「接続する」を押すと、近くで同じアプリを開いている人をBluetoothで探しはじめる 見つかった相手とお互いに「会話する」を押すと、そこでマッチングが成立する あとはニックネームと絵文字だけで1対1のチャットをする 相手と離れると会話は終わり、履歴も残らない 電話番号もメールアドレスも要りませんし、アカウント登録もありません。サーバーを持っていないので、そもそも会話がどこかに保存されることもないです。 iOSで公開しています。 https://apps.apple.com/jp/app/konta/id6797600072 どうやって作っていたか 恵比寿の「いいオフィス」というレンタルスペースにこもって、半日くらいずっと開発する、というのをリリースまでに2回やりました。 平日は、僕はClaudeを使って開発を進めていました。友達はエンジニアではないんですが、機能要件とか利用規約とかを中心に進めてくれていました。 僕が詰まっているときも、いろんなユースケースを考えてくれたり、アイディアをくれたりして、突破するきっかけを常にくれていました。すごく楽しかったです。 スペシャルサンクス 友達と奥さんが、家の中や通勤のときに実際に動かして検証してくれました。これが本当に助かりました。 すれ違いのアプリなので、1人だとそもそも動作確認ができません。シミュレータではBluetoothが使えないので実機が2台以上必要ですし、手元のiPhoneとMacを並べて動いたところで、通勤中の人混みでちゃんと見つかるのか、部屋の壁を挟んだらどうなるのかは分かりません。 生活の中で普通に使ってもらえたのが、一番のテストでした🙏 この記事について Bluetoothの実装は今回が初めてでした。作る前は「近くの端末を見つけて繋ぐだけでしょ」と思っていたのですが、実際に触ってみると、想像していたのとは全然違うところでつまずき続けました。 この記事は、1周目でハマったところと、後からドキュメントを読み直して「そう書いてあったのか」となった箇所をまとめたものです。同じように「BLE何もわからん」から始める人の参考になれば嬉しいです。 つまずいたのは大きく3か所でした。 BLEの「繋がっている」「相手がいる」という状態が、仕様レベルでけっこう曖昧 サーバーを持たないので、暗号化は自分で設計するしかない E2EE(端末間暗号化)にすると、モデレーションの前提が変わってしまう 根拠になる部分は、できるだけAppleの公式ドキュメントとRFCを引用しました。自分の思い込みと、公式に書いてあることを混ぜたくなかったためです。 あと、記事を書くために検証し直したら、自分の理解が間違っていた箇所がいくつも出てきました。それも正直に書いています。いくつかの箇所は、書きながらAIに壁打ちして「そこ違うのでは」と言われ、調べ直して書き直したものです。まだ間違いが残っているかもしれないので、見つけたら教えてください。 長めなので、興味のある章だけ拾ってもらえれば大丈夫です。近接検知や1対1マッチングを作る予定がある方の参考になれば嬉しいです。 ✓ この記事はメッシュ(マルチホップ)ではなく、直接繋がった2台の1対1の話です。冒頭に書いた「橋になる」アイデアを今回入れなかった理由は、最後の章に書きました。 0. 先に用語だけ BLE の記事を読み始めたとき、僕は用語で最初につまずきました。同じものが文脈によって違う呼ばれ方をするので、先に整理しておきます。 ...

September 10, 2026 · 19 min

傷つけば楽になる

iPhoneとかApple Watchとか、高価なので最初は傷がつかないかすごく気をつけるけど、ふとした時に傷を見つけてしまった瞬間、どうでも良くなるというか、物なので傷ついてなんぼだなって思う時がくる。 でも気にしちゃうよね〜(笑)

April 21, 2026 · 1 min

タイムトラベルの終着点は、富士そばだった。

数年ぶりに、中学時代の同級生たちと集まってきた。 別に見下したいわけでも、自分が特別だと思いたいわけでもない。 ただ純粋に、「あいつ、今はどんなこと考えて生きてるのかな」という、今の彼らの輪郭を知りたかった。大人になった僕らが、それぞれの場所で積み上げてきた「今」を持ち寄って、少しだけ深い話ができればいいな、なんて期待を胸に。 けれど、いざ蓋を開けてみると、そこは想像以上に「上っ面」の、いや、もはや上っ面すら見えないほどの「思い出の霧」に包まれた空間だった。 会話のメインは、15年前の記憶。 僕が知りたかった「最近の仕事の話」や「大切にしている価値観」は、身内ノリという名の強力な結界に阻まれて、なかなかテーブルの上にのぼらない。 なんとか場を盛り上げようと、少し自分の話を大袈裟にしてみたり、ストレートな質問を投げてみたりもしたけれど、どうやら僕の投げたボールは、彼らのグローブには種類が違いすぎたみたいだ。 ヒゲのスタイルを揶揄されたり、信頼して相談したつもりの話がいつの間にかエンタメとして共有されていたり。 向こうに悪気はないんだろうし、彼らなりの「励まし」だったのかもしれない。 でも、その善意のすれ違いが、なんだか可笑しくて、それでいて少しだけ切なかった。 高校時代の友人と会うときは、不思議とこういう違和感がない。 けれど、中学という「偶然の集まり」から始まった関係は、大人になって住む世界が変わるほどに、根本的な「噛み合わなさ」が浮き彫りになっていく。 相談したことへの反応ひとつとっても、僕が求めていた距離感と、彼らが差し出す空気感は、もう交わることがないのだと実感した。 結局、お互いの「現在地」を教え合うこともないまま、夜は更けていった。 「またな」と手を振って別れた後、どうしてもお腹が空いて、吸い込まれるように富士そばへ。 もりそばとミニカツ丼。 今日という日の、なんだか噛み合わなかった歯車を、このセットと一緒にゆっくりと咀嚼していく。 あぁ、僕はもう、あの頃とは違うリズムで生きてるんだな。 それは寂しいことではなくて、自分がそれだけ外の世界で、自分の人生を積み重ねてきたということなんだと思う。 みんなが良いと思うものより、自分が納得できる場所や価値観を選びたい。その感覚が、今の自分にはしっくりくる。 期待していた「近況」は分からなかったけれど、「自分の現在地」はよく分かった。そういう意味では、なかなか面白い時間だった。 明日からは、また僕のリズムで。 自分に合う場所で、自分に合う言葉を大切にしながら、やっていこうと思う。

March 18, 2026 · 1 min

年末年始、起きて運動して規則正しい生活を送るために

✓ この記事はGMOペパボ エンジニア Advent Calendar 2025の23日目です ...

December 23, 2025 · 2 min

Personal Development

個人開発のプチ成果 しょうもないアプリだけど、月2,3千円は収入が入るようになったので、 AppleのDeveloper Program代は賄えるようになったかな。 今年は全然アウトプットができなかったので、やりたいことガシガシやっていきたい。

December 15, 2025 · 1 min

Normally

普通とは 最近、「普通にうまい」とか「普通に買いました」とか、普通を使いすぎてなんだかなあという気持ち。よく考えて話したい。

October 28, 2025 · 1 min

SwiftUI Text Alignment

SwiftUIでテキストの位置を揃えたいとき…🤔 SwiftUIで横並びのテキストのAlignmentを下揃えにするのはどうするんだろ?と思い調べた。 .lastTextBaselineを指定すると良いみたい。 A guide that marks the bottom-most text baseline in a view. Use this guide to align with the baseline of the bottom-most text in a view. The guide aligns with the bottom of a view that contains no text." https://developer.apple.com/documentation/swiftui/verticalalignment/firsttextbaseline import SwiftUI struct ContentView: View { var body: some View { VStack(alignment: .leading, spacing: 8.0) { Group { HStack(alignment: .top) { Text("山田 太郎").font(.title) Text("25歳").font(.callout) } Text(".top") HStack(alignment: .center) { Text("山田 太郎").font(.title) Text("25歳").font(.callout) } Text(".center") HStack(alignment: .bottom) { Text("山田 太郎").font(.title) Text("25歳").font(.callout) } Text(".bottom") HStack(alignment: .firstTextBaseline) { Text("山田 太郎").font(.title) Text("25歳").font(.callout) } Text(".firstTextBaseline") } HStack(alignment: .lastTextBaseline) { Text("山田 太郎\n(開発チーム所属)") .font(.title) Text("25歳") .font(.callout) } Text(".lastTextBaseline(2行テキストの場合)") } .padding() } } #Preview { ContentView() }

October 21, 2025 · 1 min

食欲が止まらない

食欲が止まらない 健康診断が終わり気が緩んだせいか、食欲が爆発してしまった。 土日はマクドナルドのポテトLサイズを連続で食べてしまった。 食べても食べても食欲を抑えられないので、ひとまず散歩をして気を紛らせることにした。 そういえば、MusikKitを使ってアプリを作ろうと思っている。 音楽系のAPIはいろいろあるっぽい。面白い。 面白いAPIを作ってみたいなあ。

October 19, 2025 · 1 min

Getting Started With Hugo

Hugoでブログを始める 今まで適当にHTMLとCSSで作ってfirebaseにホスティングするというやり方を撮っていたのですが、HUGOという便利そうなやつを使ってみることにした。どこにデプロイしようかな。 HUGOについてはこちら

October 15, 2025 · 1 min