我是 Megabits,是一個普通的 iOS 開發者。直到有一天我買了個 Apple Watch。git
PomoNow 是個人一款集成 Todolist 的番茄鍾應用,主打「平衡了儀式感和功能性」的交互設計,不只可以讓新手當即開始使用番茄工做法,也具有很高的靈活性,適合於各層次番茄工做法用戶。目前我 Mac 版本以及同步功能正在開發中。具體介紹見:PomoNow 2,給你一個有儀式感的番茄鍾丨Matrix 精選,Watch 版本使用效果見:微博視頻github
這是一個初代 Apple Watch,做爲第一代產品,它完美的執行着隨着時間愈來愈卡的歷史使命。雖然說就連隨便打開一個 App 都要好些時間,但我硬是在這樣一個卡的不要不要的玩意上面把 PomoNow Watch 作完了。
swift
PomoNow 是一個番茄鍾。對於一個番茄鍾來講最重要的東西是什麼?能用!沒錯就是能用,但就是作到這一點就已經很是困難了。番茄工做法的通常流程是這樣的:25分鐘工做,5分鐘休息,重複四次後進行一次25分鐘長休息。前兩個都算輕鬆,坑就坑在這個重複四次。支持在 Watch 上長休息就意味着要在一次番茄結束以後自動開始下一個番茄,這就是難點所在了。接下來我會開始詳細講講這個功能具體困難在哪,我又是怎麼考慮的。也歡迎你和本文一塊兒思考。以後我會講講我在開發過程當中遇到的其餘問題和解決方案,這些問題不少是 watchOS 或者 Xcode 自己的問題,我在實踐中找到了一些不那麼完美的解決方案,但但願能幫到你。緩存
在第一次開始製做 Watch 版 PomoNow 的時候,我但願讓 Watch app 可以獨立運行。bash
對於 Apple Watch 這樣一個小體積設備,長時間在後臺運行 App 十分耗電,因此一旦 Watch app 進入後臺就會暫停運行。想要直接在 Watch app 上計時能夠說是很麻煩的一件事,通常來說在 Watch 上作一個停表的思路是這樣的:在開始計時的時候計算結束時間,用一個計時器每秒計算一次剩餘時間而後顯示出來。app
這樣一來就不會受後臺凍結的影響了。由於時間是根據目標時間減去當前時間實時計算出來的。咱們也能夠經過把時間分紅塊來計算如今處在「工做時間段」仍是「休息時間段」。工具
聰明的你也許已經想到該怎麼經過相似的思路實現連續自動計時了。
post
按照上圖的思路,從前向後一個格子一個格子的掃描,在「當前時間」的指針進入咱們掃描到的格子以後,咱們就清楚的知道如今在工做仍是在休息,以及還有多長時間了。
測試
因此問題解決了嗎?Naive!最大的問題其實並不在計時,而是在推送通知上。咱們上文已經提到,Watch app 是不能在後臺一直運行的,那麼想要告訴用戶計時結束就必需要靠一個定時發送的通知來實現。對於單個番茄來說比較好辦,兩個通知就 OK 了,但在自動開始新番茄的狀況下,假設用戶一直不擡起手腕開一下 App 的話,就要定無數個定時通知在後臺。也許你想說:一百個(有限個)應該夠了吧,誰會計時一百個番茄啊?這也許是個事實,但這樣的解決方案實在是不夠優雅。spa
那有沒有辦法比較優雅的作到這一點呢?我當時想出了這樣一種方案,雖然看起來和上面的計時的作法同樣糾結。咱們知道,推送通知是能夠設置重複的。假如按照初始條件每四個番茄進行一次長休息,咱們也許就能夠指定以下 8 個位置定時重複的推送通知,使其按照相同的時間間隔(工做時間 x 4 + 休息時間 x 3 + 長休息時間)重複推送便可。
但很惋惜這種作法是沒有用的。由於定時推送通知的時間間隔必須以此刻爲基準給出,根本沒法作到在第一次讓每一個通知在對應時間彈出來。
因此我決定在初版 PomoNow Watch 中放棄自動計時的功能,用戶只能在 Watch 上手動啓動計時。並且,因爲不能在 Watch 上直接推送通知的系統限制,我還須要喚醒 iOS App 才能提醒用戶時間到了。想要這個 Watch app 獨立運行,根本作不到。
根據上面的分析,我初版的 Watch app 使用這樣的作法:在 Watch 上獨立計時,只支持完成單個番茄,結束後須要用戶手動開始新番茄。
在開始製做以後首先遇到的就是調試的問題。模擬器中問題不大,真機調試倒是很是可怕的。因爲 Watch app 不能從電腦直接安裝,Xcode 須要首先把 swift 的運行時和一系列安裝腳本先傳到手機上,再由手機完成安裝過程。以後 Xcode 還須要經過手機來和 Watch 創建鏈接才能調試。前者等待時間超長,後者失敗機率極高。我來說一講調試過程當中可能遇到的各類問題。
首先是鏈接問題。好比你在把 iPhone 插在電腦上以前 Watch 處於鎖定狀態,以後再解除鎖定,Xcode 顯示已經檢測到手機和表,這時點擊運行就會有必定機率出現沒法鏈接的問題。雖然狀況各有不一樣,但鏈接不上的情況確實時有發生。發生這種狀況的時候,我通常會把數據線拔掉從新插一下,等到 Xcode 從新檢測出 Watch 以後,通常就沒什麼問題了。
另外在調試的時候無論是手機仍是表都必需要保持在解鎖狀態。在比較早的版本中,表沒有解鎖會直接致使調試失敗,後期版本中才會給出提示等待解鎖。這耽誤了我很多時間。
好不容易不會直接提醒鏈接不上了,以後還有更坑的問題可能會出現。點擊運行數秒後,沒有通過安裝過程就已經顯示「正在運行」,Watch 上一點反應都沒。這種狀況可能有兩種可能性,一種是顯示錯誤,Xcode 雖然提示正在運行,但實際的狀態倒是在準備安裝腳本,這時候你只要等一會就行了。另一種可能性是 Xcode 炸掉了,有時候你重插數據線可能有用,有時候就須要你退掉 Xcode 重開。
那若是是通過安裝過程以後出這個問題呢?這就有多是你本身走神了。當屏幕熄滅數分鐘以後,Apple Watch 就會自動回到錶盤,這是一個方便用戶的設計。因此先檢查一下你的 app 在不在後臺,先不要急着怪蘋果。
不過上面這些問題都只是偶爾出現,或者在初次運行的時候出現一次,下面的問題則是常常出現。
終於把 Watch app 安裝好以後,接下來就是等待鏈接的時間。你看着屏幕轉啊轉啊轉啊轉啊,等到天荒地老,而後發現你的 app 崩掉了。這就是以前說的鏈接問題。這種問題通常是玄學問題,尤爲對於我這種初代用戶,更是搞不懂是由於本身的表比較卡,仍是哪裏炸掉了。這時,你中止了調試操做,想要嘗試手動打開本身的 app 試試能不能運行。可並無什麼用,結果依舊是轉啊轉啊轉啊轉啊轉啊 Boom,多少次都沒用。這時候有兩種方法。第一種是在 app 加載的時候將其強制退出,方法是按住開關機按鈕直至出現關機畫面,而後按住錶冠直到回到主屏幕。以後即可以再次嘗試運行,成功機率較低。第二種方法比較簡單粗暴,重啓手錶。若是你有時間等它重啓完的話,基本上都能解決問題。(刪掉 Watch app 從新安裝有時候也能解決問題)
通過了九九八十一難終於把 Watch app 安裝好以後,看一眼時間已通過去了十多分鐘。我想起我大好的青春年華再也不回來。爲了避免耽誤我大好的青春年華,我每次點完那個調試按鈕以後就會去玩一局以撒,等我死了之後回來看一眼差很少也就運行了。
因此有沒有解決辦法呢?仍是有的。Watch app 在模擬器和實機上差異不是很大,不少時候咱們只是想看一下運行效果並不須要調試信息。這時候咱們只要把運行目標改爲 iOS app,而後運行就能夠。由於 iOS app 在安裝的時候會把 Watch app 一樣編譯安裝,以後只要手動運行就能夠了。這樣就能夠避開問題一堆速度又慢的調試器鏈接過程。
在製做初版的時候,其實我對 PomoNow 在 Watch 上的體驗提出了諸多的「偉大構想」,如和 iPhone 計時同步、在 Watch 上添加任務等。但因爲 Apple Watch 的調試體驗實在是太糟糕,我不得不在把本身逼瘋以前放棄。並且無論是從保有量仍是從使用頻率上來講,Apple Watch 都不值得我花太多的精力去開發。因此在作了完成一次番茄的功能以後,我就沒有再添加新功能,並將其定義爲「實驗性」給一些比較愛用 Watch 的用戶嘗試。
今年 6 月 1 日,一位叫 madsights 的用戶在 Github 上給我發消息詢問關於不能自動計時以及長休息的問題。我真沒想到會有人在這個問題上反饋,這讓我從新把 Watch 版本的開發提上日程。
上文我已經講過,初版雖然能夠獨立計時,可是推送通知依然要由手機發送,獨立計時基本上沒有什麼意義。既然我須要一個完整的計時邏輯,爲何不把計時的部分所有放在手機上?因而第二版 PomoNow Watch 成爲了一個只有顯示做用的擴展。當你在 Watch 上啓動計時的時候,會喚醒 iOS 設備在後臺計時,這樣既解決了功能不完整的問題,也能夠直接實現 Watch 和 iPhone 計時同步。並且還很是簡單。
因而我在 6 月 19 日完成了新版本的製做。本覺得以後只要修一些小 bug 就沒事了,結果又遇到了新問題。
PomoNow 目前提供了四種語言的版本:簡體中文、繁體中文、English、日本語,在作本地化的時候我遇到了至關大的玄學問題,困擾了我很長時間。咱們知道,在 Xcode 中進行本地化主要是經過添加對應語言的翻譯文件,能夠手動輸入也能夠導入導出一個標準的交換格式。
問題是在我所有弄完以後發現的:Watch app 在全部語言的設備上都顯示日語(個人主語言是英語)。網上有些人這麼說:「這個問題是由於你本地的緩存,你上傳給蘋果的版本是什麼問題都不會有滴。」然而並非全部時候都是這樣。在我製做初版的過程當中,問題確實如他所描述,雖然在本地模擬器和設備中調試均只顯示中文,但上架以後就會恢復正常。到了作第二版的時候,事情就不同了。我像以前同樣弄好了全部本地化,雖然看到模擬器裏沒顯示英語,可是也沒怎麼當回事,直到有用戶反饋郵件告訴我。
7 月 19 日,一位叫 Clifford D'Souza 的用戶給我反饋郵件,指出 PomoNow 在他的 Watch 上顯示了一堆看不懂的日文。???我不是都已經弄好了嗎?說實話若是是一箇中文用戶顯示英語我卻是能夠理解,不就是本地化沒生效嘛,但是這日文是怎麼回事?我這會已經完全蒙了,我把整個工程翻了個底掉也沒有找到一處本身作錯的地方。
最後我實在是折騰累了,差很少當最後稻草同樣的刪掉了所有語言文件從頭來過。而後就。。。就解決了???WTF?好吧無論怎樣能用了就行,我因而儘快打包了新版本上傳。算是順利解決了問題。
可平靜的日子就過了幾天,在我又發佈了幾個版本以後問題再次出現。此次是在審覈階段被打回。蘋果的審覈員問我:「爲啥你這玩意在全部語言的設備上都顯示日文,請你解釋一下。」解釋一下?這明明是大家的 Bug 好吧爲毛要我解釋一下?我怎麼解釋啊?我只好又把工程翻了個底掉,並無什麼卵用。刪掉語言文件重作,也沒有什麼卵用。我這個時候已經想放棄了,實在不行我就不作 Watch app 了。
通過了士氣低落的一個下午以後,次日早上,我忽然想到了一個可能的解決方案。
通常來說,除 Storyboard 外,咱們是不須要提供未翻譯的語言文件的,由於在調用字符串的語句中就已經包含了未翻譯的字符串。一條典型的語句以下:(這個「Time to work!」就是原文。)
content.title = NSLocalizedString("Time to work!", comment: "Time to work!")
複製代碼
在分析以前的問題以後我發現,這個錯誤並不影響 Storyboard 的翻譯結果,這意味着什麼呢?剛纔咱們講到 Storyboard 包含了一個未翻譯的語言文件,是否是就是由於缺乏了這個文件才致使這些字符串顯示異常呢?在製做以前版本的時候,我就已經嘗試過添加未翻譯的語言文件,但當時並無起做用。不過已經到了這個份上了,試試就試試吧。
因而我添加了一個空的英文 Strings 文件,你們應該已經猜到發生什麼了。
到如今我也沒想通這是什麼毛病。在這個修復過的版本推送更新以前,我先讓 Junyi Lou 幫忙測試了一下以前的版本。使人驚奇的是,在他刷了 Beta 版系統的 Apple Watch 上本地化一切正常,我怕不是被蘋果坑了一波。
在踩了無數坑浪費了大量時間以後,我終於把這玩意搞出來了。我之因此想要堅持完成 Watch app,是由於我認爲運行在手錶上是番茄鍾這樣一個計時工具應該有的形態,而我以前所構思的「上發條」的交互也能夠在手錶上獲得很好的體現。
我不知道爲何沒聽別人提及過那些糟心的問題,是否是由於我建立工程的那個 Xcode 版本有 bug,仍是說這一切僅僅是由於個人 Watch 太卡了。無論怎麼樣,但願這篇文章中提到的解決方案可以對從此有跳坑意願的同窗有所幫助,再次感謝 格里芬顧 出給個人二手 Apple Watch 讓這個 Watch app 得以面世。若是你願意支持我,歡迎在 App Store 購買 PomoNow。 好了就說這麼多,我得去歇一會了。
PomoNow:AppStore
1. 本文內容爲做者在初代 Apple watch 上的我的開發體驗,不保證覆蓋所有其餘狀況。
2. 因爲商標權緣由,PomoNow 還沒有在美國和歐洲地區上架(整個 App 不能含有 Pomodoro 這個單詞或這個單詞的一部分),之後更名了可能會再上架。
3. 題圖是我實拍來搞笑的,我爲了拍這照片剁了兩個蘋果(一會還要吃掉)。但願沒有嚇到人(笑)。