store-publishing 是做什麼的?
此程序最後一次實際操作於 2026 年 11 月 8 日,針對真實的 Google Play Console 和 App Store Connect。這兩個控制檯的畫面、欄位名稱和導航方式會隨時變動,恕不另行通知——如果以下步驟與你看到的實際情況不符,請在此 repo 中開 issue,不要自行猜測;如果你找到了修正方法,也請發送 PR。
0. 決定你的路線
| 情況 | 前往章節 |
|---|---|
| 應用程式從未提交過,任一控制檯中也無記錄 | §1,然後 §2、§3、§4 |
| 應用程式已上架,需要發布新版本 | §5(重複路線) |
| 帳戶問題(個人 vs 組織、移轉、套件名稱) | §6 |
| 審查人員無法登入,或應用程式被拒絕 | §7 |
適用於所有情況的規則:每次上傳都必須為其發行的每種語言提供版本說明。絕對不要讓「新功能」欄位留空——對審查人員來說,空白欄位等同於未經測試的版本。
1. 首次設定檢查清單(兩個商店)
請按順序執行;每一步都會為下一步解鎖。
- 開發者帳戶已存在並通過驗證。應用程式應由實際擁有產品的帳戶發布——也就是記錄中的發佈者,而非跨無關應用程式使用的共享或代理商帳戶。Apple 特別會拒絕那些看起來像是從商業化模板或應用程式生成服務產生的應用程式,尤其是當提交帳戶持有許多無關產品時;此外(指南 5.2.1),Apple 也期望智慧財產權擁有者就是提交者。關於個人與組織的決定,請參閱 §6。
- 法律頁面位於正式環境網域:隱私權政策、使用條款,以及如果應用程式允許註冊,則需提供帳戶刪除頁面。兩個商店都會要求這些 URL;Google 的資料安全表單會直接連結刪除頁面。在提交使用前,請從產品擁有者那裡獲得法律文字的批准——這是商業決策,而非技術決策。
- 真實的應用程式圖示,而非框架預設值——兩個商店都會拒絕或標記未經修改的預設圖示為低品質。需要的素材:二進位檔內的 adaptive/foreground 圖示、512×512 的 Play 圖示、1024×500 的 Play 特色圖片,以及素材目錄中的 1024×1024 Apple 圖示(無透明度——Apple 會將其扁平化,通常變為黑色)。
- 審查示範帳戶(如果應用程式需要登入)。它需要:一個固定識別碼(電話、電子郵件或使用者名稱),配對一個僅對該識別碼有效的固定一次性驗證碼或密碼;一個可供審查人員實際操作的預先植入示範狀態;且無對外副作用(無真實簡訊、無真實收費)。將憑證儲存在控制檯頁面以外的某處——永遠不要以純文字形式貼到 App Review 備註中,因為這會變成永久且廣泛可讀的記錄。每次提交前,務必針對要提交的確切版本驗證登入功能是否正常。
- 資料盤點清單:一份文件(在 repo 中、wiki 中,或團隊存放規格的任何地方),列出應用程式收集的所有資料類型、原因以及透過哪個 SDK。Google 的資料安全表單和 Apple 的應用程式隱私表單應根據此文件填寫,而非憑記憶填寫——每當應用程式新增權限或新的分析/診斷 SDK 時,此盤點清單也應隨之更新,且在下次提交前重新填寫兩個表單。表單陳述與二進位檔實際行為不符,是常見但可避免的拒絕原因。
- Google Play——建立應用程式,然後依序完成「設定應用程式」:隱私權政策 URL、應用程式存取權限(公開,或受限並附上審查帳戶與操作說明)、廣告宣告、內容分級問卷(根據應用程式實際行為如實回答)、目標對象與年齡、政府應用程式宣告、金融功能宣告、健康宣告、資料安全(來自盤點清單)、廣告 ID 宣告。接受 Play 應用程式簽署,讓 Google 持有應用程式簽署金鑰,而上傳金鑰則保持可更換性。填寫主要商店資訊(名稱、描述、圖示、特色圖片、至少 2 張手機截圖)。然後,在接觸正式環境之前,先建立封閉測試軌道和版本。
- Apple——註冊明確的 App ID,在 App Store Connect 中建立應用程式記錄(名稱、SKU、主要語言),填寫應用程式資訊(類別、內容權利、年齡分級)、應用程式隱私(來自盤點清單)、定價與供應狀況、版本頁面(截圖、描述、關鍵字 ≤100 個字元、支援 URL、版權)、App Review 資訊(登入說明(如有需要)、審查聯絡人、備註),並選擇發行選項(手動發行是較安全的預設值——它將「上線」決策權留在批准後一個獨立、謹慎的點擊操作中)。對於 TestFlight 版本,每次都要回答出口合規問題,或者如果情況屬實,可以在 Info.plist 中新增一次
ITSAppUsesNonExemptEncryption=false,以避免重複出現該問題。 - 儘早提交兩者。 每個商店的審查需要數小時到數天,而且首次審查通常會暴露真正的問題——請為至少一次拒絕和一次重新提交預留時間,特別是 Apple。
2. 建置發行套件
無論使用哪種工具鏈——Flutter、React Native、Expo 或原生 Swift/Kotlin 專案——都應從要發行確切提交版本的乾淨檢出中建置,切勿從包含未提交變更的工作目錄中建置。未提交的編輯內容洩漏到商店二進位檔中,事後很難察覺。
- Android:產生一個已簽署的發行版 AAB(切勿為商店上傳使用 APK),其建置編號(
versionCode或同等內容)必須嚴格高於上次發行的版本。在上傳前,請檢查套件名稱是否與目標 Play 帳戶所擁有的相符——套件名稱不符會在上傳步驟失敗。 - iOS:歸檔並匯出(或從歸檔步驟直接上傳到 App Store Connect),使用正確的 Apple Developer Program 會員資格(應用程式憑證和應用程式記錄所屬的「團隊」)進行簽署,建置編號必須嚴格高於上次發行的版本,且使用與 App Store Connect 記錄建立時完全相同的 bundle identifier。在正確的團隊下使用自動簽署可避免大多數憑證問題。
- 兩者:將建置指向正式環境的 API/後端,而非測試環境或本地端——請確認這一點已實際嵌入二進位檔中,而非僅作為可能靜默回退到預設值的建置旗標傳遞。當產品使用統一的版本字串時,請讓 iOS 和 Android 保持相同的建置/版本編號,這樣關於「版本 2.3」的支援對話在兩個平台上意義相同。
3. 截圖
僅限真實截圖——Apple 指南 2.3.3 明確拒絕以螢幕截圖形式呈現的模擬圖和行銷合成圖。可靠的做法是編寫自動化 UI 測試,執行實際應用程式,使用審查帳戶登入真實(非模擬)後端,導航到每個畫面,並捕捉畫面——切勿使用手持手機拍攝模擬器的照片。
需要涵蓋的典型裝置尺寸(請先檢查當前商店要求,因為這些要求會變動):一個大型現代 iPhone(Apple 目前的「最大」要求)、一個 iPad(如果應用程式支援 iPad),以及一個代表性的 Android 手機和/或平板電腦(用於 Play)。在大多數情況下,Apple 會自動從最大尺寸衍生出較小的 iPhone 尺寸。
選擇一個小集合(5-8 張圖片),按順序講述產品的故事:清單或首頁、核心結構畫面、單一項目/詳細資料畫面、正在進行中的主要工作流程、完成/成功狀態,以及相關的設定。跳過純登入畫面和空白狀態——它們無法說明應用程式的功能。
已知陷阱(與工具鏈無關):
- 偵錯版本通常會顯示可見的偵錯邊框或浮水印——請在捕捉前關閉它。
- 模擬器或模擬機工作階段可能會在重新安裝後保留先前的登入狀態;請在測試中明確登出,或先清除模擬器/模擬機狀態。
- 使用不同參數重新導航到「相同」畫面時,有時無法乾淨地重新渲染有狀態的畫面;請在兩次捕捉之間透過上層畫面進行導航。
- 從同一個專案目錄同時執行兩個捕捉工作階段,通常會在建置產生的人工產物上發生衝突;如果需要並行執行,請使用獨立的工作副本。
4. 更新流程(應用程式已上架)
請參閱 §5 了解專門的重新發行檢查清單。簡短版本:新版本的建置編號必須嚴格高於上次發行的版本;自上次發行以來的資料盤點差異決定是否需要更新隱私表單;版本說明絕不能省略;在每次提交前,都必須使用新二進位檔指向的實際環境重新驗證審查示範帳戶。
5. 重複路線——當應用程式已上線時的發行
一次發行 = 從上到下執行一次此清單。
前置條件(如果任何一項失敗則停止)
- 要發行的程式碼已實際部署到正式環境,且任何資料庫遷移都已完成——部署和遷移不是同一個步驟,在遷移前部署(或根本不遷移)會產生一個與尚未準備好的後端通訊的版本。
- 審查示範帳戶能登入正式環境,並到達審查人員需要看到的示範狀態。
- 已檢查自上次發行版本以來的資料盤點差異。任何新增的資料列都意味著隱私表單必須在提交前更改,而不是在被拒絕後才發現。
- Apple 的版本插槽可用。 如果先前的版本處於「Pending Developer Release」或仍在審查中,App Store Connect 將不允許你建立下一個版本行。請先發行或取消待處理的版本——沒有「保留此版本,提交更新的版本」選項。
- 已決定版本字串和建置編號:每個平台的建置編號 = 上次發行的版本 + 1;版本字串僅在使用者實際能注意到的變更時才需要提升。
版本說明
根據實際發行的內容(自上次發行以來合併的變更)撰寫,僅包含使用者可見的項目,大約 4-8 個重點,使用商店資訊中的所有語言——請先確認商店資訊實際支援哪些語言,不要假設需要多種語言;僅配置一種語言的商店資訊,若為其不支援的語言填寫版本說明欄位將會被拒絕。在 Apple 上,為商店資訊新增一種全新語言本身就是一個專案(名稱、副標題、描述、關鍵字,以及其專屬的截圖組)——切勿假設它只是一個文字框的變更。
截圖
僅在畫面實際發生消費者會注意到的變更時才重新製作。否則請保留現有截圖。如果需要更換,請一次性更換整個截圖組並保持原有順序,而不是附加——大多數控制檯會限制每個商店資訊的截圖數量,部分更換有達到上限的風險。
控制檯
Google Play:如果盤點清單有變更,請先更新資料安全表單。然後:相關的測試或正式環境軌道 → 建立新版本 → 上傳 AAB → 為每種已配置的語言填寫版本說明 → 審查版本 → 開始推出(將「開始推出」視為一個經過確認的審慎操作——這是 Play 流程中唯一不可逆的點擊)。正式環境的推出可以按百分比分階段進行,如果推出幾個百分比後發現問題,可以暫停。
Apple App Store Connect:先將新版本附加到 TestFlight(出口合規、「測試內容」),然後編輯現有版本頁面(如果版本字串未變更且先前的版本尚未發行)或建立新版本(僅在目前沒有版本處於「Prepare for Submission」狀態時才可能——請參閱上述前置條件)。重新檢查 App Review Information 是否仍準確,如果盤點清單有變更則重新檢查 App Privacy,選擇新版本,填寫「新功能」,然後提交審查。將「提交審查」視為與 Play 的推出點擊相同——一個經過確認的審慎操作,而非自動觸發的動作。
記錄保存
團隊用於發行的任何記錄保存方式(變更日誌、發行 issue、試算表)都應包含:已發行的版本和建置編號、上傳時間、使用的軌道/階段、確認推出或提交的人員,以及已知的審查結果。將專案本身的版本檔案更新為實際發行的版本——此處不一致正是下一次發行意外重複使用建置編號的原因。
絕不保留已準備好的版本
一個處於「Prepare for Submission」狀態的版本會佔用唯一的可用版本插槽——無法在其下建立新版本。因此:在準備版本的同一時間決定其命運。要麼提交它,要麼就別建立這行。
如果在較舊的已準備好版本仍被保留時,已有較新的版本準備就緒,請勿刪除被保留的行,也請勿為了清空插槽而提交過時的版本。當一個版本處於「Prepare for Submission」狀態時,其版本字串仍然是一個可編輯的欄位——請直接原地更新:將版本字串改為新的,附加新版本,並更換「新功能」。截圖、審查備註和隱私答案會保留,因此已準備的內容都不會浪費。
測試人員版本(TestFlight)和公開提交是獨立的決策——特別是 TestFlight 的內部測試軌道不需要審查,也不需要任何版本行,因此「測試人員今天需要一個版本」絕不是公開提交必須等待的理由,反之,待處理的公開提交也絕不是測試人員必須等待的理由。
6. 帳戶、移轉、套件名稱
- 在政策截止日期(截至本文撰寫時為 2023 年 11 月 13 日——請檢查當前政策)之後建立的個人 Google Play 開發者帳戶,必須完成一項最少參與者人數的封閉測試。
…
[後續章節已省略以符合 tokens 限制]