<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>CoreBluetooth on satton</title><link>https://shunsato.me/tags/corebluetooth/</link><description>Recent content in CoreBluetooth on satton</description><generator>Hugo -- 0.151.0</generator><language>ja</language><lastBuildDate>Thu, 10 Sep 2026 00:00:00 +0900</lastBuildDate><atom:link href="https://shunsato.me/tags/corebluetooth/index.xml" rel="self" type="application/rss+xml"/><item><title>Bluetoothで地球の裏側まで ─ すれ違いアプリKontaの中身</title><link>https://shunsato.me/posts/corebluetooth-proximity-chat/</link><pubDate>Thu, 10 Sep 2026 00:00:00 +0900</pubDate><guid>https://shunsato.me/posts/corebluetooth-proximity-chat/</guid><description>&lt;h3 id="きっかけ"&gt;きっかけ&lt;/h3&gt;
&lt;p&gt;お酒を飲みながら友達と「こういうアプリあったら面白いよね」みたいな話をすることってあると思うんですが、今回はなぜか本当に作ることになりました。流れはあんまり覚えていません。&lt;/p&gt;
&lt;p&gt;元々はもっと大きいアプリを作ろうとしていて、その機能の一つにBluetoothを使う想定がありました。その話をしているときに「Kontaみたいなアプリがあってもいいよね」という感じになって、じゃあとりあえずこっちから作るか、と。&lt;/p&gt;
&lt;p&gt;（Kontaという名前の由来については、また今度書きます笑）&lt;/p&gt;
&lt;p&gt;それでBluetoothについて調べていたら、だんだん妄想がふくらんできました。&lt;/p&gt;
&lt;p&gt;アプリを入れた人が増えれば増えるほど、その人たちが中継機になって、いつか地球の裏側の人とも繋がるんじゃないか。&lt;/p&gt;
&lt;p&gt;日本にいるAさんと、ブラジルにいるBさん。この2人は直接は知り合いません。でも間にいる人たちが少しずつメッセージを運んでくれれば、いつかは届くんじゃないかなと。会話には出てこない人たちが橋になるイメージです。&lt;/p&gt;
&lt;p&gt;サーバーもいらないし、通信キャリアもいらない。人がいればそれでネットワークになる、みたいなことを考えていました。&lt;/p&gt;
&lt;p&gt;結果としては、まだ全然そこまで行っていません。作ったのは、目の前ですれ違った人と1対1で話すだけのアプリ（Konta）です。サーバーは使っていないので圏外でも動きますが、届く範囲は十数メートルくらいです。&lt;/p&gt;
&lt;h3 id="どんなアプリか"&gt;どんなアプリか&lt;/h3&gt;
&lt;p&gt;Konta というアプリです。紹介ページはこちらです。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://konta.world/"&gt;https://konta.world/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;やることはシンプルで、&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;「接続する」を押すと、近くで同じアプリを開いている人をBluetoothで探しはじめる&lt;/li&gt;
&lt;li&gt;見つかった相手とお互いに「会話する」を押すと、そこでマッチングが成立する&lt;/li&gt;
&lt;li&gt;あとはニックネームと絵文字だけで1対1のチャットをする&lt;/li&gt;
&lt;li&gt;相手と離れると会話は終わり、履歴も残らない&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;電話番号もメールアドレスも要りませんし、アカウント登録もありません。サーバーを持っていないので、そもそも会話がどこかに保存されることもないです。&lt;/p&gt;
&lt;p&gt;iOSで公開しています。&lt;/p&gt;
&lt;p&gt;&lt;a href="https://apps.apple.com/jp/app/konta/id6797600072"&gt;https://apps.apple.com/jp/app/konta/id6797600072&lt;/a&gt;&lt;/p&gt;
&lt;h3 id="どうやって作っていたか"&gt;どうやって作っていたか&lt;/h3&gt;
&lt;p&gt;恵比寿の「いいオフィス」というレンタルスペースにこもって、半日くらいずっと開発する、というのをリリースまでに2回やりました。&lt;/p&gt;
&lt;p&gt;平日は、僕はClaudeを使って開発を進めていました。友達はエンジニアではないんですが、機能要件とか利用規約とかを中心に進めてくれていました。&lt;/p&gt;
&lt;p&gt;僕が詰まっているときも、いろんなユースケースを考えてくれたり、アイディアをくれたりして、突破するきっかけを常にくれていました。すごく楽しかったです。&lt;/p&gt;
&lt;h4 id="スペシャルサンクス"&gt;スペシャルサンクス&lt;/h4&gt;
&lt;p&gt;友達と奥さんが、家の中や通勤のときに実際に動かして検証してくれました。これが本当に助かりました。&lt;/p&gt;
&lt;p&gt;すれ違いのアプリなので、1人だとそもそも動作確認ができません。シミュレータではBluetoothが使えないので実機が2台以上必要ですし、手元のiPhoneとMacを並べて動いたところで、通勤中の人混みでちゃんと見つかるのか、部屋の壁を挟んだらどうなるのかは分かりません。&lt;/p&gt;
&lt;p&gt;生活の中で普通に使ってもらえたのが、一番のテストでした🙏&lt;/p&gt;
&lt;h3 id="この記事について"&gt;この記事について&lt;/h3&gt;
&lt;p&gt;Bluetoothの実装は今回が初めてでした。作る前は「近くの端末を見つけて繋ぐだけでしょ」と思っていたのですが、実際に触ってみると、想像していたのとは全然違うところでつまずき続けました。&lt;/p&gt;
&lt;p&gt;この記事は、1周目でハマったところと、後からドキュメントを読み直して「そう書いてあったのか」となった箇所をまとめたものです。同じように「BLE何もわからん」から始める人の参考になれば嬉しいです。&lt;/p&gt;
&lt;p&gt;つまずいたのは大きく3か所でした。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;BLEの「繋がっている」「相手がいる」という状態が、仕様レベルでけっこう曖昧&lt;/li&gt;
&lt;li&gt;サーバーを持たないので、暗号化は自分で設計するしかない&lt;/li&gt;
&lt;li&gt;E2EE（端末間暗号化）にすると、モデレーションの前提が変わってしまう&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;根拠になる部分は、できるだけAppleの公式ドキュメントとRFCを引用しました。自分の思い込みと、公式に書いてあることを混ぜたくなかったためです。&lt;/p&gt;
&lt;p&gt;あと、記事を書くために検証し直したら、自分の理解が間違っていた箇所がいくつも出てきました。それも正直に書いています。いくつかの箇所は、書きながらAIに壁打ちして「そこ違うのでは」と言われ、調べ直して書き直したものです。まだ間違いが残っているかもしれないので、見つけたら教えてください。&lt;/p&gt;
&lt;p&gt;長めなので、興味のある章だけ拾ってもらえれば大丈夫です。近接検知や1対1マッチングを作る予定がある方の参考になれば嬉しいです。&lt;/p&gt;
&lt;style&gt;
.note-box {
border-radius: 8px;
padding: 20px;
margin: 20px 0;
display: flex;
align-items: flex-start;
gap: 15px;
}
.note-box.note-info {
background-color: #e8f5e9;
}
.note-box.note-warning {
background-color: #fff3e0;
}
.note-box.note-danger {
background-color: #ffebee;
}
.note-icon {
color: white;
width: 32px;
height: 32px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
font-weight: bold;
}
.note-info .note-icon {
background-color: #4caf50;
}
.note-warning .note-icon {
background-color: #ff9800;
}
.note-danger .note-icon {
background-color: #f44336;
}
.note-content {
flex: 1;
}
@media (prefers-color-scheme: dark) {
.note-box.note-info {
background-color: #1b3a1f;
color: #c8e6c9;
}
.note-box.note-warning {
background-color: #3a2e1b;
color: #ffe0b2;
}
.note-box.note-danger {
background-color: #3a1b1b;
color: #ffcdd2;
}
.note-info .note-icon {
background-color: #66bb6a;
}
.note-warning .note-icon {
background-color: #ffa726;
}
.note-danger .note-icon {
background-color: #ef5350;
}
}
body:not([class*="dark"]) .note-box.note-info {
background-color: #e8f5e9;
color: inherit;
}
body:not([class*="dark"]) .note-box.note-warning {
background-color: #fff3e0;
color: inherit;
}
body:not([class*="dark"]) .note-box.note-danger {
background-color: #ffebee;
color: inherit;
}
body:not([class*="dark"]) .note-info .note-icon {
background-color: #4caf50;
}
body:not([class*="dark"]) .note-warning .note-icon {
background-color: #ff9800;
}
body:not([class*="dark"]) .note-danger .note-icon {
background-color: #f44336;
}
&lt;/style&gt;
&lt;div class="note-box note-info"&gt;
&lt;div class="note-icon"&gt;✓&lt;/div&gt;
&lt;div class="note-content"&gt;
この記事はメッシュ（マルチホップ）ではなく、直接繋がった2台の1対1の話です。冒頭に書いた「橋になる」アイデアを今回入れなかった理由は、最後の章に書きました。
&lt;/div&gt;
&lt;/div&gt;
&lt;hr&gt;
&lt;h2 id="0-先に用語だけ"&gt;0. 先に用語だけ&lt;/h2&gt;
&lt;p&gt;BLE の記事を読み始めたとき、僕は用語で最初につまずきました。同じものが文脈によって違う呼ばれ方をするので、先に整理しておきます。&lt;/p&gt;</description></item></channel></rss>