NOTE / 2026-09-23
From Keychain to App Store:Apple 開發全流程
以 iCodexBar 實際建置為例的 Apple 開發全流程:四種身分、簽章鏈、兩條產線、CloudKit 容器、四種發佈方式,以及做付費 App 還缺什麼。
以 iCodexBar 實際建置為例,拆解 Apple 開發的身分、簽章與發佈。
四種身分,先分清楚
| 身分 | 本例的值 | 管什麼 | 誰決定 |
|---|---|---|---|
| 開發者 Apple ID | ian902792@… | 登入 Xcode、管理憑證與 App ID | 付費的那個帳號 |
| Team ID | <TEAM_ID> | 擁有憑證、App ID、容器。簽章時烙進 app | Apple 指派,不可改 |
| Bundle ID | com.ian902792.codexbar | 這個 app 在全世界的唯一名字 | 自己取,全球唯一 |
| iCloud 帳號 | 個人帳號 | 資料存在誰的私有資料庫 | Mac/手機上登入的那個 |
簽章鏈:五個環節,缺一不可
多數「build failed」是這條鏈斷了一環。
-
憑證 Certificate
一組公私鑰:私鑰在鑰匙圈,公鑰由 Apple 簽署。
Developer ID Application: <你的名字> (<TEAM_ID>) -
App ID(Identifier)
登記 bundle ID 並勾選允許的能力(iCloud、App Groups、Push…),沒勾就拿不到。
com.ian902792.codexbar + iCloud + App Groups -
Provisioning Profile
Apple 簽發的許可:這張憑證可簽這個 App ID、用這些能力、裝在這些裝置。嵌入 app:
CodexBar.app/Contents/embedded.provisionprofile -
Entitlements
plist,宣告實際要用的能力;須為 profile 允許範圍的子集,否則簽章失敗或執行時被拒。
com.apple.developer.icloud-container-identifiers = [iCloud.com.ian902792.codexbar] -
codesign
用私鑰簽下程式碼、entitlements 與 profile;任何位元被改,簽章即失效。
codesign --verify --deep --strict
兩條產線,檔案怎麼串起來
Mac · SwiftPM
swift build -c release 後由 Scripts/package_app.sh 組 .app、產生 entitlements plist、嵌入 provisionprofile、codesign。可全自動,但 Info.plist、圖示等 Xcode 代勞的事都得自己做。
iOS · Xcode
xcodegen generate 從 project.yml 產生 .xcodeproj,規範禁止手改:它難審閱、易衝突,YAML 才進得了 code review。再以 xcodebuild -allowProvisioningUpdates 建置、devicectl device install 安裝。
CloudKit:容器歸團隊,資料歸使用者
| 層級 | 歸屬 | 意義 |
|---|---|---|
ContaineriCloud.com.ian902792.codexbar | 你的 Team | 一個命名空間,全球唯一,不可轉移 |
| Private Database | 每個 iCloud 使用者各一份 | A 寫的東西 B 看不到,即使同一個容器 |
| Public Database | 全容器共用 | 所有使用者讀得到,適合共用設定檔 |
| Zone / Record Type | 資料結構 | 類似資料表,欄位與索引在此定義 |
Development 與 Production 是兩套 schema
開發時改 Development,確認後在 Console 按 Deploy Schema Changes 推到 Production:
- 推上 Production 不可逆:record type 刪不掉、欄位型別改不了,只能新增。
- entitlements 的
icloud-container-environment決定連哪一套;不一致就會「明明有寫入卻讀不到」。
四種發佈方式,怎麼選
| 方式 | 簽章 | 誰能裝 | 效期 | 要過審 | 典型用途 |
|---|---|---|---|---|---|
| 側載 本例使用 | Apple Development | 已註冊的裝置 | 約 1 年 | 否 | 自己用、開發測試 |
| TestFlight | Apple 重簽 | 最多 100 內部 + 10000 外部 | 90 天/build | 內部否 外部是 | beta 測試、不想接線 |
| App Store | Apple 重簽 | 所有人 | 無限 | 是 | 正式販售 |
| Developer ID Mac 限定 | Developer ID + 公證 | 任何 Mac | 無限 | 自動公證 | 官網下載、Homebrew |
本例的 Mac app 只走了第四種的前半:有簽章、沒公證。本機自建無 quarantine 標記,Gatekeeper 不擋;別人下載則會看到「無法打開」。
開發者後台:哪些會常用
Certificates, Identifiers & Profiles
- Certificates
- Development(開發機)、Distribution(上架)、Developer ID(Mac 自行分發)。私鑰只在產生它的 Mac 鑰匙圈:換機用
.p12匯出,弄丟只能撤銷重發。 - Identifiers
- App IDs、App Groups、iCloud Containers、Merchant IDs(Apple Pay)、Pass Type IDs(Wallet)。
- Devices
- 測試機 UDID;每種裝置類型每年上限 100 台,會籍週年才重置。
- Profiles
- Development / Ad Hoc / App Store / Developer ID。
- Keys
- APNs、App Store Connect API、Sign in with Apple 金鑰;
.p8只能下載一次,務必備份。
App Store Connect:上架後主戰場
- My Apps
- app 記錄、商店頁面、送審、版本。
- TestFlight
- build、測試者群組、回饋。
- Pricing & Availability
- 定價層級、上架國家、自動換算。
- In-App Purchases / Subscriptions
- 消耗型、非消耗型、自動續訂訂閱、優惠代碼、introductory offer。
- App Analytics / Sales
- 安裝、留存、轉換、營收。
- App Privacy
- 隱私營養標籤,送審必填。
Capabilities
本例用 iCloud(CloudKit)、App Groups、Push Notifications;另有 Sign in with Apple、Apple Pay、HealthKit、HomeKit、Background Modes、Keychain Sharing、Associated Domains(Universal Links)、Family Controls、Network Extensions、WeatherKit、App Attest。改了能力,profile 與 entitlements 都要更新。
往付費 App 還缺什麼
多平台
- iPad:同一 iOS target 勾 iPad 家族;難在版面(size class、多欄、鍵盤、觸控筆)。
- Mac:Mac Catalyst,或體驗較好的原生 SwiftUI target。
- Watch:獨立 target,自有生命週期,效能限制極嚴。
- Universal Purchase:同一 bundle ID 跨平台、買一次通用;須一開始規劃。
變現
- StoreKit 2:買斷、訂閱、試用期;配
.storekit檔可在本機模擬購買。 - App Store Server API / Notifications:伺服器端驗證收據與訂閱、接收續訂與退款事件。
- 抽成:標準 30%;年營收 100 萬美元以下可申請 Small Business Program 降到 15%。
- 稅務與銀行:填完 App Store Connect 的稅表與收款帳戶才領得到錢。
審核門檻
- Privacy Manifest(
PrivacyInfo.xcprivacy):宣告收集的資料與特定 API 用途,硬性要求。 - App Privacy 標籤:須與實際行為一致,否則被退。
- Export Compliance:用加密就要回答(HTTPS 通常豁免)。
- Demo 帳號:有登入就須提供給審核員。
- 支援與隱私政策網址:皆必填且須能打開。
工程實務
- 版本號:
MARKETING_VERSION給人看,CURRENT_PROJECT_VERSION給 Apple 看且須遞增。 - API 金鑰:App Store Connect API 金鑰可自動上傳,免二階段驗證。
- fastlane 或 Xcode Cloud(Apple CI,直通 TestFlight,小專案免費):自動化截圖、上傳、版本號。
- 崩潰蒐集:Xcode Organizer 內建,上架後先看;SDK bug 用 Feedback Assistant 回報。
錯誤訊息與它們教會的事
| 錯誤訊息 | 真正的原因 | 解法 |
|---|---|---|
Developer Mode disabled | iOS 16 起新增的閘門,預設關閉 | 手機設定 → 隱私權與安全性 → 開發者模式 → 重開機 |
needs to be unlocked | 開發服務需要裝置解鎖才啟用 | 解鎖並暫時關閉自動鎖定 |
「No profiles were found」 | project.yml 沒寫 CODE_SIGN_STYLE,xcodebuild 視為手動簽章,-allowProvisioningUpdates 既不註冊裝置也不建 App ID | 補上 CODE_SIGN_STYLE: Automatic |
Device isn't registered | CODE_SIGN_STYLE 未設 → 退回手動簽章 → 自動註冊失效 | 設成 Automatic;首次註冊仍須 Xcode GUI 跑一次 |
Build input file cannot be found…mobileprovision | Xcode 快取了舊的 profile UUID | 清掉 DerivedData 重建 |
codesign 想存取鑰匙圈 | 簽章需要私鑰,這是正常流程 | 選「永遠允許」,否則每次建置都會卡住 |
rejectedsource=Unnotarized Developer ID | 有簽章但未公證 | 自用無妨;要分發給別人才需 notarytool |
依 2026-09-23 建置 iCodexBar 0.64.1.1 的流程整理;Apple 的版本、UI 與政策會變,以官方文件為準。