記事一覧に戻る
技術記事App StoreGitHub ActionsAWS EC2 MacSafari Web Extension

如何在只有 Windows 的環境下開發並上架 App Store

沒有 Mac,打包、上傳、簽章、公證交給 GitHub Actions,要看畫面的測試租 AWS 的 Mac 24 小時。十家雲端 Mac 怎麼挑、VNC 讓 AI 點不了的坑、B 站擋機房 IP 的繞路法、兩台電腦兩個 Claude 怎麼分工,以及公證送了四次的經過。

更新日 16 min12 回表示記事の言語

一台 Windows 筆電、一個 Apple 開發者帳號,花了兩天把 Safari 版擴充送進 Mac App Store 審核。打包、上傳、簽章、公證交給 GitHub Actions,要實際摸到 Mac 的部分租 AWS 的 Mac 24 小時。卡最久的是進到那台 Mac 的桌面,還有讓 AI 能自己點畫面。

我的 B 站擴充(BiBoost)有 Safari 版,要上 Mac App Store。

問題是我沒有 Mac。

之前寫過〈在 B 站擴充裡用一份原始碼發佈到四個商店〉,Safari 版的打包、上傳早就交給 GitHub Actions 的 macOS runner(GitHub 借你跑腳本的雲端 Mac,不能即時操作)。但那篇只解決了「把 App 送進 App Store Connect」。這次要做的是:

  • Mac 版 2.7.0 送 TestFlight(Apple 的測試版發佈管道),自己裝起來做回歸測試
  • 順便在 iPhone、iPad 模擬器上測 iOS 版
  • 擴充有一個給使用者回報網速的測速工具(Python 寫的 Windows .exe),要做出 Mac 版。而且要簽章、公證(給 Apple 掃過、蓋章),不然使用者一打開就被 macOS 擋掉
  • 最後發版:Chrome、Edge、Firefox、Mac App Store、GitHub Release 一起出

我手上只有一台 Windows 筆電。實際動手的大多是 Claude Code(Anthropic 的 AI 寫程式工具),我負責做決定、輸密碼、按按鈕。

哪些事真的需要 Mac?

先講結論:不用自己買一台 Mac。

要做的事需要 Mac 嗎我怎麼做
打包、簽章、上傳 App Store Connect要,但不用自己的GitHub Actions 的 macOS runner
App Store Connect 的文案、截圖、版本設定不用瀏覽器(後台本身就是網頁)
申請 Developer ID 憑證(給測速工具簽章用)不用瀏覽器+任何一台能跑 openssl 的電腦產 CSR
測速工具的 Apple 公證(notarization)要,但不用自己的GitHub Actions 跑 notarytool
裝 TestFlight 版、在 Safari 實際點一遍要,而且要能看到畫面租雲端 Mac
iPhone/iPad 模擬器要,而且要能看到畫面同一台雲端 Mac 裝 Xcode
開發 Mac 版測速工具(要邊改邊跑)要,而且要能看到畫面同一台雲端 Mac

會用到 Mac 的事分兩種:不用看畫面的(打包、上傳、公證)丟給 GitHub 的雲端 Mac 跑;要看畫面的(測試、邊改邊跑)才需要一台能遠端桌面的 Mac。後者這次只要一兩天,所以用租的。

沒有 Mac,上架 App Store 在哪裡做 · 在 Miro 開啟

雲端 Mac 要怎麼挑?

先定條件

雲端 Mac 的方案很多,價格差好幾倍,但大部分在第一關就出局了。我的條件:

  1. 要有管理員權限。這條最重要:裝 Xcode、改系統設定都要管理員;之後要讓 AI 直接在 Mac 上截圖、點畫面,也得自己去開「螢幕錄製」「輔助使用」權限。
  2. macOS 要夠新。專案是 Xcode 26 建的,Xcode 26 要 macOS 15.6 以上。
  3. 能短租。只測一兩天,按小時或按天算最好。
  4. 要能遠端桌面(VNC)。只給 SSH 的話看不到畫面,沒辦法測 Safari。
  5. 現在就開得起來。

第一選擇:Scaleway,最便宜但沒貨

照這些條件,第一名是 Scaleway(法國的雲,Mac mini 按小時租):

  • M4 的 Mac mini,€0.22/小時,最少 24 小時,一次測試大概 NT$195,比後面所有方案都便宜
  • 有完整管理員權限,可以選新版 macOS
  • 註冊綁卡就能開,不用另外申請配額

帳號開好、信用卡綁好,按下去:全部沒貨。

Claude 直接去查 Scaleway 的 API,巴黎兩個機房所有能裝 macOS 的機型都回 no_stock。唯一還有貨的 M2-L-ASAHI 裝的是 Linux(Asahi),跑不了 Xcode,等於沒有。

機房真的沒機器。2026 年 Mac mini 本身就缺貨,Apple 在 4 月的財報會議說記憶體和晶片產能不夠,缺貨會持續好幾個月,雲端廠商要補機器也只能等。

我開了客服工單問補貨時間,同時讓 Claude 每 5 分鐘查一次,一有貨就自動開機。等了一整晚,還是沒有(工單到現在也還沒回)。

重新比價:每一家都回官網查

只好重新比價。這一步有個坑:網路上一堆「雲端 Mac 比較表」,很多其實是某一家的聯盟行銷頁。Claude 第一次整理的表格裡寫 RentAMac「US$2/小時、最少 4 小時」,回官網一查根本沒有這個方案,只有月租。所以我讓它每一家都回官網重查一次(2026 年 10 月 26 日。我住新加坡,但價格換成台幣給台灣讀者參考,1 美元 ≈ NT$32.58):

方案一次測試(約 24 小時)管理員權限機房問題
Scaleway M4≈ NT$195有巴黎沒貨,補貨時間不明
AWS EC2 mac2.metal≈ NT$610(US$0.779/小時,最少 24 小時)有(sudo、root)新加坡新加坡只有 mac2(M1);新帳號的 Mac 配額預設是 0,要先申請
My Remote Mac≈ NT$456(US$14/天)有,SSH、VNC 都有法國南特很新的小公司(登記資本額 €1,000);日租不退款;沒寫提供哪個 macOS 版本
MacRent≈ NT$489(US$15/天)有美國、法國、荷蘭官網沒有公司名稱和地址,只有一個 email;日租快沒貨
RunMini≈ NT$619(US$19/天)官網沒寫新加坡、香港唯一有亞洲機房又能日租的,但不知道有沒有管理員權限,也沒有公司資訊
RentAMac只有月租(US$119 起)有美國等沒有 VNC;目前全部租出,要排候補
MacinCloud 按次方案≈ NT$130(US$4/天)沒有有新加坡官方明寫不給管理員權限;有權限的獨享機全部售完
MacStadium只有月租(US$149 ≈ NT$4,850)有美國等測一次付一個月,太浪費
GitHub Actions macOS runner免費(公開 repo)有—不能即時操作,每改一次就要重跑整個 workflow 看截圖,拿來測 UI 太慢
二手 M1 Mac mini一次 NT$5,500~6,500有我家要先付一筆錢;只測這一次不划算

MacinCloud 便宜但沒有管理員權限,RentAMac 沒有 VNC 又只有月租,都出局。剩下能用的只有三種:

  • AWS:貴一點,但大廠、機房就在新加坡(延遲只有幾 ms)、權限完整、可以用 CLI 開機和設定。
  • 按天租的小公司(My Remote Mac、MacRent):比 AWS 便宜 NT$100~150,但公司資訊很少,有一家連公司名稱都查不到。我要在那台機器上登入自己的 Apple ID,交給一家查不到地址的公司,風險太大。
  • RunMini:有新加坡機房,但連最重要的管理員權限都要先寫信問。

最後選 AWS,比 Scaleway 貴大約 NT$400。多花的錢就是買「現在能開」跟「大廠」。

還有一個運氣成分:AWS 新帳號的 Mac 配額預設是 0,申請可能要等好幾天。我查了才發現帳號裡本來就有 5 台的配額(應該是以前申請過),所以當下就開得起來。如果你是新帳號,先去申請配額,申請不用錢,批下來再決定要不要用。

AWS 的計費方式

AWS 的 Mac 是獨享主機(Dedicated Host):你租的是一整台實體 Mac mini,一開就算 24 小時,中途關掉也照收,24 小時內連「釋放主機」都不給你按。反過來,24 小時到了也不會自動停,要自己去釋放,不然會一直按小時算下去。

所以開之前先把要測的東西列好,一次測完;24 小時一到,記得去釋放主機。

NOTE

二手 Mac mini 大概是租 AWS 十次的錢。如果你每次發版都要測,買一台放家裡比較划算(8 GB 記憶體跑 Xcode 加模擬器會有點緊,但堪用)。我這次是「一年用不到幾次」,所以租。

為什麼進不了桌面?

開機很快,SSH 也馬上連得上。我以為最難的是裝 Xcode,結果卡最久的是桌面。

1. 硬碟要我輸入密碼

AWS 的 macOS 映像檔裡,ec2-user 沒有密碼。我用 SSH 設好密碼、開好螢幕共享,從 Windows 用 TigerVNC 連進去(VNC 走 SSH 通道,防火牆只開 SSH,而且只開給我家的 IP)。

登入桌面沒問題,但只要去系統設定改需要管理員授權的東西(例如隱私權設定),就跳這個:

TigerVNC 連到 AWS 的 Mac,系統設定跳出「輸入密碼來解鎖磁碟 InternalDisk - Data」,紅框是這個對話框

密碼明明是對的(dscl -authonly 驗過帳號密碼),就是解不開。

原因是 Apple silicon 的 Mac 上,內建硬碟有一個「擁有者」的身分,帳號密碼對了不代表你是擁有者。AWS 的做法是呼叫 CreateDelegateMacVolumeOwnershipTask,把 ec2-user 設成擁有者。這個工作跑的時候整台機器會重開、連不上,官方說要 30~90 分鐘,我實測 45 分鐘。

30~90 分鐘? 有沒有那麼誇張! 而且 24 小時的計費照跑。

所以開機後第一件事就先做這步,不要等到要改設定才發現。

2. VNC 進得去,但 Claude 點不了

硬碟搞定後,我想讓 Claude 自己操作桌面(截圖、點按鈕),不要每一步都叫我。

我自己用 TigerVNC 可以操作,只是延遲很明顯,打密碼打到想摔筆電(網路只有幾 ms,慢的是 Mac 用 Retina 解析度在傳畫面,從 SSH 把解析度調低才好一點)。換 RealVNC 直接報錯,看起來是它跟這版 macOS 的帳密驗證不相容,就沒再試了:

RealVNC 連線時跳出 Protocol error: key length too large

給 Claude 用的是一個 VNC 的 MCP 套件(讓 AI 能看畫面、點滑鼠的外掛)。畫面看得到,但點擊、打字全部沒反應,而且看到的是一個登入畫面,不是我已經登入的桌面。

查 screensharingd 的 log,它的連線被標成 viewer->mode 1,輸入都被丟掉。

奇怪的是 TigerVNC 用的也是同一種舊式 VNC 密碼,卻能操作。確切原因我沒查到,只知道那個 MCP 只支援舊式密碼,沒得選。所以換一條路:讓 Claude 寫一個 100 多行的小 VNC client,改用 macOS 自己的認證(Apple Diffie-Hellman,RFB 協定裡的 security type 30,用 macOS 帳號密碼登入)。核心就這幾行:

// Apple DH(簡化版):跟伺服器交換 DH 金鑰,用共用密鑰的 MD5 當 AES-128 金鑰,加密「帳號+密碼」送回去
const dh = crypto.createDiffieHellman(prime, generator);
const myPub = dh.generateKeys();
const key = crypto.createHash("md5").update(dh.computeSecret(serverPub)).digest();
const creds = crypto.randomBytes(128);
Buffer.from(user + "\0").copy(creds, 0);
Buffer.from(pass + "\0").copy(creds, 64);
const c = crypto.createCipheriv("aes-128-ecb", key, null);
c.setAutoPadding(false);
conn.write(Buffer.concat([c.update(creds), c.final(), myPub]));

還有兩個小坑:

  • 版本要回 RFB 003.008。macOS 會先問你要不要用它自己的 003.889,回了 889 一樣只能看不能點。
  • Mac 的 ⌘ 鍵在 VNC 裡是 Super(0xffeb),不是 Meta。送錯的話 ⌘R、⌘L 全部變成打字。

這樣之後 Claude 就能自己截圖、點按鈕、打字,連到的是已登入的桌面,我不用一直被叫去點 VNC。

雲端 Mac 連不到 B 站

Mac 終於能用了,打開 Safari 進 B 站:轉圈圈,沒有內容。

curl 一下 B 站的 API,回 412。一樣的請求從我家的 Windows 發就正常,所以是 B 站擋掉 AWS 機房的 IP。我測的是 B 站的擴充,B 站進不去等於什麼都不能測。

解法:讓 Mac 上「跟 B 站有關的連線」繞回我家的網路出去,其他連線照走 AWS。

雲端 Mac 為什麼看不了 B 站 · 在 Miro 開啟

我家在 NAT 後面,AWS 連不進來,所以是反過來由 Windows 主動連到 Mac,開一條「反向」通道:

# 在 Windows 這端執行:Mac 上的 127.0.0.1:1080 變成一個 SOCKS 代理,流量從我家的網路出去
ssh -N -R 1080 cloud-mac

再寫一個 PAC 檔(一個小設定檔,告訴系統哪些網址要走代理):

// 只有 B 站的網域走通道,其他直連(不然 Xcode、App Store 的下載也會繞回我家,慢死)
// akamaized.net 是 B 站海外節點用的 Akamai,範圍比較大,測試機上無所謂
function FindProxyForURL(url, host) {
  var d = ["bilibili.com", "hdslb.com", "bilivideo.com", "biliapi.net", "akamaized.net"];
  for (var i = 0; i < d.length; i++)
    if (host === d[i] || dnsDomainIs(host, "." + d[i])) return "SOCKS5 127.0.0.1:1080";
  return "DIRECT";
}

用 networksetup -setautoproxyurl 掛上去,Safari 就能看 B 站了。

WARNING

這樣影片要先下載到我家,再從我家的「上傳」頻寬經 SSH 通道送到 AWS,速度會被家用上傳卡住。擴充內建的節點測速在雲端 Mac 上跑出來偏低,我請 Claude 查是 bug 還是環境問題,它查完順手把測速的計算方式改了.... 結論其實是環境問題,最後整個改回去。所以在雲端 Mac 上只測功能,不要看數字;叫 AI 查問題時,也要講清楚是「查原因」還是「修掉」。

兩台電腦、兩個 Claude,讓它們自己對話

隔著 SSH 遙控 Mac 很痛苦:每個指令都要跳脫好幾層引號,GUI 要隔著 VNC 截圖、點一下等好幾秒。Mac 版測速工具又是「改一行、跑一次、看畫面」的工作,全部隔著 SSH 做會慢到死。

所以我乾脆在 Mac 上也裝了一個 Claude Code,讓兩個 Claude 分工。

怎麼接起來

一開始 Windows 這邊的 Claude 跟我說它「沒辦法直接指揮另一個 session」,要我自己用 VNC 開 Terminal 去跟它講話。那我還要 AI 幹嘛....

後來用的是 Claude Code 的 Remote Control:一個 session 開了 Remote Control,就會出現在 claude.ai 的 session 清單上,手機、網頁都能操作它。同一個帳號底下的其他 Claude session,也能用 SendMessage 工具傳訊息給它,兩邊就能互相對話。

在 Mac 上要讓它自己跑起來,有兩個小坑:

# remote-control 需要 TTY,用 script 包一層;stdin 接 tail -f /dev/null,不然讀到 EOF 就自己結束
tail -f /dev/null | script -q /dev/null ~/.local/bin/claude remote-control --spawn same-dir

把這行包成 launchd 的 LaunchAgent,Mac 開機自動登入後它就在線上。Windows 的 Claude 先送一則「回我 hostname 和 pwd」,Mac 那邊開了新 session 回覆,管道就通了。

怎麼分工

  • Windows 的 Claude(總指揮):改擴充、發版、管商店後台;把我的決定轉給 Mac;Mac 卡在權限對話框時,用自己那個 VNC client 過去按;需要我輸入密碼、掃 QR code 時來叫我。
  • Mac 的 Claude:做 Mac 版測速工具、在 iPhone/iPad 模擬器上逐步截圖驗證、查 macOS 的 log。它在本機操作,沒有 VNC 的延遲。

派工的流程是:Windows 的 Claude 先叫 Mac 那邊只讀程式碼、交一份計畫,不准改。計畫回來,Windows 這邊先看過,把需要我決定的事整理成選擇題問我,再把我的答案傳回去,Mac 那邊才開始做。

Mac 版測速工具就是這樣做出來的:原本是 Python+tkinter 打包成 .exe,改成整包用 universal2 打包成 .app,同一個檔案在 Intel 和 Apple silicon 都能跑(Python 用 python.org 的 universal2 版;Pillow 這類套件 PyPI 上只有分開的 arm64、x86_64 版本,各下載一份再用 lipo 合成一個)。

踩到的坑

  1. 對話記錄帶不過去。Mac 上的 Claude 是全新的,不知道前面發生過什麼(例如 B 站會擋 AWS 的 IP)。所以先寫一份交接文件放進 repo,再把專案的記憶和語言偏好複製過去。有 token 的設定檔用 scp 傳,不放進 git。

  2. 傳出去的訊息沒有回條。對方沒收到、或收到但拒絕,送出的這邊完全不會知道。Windows 的 Claude 也沒辦法主動看 Mac 那邊做到哪,只能等它回報。想看即時進度,我自己打開 claude.ai 上那個 session 最快,也可以直接在裡面插話。

  3. 同一個 repo 有兩份工作目錄。Mac 版測速工具是 Mac 自己的地盤,做完一段就直接 commit、push。麻煩的是擴充的 src/:Windows 這邊改了一堆還沒 commit,又要給 Mac 重編、測試,兩邊都在改,就沒辦法單純 git pull:

    • Windows 把還沒 commit 的改動打包(tar)同步過去時,可能蓋掉 Mac 改到一半的檔案。後來的規則是:同步 src/ 之前先通知對方。
    • Mac 改完的東西不整個檔案傳回來,而是傳 patch,Windows 用 git apply 套上去。只動它改過的那幾行,不會蓋掉我這邊的新改動。
    • 有一次反過來,是 Windows 的 Claude 自己的腳本出錯,用舊版產生器把三個引導頁的 HTML 蓋掉了。剛好 Mac 那邊還有正確的一份,從那裡拿回來才沒事。兩份工作目錄有時候也是備份 XD
  4. 一堆權限要按「允許」。Mac 的 Claude 要在本機截圖、用程式點畫面,macOS 會跳隱私權詢問(螢幕錄製、輔助使用、控制其他 App)。這些只能在桌面上按,SSH 按不到,所以是 Windows 的 Claude 用 VNC 過去按:

    macOS 跳出「zsh 要求略過系統的視窗選擇器,直接存取你的螢幕和音訊」,紅框是這個對話框,背景是 Mac 版測速工具

    這個詢問寫的是 zsh,因為截圖是 Claude 叫出來的 shell 在做。螢幕錄製、輔助使用的清單裡記的則是 Claude Code 的執行檔 ~/.local/share/claude/versions/2.1.310,路徑裡有版本號,所以以我觀察,它每次自動更新完就要重開一次權限。另外「輔助使用」的檔案選擇視窗只能選 App,選不到這個執行檔,要讓 Mac 的 Claude 先觸發一次權限要求,等它出現在清單裡再打開。

  5. Mac 會被刪。測完我就把主機釋放,整台連硬碟一起消失,所以東西不要只活在那台機器上:程式要 push,簽章私鑰要另外備份。

整理起來,兩個 Claude 之間其實有四條路,各管一件事:

兩個 Claude 怎麼隔著兩台電腦合作 · 在 Miro 開啟

用起來很順。我只要看兩邊的進度,偶爾輸入密碼、用手機掃測速工具裡 B 站登入的 QR code,其他時間它們自己傳來傳去。

實際裝起來才看得到的 bug

TestFlight 版裝起來(這一步要輸入 Apple ID 密碼,密碼我不交給 AI,自己打):

Mac 上的 TestFlight,紅框是 BiBoost 2.7.0 Build 19

在 Mac 上和模擬器裡實際點一遍,抓到好幾個 Chrome 上永遠不會出現的問題:

  • Mac Safari 的擴充選單捲不動:內容比選單高的時候,滾輪、觸控板都沒反應,下半部的設定根本點不到。iPhone、iPad 正常,只有 Mac 會這樣。改成「固定 html 高度、讓 body 自己捲」才好。

  • iPhone 上選單貼在左邊:iPhone 的擴充選單是整個螢幕寬的底部面板,原本寫死 320px 寬。

  • 「給我 5 星」按鈕打不開評分:Mac App Store 的網址要用 macappstore://…?action=write-review,用 https 只會打開商品頁。

  • iPhone 上的 B 站網頁根本不能播:

    iPhone 模擬器的 Safari 開 B 站影片頁,只有「Play Now」和「開啟 App」,紅框是這兩個按鈕,按下去都會導到 App 下載頁

    B 站會把 iPhone 導到手機版網頁,那裡沒有播放器,只有「Play Now」跟「開啟 App」,兩個都導去下載 App。拿一台沒裝擴充的 iPhone 模擬器對照,一樣不能播,所以看起來不是擴充的問題(實機還沒驗)。iPad 就正常,iPhone 切成「電腦版網站」也能看。

另外,我用 iOS 26.2 新的 API 做了一顆「直接打開設定裡的擴充頁」按鈕,模擬器上永遠只停在設定首頁。查 log 才發現模擬器的「設定」一直在建搜尋索引(indexingIncomplete),跳轉進不去。這種只能等實機。

這些修完,就是後來送審的 2.8.0。

簽章、公證要不要 Mac?

Mac 版測速工具不走 App Store,是放在 GitHub Release 給人下載,所以要 Developer ID 簽章+Apple 公證。沒公證的 App,使用者雙擊會被 macOS 擋下來,要自己去設定裡開例外。(上 App Store 的 Safari 版不用公證,App Store 審核會處理)

這整段都不需要自己的 Mac:

  1. 產 CSR:openssl req -new 就能產,Windows 上也行。我是剛好在雲端 Mac 上產,私鑰就留在那台。
  2. 申請憑證:developer.apple.com 選 Developer ID Application(G2),上傳 CSR,下載 .cer。
  3. 包成 p12:私鑰+憑證+中繼憑證包成有密碼的 p12,存進 GitHub secrets。雲端 Mac 一刪私鑰就沒了,所以另外備份一份(我放私人 repo 是圖方便,講究一點應該放密碼管理器)。
  4. GitHub Actions:macOS runner 把 p12 匯入暫時的 keychain → 簽章 → 壓 zip → notarytool submit → stapler staple(把公證結果釘進 App,離線也能驗)→ 再壓一次 zip。

公證這步前後送了四次:

第一次:notarytool submit --wait 等了 30 分鐘還沒結果,workflow 逾時失敗。這是這個帳號第一次送公證,排隊特別久。

更慘的是,送去公證的那份 App 只存在 runner 上。workflow 一失敗,runner 被回收,那份檔案就沒了。重新打包出來的是另一個檔案,等於要重新送一次公證。

所以 workflow 改成:

  • 送出公證後,先把這份還沒 staple 的 zip 上傳成 artifact(後面的步驟失敗也照樣上傳)
  • 改用 notarytool wait <id> --timeout 4h 慢慢等
  • 還是等不到的話,下一次 run 帶上前一次的 run ID 接續,不用重新打包

第二次:被一行 echo 弄死。workflow 裡有這行:

echo "接續請帶 resume_run_id=$GITHUB_RUN_ID;..." >> "$GITHUB_STEP_SUMMARY"

在 set -u 底下直接失敗,報 unbound variable。bash 把變數後面緊接的全形「;」也當成變數名稱的一部分(至少在 macOS runner 上是這樣)。這行剛好在上傳 artifact 之前,而當時上傳那步只有前面全部成功才會跑,所以它一失敗,artifact 也沒傳上去,第二次送的那份又作廢了。改成 ${GITHUB_RUN_ID},上傳那步也改成「沒被取消就跑」(if: !cancelled()),之後變數一律用 ${}。

第三次:等了 47 分鐘,通過。

第四次:同一天晚上正式發版,1 分鐘就過。所以慢的是帳號剛開始送公證的那幾次。

花了多少

  • AWS mac2.metal:24 小時 ≈ US$18.7(約 NT$610)
  • Apple Developer Program:US$99/年(本來就有)
  • GitHub Actions:公開 repo 的 macOS runner 不用錢
  • 時間:前後兩天,中間睡了一覺等 Scaleway 補貨(沒等到)。真正在做事的時間大概一天,其他都在等:等補貨、等硬碟擁有者、等公證

下次開雲端 Mac 的清單

  1. 開機前:列好要測的東西;確認 Mac 配額;記下 24 小時後要去釋放主機
  2. 開機後先跑 CreateDelegateMacVolumeOwnershipTask,等它跑完(45 分鐘)
  3. 設 ec2-user 密碼、開螢幕共享和自動登入;VNC 走 SSH 通道
  4. 用 Apple 自己的認證(type 30)連 VNC,不要用舊式 VNC 密碼
  5. 開反向 SSH 通道+PAC,只讓被擋的網域繞回家
  6. 裝 Claude Code、開 Remote Control,按完螢幕錄製、輔助使用的權限(不想每次重按,就關掉 Claude Code 的自動更新)
  7. 東西做完一段就 push

這次 Mac App Store 2.8.0 已經送審,Mac 版測速工具也公證過、放上 GitHub Release 了。

結果隔天早上起床,2.8.0 就審過了。Mac 版初版送審來來回回花了一個月,版本更新卻秒過。可惜的是 iOS 版還在一個月的 CD 中.... 不是說好 90% 的 App 可以在 48 小時內審完嗎?

コメント(0)

まだコメントはありません。最初のコメントを書いてみませんか?

関連記事

Cover: one src/ folder goes through build.mjs into Chrome, Edge and Firefox zips (Chrome and Edge share one sha256), while Safari goes through an Xcode project to the App Store
技術記事19 min

Shipping a Bilibili Extension from One Codebase to Chrome, Edge, Firefox and Safari

How one src/ becomes four store builds, why the zips must be reproducible (with real sha256 runs and a line-ending gotcha), 5-language release notes guarded by a pre-push hook, and which release steps are scripted versus always done by hand.

繁體中文 / English

速度テスト実行中の CDNSpeedTest 画面
ハウツー9 min

Bilibili CDN 速度テスト — 参加ガイド

画像付きガイド:CDNSpeedTest(Windows/Mac)をダウンロードし、ネットワークチェック後に QR コードでログイン、テスト結果を送信して各国で最速の Bilibili サーバーを探します。

繁體中文 / 简体中文 / English / 日本語 / 한국어

「世界で3人しか知らない bilibiliがカクつかない秘密の設定」
ハウツー2 min

bilibili のカクつきが消える、ひとつの秘密の設定

海外で bilibili が重いとき、DNS の変更や VPN は運任せ。本当の原因は bilibili が割り当てる遅い CDN ノードです。拡張機能ひとつで一番速いノードに固定する方法と、Android・テレビでの対処法。

繁體中文 / 廣東話 / 简体中文 / English / 日本語 / 한국어

Notice on top of the Bilibili player saying the CDN was slow and playback switched to a backup node
技術記事14 min

Detecting CDN Failures in a Bilibili Extension and Falling Back to Backup Nodes

How the extension decides a CDN node is really broken: which errors to ignore, how to detect stalls from currentTime and the forward buffer, why it switches once quietly before asking you, and how it avoids bouncing between nodes. Also covers live streams.

繁體中文 / English

Cover: the Network panel domain changes from upos-hz-mirrorakam.akamaized.net to upos-sz-mirror08ct.bilivideo.com, above the four hook points: __playinfo__, the playurl API, .m4s segments and live streams
技術記事13 min

Rewriting Bilibili's Stream CDN on the Fly from a Chrome Extension's MAIN World

Bilibili's stream URLs arrive through SSR __playinfo__, the playurl API, segment requests and the live API. Using bilibili-cdn-switcher's code, this walks through hooking each path, what gets rewritten, and the traps: one-shot Response bodies, read-only XHR responseText, and speed tests that must bypass your own hooks.

繁體中文 / English

Cover: more testers, better defaults. A loop of four steps: test at home, get custom nodes, report back, update the default list (cdn-list.json), then back to users in the next release
技術記事23 min

How Crowdsourced Speed Tests Keep Improving Bilibili CDN Server Picks

How a Windows speed test app benchmarks 299 Bilibili nodes in people's homes, picks the 10 most stable with layered videos and a three-stage funnel, writes them into the extension on the spot, and sends reports back so each country's default nodes improve by market-share-weighted coverage and missing ISPs get recruited.

繁體中文 / English

Cover: one page, two JS worlds. typeof chrome.storage is undefined in the MAIN world console and object in the ISOLATED world; both share the DOM and localStorage and talk via postMessage
技術記事14 min

Chrome Extensions: The Basics of MAIN World and ISOLATED World

Patched window.fetch in a content script and the page ignored you? What the MAIN and ISOLATED worlds can each see, the three ways to pick a world, when to split into two scripts, how they talk through localStorage and postMessage, and which forged messages to reject.

繁體中文 / English

The same 4K video before and after the extension: buffering at 9 KB/s before, 8.8 MB/s after
技術記事11 min

How to Actually Fix Bilibili Buffering for Good

Why popular Bilibili videos play fine overseas while unpopular ones stall: CDN caching and trips back to origin, why the narrowest link sets your speed, why DNS and VPN tricks are hit or miss, and how my extension picks a default node from real tests across 14 Taiwanese ISPs.

繁體中文 / English