菜鳥出巢
技術小抄

iPhone 原生 App(SwiftUI)+ Cloudflare Worker 中轉 + OpenAI 模型。拍冰箱推薦晚餐、靈動島追蹤取貨進度。

4,400行 Swift
44項商品
18道食譜
3 / 9市場 / 攤商
70張 AI 生成圖
12個單元測試

常見問題

AI
AI 用的是什麼模型?

OpenAI 的 gpt-6-luna,透過 Responses API 呼叫。可以同時吃文字和照片。

AI 會不會推薦市場沒賣的東西?

不會。App 每次把該市場的商品清單一起送出,提示詞規定只能用清單上的 productId。

回來後 Worker 過濾一次、App 再過濾一次,不存在的商品直接丟掉。

AI 回答格式怎麼保證是對的?

用 JSON Schema(strict 模式)強制模型照固定欄位回答:菜名、分鐘、鍋具、口味、標籤、冰箱已有食材、要買的商品與數量、做法步驟。

網路斷了 / AI 掛了怎麼辦?

自動改用本機規則推薦,一樣出三道菜,使用者不會卡住。

觸發情況:沒網路、超過 45 秒、被限流、AI 回空答案。

規則推薦怎麼算?

18 道食譜各算分數取前三:口味符合 +4、時間內 +3、鍋具符合 +3、預算內 +2;超預算 −2、每超時 5 分 −1、市場缺一樣食材 −3。同分取煮得快的。

冰箱照片會被存起來嗎?

不會。照片在手機上先縮到最長邊 1024px 的 JPEG,只送去分析一次。Worker 不存檔,呼叫 OpenAI 時設定 store: false。

AI 回應要多久?成本?

推理強度設成 none(最快、最省),照片用低解析度送。Worker 回應裡有 ms 欄位記錄實際耗時。逾時上限 45 秒。

為什麼不直接在 App 裡呼叫 OpenAI?

金鑰放進 App 會被拆出來盜用。所以金鑰只放在 Cloudflare Worker,App 只拿得到另一組 App token。

安全
API 金鑰安全嗎?

OpenAI 金鑰用 wrangler secret 存在 Cloudflare,不在 App、不在 git。

App 呼叫 Worker 要帶 x-app-token,沒帶就 401。

有人狂打 API 怎麼辦?

Worker 有限流:每台裝置每分鐘 20 次,超過回 429。另外檢查輸入大小:商品最多 200 項、文字 500 字、照片約 1.5 MB。

有登入 / 會員嗎?個資存哪?

原型沒有登入,預設使用者「林雨晴」。購物車、訂單、收藏都只存在這支手機(SwiftData),沒有上傳。

App
用什麼寫的?為什麼不用 Flutter / React Native?

Swift + SwiftUI 原生開發,最低 iOS 26。

靈動島(Live Activity)、Liquid Glass 玻璃質感、Apple Pay 都是 iOS 原生能力,跨平台框架做不到這麼完整。

有 Android 版嗎?

還沒有,列在之後的規劃。目前專注 iPhone,因為展示重點(靈動島)是 iOS 專屬功能。

資料存在哪?有資料庫嗎?

兩種:

① 商品、攤商、食譜:App 內建的 catalog.json(唯讀)。

② 使用者資料:SwiftData(Apple 的本機資料庫),存購物車、訂單、收藏、料理小卡、循環袋紀錄。

商品資料是真的嗎?

是假資料:3 個市場(北門、中央、西市場)、9 個攤商、44 項商品、18 道食譜。圖片用 AI 生成。

資料層抽成 CatalogRepository 介面,接真的後端只要換一個實作。

沒網路能用嗎?

可以逛、加購物車、結帳、看取貨碼。只有 AI 推薦需要網路,斷網時自動改用規則推薦。

付款是真的嗎?

不是。LINE Pay、Apple Pay、街口、取貨付款都是模擬動畫,不會扣款。

App 怎麼安裝?有上架嗎?

還沒上架 App Store,透過 TestFlight(Apple 官方測試管道)發給測試者,目前是 0.1.0 build 2。

圖片怎麼來的?

用 Codex CLI 的 image_gen(gpt-image)生成:38 張去背商品、18 張食譜、9 張攤商、4 張品牌插畫。Python 腳本批次跑,風格寫在 prompt 裡統一。上線前會換成攤商實拍。

靈動島 / 取貨
靈動島怎麼做的?

Apple 的 Live Activity(ActivityKit),畫面寫在獨立的 Widget Extension。顯示四個階段:備貨中 → 準備入櫃 → 可取貨 → 已取貨。

App 關到背景,靈動島還會更新?

會。下單時就把「預計入櫃時間」交給系統:靈動島自己倒數,時間一到靠 staleDate 自動切成「可取貨」;可取貨通知也先排好。回到 App 時再把狀態補齊。

正式版會改用伺服器推播(APNs)。

訂單進度是攤商在按的嗎?

原型還沒有攤商端,是本機計時器推進(10 秒 / 30 秒 / 手動)。

取貨碼 / QR Code 怎麼產生?

6 位數取貨碼,QR Code 用 iOS 內建 Core Image 產生,打開頁面時螢幕自動調到最亮方便掃描。冷藏櫃還沒接硬體。

點靈動島會發生什麼?

透過 deep link cainiao://order/訂單號 直接打開那張訂單。

展示現場
Demo 時怎麼讓進度跑快一點?

長按首頁左上的鳥型 logo(或 我的 → 展示控制面板)叫出 Demo 面板:可切換 快速 10 秒 / 一般 30 秒 / 手動,也能手動推進、重置資料。

AI 一直沒回應?

等它自動退回規則推薦即可(最多 45 秒)。畫面上的三道菜一樣可以一鍵加入購物車。

之後
如果要真的上線,還差什麼?

後端 API 取代 catalog.json、攤商端(接單、改價、按入櫃)、APNs 推播更新靈動島、真金流、冷藏櫃讀碼開門、Apple Foundation Models 當離線 AI 備援、Android 版。

開發花了多久?

程式從 2026/11/1 開始開發,搭配 AI 工具(Codex、Claude)加速生圖、寫程式和製作 Demo 影片。

沒有符合的問題,試試別的關鍵字

系統架構

1iPhone App(SwiftUI)
畫面逛市場・小攤靈感・訂單・我的・搜尋・購物車・結帳・取貨碼
狀態AppModel(@Observable)注入所有畫面
服務CartService・AIRecipeService・RuleBasedRecommender・OrderProgressService
資料catalog.json(商品)+ SwiftData(使用者資料)
Widget靈動島、鎖定畫面(Live Activity)
2Cloudflare Worker
  • 驗 App token
  • 每裝置 20 次/分
  • 驗輸入大小
  • 保管 OpenAI 金鑰
  • 過濾結果
3OpenAI Responses API
  • gpt-6-luna
  • 文字 + 圖片
  • JSON Schema strict
  • store: false

AI 小攤靈感流程

  1. 使用者輸入:文字、冰箱照片、人數、預算、時間、鍋具、口味
  2. App 縮圖(1024px JPEG),附上該市場商品清單和食譜庫
  3. Worker 驗證 → 呼叫 OpenAI,規定只能選清單上的 productId
  4. Worker 和 App 各過濾一次不存在的商品
  5. 一鍵加入購物車;冰箱已有的食材不重複買

失敗時:斷網、逾時 45 秒、限流、空答案 → 自動改用本機規則推薦。

規則推薦計分

口味符合+4
時間內做得完+3
鍋具符合+3
預算內 / 超預算+2 / −2
每超時 5 分鐘−1
市場缺一樣食材−3

靈動島 Live Activity

備貨中準備入櫃可取貨已取貨

難點:App 進背景會被 iOS 暫停,無法更新靈動島;正式解法是 APNs 推播,但原型沒有後端。

解法:下單時把預計入櫃時間交給系統,靈動島自己倒數,到時間靠 staleDate 切成可取貨;通知預先排程;回前景補齊狀態。

Demo 面板:長按首頁鳥型 logo → 快速 10 秒 / 一般 30 秒 / 手動推進。

哪些是真的

真的現場可操作

AI 拍冰箱推薦真的呼叫 OpenAI
靈動島 / 鎖定畫面真的 Live Activity
購物車、訂單真的存在手機
取貨 QR Code真的可以掃
安裝TestFlight build 2

模擬原型先假裝

付款動畫,不扣款
商品與價格44 項假資料
攤商接單還沒有攤商端
訂單進度本機計時器
冷藏櫃開門未接硬體

技術選型

選擇理由
SwiftUI 原生靈動島、Liquid Glass、Apple Pay 都是 iOS 原生能力
最低 iOS 26新版玻璃質感和底部配件列 API
內建 JSON不用架資料庫、離線可逛;之後換 API 只改一個實作
SwiftDataApple 官方本機資料庫,重開 App 資料還在
Worker 中轉金鑰不能放 App;順便做限流、過濾
規則版備援展場網路不穩也不會卡住

開發工具

XcodeGen(project.yml 產生專案)・Swift Testing(12 個測試)・Swift 6・wrangler(部署 Worker)・TestFlight・Codex image_gen(生圖)・Gemini TTS(Demo 影片旁白)

名詞白話

SwiftUI
Apple 的介面框架,用程式描述畫面長什麼樣子。
Liquid Glass
iOS 26 新的半透明玻璃風格,底部分頁列、按鈕都是。
Live Activity / 靈動島
鎖定畫面和瀏海旁即時更新的小卡片,像外送進度。
Widget Extension
跟 App 分開的小程式,專門負責畫靈動島和鎖定畫面。
SwiftData
Apple 的手機本機資料庫。
Cloudflare Worker
放在雲端的小函式,有請求才執行,不用自己管伺服器。
JSON Schema
規定 AI 回答的欄位和格式,讓程式能直接讀。
Rate limit 限流
限制每台裝置每分鐘最多呼叫幾次,防止濫用。
APNs
Apple 推播服務,正式版用來從伺服器更新靈動島。
Deep link
像網址一樣直接打開 App 裡的某一頁。
TestFlight
Apple 官方的 App 測試發佈管道,上架前先給人裝。
XcodeGen
用一個設定檔自動產生 Xcode 專案,避免多人改專案檔衝突。