走进 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/


你可能感兴趣的:(apple,用户,iPhone,项目,开发者)