iT邦幫忙

2026 iThome 鐵人賽

DAY 20
0
Vibe Coding

神隊友.swift:30 天 Vibe Coding 打造育兒 iOS App 系列 第 20 篇

[Day 20] 把發現的缺口寫成 verify.sh 會擋的檢查:App 圖示缺圖的掃描,和用 WCAG 公式守住顏色對比

  • 分享至 

  • xImage
  •  

Day 20

文章同步發表在我的個人 Blog

把發現的缺口寫成 verify.sh 會擋的檢查:App 圖示缺圖的掃描,和用 WCAG 公式守住顏色對比

發現一個缺口,補上去就結束了嗎?下一次有人漏掉同樣的東西,誰來擋?

Day 14 寫過:verify.sh 只驗證「寫成規則的事」,沒有寫成規則的東西,檢查不會知道少了。這幾天在手機上實際用,剛好找到兩個這種缺口:App 圖示是空的(Day 19)、Dark 模式的顏色沒有色碼(Day 19 補上)。今天把它們寫成檢查,下次漏掉,verify.sh 會直接擋下來。

先講結果:新增一項圖示掃描,加 4 個自我測試案例;新增 3 個顏色對比測試。故意把一個顏色改壞,確認測試真的會失敗。

1. 圖示掃描:每個位置都要有圖

Day 19 的問題是,AppIcon.appiconset 只有 Contents.json,每個位置都沒填 filename,建置不會出錯。掃描要檢查三件事:

  1. 每個位置都有 filename
  2. 那個檔案真的存在,而且是 PNG
  3. PNG 的寬高等於宣告的尺寸乘上倍率

PNG 的寬高不需要額外的工具:檔案開頭 8 個位元組是固定的簽名,接著 IHDR 區塊,寬和高就在第 16 到 24 個位元組。腳本用 Python 的標準函式庫讀出來:

head = open(path, "rb").read(24)
if head[:8] != b"\x89PNG\r\n\x1a\n":              # PNG signature
    problems.append(f"{name} is not a PNG")
w, h = struct.unpack(">II", head[16:24])           # width, height from IHDR

宣告是 1024x1024,圖片卻是 512×512,掃描一樣會失敗。這個掃描接進 scripts/scans.sh,所以 verify.sh 每次都會跑。

2. 自我測試:證明掃描真的抓得到

Day 14 提過,掃描本身要先證明抓得到,不然寫錯了、永遠零命中也看不出來。scans-selftest.sh 的做法是現場建立假專案,違規的一定要失敗、合法的一定要通過。這次新增 4 個案例:

案例 預期
位置沒有 filename(只宣告位置、沒有圖) 失敗
filename 有寫,但檔案不存在 失敗
圖片只有 512×512,宣告是 1024×1024 失敗
圖片齊全、尺寸正確 通過

第一個案例就是 Day 19 的原始狀況。測試要用到真的 PNG,這裡也不依賴外部工具:用 Python 的 struct 和 zlib 現場組出一張純色的 PNG。自我測試的案例從 46 個變成 50 個,全部符合預期。

3. 顏色對比:用公式算,不憑感覺

Day 19 選 Dark 模式的燈號顏色時,我算了三種做法的對比值,結果寫在文章裡。但那只是一次性的計算,之後有人改了顏色,沒有東西會提醒。所以把公式寫成測試。

WCAG 2.1 的定義:每個色頻(0 到 1)先做 gamma 轉換,再加權成亮度,對比值是亮的那個加 0.05,除以暗的那個加 0.05:

func linear(_ c: Double) -> Double {
    c <= 0.03928 ? c / 12.92 : pow((c + 0.055) / 1.055, 2.4)
}
let luminance = 0.2126 * linear(r) + 0.7152 * linear(g) + 0.0722 * linear(b)
let ratio = (lighter + 0.05) / (darker + 0.05)   // AA text: at least 4.5

新增三個測試:

  • 公式本身:黑白是 21、白配白是 1,再加一組公認的邊界:#767676 配白色剛好過 4.5,#777777 差一點不到。公式寫錯,這個測試會先失敗。
  • 文字配色:實際拿來當文字的組合(主要文字、次要文字配畫面底色和卡片,以及主按鈕上的字配主色),Light 和 Dark 都要至少 4.5。
  • Dark 燈號色:綠、黃、紅放在畫面底色和卡片上,都要至少 4.5。

4. 故意改壞,確認抓得到

測試通過只代表目前的顏色沒問題。要確認它真的會擋,我把 Dark 的紅色暫時改成一個很暗的 #8A3A33,再跑 Dark 燈號色的測試,結果失敗了。確認之後,馬上還原。

5. 算出來但沒有寫成測試的事

順便把 Light 模式的顏色也算了一遍,對畫面底色 #FBF7F2 的對比值:

顏色 對比值
綠 2.45
黃 1.74
紅 3.28

都不到 4.5,連非文字元件常見的 3:1 也有兩個不到。這幾個顏色的 Light 值是設計規範訂的,只有我能改,而且畫面上沒有拿它們當文字用,所以我沒有寫成測試(寫了,測試就會一直失敗)。這個結果只是記下來:如果之後要把這些顏色當文字,就會踩到。

6. 目前的狀態

項目 結果
圖示掃描 新增,接進 scans.sh
掃描自我測試 50 個案例(原 46 個,新增 4 個)
顏色對比測試 新增 3 個
故意改壞確認 Dark 紅色改成 #8A3A33,測試失敗,已還原
verify.sh VERIFY: PASS(規則測試 93、App 測試 170)

明天

Day 21 中場回顧:回頭看這兩週 Claude Code 和 Codex 怎麼分工,以及投票頁的結果。

參考資源

官方文件


上一篇
[Day 19] 用 Security Rules 限制陣列只能追加:留言不能被改寫,以及空陣列第一次追加被誤擋
系列文
神隊友.swift:30 天 Vibe Coding 打造育兒 iOS App 共 20 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言