走進 WatchKit Framework


寫在前面

WatchKit Apple提供的開發專題頁面如下:https://developer.apple.com/watchkit/。 其中包含兩個Demo,這兩個Demo可以讓大家快速的瞭解WatchKit的構建。

Watch App Architecture

每一個Apple Watch App和 iOS Extension一樣仍然需要依賴一個主體App,Apple Watch App 包含兩個部分:Watch App 和 WatchKit Extension,如下圖:


其中 Watch App 部分位於用戶的Apple Watch上,它目前爲止只允許包含Storyboard文件和Resources文件。在我們的項目裏,這一部分不包括任何代碼。

WatchKit Extension 部分位於用戶的iPhone安裝的對應App上,這裏包括我們需要實現的代碼邏輯和其他資源文件。

這兩個部分之間就是通過 WatchKit進行連接通訊。

WatchKit

WatchKit用來爲開發者構建Apple Watch App。它所有的類如下,其中最上層的類繼承於NSObject。


WKInterfaceController
   WKUserNotificationInterfaceController
WKInterfaceDevice
WKInterfaceObject
   WKInterfaceButton
   WKInterfaceDate
   WKInterfaceGroup
   WKInterfaceImage
   WKInterfaceLabel
   WKInterfaceMap
   WKInterfaceSeparator
   WKInterfaceSlider
   WKInterfaceSwitch
   WKInterfaceTable
   WKInterfaceTimer
WKInterfaceController


WKInterfaceController是我們開發Watch App的核心類,它的地位和之前使用的UIViewController一樣。

每一個Watch App構建時,至少需要在Storyboard上設置一個WKInterfaceController實例作爲程序入口。我們可以在Storyboard上使用Main Entry Point設置。

當用戶launch了Watch App時,Watch OS 會開始加載程序中的Storyboard。我們在Storyboard中爲每一個WKInterfaceController設置的響應事件,會在用戶觸發時在WatchKit Extension中響應。我們可以像以前一樣push, pop, present 目標WKInterfaceController。

生命週期

WKInterfaceController一樣也有自己的生命週期,以下幾個API對應了幾個不同的狀態:


- (instancetype)initWithContext:(id)context;(void)willActivate;(void)didDeactivate;

當Watch OS加載App中的Storyboard時,iPhone端也會開始加載對應的WatchKit Extension。


當Watch OS開始初始化我們Watch App的Storyboard中的UI時,iPhone端WatchKit Extension會生成對應的WKInterfaceController,並且響應initWithContext:方法。

當Watch OS顯示當前加載的UI時,WatchKit Extension中對應的WKInterfaceController響應willActivate方法。

當用戶切換頁面或者停止使用時,WatchKit Extension中對應的WKInterfaceController響應didDeactivate方法。


從上圖可知這三個API,對應了Watch OS加載一個視圖控制器的三個狀態。我們在自己的WKInterfaceController類中,應該實現這三個API用來處理不同的情況:

  • initWithContext: 我們可以在這裏加載數據或者更新在StoryBoard中當前Controller添加的interface objects。

  • willActivate 我們可以在這裏更新interface objects或者處理其他事件

  • didDeactivate 我們應該在這裏清理task或者數據。在這裏更新interface objects將會被系統忽略。

頁面跳轉

當用戶和我們的APP進行交互時,有很多時候,我們需要進行頁面的跳轉。WKInterfaceController目前支持兩組API進行頁面跳轉:


(void)pushControllerWithName:(NSString *)name context:(id)context(void)popController;(void)popToRootController;(void)presentControllerWithName:(NSString *)name context:(id)context;(void)presentControllerWithNames:(NSArray )names contexts:(NSArray )contexts;(void)dismissController;(void)becomeCurrentPage;

Push,Pop, Present, Dismiss的行爲和UIViewController中類似。我們可以在代碼中,根據程序上下文的狀態,控制跳轉到某一個頁面。

使用這一組API時有四點需要注意:

  • Push和Present方法第一個參數是對應的在Storyboard中爲WKInterfaceController設置的identifier字符串。WatchKit Extension

  • 使用這幾個API向Watch OS傳遞消息,真實的UI加載渲染行爲是在Watch端進行。

  • popToRootController是跳轉到Watch App的Storyboard中Main Entry Point對應的Controller。

  • presentControllerWithNames, 我們可以present一組Controller, 這一組Controller將以page control的形式展示。

  • becomeCurrentPage 當頁面是以page control的形式展現時,我們可以調用這個方法改變當前的page

另外一組API是:


- (id)contextForSegueWithIdentifier:(NSString *)segueIdentifier;(NSArray )contextsForSegueWithIdentifier:(NSString )segueIdentifier;(id)contextForSegueWithIdentifier:(NSString )segueIdentifier inTable:(WKInterfaceTable )table rowIndex:(NSInteger)rowIndex;(NSArray )contextsForSegueWithIdentifier:(NSString )segueIdentifier inTable:(WKInterfaceTable *)table rowIndex:(NSInteger)rowIndex;

當我們在應用設計的階段就知道需要跳轉的下一個WKInterfaceController時,我們可以直接在Storyboard中設置Triggered Segues。使用Segues時,Selection同樣支持Push和Model兩種跳轉方式。

我們可以使用上面一組API進行跳轉中的數據傳遞。

響應交互事件

WKInterfaceObject中像Button,Slider, Switch等控件可以和用戶交互,我們和往常一樣,可以在WKInterfaceController實現對應的Action,標記爲IBAction,然後連接到Storyboard中。

這裏特別的地方是,當我們的WKInterfaceController中包含WKInterfaceTable實例時,我們可以通過實現默認的- (void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex方法響應table中每一行的點擊事件,這裏和往常的UITableView的實現方式不太一樣,更加簡單。

Glance

Glance是 Watch App上新的概念,它主要作用是給用戶一個短時的提醒。我們可以通過Storyboard創建一個Glance interface Controller.對應的WatchKit Extension中,它同樣需要繼承於WKInterfaceController,享有同樣的生命週期。我們可以在其中實現自己的邏輯。

這裏需要注意的是,Glance是可以和用戶進行交互的。當用戶Tap Glance頁面時,會跳轉到我們的Watch App中。這裏可以在自定義的GlanceInterfaceController中使用- (void)updateUserActivity:(NSString *)type userInfo:(NSDictionary *)userInfo傳遞數據。比如我們需要在用戶點擊Glance之後進入到某一個特定的頁面,我們可以把目標頁面的identifier和要傳遞的其他消息包裝到字典中,然後在Initial Interface Controller中實現- (NSString *)actionForUserActivity:(NSDictionary *)userActivity context:(id *)context方法跳轉到目標頁面,這裏的userActivity就是上文傳遞的userInfo,返回的NSString是目標頁面的identifier,context指針是目標頁面initWithContext中context數據。

Notification && WKUserNotificationInterfaceController

當我們的主體App支持Notification時,Apple Watch將能夠顯示這些通知。Watch OS提供了默認的通知顯示,當用戶點擊通知進入我們的App時,Initial Interface Controller中- (void)handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)remoteNotification或者- (void)handleActionWithIdentifier:(NSString *)identifier forLocalNotification:(UILocalNotification *)localNotification方法將會被響應,我們可以通過實現這兩個方法獲得通知的消息,跳轉到目標頁面。

我們同樣可以通過Storyboard創建一個Notification interface Controller,這樣可以實現自定義的通知界面。對應的WatchKit Extension中,它繼承於WKUserNotificationInterfaceController,享有和WKInterfaceController同樣的生命週期。我們可以通過實現下面兩組API- (void)didReceiveRemoteNotification:(NSDictionary *)remoteNotification withCompletion:(void(^)(WKUserNotificationInterfaceType interface)) completionHandler或者- (void)didReceiveLocalNotification:(UILocalNotification *)localNotification withCompletion:(void(^)(WKUserNotificationInterfaceType interface)) completionHandler獲得通知內容,並設置處理完成的回調Block。

Menu

我們可以通過Storyboard在界面中添加Menu,它看起來像這樣:


我們不但可以通過Storyboard在Menu中添加Item,也可以通過WKInterfaceController中以下一組API,在上下文環境中添加相應的Item:


- (void)addMenuItemWithImage:(UIImage )image title:(NSString )title action:(SEL)action;(void)addMenuItemWithImageNamed:(NSString )imageName title:(NSString )title action:(SEL)action;(void)addMenuItemWithItemIcon:(WKMenuItemIcon)itemIcon title:(NSString *)title action:(SEL)action;(void)clearAllMenuItems;

WKInterfaceObject

WKInterfaceObject負責界面的元素,目前Apple公開了11個具體的子類用來展現各種不同類型的元素。它和之前的UIView或者UIView的子類不一樣,WKInterfaceObject只負責在WatchKit Extension和Watch App中傳遞相應的事件,具體的UI渲染在Watch App中完成。

Watch App 採取的佈局方式和 iOS App 完全不同。我們無法指定某個視圖的具體座標,也不能使用AutoLayout來進行佈局。WatchKit只能在以“行”爲基本單位進行佈局。在一行中如果要顯示多個元素,我們就要通過WKInterfaceGroup在行內進行列布局。

WKInterfaceTable

和學習iOS開發一樣,先從一個TableView開始上手。目前在WatchKit中最複雜的界面元素也是WKInterfaceTable。

我們可以通過Storyboard直接在當前WKInterfaceController中添加一個Table,每一個Table默認包含一個Table Row Controller, 這個Table Row Controller作用相當於之前的Cell,不過這裏是繼承於NSObject。我們可以使用Table Row Controller中定義每一種Row的樣式,然後設置一個唯一的identifier用來區分。

我們可以通過以下兩組設置Table的每一行的樣式,rowType對應Storyboard中Row Controller的identifier。


- (void)setRowTypes:(NSArray *)rowTypes;(void)setNumberOfRows:(NSInteger)numberOfRows withRowType:(NSString *)rowType;

我們可以通過- (id)rowControllerAtIndex:(NSInteger)index獲得某一行對應的Row Controller。下面是一段在interface controller中初始化Table Rows的例子:


- (void)loadTableRows {
   [self.interfaceTable setNumberOfRows:self.elementsList.count withRowType:@"default"];
   // Create all of the table rows.
   [self.elementsList enumerateObjectsUsingBlock:^(NSDictionary rowData, NSUInteger idx, BOOL stop) {
    AAPLElementRowController *elementRow = [self.interfaceTable rowControllerAtIndex:idx];
    [elementRow.elementLabel setText:rowData[@"label"]];
   }];
}

我們同樣可以使用下面的API進行添加,刪除Table的Rows:


(void)insertRowsAtIndexes:(NSIndexSet )rows withRowType:(NSString )rowType;

(void)removeRowsAtIndexes:(NSIndexSet )rows;
WKInterfaceDevice


這是一個單例類,可以獲得當前Apple Watch的部分信息。目前公開的信息有:

@property(nonatomic,readonly) CGRect    screenBounds;
@property(nonatomic,readonly) CGFloat   screenScale;
@property(nonatomic,readonly,strong) NSLocale currentLocale;
@property(nonatomic,readonly,copy)  NSString *preferredContentSizeCategory;

另外我們可以使用這個類中的以下一組方法來緩存圖片,以備將來繼續使用:


(void)addCachedImage:(UIImage )image name:(NSString )name;

(void)addCachedImageWithData:(NSData )imageData name:(NSString )name;

(void)removeCachedImageWithName:(NSString *)name;

(void)removeAllCachedImages;
已經緩存的圖片,可以使用WKInterfaceImage中下面的API直接讀取:

(void)setImageData:(NSData *)imageData;

(void)setImageNamed:(NSString *)imageName;
WatchKit允許每一個App最多緩存20MB的圖片,如果超過的話,WatchKit將從最老的數據開始刪除,爲新數據騰出空間。

總結

關於WatchKit Framework中API的知識點都基本包含在了上述筆記中。目前所提供的API功能有限,主要是信息的顯示,通知的接收。更多關於多媒體或者傳感器方面的API在這個版本中並沒有開放,期待蘋果的下一次更新。

轉載自:http://chun.tips/blog/2014/11/19/zou-jin-watchkit-framework/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章