幾個月前,我將 DIALØGUE(對話)個 iOS app 當成 web 版嘅移植咁出咗街。之後,我幾乎將佢全部重做成一個真正 native 嘅 app。
佢而家已經喺 App Store 上架咗——如果你好奇,去㩒吓佢啦。下面呢篇講嘅,就係到底改咗啲乜,同埋點解。
呢兩者嘅分別,聽落好似喺度玩文字遊戲,直至你將兩個版本同時揸喺手。第一個版本就係將個 web app 壓細塞入手機:一樣嘅 tab、一樣嘅多步驟創建 wizard、一樣嘅 dashboard。佢 compile 到、行得到、又過咗審核。但佢俾人嘅感覺,就好似一個網站著咗件 app 嘅戲服咁。
一個被壓細塞入手機嘅 web app,講到尾都仲係一個 web app。Native 唔係喺你嘅 web layout 上面掃多一層油——佢係同部機之間一份完全唔同嘅合約。 而呢份合約,正正就係我當初跳過咗嘅嘢。為咗認真去履行佢而重做,結果搞到啲 tab、音頻、收聽界面、offline 行為,連個 app 點樣 start 都變晒。下面就一個畫面一個畫面咁講,呢樣嘢實際上即係點。
嗰個移植版本,其實係個 dashboard
第一個版本,預設咗個 app 嘅工作就係將個 generator 攤出嚟。DIALØGUE 係做 AI podcast 嘅,所以當時嘅諗法係:將每一個 web 界面都搬上個 mon,件事就當搞掂。
咁做出嚟嘅結果,就係一個 dashboard。五個 tab、一個多步驟 wizard、樣樣都俾塊 panel 你。冇人開一個 podcast app 係為咗操作個 dashboard。佢哋開佢,係為咗將一個諗法變成聲音,係為咗聽返自己整出嚟嘅嘢,又或者係為咗開返一檔之前做過嘅 show。嗰個移植返嚟嘅界面,護住嘅係 web app 嘅 layout,護唔住嘅,偏偏就係呢三件事。
所以今次重做,由你睇到嘅第一樣嘢開始。
三個 tab,因為手機會懲罰 tab
舊 app 一開係五個 tab:Library、Studio、Create、Credits、Profile。移植 web app 就會得到呢種結果——每一個 web 界面都要爭一個 tab。
重做之後個 app 得三個:收聽(Listen)、創建(Create)、你(You)。
有兩個 tab 冇捱得住。Credits 唔再係一個目的地——冇人會開一個 app 專登去望住個結餘。佢俾人搬咗入「你」裏面,而唯一真正緊要嗰個時刻——啱啱要去生成嗰陣結餘剛剛唔夠——而家就會啱啱喺嗰一步彈出一張購買 sheet。Studio 都唔再係一個「地方」。 佢變咗做 系列(Series)——一套儲好嘅設定(主持人、語氣、format、語言、來源 pattern),佢住喺「創建」裏面,又喺「收聽」度以一個合集嘅形式出現,而唔係扮成一間控制室嘅 tab。Library 同 Profile 就變咗更樸素嘅「收聽」同「你」。
喺桌面,多一個 tab 係免費嘅。喺手機,每一個 tab 都係向注意力抽嘅稅。今次重做,就係將呢筆稅還返。
跟住 iOS 期望嘅方式去做音頻
就係喺呢度,「native 係一份合約」呢句嘢唔再咁抽象。
嗰個移植版本,並唔係完全唔識音頻。佢已經出得到喺上鎖畫面,有播放、暫停、跳過,有電話入嗰陣會暫停,你拔走耳機佢又會停。呢啲係最基本嘅嘢,佢的確都做到。
佢做唔到嘅,係一鎖畫面之後仲可以好似一個真正嘅音頻 app 咁行返。你冇得喺上鎖畫面度拖個播放點。嗰度冇 cover art——得返文字。冇 AirPlay 掣、冇 sleep timer,跳過永遠都係固定嘅十五秒,鍾唔鍾意都係咁。
今次重做,係順住個 platform 去補返呢個窿,而唔係兜過佢。而家上鎖畫面會載住呢一集嘅動態封面圖,仲有一條你拖得到去任何位嘅 scrubber。有 AirPlay,有一個會將音量慢慢淡走、而唔係一刀切死嘅 sleep timer,仲有一個由十秒到六十秒任你揀嘅跳過間隔——而呢個設定仲會同時 drive 埋上鎖畫面嗰啲掣,因為個 system 嘅控件本來就應該同個 app 對得返。個 audio session 會將自己 declare 成「語音類音頻」,所以個 OS 會當佢係講嘢咁對待,而唔係音樂。
呢啲嘢一啲都唔靚仔。呢個正正就係重點。喺手機,一個無視上鎖畫面同 AirPlay 嘅音頻,唔叫「精簡」。佢偏偏就係喺人哋真正會聽嘅嗰啲時刻爛咗——行緊路、揸緊車、部機擺喺褲袋嗰陣。
一份淨係 AI podcast 先做得出嘅字幕
跟住呢一 part,係真正屬於我哋自己嘅嘢,唔淨止係幾好嘅 iOS hygiene。
播緊一集嗰陣,個 app 會 show 一份同步字幕:當下嗰句會 highlight,個 view 會自動 scroll 令佢留喺中間,你㩒任何一句,就直接 jump 去嗰個位。一個 generic 嘅 podcast app 其實係做唔到呢樣嘢,因為佢唔知邊句嘢喺幾時講出嚟。DIALØGUE 知——係佢生成個 script,所以佢一早就知道呢一集嘅結構。
老實講一個工程上嘅細節:一句嘢淨係喺個音頻有精確嘅逐段 timing 嗰陣,先至㩒得。當個 timing 只係大概,嗰句嘢照樣會 render 出嚟,只係 seek 唔到,而個 app 唔會扮自己做得到。同一套 segment timing 仲會直接喺條 scrubber 上面畫返啲章節刻度,咁你就可以好似掃音頻咁略讀一集,但手上仲多咗一張「個 system 究竟整咗啲乜」嘅地圖。份字幕甚至會標返邊句嘢係邊個主持人講嘅,因為個 script 本來就係當成雙主持人對話咁寫。
呢個就係「喺個 player 上面硬裝一份字幕」同「將生成嘅 script 當成成個收聽體驗嘅事實來源」之間嘅分別。
有兩樣嘢令呢件事成立,而佢哋都唔會喺畫面度出現。個 backend 會俾每一段都蓋返佢嘅開始同結束時間,仲標明個 timing 係精確定係淨係估算——咁個 app 先可以俾你㩒一句精確計時嘅嘢,又靜雞雞咁拒絕喺一句估算嘅嘢上面呃你。仲有,你嘅播放位置係存喺 server 度,唔淨止存喺部機度,所以「由上次嗰個位接住聽」就算你喺 web 度開咗一集、再喺手機度接住聽完,都一樣 hold 得住。
捱得住一程真實通勤嘅 offline
呢個 app 由一開始就 download 得到單集。呢樣嘢唔係新嘢,我想講得準確啲。今次重做加返上去嘅,係韌性——係「一個 download 功能」同「一份你信得過嘅 offline」之間嘅分別。
而家一個俾人 interrupt 咗嘅 download 會由斷咗嗰個位 resume,而唔係由頭嚟過,因為個 app 會逐集儲返個 system 嘅 resume data,再由嗰度 restart。有一個「淨係 Wi-Fi」嘅選項,佢會真係封住 cellular,所以一個排緊隊嘅 download 會乖乖等 Wi-Fi,而唔係靜雞雞燒晒你個數據 plan。download 最多同時行三個,排成一條 FIFO 隊列,而唔係一窩蜂咁去逼個網絡。有一個 storage 界面,俾你睇得到、又 delete 得到部機上面嘅嘢。嗰啲喺網絡唔穩陣嗰陣會 fail 嘅臨時 fetch,會帶住 backoff 去 retry——試三次,由半秒開始向上加直到一個上限,而且絕對唔會去 retry 一個 user 自己 cancel 咗嘅操作。
Retry 好易;難嘅係 retry 嗰陣唔好同一個啱啱㩒咗 cancel 嘅 user 鬥氣——正正就係呢一點,先令 offline 喺爛地鐵訊號下感覺係穩陣嘅,而唔係喺度乾轉圈。
即時,因為轉圈圈會俾人讀成「壞咗」
喺手機,latency 係一種感覺,唔係一個數字。cold launch 嗰陣一個轉緊嘅圈,會俾人讀成「呢個 app 壞咗」,就算其實乜事都冇。
嗰個移植版本,每次 cold launch 都會重新 download 每一張封面圖,所以一開 Library 睇到嘅係成個 mon 嘅轉圈圈。今次重做加咗一層封面圖嘅 memory 加 disk 共享 cache——disk 嗰層捱得過 relaunch,memory 嗰層令 scroll 保持順滑,連上鎖畫面都係 reuse 同一份 cache 嚟 show 佢嘅封面圖。重新開一集以前要等一次網絡 round trip;而家每一集嘅 segments 同字幕都被 cache 起,會即刻 render 出嚟,再喺 background 靜雞雞 refresh。我仲將嗰個每半秒一次嘅播放 tick 由啲 list rows 度抽咗出嚟,咁個 timer 就唔會再逼成個 Library 重畫一次。
呢個唔係一個你 screenshot 得到嘅功能。佢係 app 同網站之間嗰道罅。
一集整好,佢會 ping 返你
生成一檔 podcast 要嘅係幾分鐘,唔係幾秒——要做 research、列 outline、寫 script,之後先至到音頻。嗰個移植版本,由頭到尾都要你望住條 progress bar。呢個 native app 唔會。
喺你俾 permission 嘅前提下,你嗰一集一整好,佢就 send 一條 push notification 俾你,所以你大可以鎖咗部機、去做第啲嘢,等佢一震你先返嚟。個 device token 存喺 server 端,淨係嗰個負責發通知嘅 job 先讀得到佢,而且你喺 settings 度可以將成套嘢熄咗。呢個淨係一小段 plumbing——一張 table、一個 worker、Apple 嘅 push service——但佢將個產品俾人嘅感覺,由「喺呢個畫面前面等」變成「整好我會話你知」。
個 workflow 可以由 app 之外 start
一個 native app 唔淨止係活喺自己個 window 裏面。今次重做透過 App Intents 加咗 Siri 同捷徑嘅支援,所以「create a podcast」、「resume listening」同「open my podcasts」都用得到——當係講出嚟嘅 phrase、喺捷徑 app 裏面、以及喺 Spotlight 度——唔使任何特殊 entitlement。至於「resume」究竟應該做啲乜(接住播當下嗰一集,定係喺乜都冇 load 嗰陣開 Library),呢個決定係一個好細嘅 pure function,我可以單獨俾佢寫 unit test——正正就係呢種嘢,可以令 Siri 嘅行為唔會 drift 走。
第一次開仲有一段好克制嘅三頁歡迎——create、voices、隨處收聽——淨係 show 一次;仲有 deep link,令一條俾人㩒咗嘅 link 開返正確嘅畫面,而唔係將你掟喺 home tab 度。都係啲細嘢嚟。但佢哋正正就係「一個攤喺手機度嘅 app」同「一個屬於部機嘅 app」之間嘅分別。
講多句我喺邊度停咗手:目前仲未有 home-screen widgets、未有 Live Activities、亦都未有 CarPlay——每一樣都要佢自己嘅 extension,或者一份要 Apple 批嘅 entitlement,而我揀咗先將收聽呢個核心出咗街。呢度嘅「Native」係一個方向,唔係一張 tick 晒嘅 checklist。
我喺呢件事度帶走嘅一課
如果你而家將某樣嘢移植去一個新 platform,最誘惑人嘅做法,就係令佢喺嗰度行得起,然後就當搞掂。佢的確會行。但佢都會俾人感覺係借返嚟嘅。
Native 係同部機之間一份合約:尊重上鎖畫面、尊重 audio output 嘅變化、尊重 offline 嘅現實、尊重人哋一早已經喺度用嗰啲 system 界面。一個移植版本,護嘅係你舊嗰個 layout。一個 native app,護嘅係個 platform 嘅慣例——就算呢樣嘢意味住要 delete tab、重寫你已經出咗街嘅畫面。
我手上冇乜驚人嘅安裝量或者 retention 數字可以攞出嚟揮——當前呢個版本就喺 App Store 度,呢個就係佢老實嘅狀態。真正嘅考驗,從來都唔係啲 screenshot 睇落夠唔夠 native。佢係:有冇人整咗一集,喺鎖住個 mon 嘅散步路上聽完,然後返嚟再整多一集。
如果你喺度做 mobile,我好好奇你將條線畫喺邊:幾時「佢喺手機行到」就夠,幾時個 platform 嘅合約逼你不得不重做?
常見問題
DIALØGUE 個 iOS 重做究竟改咗啲乜?
呢個 app 由 web 版嘅一次移植,變成咗一次 native 重做。Information architecture 由五個 tab 收到三個(收聽、創建、你)。收聽體驗加咗㩒落去 jump 嘅同步字幕、章節標記、上鎖畫面拖動進度同封面圖、AirPlay、sleep timer,仲有可以設定嘅跳過間隔。Offline download 變得有韌性,個 app 會 cache 封面圖同 segments 嚟做到即時嘅感覺,Siri 同捷徑令核心操作由 app 之外 start 得到,仲有一條「一集整好」嘅 push notification 會話你知幾時完成。
點解五個 tab 變成三個?
因為手機會懲罰每一個多出嚟嘅 tab。Credits 唔係任何人想去嘅地方,所以佢俾人 fold 咗入「你」,再加一張喺你真係結餘唔夠嗰陣先出現嘅購買 sheet。Studio 變咗做系列——一套住喺「創建」裏面、儲好嘅設定,而唔係佢自己一個 tab。Library 同 Profile 就變咗更樸素嘅「收聽」同「你」。
今次重做加咗啲乜 native iOS 功能?
上鎖畫面拖動進度同動態封面圖、AirPlay、有音量淡走嘅 sleep timer、可以設定嘅跳過間隔(10–60 秒,仲會同時 drive 埋上鎖畫面嘅控件)、scrubber 上面嘅章節刻度、㩒落去 jump 嘅同步字幕、有韌性嘅 offline download(斷點續傳、淨係 Wi-Fi、storage 管理、有上限嘅隊列)、封面圖同 segment 嘅共享 cache 做到即時 render、Siri 同捷徑 intents、「一集整好」嘅 push notification、存喺 server 端、喺 web 同手機之間接得返嘅播放位置、deep link,以及第一次開嘅 onboarding。
呢份同步字幕係咪每一集都用得到?
淨係喺個音頻有精確嘅逐段 timing 嗰陣,字幕裏面某一句先至㩒得落去 seek。當個 timing 只係大概,嗰句嘢照樣會 show 出嚟,但 seek 唔到,而個 app 唔會扮自己做得到。呢份字幕做得到,係因為個 script 本來就係 DIALØGUE 生成,所以佢知道結構、又知道邊個講咗啲乜。
Studio 同系列(Series)有乜分別?
Studio 暗示嘅係一間滿係掣嘅控制室。系列就淨係一套儲好嘅設定——主持人、語氣、format、語言、來源 pattern——令你唔使重新 config 晒所有嘢,就可以開始下一集。佢係住喺「創建」裏面嘅一個 preset,唔係一個獨立嘅 tab。
呢個同 NotebookLM 嘅 audio overview 有乜唔同?
NotebookLM 的確好有用,又免費,可以將你嘅 source 變成一段快速嘅 audio overview。DIALØGUE 想做嘅,係喺「生成」之上做一個完整嘅 native 收聽產品:喺出音頻之前先審 outline 同 script、揀聲音、一份㩒落去 jump 嘅同步字幕、章節、上鎖畫面同 AirPlay 控制、offline download、Siri,仲有俾重複節目用嘅系列。老實講,呢個分別與其話係「邊個生成嘅音頻好啲」,不如話係「呢一集存在之後,跟住會發生啲乜」。
今次重做係咪將 offline 收聽加咗上去?
Offline download 一早就有。今次重做令佢變得有韌性:俾人 interrupt 咗嘅 download 會續傳而唔係重嚟,有一個「淨係 Wi-Fi」選項同一個 storage 界面,download 最多同時行三個,臨時嘅網絡 failure 會帶住 backoff 去 retry,又唔會同一個㩒咗 cancel 嘅 user 鬥氣。
我呢邊暫時就咁多啦。
祝好,Chandler


