自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Apple WatchKit 初探

移動開發(fā) iOS
隨著 Apple 發(fā)布了第一版的 Watch Kit 的 API,對于開發(fā)者來說,這款新設(shè)備的一些更詳細(xì)的信息也算是逐漸浮出水面??梢哉f第一版的 WatchKit 開放的功能總體還是令人滿意的。Apple 在承諾逐漸開放的方向上繼續(xù)前進。

[[126586]]

隨著 Apple 發(fā)布了***版的 Watch Kit 的 API,對于開發(fā)者來說,這款新設(shè)備的一些更詳細(xì)的信息也算是逐漸浮出水面??梢哉f***版的 WatchKit 開放的功能總體還是令人滿意的。Apple 在承諾逐漸開放的方向上繼續(xù)前進。本來在 WWDC 之后預(yù)期 Today Widget 會是各類新穎 app 的舞臺以及對 iOS 功能的極大擴展,但是隨著像 Launcher 和 PCalc 這些創(chuàng)意型的 Today Widget 接連被下架事件,讓開發(fā)者也不得不下調(diào)對 WatchKit 的預(yù)期。但是至少從現(xiàn)在的資料來看,WatchKit 是允許進行復(fù)雜交互以及完成一些獨立功能的。雖然需要依托于 iPhone app,但是至少能夠發(fā)揮的舞臺和空間要比我原先想象的大不少。

當(dāng)然,因為設(shè)備本身的無論是電量還是運算能力的限制,在進行 Watch app 開發(fā)的時候也還是有很多掣肘?,F(xiàn)在 Watch app 僅僅只是作為視圖顯示和回傳用戶交互的存在,但是考慮到這是這款設(shè)備的***版 SDK,另外 Apple 也有承諾之后會允許真正運行在 Watch 上的 app 的出現(xiàn),Apple Watch 和 WatchKit 的未來還是很值得期待的。

廢話不再多,我們來簡單看看 WatchKit 的一些基本信息吧。

我們能做什么

Watch app 架構(gòu)

首先需要明確的是,在 iOS 系統(tǒng)上,app 本體是核心。所有的運行實體都是依托在本體上的:在 iOS 8 之前這是毋庸置疑的,而在 iOS 8 中添加的各種 Extension 也必須隨同 app 本體捆綁,作為 app 的功能的補充。Watch app 雖然也類似于此,我們要針對 Apple Watch 進行開發(fā),首先還是需要建立一個傳統(tǒng)的 iOS app,然后在其中添加 Watch App 的 target。在添加之后,會發(fā)現(xiàn)項目中多出兩個 target:其中一個是 WatchKit 的擴展,另一個是 Watch App。在項目相應(yīng)的 group 下可以看到,WatchKit Extension 中含有代碼 (InterfaceController.h/m 等),而 Watch App 里只包含了 Interface.storyboard?,F(xiàn)在暫時看來 Watch App 依然是傳統(tǒng) iOS 設(shè)備 app 的擴展和衍生,Apple 估計會采取和 Extension 同樣的態(tài)度來對待 Watch Kit。而原生可以直接運行在手表上的 app 有消息說 2015 年中后期才可能被允許。

在應(yīng)用安裝時,負(fù)責(zé)邏輯部分的 WatchKit Extension 將隨 iOS app 的主 target 被一同安裝到 iPhone 中,而負(fù)責(zé)界面部分的 WatchKit App 將會在主程序安裝后由 iPhone 檢測有沒有配對的 Apple Watch,并提示安裝到 Apple Watch 中。所以在實際使用時,所有的運算、邏輯以及控制實際上都是在 iPhone 中完成的。在需要界面刷新時,由 iPhone 向 Watch 發(fā)送指令進行描畫并在手表盤面上顯示。反過來,用戶觸摸手表交互時的信息也由手表傳回給 iPhone 并進行處理。而這個過程 WatchKit 會在幕后為我們完成,并不需要開發(fā)者操心。我們需要知道的就是,原則上來說,我們應(yīng)該將界面相關(guān)的內(nèi)容放在 Watch App 的 target 中,而將所有代碼邏輯等放到 Extension 里。

在手表上點擊 app 圖標(biāo)運行 Watch App 時,手表將會負(fù)責(zé)喚醒手機上的 WatchKit Extension。而 WatchKit Extension 和 iOS app 之間的數(shù)據(jù)交互需求則由 App Groups 來完成,這和 Today Widget 以及其他一些 Extension 是一樣的。如果你還沒有了解過相關(guān)內(nèi)容,可以參看我之前寫過的一篇 Today Extension 的教程。

主要類

WKInterfaceController 和生命周期

WKInterfaceController 是 WatchKit 中的 UIViewController 一樣的存在,也會是開發(fā) Watch App 時花時間最多的類。每個 WKInterfaceController 或者其子類應(yīng)該對應(yīng)手表上的一個整屏內(nèi)容。但是需要記住整個 WatchKit 是獨立于 UIKit 而存在的,WKInterfaceController 是一個直接繼承自 NSObject 的類,并沒有像 UIKit 中 UIResponser 那樣的對用戶交互的響應(yīng)功能和完備的回調(diào)。

不僅在功能上相對 UIViewController 簡單很多,在生命周期上也進行了大幅簡化。每個 WKInterfaceController 對象必然會被調(diào)用的生命周期方法有三個,分別是該對象被初始化時的 -initWithContext:,將要呈現(xiàn)時的 -willActivate 以及呈現(xiàn)結(jié)束后的 -didDeactivate。同樣類比 UIViewController 的話,可以將它們理解為分別對應(yīng) -viewDidLoad,viewWillAppear: 以及 -viewDidDisappear:。雖然看方法名和實際使用上可能你會認(rèn)為 -initWithContext: 應(yīng)該對應(yīng) UIViewController 的 init 或者 initWithCoder: 這樣的方法,但是事實上在 -initWithContext: 時 WKInterfaceController 中的“視圖元素” (請注意這里我加上了引號,因為它們不是真正的視圖,稍后會再說明) 都已經(jīng)初始化完畢可用,這其實和 -viewDidLoad 中的行為更加相似。

我們一般在 -initWithContext: 和 -willActivate 中配置“視圖元素”的屬性,在 -didDeactivate 中停用像是 NSTimer 之類的會 hold 住 self 的對象。需要特別注意的是,在 -didDeactivate 中對“視圖元素”屬性進行設(shè)置是無效的,因為當(dāng)前的 WKInterfaceController 已經(jīng)非活躍。

WKInterfaceObject 及其子類

WKInterfaceObject 負(fù)責(zé)具體的界面元素設(shè)置,包括像是 WKInterfaceButton,WKInterfaceLabel 或 WKInterfaceImage 這類物件,也就是我們上面所提到的“視圖元素”??赡芤婚_始會產(chǎn)生錯覺,覺得 WKInterfaceObject 應(yīng)該對應(yīng) UIView,但其實上并非如此。WKInterfaceObject 只是 WatchKit 的實際的 View 的一個在 Watch Extension 端的代理,而非 View 本身。Watch App 中實際展現(xiàn)和渲染在屏幕上的 view 對于代碼來說是非直接可見的,我們只能在 Extension target 中通過對應(yīng)的代理對象對屬性進行設(shè)置,然后在每個 run loop 需要刷新 UI 時由 WatchKit 將新的屬性值從手機中傳遞給手表中的 Watch App 并進行界面刷新。

反過來,手表中的實際的 view 想要將用戶交互事件傳遞給 iPhone 也需要通過 WKInterfaceObject 代理進行。每個可交互的 WKInterfaceObject 子類都對應(yīng)了一個 action,比如 button 對應(yīng)點擊事件,switch 對應(yīng)開或者關(guān)的狀態(tài),slider 對應(yīng)一個浮點數(shù)值表明選取值等等。關(guān)聯(lián)這些事件也很簡單,直接從 StoryBoard 文件中 Ctrl 拖拽到實現(xiàn)中就能生成對應(yīng)的事件了。雖然 UI 資源文件和代碼實現(xiàn)是在不同的 target 中的,但是在 Xcode 中的協(xié)作已然天衣無縫。

Watch App 采取的布局方式和 iOS app 完全不同。你無法自由指定某個視圖的具體坐標(biāo),當(dāng)然也不能使用像 AutoLayout 或者 Size Classes 這樣的靈活的界面布局方案。WatchKit 提供的布局可能性和靈活性相對較小,你只能在以“行”為基本單位的同時通過 group 來在行內(nèi)進行“列”布局。這帶來了相對簡單的布局實現(xiàn),當(dāng)然,同時也是對界面交互的設(shè)計的一種挑戰(zhàn)。

另外值得一提的是,隨著 WatchKit 的出現(xiàn)及其開發(fā)方式的轉(zhuǎn)變,代碼寫 UI 還是使用 StoryBoard 這個爭論了多年的話題可以暫時落下帷幕了。針對 Watch 的開發(fā)不能使用代碼的方式。首先,所有的 WKInterfaceObject 對象都必須要設(shè)計的時候經(jīng)由 StoryBoard 進行添加,運行時我們無法再向界面上添加或者移除元素 (如果有移除需要的,可以使用隱藏);其次 WKInterfaceObject 與布局相關(guān)的某些屬性,比如行高行數(shù)等,不能夠在運行時進行變更和設(shè)定?;緛碚f在運行時我們只能夠改變視圖的內(nèi)容,以及通過隱藏某些視圖元素來達(dá)到有限地改變布局 (其他視圖元素會試圖填充被隱藏的元素)。

總之,代碼進行 UI 編寫的傳統(tǒng),在 Apple 的不斷努力下,于 WatchKit 發(fā)布的今天,被正式宣判了死刑。

Table 和 Context Menu

大部分 WKInterfaceObject 子類都很直接簡單,但是有兩個我想要單獨說一說,那就是 WKInterfaceTable 和 WKInterfaceMenu。UITableView 大家都很熟悉了,在 WatchKit 中的 WKInterfaceTable 雖然也是用來展示一組數(shù)據(jù),但是因為 WatchKit API 的數(shù)據(jù)傳輸?shù)奶攸c,使用上相較 UITableView 有很大不同和簡化。首先不存在 DataSource 和 Delegate,WKInterfaceTable 中需要呈現(xiàn)的數(shù)據(jù)數(shù)量直接由其實例方法 -setNumberOfRows:withRowType: 進行設(shè)定。在進行設(shè)定后,使用 -rowControllerAtIndex: 枚舉所有的 rowController 進行設(shè)定。這里的 rowController 是在 StoryBoard 中所設(shè)定的相當(dāng)于 UITableViewCell 的東西,只不過和其他 WKInterfaceObject 一樣,它是直接繼承自 NSObject 的。你可以通過自定義 rowController 并連接 StoryBoard 的元素,并在取得 rowController 對其進行設(shè)定,即可完成 table 的顯示。代碼大概是這樣的:

  1. //  MyRowController.swift 
  2. import Foundation   
  3. import WatchKit 
  4.  
  5. class MyRowController: NSObject {   
  6.     @IBOutlet weak var label: WKInterfaceLabel! 
  7.  
  8. //  InterfaceController.swift 
  9. import WatchKit   
  10. import Foundation 
  11.  
  12. class InterfaceController: WKInterfaceController { 
  13.  
  14.     @IBOutlet weak var table: WKInterfaceTable! 
  15.     let data = ["Index 0","Index 1","Index 2"
  16.  
  17.     override init(context: AnyObject?) { 
  18.         // Initialize variables here. 
  19.         super.init(context: context) 
  20.  
  21.         // Configure interface objects here. 
  22.         NSLog("%@ init", self) 
  23.  
  24.         // 注意需要在 StoryBoard 中設(shè)置 myRowControllerType 
  25.         // 類似 cell 的 reuse id 
  26.         table.setNumberOfRows(data.count, withRowType: "myRowControllerType"
  27.         for (i, value) in enumerate(data) { 
  28.             if let rowController = table.rowControllerAtIndex(i) as? MyRowController { 
  29.                 rowController.label.setText(value) 
  30.             } 
  31.         } 
  32.     } 

對于點擊事件,并沒有一個實際的 delegate 存在,而是類似于其他 WKInterfaceObject 那樣通過 action 將點擊了哪個 row 作為參數(shù)發(fā)送回 WKInterfaceController 進行處理。

另一個比較好玩的是 Context Menu,這是 WatchKit 獨有的交互,在 iOS 中并不存在。在任意一個 WKInterfaceController 界面中,長按手表屏幕,如果當(dāng)前 WKInterfaceController 中存在上下文菜單的話,就會嘗試呼出找這個界面對應(yīng)的 Context Menu。這個菜單最多可以提供四個按鈕,用來針對當(dāng)前環(huán)境向用戶征詢操作。因為手表屏幕有限,在信息顯示的同時再放一些交互按鈕是挺不現(xiàn)實的一件事情, 也會很丑。而上下文菜單很好地解決了這個問題,相信長按呼出交互菜單這個操作會成為今后 Watch App 的一個很標(biāo)準(zhǔn)的交互操作。

添加 Context Menu 非常簡單,在 StoryBoard 里向 WKInterfaceController 中添加一個 Menu,并在這個 Menu 里添加對應(yīng)的 MenuItem 就行了。在 WKInterfaceController 我們也有對應(yīng)的 API 來在運行時根據(jù)上下文環(huán)境進行 MenuItem 的添加 (這是少數(shù)幾個允許我們在運行時添加元素的方法之一)。

  1. -addMenuItemWithItemIcon:title:action: 
  2. -addMenuItemWithImageNamed:title:action: 
  3. -addMenuItemWithImage:title:action: 
  4. -clearAllMenuItems 

但是 Menu 和 MenuItem 對應(yīng)的類 WKInterfaceMenu 和 WKInterfaceMenuItem 我們是沒有辦法拿到的。沒錯,它們甚至都沒有存在于文檔里 :(

基礎(chǔ)導(dǎo)航

WKInterfaceController 的內(nèi)建的導(dǎo)航關(guān)系基本上分為三類。首先是像 UINavigationController 控制的類似棧的導(dǎo)航方式。相關(guān)的 API 有 -pushControllerWithName:context:,-popController 以及 -popToRootController。后兩個我想不必太多解釋,對于***個方法,我們需要使用目標(biāo) controller 的 Identifier 字符串 (沒有你只能在 StoryBoard 里進行設(shè)置) 進行創(chuàng)建。context 參數(shù)也會被傳遞到目標(biāo) controller 的 -initWithContext: 中,所以你可以以此來在 controller 中進行數(shù)據(jù)傳遞。

另一種是我們大家熟悉的 modal 形式,對應(yīng) API 是 -presentControllerWithName:context: 和 -dismissController。對于這種導(dǎo)航,和 UIKit 中的不同之處就是在目標(biāo) controller 中會默認(rèn)在左上角加上一個 Cancel 按鈕,點擊的話會直接關(guān)閉被 present 的 controller。我只想說 Apple 終于想通了,每個 modal 出來的 controller 都是需要關(guān)閉的這個事實...

***一種導(dǎo)航方式是類似 UIPageController 的分頁式導(dǎo)航。在 iOS app 中,在應(yīng)用***次開始時的教學(xué)模塊中這種導(dǎo)航方式非常常見,而在 WatchKit 里可以說得到了發(fā)揚光大。事實上我個人也認(rèn)為這會是 WatchKit 里***使用習(xí)慣的導(dǎo)航方式。在 WatchKit 上的 page 導(dǎo)航可能會和 iOS app 的 Tab 導(dǎo)航所提供的功能相對應(yīng)。

在實現(xiàn)上,page 導(dǎo)航需要在 StoryBoard 中用 segue 的方式將不同 page 進行連接,新添加的 next page segue 就是干這個的:

另外 modal 導(dǎo)航的另一個 API -presentControllerWithNames:contexts: 接受復(fù)數(shù)個的 names 和 context,通過這種方式 modal 呼出的復(fù)數(shù)個 Controller 也將以 page 導(dǎo)航方式呈現(xiàn)。

當(dāng)然,作為 StoryBoard 的經(jīng)典使用方式,modal 和 push 的導(dǎo)航方式也是可以在 StoryBoard 中通過 segue 來實現(xiàn)的。同時 WatchKit 也為 segue 的方式提供了必要的 API。

一些界面實踐

因為整個架構(gòu)和 UIKit 完全不同,所以很多之前的實踐是無法直接搬到 WatchKit App 中的。

圖像處理

在 UIKit 中我們顯示圖片一般使用 UIImageView,然后為其 image 屬性設(shè)置一個創(chuàng)建好的 UIImage 對象。而對于 WatchKit 來說,***實踐是將圖片存放在 Watch App 的 target 中 (也就是 StoryBoard 的那個 target),在對 WKInterfaceImage 進行圖像設(shè)置時,盡量使用它的 -setImageNamed: 方法。這個方法將只會把圖像名字通過手機傳遞到手表,然后由手表在自己的 bundle 中尋找圖片并加載,是最快的途徑。注意我們的代碼是運行在于手表的 Watch App 不同的設(shè)備上的,雖然我們也可以先通過 UIImage 的相關(guān)方法生成 UIImage 對象,然后再用 -setImage: 或者 -setImageData: 來設(shè)置手表上的圖片,但是這樣的話我們就需要將圖片放到 Extension 的 target 中,并且需要將圖片的數(shù)據(jù)通過藍(lán)牙傳到手表,一般來說這會造成不可忽視的延遲,會很影響體驗。

如果對于某些情況下,我們只能在 Extension 的 target 中獲得圖片 (比如從網(wǎng)絡(luò)下載或者代碼動態(tài)生成等),并且需要重復(fù)使用的話,***用 WKInterfaceDevice 的 -addCachedImage:name: 方法將其緩存到手表中。這樣,當(dāng)我們之后再使用這張圖片的時候就可以直接通過 -setImageNamed: 來快速地從手表上生成并使用了。每個 app 的 cache 的尺寸大約是 20M,超過的話 WatchKit 將會從最老的數(shù)據(jù)開始刪除,以騰出空間存儲新的數(shù)據(jù)。

動畫

因為無法拿到實際的視圖元素,只有 WKInterfaceObject 這樣的代理對象,以及布局系統(tǒng)的限制,所以復(fù)雜的動畫,尤其是 UIView 系列或者是 CALayer 系列的動畫是無法實現(xiàn)的。現(xiàn)在看來唯一可行的是幀動畫,通過為 WKInterfaceImage 設(shè)置包含多個 image 的圖像,或者是通過計時器定時替換圖像的話,可以實現(xiàn)幀動畫。雖然 Apple 自己的例子也通過這種方法實現(xiàn)了動畫,但是對于設(shè)備的存儲空間和能耗都可能會是挑戰(zhàn),還需要實際拿到設(shè)備以后進行實驗和觀察。

其他 Cocoa Touch 框架的使用

Apple 建議***不要使用那些需要 prompt 用戶許可的特性,比如 CoreLocation 定位等。因為實際的代碼是在手機上運行的,這類許可也會在手機上彈出,但是用戶并不一定正好在看手機,所以很可能造成體驗下降。另外大部分后臺運行權(quán)限也是不建議的。

對于要獲取這些數(shù)據(jù)和權(quán)限,Apple 建議還是在 iOS app 中完成,并通過 App Groups 進行數(shù)據(jù)共享,從而在 Watch Extension 中拿到這些數(shù)據(jù)。

代碼分享

因為現(xiàn)在一個項目會有很多不同的 target,所以使用 framework 的方式封裝不同 target 的公用部分的代碼,而只在各 target 中實現(xiàn)界面相關(guān)的代碼應(yīng)該是必行的了。這么做的優(yōu)點不僅是可以減少代碼重復(fù),也會使代碼測試和品質(zhì)得到提升。如果還沒有進行邏輯部分的框架化和測試分離的 話,在實現(xiàn)像各類 Extension 或者 Watch App 時可能會遇到非常多的麻煩。

因為如果原有 app 有計劃進行擴展推出各種 Extension 的話,將邏輯代碼抽離并封裝為 framework 應(yīng)該是優(yōu)先級***的工作。另外新開的項目如果沒有特殊原因,也強烈建議使用 framework 來組織通用代碼。

Glance 和 Notification

除了 Watch App 本體以外,Glance 和手表的 Notification 也是重要的使用情景。Notification 雖然概念上比較簡單,但是相對于 iOS 的通知來說是天差地別。WatchKit 的通知允許開發(fā)者自行構(gòu)建界面,我們可以通過 payload 設(shè)置比較復(fù)雜和帶有更多信息的通知,包括圖像,大段文字甚至可以交互的按鈕,而不是像 iOS 上那樣被限制在文字和一個對話框內(nèi)。首先無論是通過 Local 還是 Remote 進行的通知發(fā)送會先到達(dá) iPhone,然后再由 iPhone 根據(jù)內(nèi)容判斷是否轉(zhuǎn)發(fā)到手表。WatchKit App 接收到通知后先會顯示一個簡短的通知,告訴用戶這個 app 有一個通知。如果用戶對通知的內(nèi)容感興趣的話,可以點擊或者抬手觀看,這樣由開發(fā)者自定義的長版本的通知就會顯現(xiàn)。

Glance 是 WatchKit 的新概念,它允許 Watch App 展示一個布局固定的 WKInterfaceController 頁面。它和 Watch App 本體相對地位相當(dāng)于 iOS 上的 Today Widget 和 iOS app 本身的地位,是作為手表上的 app 的最重要的信息展示出現(xiàn)的。Glance 正如其名,是短時存在的提醒,不能存在可交互的元素。不過如果用戶點擊 Glance 頁面的話,是可以啟動到 Watch App 的?,F(xiàn)在關(guān)于 Glance 本身如何啟動和呈現(xiàn)還不是很明確,猜測是某種類似 Today Widget 的呈現(xiàn)方式?(比如按下兩次表側(cè)面的旋鈕)

疑問和改進方向

WatchKit 總體令人滿意,提供的 API 和開發(fā)環(huán)境已經(jīng)足夠開發(fā)者作出一些有趣的東西。但是有幾個現(xiàn)在看來很明顯的限制和希望能加強的方向。

首先是從現(xiàn)在來看 WatchKit 并沒有提供任何獲取設(shè)備傳感信息的 API。不論是心跳、計步或者是用戶是否正在佩戴 Watch 的信息我們都是拿不到的,這限制了很多數(shù)據(jù)收集和監(jiān)視的健康類 app 的制作。如果希望請求數(shù)據(jù),還是不得不轉(zhuǎn)向使用 HealthKit。但是隨著 iPhone 6 和 6s 的大屏化,在運動時攜帶 iPhone 的人可以說是變少了。如果 Watch 不能在沒有 iPhone 配對的情況下收集記錄,并在之后和 iPhone 連接后將數(shù)據(jù)回傳的話,那 Apple 的健康牌就失敗了一大半。相信 Apple 不會放過這種把用戶捆綁的機會...不過如果第三方應(yīng)用能實時獲取用戶的佩戴狀況的話,相信會有很多有意思的應(yīng)用出現(xiàn)。

另外作為在發(fā)布會上鼓吹的交互革命的旋鈕和觸感屏幕,現(xiàn)在看來并沒有開放任何 API 供開發(fā)者使用,所以我們無法得知用戶旋轉(zhuǎn)了手表旋鈕這個重要的交互事件。現(xiàn)在看來我們能獲取的操作僅只是用戶點擊屏幕上的按鈕或者拖動滑條這個層級,從這 個角度來說,現(xiàn)在的 WatchKit 還遠(yuǎn)沒達(dá)到可以顛覆移動應(yīng)用的地步。

希望之后 Apple 會給我們帶來其他的好消息吧。

總之,舞臺已經(jīng)搭好,之后唱什么戲,就要看我們的了。

責(zé)任編輯:閆佳明 來源: onevcat.com
相關(guān)推薦

2014-11-20 15:44:40

Apple Watch

2015-05-25 10:01:17

WatchKitAPP

2014-11-20 16:02:22

WatchKit

2015-10-21 13:57:09

WatchKit 要點開發(fā)

2015-07-20 09:16:42

iOSWatchKit開發(fā)

2015-08-13 10:15:02

WatchKitHealthKitApplePay

2015-04-14 09:33:17

WatchKitAPP

2015-06-30 10:48:41

iOSAPPwarchkit

2010-06-03 12:57:06

Hadoop

2009-06-24 13:22:27

Glassfish

2016-10-11 13:48:41

WebGLJavascriptWeb

2015-03-10 09:35:53

AppleWatch開發(fā)Swift

2015-03-24 19:48:24

2012-02-29 15:03:30

2011-04-18 09:53:08

Ruby

2011-05-17 14:11:06

Dijkstra

2014-12-23 09:39:41

Apple Watch

2010-09-08 17:26:46

JavaScript

2011-06-16 10:25:29

AndroidAIR

2017-05-29 08:18:11

Serverless架構(gòu)軟件系統(tǒng)
點贊
收藏

51CTO技術(shù)棧公眾號