Tiger的小站

得失从缘,心无增减

为 Apple Watch 开发应用

必要条件

目前 Apple Watch 应用不能独立于 iPhone 应用存在,它其实只能算作你的 iPhone 应用的一个扩展。所以在开始前你需要有:

  • 一个现有的 iPhone 程序
  • Xcode 6.2 或以上版本

项目配置

  1. 打开你的 iPhone 项目文件
  2. 在 Xcode 中选择 File > New > Target > Apple Watch > WatchKit App 点击 Next
  3. 根据项目需要选择 Include Notification SceneInclude Glance Scene 是否勾选(关于 Notification 和 Glance 我们稍后会谈) 点击 `Finish`

此时项目中多出了类似下图的两个目录

细心一点,你还会发现在 Targets 里面多出了 * WatchKit Extension * WatchKit App 两个 target

  • WatchKit Extension 运行在 iPhone 上,包含资源文件和代码
  • WatchKit App 运行在 Apple Watch 上,包含资源文件和 Storyboard

可以这么理解,Apple Watch 不负责逻辑,只负责界面的显示,逻辑在 iPhone 以扩展的形式存在,是 iPhone 将计算好后需要显示的内容通过 WatchKit 传给 Apple Watch(当然这一步并不需要我们操心)。

现在 Xcode 中 Scheme 选择 * WatchKit App 先运行一下

调出 Apple Watch 模拟器

iOS Simulator > Hardware > External Displays > Apple Watch

咳,当然现在什么也没有。。

展现类型

WatchKit App (必须)

你的 Apple Watch 主 App,在下一节我们会着重讲一下。

Glance (可选)

Glance 用于展示你的应用的最重要的内容,不能 scroll、点击等交互,纯信息浏览,并且它的样式也很固定,形如

要把信息塞进这两个小小的 Group 中,要兼顾美观和实用,还是很有考验。

Notification (可选)

Notificatin 用于显示用户的本地通知和远程通知,它包括 Short-Look 和 Long-Look 两种形式,其中 Short-Look 长这样:

Short-Look 样式是固定的,开发者无法定制,iOS 8.2 开始 UILocalNotification 新增了一个 alertTilte 属性,专门用于在 Apple Watch 的 Short-Look 中显示,这个 alertTilte 不要太长,用于描述这条通知的显示原因,如果为空,应该就是显示 alertBody 的内容。

当有通知来了,系统会先显示 Short-Look 界面,如果用户仍在看屏幕,就会继续显 Long-Look 界面。

Long-Look 又有 Static Interface 和 Dynamic Interface 两种情况。

Static 和 Dynamic 长的差不多,它们都是只有上图中 App content 部分可以自由定制,sash 的颜色可以在 Storyboard 中定制。

Static 只有一个 Label 可以用来显示通知的主内容,你可以放一些图片啊,什么的装饰一下,让它变的好看一点。

如果还想显示一些额外的内容,就要用上 Dynamic 界面,在 Storyboard 中定好 Dynamic Notification 的样式,详细的要显示的信息(比如上图中的时间地点信息等等)可以放在 UILocalNotification 的 userInfo 属性中,等有通知来了,界面相关联的 WKUserNotificationInterfaceController 子类会调用下面两个方法,此时在其中根据相应的 notification 信息更新界面就好。

- (void)didReceiveLocalNotification:(UILocalNotification *)localNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler

- (void)didReceiveRemoteNotification:(NSDictionary *)remoteNotification withCompletion:(void (^)(WKUserNotificationInterfaceType))completionHandler

如果你的计算时间过长或者 completionHandler 返回的是WKUserNotificationInterfaceTypeCustom 或者在 Storyboard 中没有勾选 Has Dynamic Interface 那么就显示 Static 界面。

你可以通过 Notification 的 category 设计相应的不同的显示样式。

WatchKit Apps

界面要点

WatchKit 的界面都要在 Storyboard 中完成,不同于其他 iOS Apps,它不能设置 frame 也不支持autolayout,它有一个比较重要的 Group 的概念:

  • 所有在 Group 中的 View 按照横向或者竖向的顺序依次自动排列(在 Storyboard 中设置 Group 的 layout 属性)
  • View 可以设置在 Group 中的相对位置,垂直居中/左右居中/居左/居右/居上/居下(在 Storyboard 中设置 View 的 Position 属性)
  • Group 中 View 之间的间隙可以通过 Storyboard 中设置 Group 的 Space 大小来调节
  • Group 的上下左右留白可以通过 Storyboard 中设置 Group 的 Insets 设置成 Custom 来调节
  • Group 可以设置背景图片或背景颜色

其他还有:

  • 可以通过 View 的 Size 属性设置 View 的大小,当设置成Size to Fit Content,View 的大小会随着其中的内容自动撑开,比如一个 Label,它就可以随着文字的长短自适应宽高,在比如 Group,就可以随着里面 View 的大小自适应宽高。
  • 在 Storyboard 中,属性的前面有+号的,可以对 38mm 和 42mm 两个尺寸的屏幕分别设置
  • 在 Storyboard 右边栏第一个 tab 下,设置Group Tint的颜色,这个颜色也是每个 Controller 的 title 的颜色。

Navigation

在 WatchKit 中,Navigation 有两种形式

  • Page based. 类似于 iOS 系统天气应用,是卡片式的,一页一页的,下方自带 PageControl
  • Hierarchical. 就是我们通常用的,push,pop 是一级一级往下的,自带边缘右滑返回

这两种 Navigation 形式 在你的程序中只能出现一种,比如不能 push 进去之后,在 page 一页一页的详情页左右滑。

WKInterfaceController 提供了下面几种方法

- (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;

比如 Master-Detail 模型,第一页是个 table,点击某个 cell,进入相应的详情页。那么你可以在 MasterInterfaceControlloer 中添加这样一个方法,返回下一页需要的数据对象:

- (id)contextForSegueWithIdentifier:(NSString *)segueIdentifier inTable:(WKInterfaceTable *)table rowIndex:(NSInteger)rowIndex {
    return dataObjects[rowIndex];
}

在 DetailInterfaceController 中

- (void)awakeWithContext:(id)context {
    ...
}

这个 context 就是 MasterInterfaceController 传给你的值。

View

关于界面,想扒一张 Mattt 的图,原文在这里,这里就不多说了。

还是在多说两句吧 orz,Menu 是点击屏幕长按弹出来的,每个 InterfateController 最多有一个 Menu。

WKInterfaceTable 没有 dataSorce 和 delegate。数据的设置看 这里,当有 cell 被点到了 WKInterfaceController 会 call 下面的这个方法。

- (void)table:(WKInterfaceTable *)table didSelectRowAtIndex:(NSInteger)rowIndex;

数据

Apple Watch 和 iPhone 的数据共享也是通过 App Groups 实现的,如果有需要可以看一下我之前拙文iOS 8 中 Extension 和 Containing App 之间的数据共享

打开 iPhone

WKInterfaceController 提供了这样一个类方法用于打开相应 iPhone 程序,userInfo 不能为空

+ (BOOL)openParentApplication:(NSDictionary *)userInfo reply:(void(^)(NSDictionary *replyInfo, NSError *error)) reply;

同时在 iPhone 程序的 AppDeleage.m 中要给出相应的应答

- (void)application:(UIApplication *)application handleWatchKitExtensionRequest:(NSDictionary *)userInfo reply:(void (^)(NSDictionary *))reply;

总结

总的来说,为 Apple Watch 开发 App 还是很简单的,界面的排版几乎是半自动的,如果之前已经做了通知中心挂件,在数据方面也有现成的。上周苹果的发布会上正式确定了 Apple Watch 的发布时间,做为脑残粉还是非常期待的。希望大家打开思路,不要被小小的屏幕所局限,希望看到更多有趣的 Apple Watch App,与大家共勉。

还有就是 Apple Watch Programming Guide 还是要看的,嗯!

如有错误,欢迎留言指出。

, ,

  • 如果blog支持RSS就更好了