Upgrade to Pro — share decks privately, control downloads, hide ads and more …

初代 SwiftUI 就用來寫 Watch App 吧!

Ethan Huang
September 21, 2019

初代 SwiftUI 就用來寫 Watch App 吧!

許多人對 SwiftUI 抱持高度興趣,想找機會來使用與學習。但是實際玩過以後會發現它的成熟度還不足以取代 UIKit,作為開發 iOS app 的主要 UI 框架。開發者普遍的共識是,在 iOS 13 使用 SwiftUI 的風險很大,用在 side project 或小型專案還可以,但不適用於商業上的應用。

難道 SwiftUI 就無用武之地嗎?2019 年第一版它只能當玩具嗎?其實 Apple 規劃出一個很不錯的路線,讓 SwiftUI 可以用在商業應用上,只是很容易被開發者忽略——watchOS 6 才是 SwiftUI 在今年發揮作用的平台。

watchOS 6 在開發方面有幾個特色:
1. 因為 Swift ABI 穩定,app 體積小,安裝到實機開發節省相當多時間
2. 可以使用 SwiftUI,不再受限 WKInterface
3. 可以獨立打包上架,不一定要有 iOS app
4. WKExtendedRuntimeSession 增加了好幾個應用情境

過去 watch app 很少人開發,很大的原因就是上述幾點困難尚未被克服。既然開發者大多都沒有寫過、甚或移除了原有的 watch app,watchOS 6 + SwiftUI 或許就是很好的重新來一次的機會,也可以想出許多 side project 的題目。

Ethan Huang

September 21, 2019
Tweet

More Decks by Ethan Huang

Other Decks in Programming

Transcript

  1. 初代 SwiftUI 就⽤來寫
    Watch App 吧!
    13 @ iPlayground19

    View Slide

  2. 我是 13
    • 任職於 CATCHPLAY

    • 獨立開發者,作品:
    NoteBox、Blahker、
    Ladybug、Knil...

    • Twitter: @ethanhuang13

    #iplayground #102

    • GitHub: ethanhuang13

    View Slide

  3. 先來個⼯商時間
    最近 side projects 太多

    View Slide

  4. CATCHPLAY

    View Slide

  5. weak self
    https://weakself.dev

    台灣唯⼀ iOS 開發 podcast

    View Slide

  6. «13的開發者週報»
    https://ethanhuang13.substack.com

    減低你的資訊焦慮

    Google Search “開發者週報”

    View Slide

  7. 本議程的 HackMD
    https://hackmd.io/@iPlayground/rJdZOKrSB

    View Slide

  8. 為什麼要講 watchOS

    View Slide

  9. 為什麼要講 watchOS
    因為想來玩 SwiftUI,但是 iOS 13 才能⽤

    View Slide

  10. 為什麼要講 watchOS
    之前沒有 Watch App,直接來⽤ watchOS 6

    View Slide

  11. 為什麼要講 watchOS
    據說 SwiftUI ⼀開始是為了 watchOS ⽽做,

    完成度應該比較⾼


    好天真

    View Slide

  12. 為什麼要講 watchOS
    現在寫 watch app 比以前更容易,

    對 iOS ⼯程師應該也不難吧


    長⼤了還是這麼天真

    View Slide

  13. 為什麼要講 watchOS
    我最喜歡去做沒⼈在研究的題⽬

    View Slide

  14. 需要先備知識
    • 有 Apple Watch 使⽤經驗

    • 這不是 SwiftUI 入⾨,

    ⾄少要玩過官⽅的 SwiftUI Tutorials

    View Slide

  15. 你會聽到什麼?
    ⽤ SwiftUI 做 Watch App

    會遇到的常⾒問題

    View Slide

  16. 你會聽到什麼?
    獨立的 Watch App 怎麼送審、上架

    View Slide

  17. 你會聽到什麼?
    幾個實驗性的 Watch Apps

    View Slide

  18. 你不會聽到什麼?
    畢竟我才玩三個禮拜

    View Slide

  19. 不會聽到什麼?
    • ⽤ WCSession 整合 iOS app

    • 多媒體

    • 串接網路或 iCloud

    • 怎麼靠寫 app 發⼤財

    View Slide

  20. 對⼯作的幫助 0%
    iPlayground 無⽤ session 系列

    View Slide

  21. 邊緣開發?
    tvOS

    View Slide

  22. 末梢開發!
    watchOS

    View Slide

  23. 如果不是你想聽的,
    可以去聽別的

    View Slide

  24. 2019 獨立 vs 統⼀
    你要選哪⼀個

    View Slide

  25. 以前只能統⼀⽤
    iOS + watchOS app

    View Slide

  26. 到最後往往變成
    「先做好 iOS app」

    View Slide

  27. 然後就沒有然後了

    View Slide

  28. watchOS 6
    可以做 獨立的 watch app

    View Slide

  29. watchOS 6
    UI framework ⽅⾯,SwiftUI 比 WatchKit 強⼤

    ⾃訂 UI 元件、⽅便更新畫⾯

    View Slide

  30. watchOS 6
    獨立上架到 Watch App Store

    雖然可能沒⼈會⽤

    View Slide

  31. watchOS 6
    獨立的 target 可以跟 iOS 分開安裝或移除

    View Slide

  32. watchOS
    歷年進化很⼤

    可⾒ iOSDC Japan 2019

    堤 修⼀ 的今こそwatchOS

    View Slide

  33. 基本架構
    • iOS App Target: 可割可棄

    • Watch App Target 放 Storyboard

    • WatchKit Extension Target 放 code

    • Complication 顯⽰在錶⾯

    • Notification 適時的個⼈化通知

    View Slide

  34. Storyboard
    Code, Complication, Notification

    View Slide

  35. Storyboard
    Code, Complication, Notification

    View Slide

  36. 怎樣建立獨立
    Watch App
    直接⽤官網的圖

    View Slide

  37. View Slide

  38. View Slide

  39. 獨立 Watch App
    怎麼送審與上架?

    View Slide

  40. App Store Connect
    • ⼀樣在 Developer Account 開新的 Bundle ID

    • ⼀樣在 App Store Connect 開新的 app,選 iOS

    • ⽤ Xcode 11 上傳 binary

    • 附上 watch app 截圖,但不⽤ iOS 的

    • 其他都⼀樣,定價、Pre-release、⾃動發布...

    View Slide

  41. iOS App 不在了嗎?
    • 獨立 watch app 其實藏了⼀個不會顯⽰在 iPhone 桌⾯跟系
    統設定的 iOS app

    • iOS app 與 watchOS 仍然是同⼀個 bundle ID prefix、同⼀
    個 binary

    • 如果將來要加上 iOS app,在 App Store 上是就會是同⼀個
    app

    View Slide

  42. TestFlight?
    • 發送流程、安裝流程,都跟
    iOS TestFlight 完全⼀樣。因為
    Apple Watch 上沒有 TestFlight
    app,所以你也只能⽤ iOS 來
    安裝

    • 獨立 watch app 的圖⽰會顯⽰
    圓形的版本。也會有⼩字標
    「Apple Watch 上」

    View Slide

  43. IAP?
    妹有~

    View Slide

  44. Watch App 的
    UX 設計

    View Slide

  45. 以秒為計的使⽤時間
    ⼿會痠
    ,不想等

    View Slide

  46. 能點兩下就不要點三下
    螢幕太⼩不好按

    View Slide

  47. 按鈕跟資訊不能多
    精簡、重點⼀眼就看懂

    View Slide

  48. 獨有的控制⽅式
    • Force Touch Menu

    • 觸覺回饋 Haptic Feedback

    • 數位錶冠 Digital Crown

    View Slide

  49. 不⽤⽀援 Dark Mode

    View Slide

  50. 其他我個⼈想法
    • 不要把 iOS app 搬到 watchOS,從頭開始想

    • 畫⾯能夠不要捲動就不要捲動

    • 但可以⽤ Digital Crown 來精準改變數值

    • ⽤ Paged Navigation,主畫⾯⼀⾴、設定畫⾯⼀⾴

    View Slide

  51. #我有⼀個⼤膽的想法

    View Slide

  52. App 1

    View Slide

  53. 想記錄喝了幾杯飲料

    View Slide

  54. DrinkBobo

    View Slide

  55. View Slide

  56. View Slide

  57. 在等珍珠奶茶的 Emoji
    ⽬前還不能上架

    View Slide

  58. ⼯程師是不是
    想得太複雜了

    View Slide

  59. DrinkBobo
    https://github.com/ethanhuang13/DrinkBobo

    如果 404 的話表⽰還沒上傳

    View Slide

  60. App 2

    View Slide

  61. 想要快速啟動世界迷霧

    View Slide

  62. View Slide

  63. 想要快速啟動世界迷霧
    • 走在路上突然想要記錄軌跡

    • ⼿機版:

    拿出⼿機 ➡
    解鎖 ➡
    找到 app ➡
    點開 等載入 點⼀下
    開始記錄 ➡
    上鎖 ➡
    收起⼿機

    • ⼿錶版:

    抬⼿ ➡
    點⼀下錶⾯進入 app ➡
    點⼀下開始記錄 放⼿

    View Slide

  64. 概念
    • 點⼀下開始記錄、再點⼀下結束

    • ⽤ CoreLocation 追蹤⼀系列座標

    • 儲存在 CloudKit(watchOS 沒有 iCloud Drive 與 iCloud
    Key-Value Store)

    • 輸出前,把經緯度與時間轉成 GPX(XML) 格式

    View Slide

  65. 這個還沒做完
    因為我懶得寫 iOS app...

    View Slide

  66. Defog 底法格
    https://github.com/ethanhuang13/Defog

    如果 404 的話表⽰還沒上傳

    View Slide

  67. App 3

    View Slide

  68. 番茄鐘計時器

    View Slide

  69. 番茄鐘⼯作法
    • The Pomodoro Technique

    • 安排要作的事情

    • 固定 25 分鐘為專注的時間單位

    • 設定倒數計時器,做事直到計時器響起

    • 記錄完成事項,辨別內外在⼲擾因素

    • 休息 5 分鐘後進⾏下⼀個...

    View Slide

  70. View Slide

  71. 爛⼤街題⽬

    View Slide

  72. Pineapple Timer

    View Slide

  73. ⼩巧思:旋轉錶冠來模擬轉緊番茄鐘

    View Slide

  74. Public TestFlight
    請⽤ iPhone 掃描

    View Slide

  75. Timer
    https://github.com/ethanhuang13/
    PineappleTimer

    View Slide

  76. App 4

    View Slide

  77. 會講話的鬧鐘

    View Slide

  78. 原始概念很善良
    • 利⽤字串搭配 AVSpeechSynthesizer(語⾳合成器)

    • 鬧鐘可以講話告訴我當天的天氣、有沒有下雨

    • ⾏事曆、會議

    • 提醒事項

    • 親友的⽣⽇

    View Slide

  79. 後來卻變成
    X提諾狂新聞

    View Slide

  80. 前⾝是失敗的 iOS 版
    如何在指定時間響起鬧鐘?

    View Slide

  81. 如何在指定時間
    響起鬧鐘?
    ⽅法 1 Local Notification

    View Slide


  82. 不能呼叫語⾳合成器

    View Slide

  83. 如何在指定時間
    響起鬧鐘?
    ⽅法 2 Push Notification

    View Slide


  84. 我⽣平知道最邪惡的 iOS 技巧

    View Slide


  85. 需要確保網路暢通

    View Slide

  86. 如何在指定時間
    響起鬧鐘?
    ⽅法3 Audio Session

    View Slide


  87. 開啟指定長度的錄⾳ session

    View Slide


  88. 有可能會被中斷、隱私問題

    View Slide


  89. 實⽤度也是個問題

    View Slide

  90. watchOS 6
    Extended Runtime: Smart Alarm


    View Slide

  91. 狂鬧鐘

    View Slide

  92. 百聞不如⼀⾒
    如果播⾳失敗的話

    請到這個連結

    View Slide

  93. 限制
    • Alarm 偶爾會失效


    • AVSpeechSynthesizer 只能講話 30 秒。我還在找⽅法

    • 規定要 call 震動 API。⼀開始會震動,講話完就不震動了

    View Slide

  94. 狂鬧鐘
    https://github.com/ethanhuang13/Crazy

    如果 404 的話表⽰還沒上傳

    View Slide

  95. 實際開發遇到的

    View Slide

  96. 新專案預設名稱是
    OOO WatchKit App
    • 在 WatchKit App 的 Info.plist 或 Targets General 把
    Display Name 改掉

    • 或是新增 InfoPlist.strings 再加上 CFBundleDisplayName
    的 key value

    • 注意 target 是 WatchKit App ⽽不是 WatchKit Extension

    View Slide

  97. ⼿錶⼀直戴在⼿上很⿇煩
    • 把 Pass Code 關掉

    • 放在充電座上

    • ⼿機還是要插線接 Xcode

    View Slide

  98. 不能同時跑兩個 Simulator?
    • 對... ⾄少 Xcode 11 GM 2 還是這樣

    • 有⼈知道怎麼解決的話請告訴我

    View Slide

  99. 安裝到實機裝不起來
    • 你不孤單

    • 檢查⼀下是不是有另外的 session 在跑

    • 其實它已經裝起來了,但是不會進入 debug session

    • 有⼈知道怎麼解決的話請告訴我

    View Slide

  100. 怎樣同時 Preview 多個裝置
    • 裝置名稱的字串規格在此

    View Slide

  101. 怎樣同時 Preview 多個裝置

    View Slide

  102. PreviewProvider
    怎麼傳入 @Binding
    • 可以⽤ .constant(Value)

    • 不過在 Preview 裡它的值就不會有變化

    View Slide

  103. WKHostingViewController
    要怎麼加 environmentObject
    • 因為 Type 會不⼀樣

    • ⽤ AnyView() 包起來

    • 但是據說⽤ type eraser 效能會差,盡量避免

    View Slide

  104. WKHostingViewController
    要怎麼加 environmentObject
    • 那就再包⼀層就好

    View Slide

  105. 怎麼做 Paged Navigation?
    • 左右滑動換⾴

    • SwiftUI 沒有直接⽀援的⽅法

    • 可以⽤ WatchKit 本來的作法,也就是在 Storyboard 裡⾯
    拉 next page 的 segue

    • ⽤ HostingController 的 didAppear() 來判斷⽬前畫⾯

    View Slide

  106. View Slide

  107. 狀態機
    • 以往我們會⽤ enum 來表⽰狀態,以狂鬧鐘為例,就是
    「未設定鬧鐘」、「已設定鬧鐘」、「鈴響中」三種狀態

    • SwiftUI 的 View 採⽤的 function builder 還是半殘狀態,

    只⽀援 if,不⽀援 switch case

    • 所以就是各種 if else,⾃⼰⼩⼼

    View Slide

  108. 怎麼做圓形的圖案
    • .clipShape(Circle())

    • 其他形狀同理

    View Slide

  109. List 怎麼改背景顏⾊
    • iOS 在⽤的 listRowBackground(_:) 沒有作⽤,

    watchOS 要⽤ listRowPlatterColor

    • 直接⽤ List() 的話不起作⽤


    • 要寫成這樣才⾏

    View Slide

  110. 並排的東⻄⽤ List
    會變成共⽤背景
    • watchOS 的 List 應該是⽤ WatchKit 原⽣的

    • 暫時只能⽤ ScrollView + HStack

    View Slide

  111. @Binding 不能⽤在 collection
    • Beta 7 之後改掉了...

    • Release notes: 51624798

    • 直接照抄程式碼

    View Slide

  112. View Slide

  113. View Slide

  114. View Slide

  115. Context Menu
    • SwiftUI Preview 不⽀援

    • ⽤ Simulator 要注意 Hardware ➡
    Touch Pressure 是
    Shallow or Deep

    View Slide

  116. Haptic Feedback
    • 沿⽤ WatchKit 的 API

    View Slide

  117. SwiftUI 常⽤快速鍵
    • 繼續跑 Preview: Cmd + Opt + P

    • 叫出選單 Cmd + Shift + L

    View Slide

  118. SwiftUI 常⽤快速鍵
    • 打開 Preview:Cmd + Opt + Enter

    • 關閉 Preview:Cmd + Enter

    View Slide

  119. 單元測試?
    • watchOS 根本沒有 test target 可以建立

    • 就算開 watchOS framework 也是沒有

    • 這個時候可以考慮開個 Swift Package

    • CI 什麼的可以順理成章不做(誤)

    View Slide

  120. Digital Crown API
    • 先幫 View 加上 .focusable(_:onFocusChange:)

    • 再加上 

    .digitalCrownRotation(_:from:through:by:sensitivity:isConti
    nuous:isHapticFeedbackEnabled:)

    View Slide

  121. View Slide

  122. 怎麼在左上⾓顯⽰標題
    • watchOS 的 SwiftUI 沒有 NavigationView

    • 但是還是可以直接設定 .navigationBarTitle(" Timer")

    • 剛進 app 常常壞掉

    View Slide

  123. 要注意錶冠⽅向
    • 系統設定可以改錶冠⽅向,API 是 WKInterfaceDevice 的
    crownOrientation(感謝 @klandortw 測試與回報問題)

    • 但是模擬器是壞的

    View Slide

  124. Complications
    「複雜功能」

    View Slide

  125. Complications
    官⽅ HIG 不好讀,看 cheat sheet 比較快

    View Slide

  126. View Slide

  127. View Slide

  128. View Slide

  129. 怎麼更新 Complication
    • ClockKit API 有更新次數限制,每個 app 每⽇的呼叫上限是 50 次

    • Apple 希望你⼀次提供⼀系列針對不同時間的 complications,⽽
    不是每隔幾分鐘呼叫系統來更新⼀次

    • watchOS 6 也可以⽤ PushKit

    • 使⽤ CLKRelativeDateTextProvider 來做計時或倒數

    • 舊錶⾯在⽤的 RingText 不⽀援每秒的更新

    • 新錶⾯在⽤的 GaugeProvider ⽀援每秒的更新

    View Slide

  130. Complication Time Travel?
    • 其實這功能在 watchOS 5 已經砍掉了,

    但沒有標 deprecated


    • getSupportedTimeTravelDirections() 還是要放個空的

    View Slide

  131. 程式碼架構
    • 我書讀得少,不懂架構


    • 不過我幾乎都可以⽤⼀個 ObservableObject 作為 user
    data/state 的 singleton 來解決

    • SwiftUI 的部分,乖乖從 HostingController
    丟 .environmentObject() 進去

    • 其他地⽅則直接使⽤同⼀個 singleton(例如
    ExtensionDelegate or ComplicationController)

    View Slide

  132. Code 寫得不好
    但是我都會開源

    View Slide

  133. ⼼靈雞湯配⼤餅

    View Slide

  134. ⼀起來寫 Watch App?
    • iOS ⼯程師的盲點?Apple Watch 能做的事真的很少嗎?還
    是我們想得太多

    • Apple 平台還有很多,iOS ⼯程師可以嘗試把技能遷移過去

    • 做這種很少資源可以查詢,要⾃⼰摸索的⼩題⽬⼩產品,
    很有回到初⼼的感覺

    View Slide

  135. ⼀起來寫 Watch App?
    • 不要想得太複雜

    • 兩天就可以做完的 side project

    • 伸⼿下去做了才會有 fu

    View Slide

  136. #我有⼀個⼤膽的想法

    View Slide

  137. #我有⼀個⼤膽的想法

    View Slide

  138. Just Do It.

    View Slide

  139. 謝謝
    請不吝指教

    View Slide

  140. Reference
    • Creating a watchOS App with SwiftUI (sample code)

    • Creating Independent Watch Apps (WWDC19, 208)

    • SwiftUI on watchOS (WWDC19, 219)

    • Extended Runtime for watchOS Apps (WWDC19, 251)

    • Exploring Tinted Graphic Complications (WWDC19, 253)

    • Streaming Audio on watchOS 6 (WWDC19, 716)

    • Building Activity Classification Models in Create ML (WWDC19,
    426)

    View Slide