最近「Vibe Coding」這個詞在開發者社群中掀起熱議——與其逐行敲鍵盤,不如用自然語言描述你想要的功能,讓 AI 幫你實現。聽起來很美好,但真的能用來開發生產級別的應用嗎?
我決定用 Claude Code 和 Claude 4.5 Opus 來驗證這個想法,從零開始打造一款完整的 iOS 應用程式:AlphaGPS——一個透過藍牙低功耗(BLE)將 iPhone GPS 資料同步到 Sony 相機的工具。
值得一提的是:我從來沒有寫過任何 Swift 程式。雖然我有 Objective-C 的 iOS 開發經驗,但 Swift 和現代 iOS 開發框架對我來說是全新的領域——SwiftUI、Combine 框架、async/await 語法、Live Activity,這些我都是第一次接觸。
這不是一個簡單的 Hello World 專案。它涉及 BLE 硬體協議、iOS 背景執行限制、複雜的狀態管理,以及 Live Activity 整合。最終成果?約 4,100 行 Swift 程式碼、30 個檔案、90 個 commits,以及一個真正能用的產品。
為什麼選擇這個專案?
作為攝影愛好者,我一直希望照片能自動記錄拍攝地點。雖然 Sony 有官方的 Creators App,但它的背景同步體驗並不理想——經常需要手動重新連線,而且會中斷其他藍牙連接。
我想要的是:打開相機就自動連線、App 在背景時持續同步、完全不需要人工干預。
這個需求恰好涵蓋了許多有趣的技術挑戰,非常適合測試 AI 輔助開發的極限。
Vibe Coding 的實際體驗
第一天(1/11):從協議規格到基礎架構
第一個 commit 是 Initial commit with Sony GPS protocol spec——我先把逆向工程得到的 Sony 藍牙 GPS 協議文件放進去,然後告訴 Claude:「根據這份協議規格,幫我設計一個 iOS App。」
接下來的兩個 commits 分別是:
feat(phase1): implement iOS app foundation for Sony camera GPS syncfeat(phase2): implement BLE foundation and GPS encoding
Claude 建議使用 Multi-Manager Singleton 模式搭配 Combine 響應式框架:
「你的 App 需要協調多個系統:藍牙掃描、GPS 定位、相機連線狀態。
建議使用獨立的 Manager 單例,各自管理 @Published 狀態,
透過 Combine 讓 UI 自動響應變化。」
這不是 Claude 隨意生成的建議——它是基於 iOS 開發的最佳實踐,考慮到 CoreBluetooth 的 Delegate 模式和 SwiftUI 的響應式特性。
第二到第三天(1/12-1/13):攻克背景執行
iOS 對背景執行有嚴格限制。大多數 App 在進入背景後很快就會被系統終止。但我需要的是:即使 App 被殺掉,當相機重新開機時也能自動重連。
這部分的開發歷程可以從 commit 歷史看出挑戰有多大:
feat(phase4): implement background lifecycle and persistenceImplement iOS background BLE state preservation and cleanup codeStart scanning in background when cameras exist but none connectedStart scanning when last connected camera disconnects in backgroundAbort connecting cameras when app enters backgroundStop scanning when camera connects in background
這就是 iOS Core Bluetooth State Preservation 登場的時候。我向 Claude 解釋了需求:
「我需要相機關機後再開機時自動重連,
即使使用者已經完全關閉 App。」
Claude 不只給了程式碼,還解釋了整個機制:
- 用
CBCentralManagerOptionRestoreIdentifierKey初始化藍牙管理器 - iOS 會在背景記住連線意圖
- 當藍牙事件發生時,iOS 會喚醒 App 並呼叫
willRestoreState - App 需要在這個回調中重建狀態並恢復連線
最困難的是處理邊界情況:藍牙 UUID 可能改變、相機可能同時連線多台、恢復可能在位置權限授權之前發生。Claude 幫我逐一考慮這些情況,最終實現了真正的「零操作」體驗。
Sony 的 BLE 協議
Sony 沒有公開他們的藍牙 GPS 同步協議。幸運的是,我在網路上找到了其他開發者的逆向工程成果(特別是 camera-gps-link 專案),他們已經分析出協議的細節。我把整理後的協議規格放在 docs/sony-gps-protocol-spec.md。
協議的關鍵:寫入 GPS 資料需要一個三步驟的「解鎖」序列:
- 寫入解鎖指令到 DD30 characteristic
- 寫入鎖定指令到 DD31 characteristic
- 寫入 GPS 封包到 DD11 characteristic(91 或 95 bytes)
跳過任何一步,相機會靜默忽略資料——沒有錯誤回報。
當我把這個發現告訴 Claude 時,它立刻理解了非同步寫入的挑戰:
// Claude 建議的解決方案
private var unlockWriteComplete = false
private var lockWriteComplete = false
// 只有在兩個階段都完成後才發送 GPS
func checkAndWriteLocation() {
guard unlockWriteComplete, lockWriteComplete else { return }
// 發送 GPS 封包...
}這種狀態追蹤模式解決了 BLE 寫入回調可能亂序或遺失的問題。
印象深刻的地方
1. 理解上下文的能力
1/13 那天,我花了不少時間實作 Live Activity。Commit 歷史反映了這段旅程:
Implement Live Activity for camera connection statusFix iOS availability checks for Live Activity APIFix Widget Extension bundle configurationFix ActivityViewContext build error by inlining Live Activity view
後來在 1/16,我發現「這個 Live Activity 在斷線時沒有正確結束」。Claude 不只是搜尋關鍵字,它追蹤了整個程式碼流程,發現問題出在狀態轉換的時序:
didConnect → 狀態設為 .connected → 啟動 Live Activity
↓
handleConnection → 狀態改為 .connecting(進行服務發現)
↓
didDisconnect → wasConnected 檢查回傳 false → Live Activity 沒有結束!
修復結果就是 fix(ble): always end Live Activity on disconnect 這個 commit。有這種程度的理解,除錯快了很多。
2. 主動考慮邊界情況
在實作電池優化時,Claude 主動提出:
「你需要考慮這些情況:
- App 在背景但沒有相機連線 → 應該暫停 GPS
- 相機在背景連線 → 立即恢復 GPS
- 使用者關閉背景同步設定 → 停止所有更新」
這最終成為 feat(location): stop GPS updates when no cameras connected in background 這個 commit。這些不是我明確要求的,但對產品品質至關重要。
3. 架構一致性
隨著專案成長到 30 個 Swift 檔案,Claude 始終記得我們建立的模式:Manager 單例、原子性狀態更新、Combine 訂閱管理。它不會突然建議一個風格完全不同的實作。
看看這些 refactor commits,Claude 幫我持續改進架構而不破壞一致性:
Refactor to single camera list and state-based architectureConsolidate Camera discovering and connecting statesRefactor autoConnect to separate field from connection stateConsolidate connected and syncing states into single connected staterefactor: simplify connecting state by removing retryCount
不完美的地方
坦白說,Vibe Coding 不是萬能的。從 90 個 commits 中可以看到很多 fix commits:
Bug fixes 佔了很大比例:
fix(ble): clear peripheral when aborting connectionfix(ble): cancel connection timeout on disconnectfix(ble): fix critical disconnect handling issuesfix(ble): clear stale peripheral on background disconnect
這些都是在實機測試時發現的問題。Claude 可以寫出結構良好的程式碼,但 BLE 和 iOS 背景執行的邊界情況太多,只有實際測試才能發現。
需要明確指示:Claude 有時會過度工程化。我必須明確說「保持簡單,不要加額外功能」。
測試依然困難:BLE 和 Live Activity 無法在模擬器中測試。我仍然需要在實體裝置上手動測試每個功能。
領域知識必要:雖然 Claude 幫我寫程式碼,但理解 Sony 協議、iOS 背景限制、BLE 特性——這些需要我自己研究。AI 是超強的副駕駛,但你還是需要知道要去哪裡。
成果總覽
| 指標 | 數值 |
|---|---|
| 程式碼行數 | ~4,100 行 |
| Swift 檔案數量 | 30 |
| Git commits | 90 |
| 開發時間 | 6 天(兼職,1/11 - 1/16) |
| 手動寫的程式碼 | < 5% |
功能清單:
- 自動掃描和連接 Sony 相機
- 背景 GPS 同步(App 在背景時持續運作)
- Live Activity 即時顯示同步狀態
- 相機斷線自動重連
- 電池優化的智慧掃描
- 支援 iOS 15.0+,完整功能需 iOS 16.1+
我學到的事
-
Vibe Coding 是真的:對於有經驗的開發者,AI 可以將生產力提升 5-10 倍。關鍵是你要能驗證和引導它的輸出。
-
對話品質決定結果:模糊的指示得到模糊的程式碼。具體描述需求、約束和邊界情況,Claude 就能給出專業級的解決方案。
-
Claude 4.5 Opus 的差異:相比之前的模型,Opus 4.5 在理解複雜系統、保持上下文一致性、主動考慮邊界情況方面有明顯提升。
-
這不是取代學習:AI 讓你更快實現想法,但你還是需要理解底層技術。否則你無法判斷 AI 的建議是否正確。
寫在最後
AlphaGPS 現在是我日常使用的工具。每次出門拍照,相機開機就自動連接、照片自動標記位置、全程不需要碰手機。
回頭看這個專案,最有意思的不是程式碼本身,而是這種新的開發方式:我專注於「想要什麼」和「為什麼」,Claude 幫我處理「怎麼做」的細節。
這就是 Vibe Coding 的精髓——不是讓 AI 取代你,而是讓你把精力放在真正重要的事情上。
如果你也想嘗試,我的建議是:找一個你真正想解決的問題,然後跟 Claude 聊聊。你可能會驚訝於它能帶你走多遠。
這篇文章本身也是用 Claude 協助撰寫的——用 AI 寫一篇關於 AI 開發的文章,似乎也是剛好而已。