15 03 2015
为 Apple Watch 开发应用
必要条件
目前 Apple Watch 应用不能独立于 iPhone 应用存在,它其实只能算作你的 iPhone 应用的一个扩展。所以在开始前你需要有:
- 一个现有的 iPhone 程序
- Xcode 6.2 或以上版本
项目配置
- 打开你的 iPhone 项目文件
- 在 Xcode 中选择 File > New > Target > Apple Watch > WatchKit App 点击
Next
- 根据项目需要选择
Include Notification Scene
、Include 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 还是要看的,嗯!
如有错误,欢迎留言指出。
iOS 8 中 Extension 和 Containing App 之间的数据共享 总算没有烂尾- MG 新安洲
-
Terry