開發規範
所有小程序上架前都必須符合這一頁的規範。每一條標示了它是怎麼被執行的:
- CLI 建置時檢查,不符合就建置失敗,不會產生
.imapp。 - 容器 App 執行時強制,違反的寫法不會生效或會被擋下。
- 必須 工具擋不到,但屬於規範,上架前自查、審核依此判斷。
- 建議 強烈建議,有理由可以不照做。
效能預算
| 規則 | 上限 | 執行 |
|---|---|---|
主包(入口 chunk 加上它靜態 import 的 chunk、CSS、index.html;雙執行緒含 logic.js) | ≤ 2 MB(壓縮前) | CLI |
| 每個分包(動態 import 的路由 chunk,扣掉主包已有的部分) | ≤ 2 MB | CLI |
| 包內所有檔案合計 | ≤ 20 MB | CLI |
| 首屏 JS(入口 chunk 經 brotli 壓縮後) | ≤ 300 KB | CLI |
| 單張圖片 | ≤ 200 KB | CLI |
邏輯層 logic.js | ≤ 2 MB | CLI |
| 不打包字型,用系統字型 | — | 必須 |
| 單頁 DOM 節點 | ≤ 1,500 | 必須 |
| 單一 JS 任務(畫面層主執行緒) | ≤ 50 ms,超過要拆分或移到邏輯層 | 必須 |
| 單一第三方依賴 | > 100 KB 要能說明理由 | 必須 |
| 圖片格式 | WebP(或 AVIF),依顯示尺寸提供 2x/3x | 建議 |
| 路由 | 首頁以外的頁面用動態 import() 分包 | 建議 |
執行期目標(p75,由容器埋點量測):
| 指標 | 目標 |
|---|---|
已快取冷啟動(點擊到 sdk.ready()) | ≤ 500 ms |
| 首次開啟(含下載,Wi-Fi) | ≤ 2 s |
| 熱啟動 | ≤ 100 ms |
| INP | ≤ 200 ms |
| CLS | ≤ 0.1 |
| 捲動 | 60 FPS,掉幀率 < 5% |
| 記憶體(單一小程序) | ≤ 150 MB |
設定與版本
| 規則 | 執行 |
|---|---|
id 只能用 [a-z0-9_-],1–64 字;發佈後不能改 | CLI |
version、minContainer 必須是語意化版本 | CLI |
內容有任何改動(含文案、樣式)都要升 version | 必須 |
minContainer 要涵蓋你用到的所有能力(見容器版本) | 必須 |
雙執行緒時 minContainer ≥ 1.1.0 | CLI |
domains 只列實際會連的網域;格式見宣告網域 | CLI 格式;必須 最小化 |
permissions 只列實際會用的權限,並提供用途說明 | 必須 |
ageRating 依內容如實填寫 | 必須 |
包內不得有 __im/、manifest.json、signature.sig、platform.sig;雙執行緒不得自帶 logic.js | CLI |
必須輸出 index.html,且要有 <head> | CLI index.html;必須 <head> |
安全與隱私
| 規則 | 執行 |
|---|---|
網路請求只能連 domains 內的 https 網址 | 容器 |
用 sdk.http.fetch 送請求,不要用瀏覽器的 fetch/XMLHttpRequest | 必須 |
不能執行包外的程式碼:不能從網路載入腳本、不能用 eval/new Function/內嵌 <script> | 容器 |
不能嵌入 iframe;主框架不能導向外部網址(外部網頁用 sdk.system.openUrl) | 容器 |
持久資料只能用 sdk.storage;cookie、IndexedDB、Cache Storage、Service Worker、OPFS 都已停用,localStorage 只在本次開啟有效 | 容器 |
| Web Worker 與 iframe 裡不得使用 IndexedDB、Cache Storage、OPFS(容器擋不到,資料會被其他小程序讀到) | 必須 |
後端一律用 sdk.auth.getSession() 的 token 判斷身分;前端的 userId 只能用來顯示 | 必須 |
不要把 token 存進 storage;每次需要時呼叫 getSession() | 必須 |
| 包內不能放任何秘密(API 金鑰、私鑰、後台帳密):包會被下載到每支手機,任何人都拿得到 | 必須 |
分享卡片的起始頁(launch.path)是不可信的輸入:找不到頁面回首頁,權限照常檢查 | 必須 |
| 不在手機上保存敏感資料(付款資訊、證件號碼、密碼) | 必須 |
| 開發者私鑰只放在 CI,不進版本控制 | 必須 |
外觀與體驗
| 規則 | 執行 |
|---|---|
顏色、間距、圓角、字級一律用 --im-* 變數,不寫死數值 | 必須 |
深淺色只用變數與 [data-im-theme],不用 prefers-color-scheme | 必須 |
字級用 --im-font-*(已隨系統字級縮放),版面要能承受最大字級 | 必須 |
固定在底部的元素加上 --im-safe-bottom;viewport 要有 viewport-fit=cover | 必須 |
首屏渲染完成後才呼叫 sdk.ready() | 必須 |
| 骨架與實際內容同尺寸;圖片、影片、非同步區塊先保留尺寸;狀態切換不推動版面(CLS ≤ 0.1) | 必須 |
| 載入中、錯誤(含重試)、空資料三種狀態都要有畫面 | 必須 |
Toast、對話框、選單、載入進度一律用 sdk.ui,不自己畫 | 必須 |
不自己畫導覽列;標題用 sdk.ui.setTitle | 必須 |
| 可點擊元素至少 44×44 px,按下有視覺回饋 | 必須 |
不監聽 resize 自己計算鍵盤高度 | 必須 |
app.pause 時停止輪詢、動畫、計時器並存檔;app.resume 時恢復 | 必須 |
返回用 sdk.navigate.back();頁面內換頁進入返回歷史(hash 路由或 pushState) | 建議 |
依 getLaunch().locale 顯示和 App 相同的語言 | 建議 |
重要操作加上 sdk.system.haptics | 建議 |
相容性
| 規則 | 執行 |
|---|---|
| JavaScript 語法轉譯到 Safari 15/Chrome 111(畫面層)、ES2020(邏輯層) | CLI 自動處理 |
CSS 只用 iOS 15(Safari 15)支援的功能;color-mix()、@container、:has()、dvh 等不能用 | 必須 |
邏輯層不用 Intl、toLocaleString,不依賴 DOM、fetch | 必須 |
| 邏輯層必須打包成單一檔案,不能 import CSS 或圖片 | CLI |
| 在 iOS 與 Android 的 App 都實際測過 | 必須 |
程式品質
| 規則 | 執行 |
|---|---|
每個 sdk.* 呼叫都要處理失敗(catch 或 try/await),不留未處理的 Promise rejection | 必須 |
用 TypeScript strict 模式 | 建議 |
| 邏輯層的迴圈要有明確的結束條件,大量資料分批處理(無窮迴圈無法中斷) | 必須 |
setData 只送有變的頂層 key,大型清單不要每次整份重送 | 建議 |
合規
| 規則 | 執行 |
|---|---|
| 不販售數位商品、不放付費功能 | 必須 |
| 只透過 SDK 使用原生能力,不嘗試繞過容器取得其他能力 | 容器 |
| 年齡分級符合內容;限制級內容不得出現在分級較低的小程序 | 必須 |
| 檢舉入口由容器提供(膠囊「⋯」),不需要也不能移除 | 容器 |
| 介面不得模仿應用程式商店(不做「安裝」、排行榜、其他小程序的分類瀏覽) | 必須 |
這些規則對應 Apple App Store 審核指南 4.7(小程式與 HTML5 內容)、2.5.2 與 3.2.2。