阅读更多
编者按:本文作者刘超在2012年加入墨迹天气,主要负责iOS平台软件开发工作。在今年年初,墨迹天气团队针对Apple Watch的硬件与交互特点,对应用做了重新设计与开发。作者从软件开发角度,分享了墨迹天气团队在开发过程中发现的问题、误区,以及解决之道。

Apple Watch的设计误区

WatchKit发布第一时间,我们的产品经理和设计师就根据设计规范和官方宣传动画迅速出了一版设计原型。Apple Watch版应用中囊括墨迹天气iPhone版的大部分功能,从实况到预报,再到时景和分享,其中包括一些新的交互,如使用Digital Crown切换短时和多天预报、缩放时景图片,在消息推送达到后直接在该推送下编辑信息回复。它相当于一个微缩版本的墨迹天气。

随后程序员也很快加入到这个项目里。当我们研究过Programming Guide和Watchkit framework Reference后,失望的发现宣传视频上展示的操作:Digital Crown、表面触感、地图缩放等是不对开发者开放的。于是我们开始重新推敲交互,设计师也发现不能再像设计iPhone应用那样自由的设计细节。由于最初我们都是没有实际的佩戴体验的,只能从宣传片和设计开发指南中找思路,揣摩用户的使用场景和心理。通过和Apple方面有佩戴经验的负责人交流,我们发现最开始的设计方向是不对的,我们不应该把设计重心Apple Watch的主程序上,而是重点设计Glance和Notification。作为一款手表上的应用程序,及时方便地查看才是它最常见的应用场景。曾经看到一位没有使用过Apple Watch的网友调侃:在那么小的屏幕上操作带来的麻烦完全抵消了从兜里掏出手机的麻烦。

Watch应用开发的五条小技巧

WatchKit提供的是一套全新的界面类。令人熟悉的地方是,大多数方法和属性的命名都有很好的延续性,几乎不需要重新学习就能够大概看出其含义。不同的是所有的界面控件都继承自WKInterfaceObject,也就是说这些界面控件不再是继承自UIView的控件实体,而更像是控制真正界面的代理控制器。

在进行开发之前,我们要先了解一下Watchkit是如何工作的。实际上一个Watch应用分为两部分,负责界面的WatchKit App,只包括storyboard和asset catalog,它运行于Apple Watch上,另一个是负责逻辑部分的WatchKit Extension,则运行于iPhone上。开发者可能会担心,这样会不会加大开发的难度呢?答案是完全不会!Apple Watch和iPhone使用Bluetooth LE 和 Wi-Fi 技术进行通信,整个通信过程实在后台完全自动进行的,所以即使界面和交互在Apple Watch上,逻辑在iPhone上,我们却根本不需要操心,只要像常规那样处理界面属性赋值和交互响应即可,确实很酷!

首先是界面开发,在使用WatchKit开发时,不会再出现“代码写UI还是Xib写?”这样的带有争议的问题,因为Watch应用只能用StoryBoard进行开发,我猜想是为了更好的控制Watch应用的界面一致性,除此之外还有比较多限制。譬如不能在运行时动态增减界面元素,只能通过设置隐藏属性来调整界面展示;元素之间不能出现叠加,只能按纵向横向依次排列; Glance必须从官方模版中选择一个来使用,不能自由堆砌界面元素等等。不过最终开发下来,发现只要运用得当,空间还是很大的,在此我们根据实践总结了一些小技巧:

  • 使用 WKInterfaceGroupWKInterfaceButton的 - setBackgroundImageNamed:和 - startAnimatingWithImagesInRange:duration:repeatCount:方法在背景上增加图片或者动画,这样就可以使控件和图形实现叠加。有些小伙伴可能会觉得很惊奇,“什么?WKInterfaceButton也可以作为容器放置控件?”是的,只要在控件的Attributes inspector里把Button的Content属性由Text修改为Group即可,这样我们就可以像使用Group一样使用button了。
  • 抬手即看的短暂应用场景要求我们必须开发出层次简洁、操作流畅的应用,过程中我们发现WKInterfaceMenu的使用效果非常生硬,实际操作时需要长按才会响应,另外当弹出的选项偏少时,界面并不美观,所以后来用WKInterfaceButton的轻点事件取代了这种长按操作。
  • 在控件的Attributes inspector里,可以针对38mm和42mm的Apple Watch分别设置属性。
  • 如果想让一组横向放置的N个控件等宽,可又因为不知道设备类型而不能设置具体的宽度,该怎么办呢? 一种比较土的办法是,在程序运行后,通过获取屏幕宽度来动态的设置控件宽度。另一种方法是直接在该控件的属性设置里把宽度设置为Reletive to Container,然后在其下方的输入框内填写所占比例,例如5等份,就填写0.2,这样系统会按照你的设置自动帮你设置好。
  • 在传统的基于界面的iOS应用中,程序可以在AppDelegate里做好界面展示的准备工作,但是Watch应用必须直接指定某个界面为入口。如果你的根界面是一个基于分页的结构(page-based), 可能会碰到这样的问题:程序在启动后才动态的决定分页数,所以需要在页面内调用reloadRootControllersWithNames来重新加载,如果加载的页面中不仅包括加载者自身又没有做处理的话,就会无限加载下去,这时候你可以使用一个static变量来解决无限reload的问题,如下:

- (void)awakeWithContext:(id)context {<br>&nbsp; [super
awakeWithContext:context];<br>&nbsp; static BOOL bReload = NO;<br>&nbsp; if (!bReload) {<br>&nbsp; bReload = YES;<br>&nbsp; //计算分页数,准备各分页context数据<br>&nbsp; //调用[WKInterfaceController
reloadRootControllersWithNames: contexts:]加载分页<br>&nbsp; }<br>&nbsp; else {<br>&nbsp; //处理输入的context,这里不加载界面,willActivate执行时再lazy加载<br>&nbsp; }<br>}

当用户抬起手腕打开Glance想看一下天气时,如果程序此时才去进行数据请求,用户就会面对一个大大的N/A界面,需要等上1~2秒,直到网络请求成功,才会显示最新的天气信息。这会带来较差的使用体验。相对来说,我认为比较好的做法是,先让iPhone应用支持后台刷新的系列功能,包括:silent notification、background fetch。如此一来,当用户查看Glance时,呈现给他的是近期更新过的数据,随后程序做出判断,如果这个还需要呈现给用户更新的数据就立即进行网络请求,请求成功后再更新界面。



数据共享与通信

Watch应用和containing iOS App之间可以通过共享数据区进行数据共享。首先启用App Groups,然后在共享容器内根据要共享数据的性质来决定是用NSUserDefaults还是直接在共享区读写文件。官方Demo推荐用NSFileCoordinator来进行文件读写,以完成多进程间的同步。不过,我自己在实践过程中发现,使用NSFileCoordinator时必须特别小心,使用不当会造成因资源引起的死锁。当时情况是这样的:程序上的一个bug导致在个别情况下会出现特别频繁的IO,以致程序几乎失去了响应。这时候如果直接将程序kill掉,资源所在目录有几率发生死锁,如果重启App,程序会卡死在NSFileCoordinator的coordinateReadingItemAtURL方法上。该方法的回调block长时间得不到执行,以致于iOS的”看门狗”会直接将App干掉,启动不起来,只能依靠重启系统来解决。对App开发者来说简直是“人间惨剧”,这种情况下没有几个用户会不删掉App的。

由于atch应用只有运行、挂起、终止三种状态,所以一旦你正在使用NSFileCoordinator写文件时被挂起,它就没有机会让出资源所有权。要解决这个问题,需要使用原子安全的保存操作,如UIDocument。

如果你需要Watch应用同containing iOS app进行通信,可以使用WKInterfaceController类的类方法openParentApplication,反过来如果需要containing iOS app同watch app通信,一种办法是通过在数据共享区读写文件,然后让watch app监听该文件从而做出响应;另一种方法,是使用Darwin Notification Center,具体开发过程,可以参照 官方的建议。
性能方面

关于这一点,官方给予的建议非常明确,简要列举如下:

  • 尽可能减少iPhone和Apple Watch之间的数据通信,比如尽可能把图片存在WatchKit app bundle里,这样显示图片的时候会更快更省电。
  • 仅更新界面上改变的部分,比如需要对 table新增了一行数据,不要重新加载整个table。
  • 减少分页结构应用的加载时间,在init和awakeWithContext做尽可能少的处理,界面如何展示的问题放在WillActivate内处理。
  • 让一个Controller负责尽可能少的场景,因为当显示其中一个场景时必须要隐藏不需要的控件,但是隐藏控件也会被创建,就会影响加载速度。

其它Tips:

官方论坛的Apple Watch模块里有很多有价值的问答,苹果的工程师会在里面对开发者的疑问进行解答。推荐下载官方Demo Lister,这是一个非常不错的开发示例。但是要注意,Demo里大量使用iOS 8及其以上的API,如果你的App还需要支持iOS 8以下的系统,在Copy代码时请做好兼容。

XCode 6.2版本有一个小bug,就是必须把相关target的Bundle Display Name 和 Bundle Name都配置为我们的应用名,才会在Watch应用启动和iPhone上Apple Watch的配对程序里正确的显示应用名称。

另外,还要给使用XCode6.2的开发者提个醒,不正确的现实应用名称有可能会被审核拒绝。需要支持国际化的开发者要针对所支持语言在infoPlist.strings内配置CFBundleName的值即可。

写在最后

根据Apple在iOS系统上日益开放的策略,我们有理由相信,随着时间的推移WatchKit会开放给开发者越来越多的API。各种App也会更准确的捕捉到Apple Watch的应用场景,开发者也会有更大的舞台去发挥!

作者简介:刘超,2012年加入墨迹天气,主要负责iOS平台软件开发工作。墨迹天气正在寻找技术高手,欢迎感兴趣的中高级iOS工程师交流。chao.liu#moji.com
  • 大小: 30.1 KB
0
0
评论 共 3 条 请登录后发表评论
3 楼 我会是微博 2015-05-11 14:36
ray_linn 写道
Apple Watch ....为啥要浪费时间给一个注定夭折的产品开发软件

+1
2 楼 freezingsky 2015-05-09 00:17
土豪的世界太复杂了!
1 楼 ray_linn 2015-05-08 15:57
Apple Watch ....为啥要浪费时间给一个注定夭折的产品开发软件

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • windows正则表达式

    实用正则表达式,对于在windows下开发经常用到的正则表达式这里有介绍

  • 正则表达式的语法

    import rem=re.findall(&quot;.&quot;,&quot;aa\nbbcc&quot;)print(m)     此处输出['a', 'a', 'a', 'b', 'b', 'c', 'c']      &quot;.&quot;表示输出所有非换行符的字符转义字符m=re.findall(&quot;\.&quot;,&quot;a.c&quot;)print(m)                        &quot;\.&quot;利用\作为转义字符,输出所有&quot;.

  • 正则表达式学习

    正则表达式,又称规则表达式。(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念。正则表达式通常被用来检索、替换那些符合某个模式(规则)的文本。比如处理网页文本的程序时,经常会有查找符合某些复杂规则的字符串的需要。正则表达式就是用于描述这些规则的工具。模式用于描述在搜索文本时要匹配的一个或多个字符串。 基础 举个栗子 比如需要匹配 w...

  • C#-正则基础 . 匹配除回车外的字符

     .NET Framework : 4.7.2        IDE : Visual Studio Community 2019        &nbsp;OS : Windows 10 x64    &nbsp;typesetting : Markdown       &nbsp;&nbsp;blog : blog.csdn.net/yushaopu      &nbsp;&nbsp;gi...

  • 关于正则表达式的学习

    正则表达式的学习

  • 正则表达式

    正则表达式概念 摘自脚本之家 正则表达式中的特殊字符 字符 含意 \ 做为转意,即通常在"\"后面的字符不按原来意义解释,如/b/匹配字符"b",当b前面加了反斜杆后/\b/,转意为匹配一个单词的边界。 -或- 对正则表达式功能字符的还原,如"*"匹配它前面元字符0次或多次,/a*/将匹配a,aa,aaa,加了"\"后,/a\*/将只匹配"a*"。 ^ 匹配一个输

  • windows计划任务 0xff_推荐!!Windows平台上三款提高工作效率的免费神器!

    作者:小侯飞氘来源:https://zhuanlan.zhihu.com/p/38942108还在用windows自带的记事本或写字板编辑文本文档?还在用window自带的搜索服务查找文件?还在手动备份重要数据和资料?如果你对以上三个问题中任何一个的回答是“是”的话,我建议你看完下面的内容。我会简单的介绍三个十分有用的免费软件,保证能提高你的办公室工作效率,为你节约出大量的时间用来刷知乎...

  • 批处理 正则表达式(findstr) 整理

    1.findstr . 2.txt 或 findstr "." 2.txt 从文件2.txt中查找任意字符,不包括空字符或空行 ==================== 2.findstr .* 2.txt 或 findstr ".*" 2.txt 从文件2.txt中查找任意字符包括空行和空字符 ==================== 3.findstr "[0-

  • Windows文件搜索高效匹配,白用十几年电脑

    最近,由于历史遗留问题,硬盘总是爆缸,于是开始整理硬盘的学习资料,嗯,真的是学习资料。真的!信不信由你······ 发现大量重复的小姐姐,噢,不,是大量重复的学习教程。 去过集中在一起还好,可以通过名称,类型过滤删除, 如果想下面这样的 要一个个选,太烦额。这只是中文的,在搜索框可以检索‘副本’出来,但是有的文件是(1),(2),(3)的后缀呢, 使用刚刚那个方法就会失效,会匹配出现错误, 搜索框里面能否使用正则?微软还真提供了一些方法。 全出来了。妈妈再也不用担心我的硬盘没内

  • 正则之字符匹配

    正则表达式字符匹配 两种模糊匹配 如果正则只有精确匹配是没多大意义的,比如/hello/,也只能匹配字符串中的"hello"这个子串 var regex = /hello/; console.log(regex.test("hello")); // =&gt; true 正则表达式之所以强大,是因为其能实现模糊匹配 而模糊匹配,有两个方向上的“模糊”:横向模糊和纵向模糊 横向模糊匹配 横向模糊指的是,一个正则可匹配的字符串的长度不是固定的,可以是多种情况的 其实现的方式是使用量词。譬如{

  • js正则以左中括号[开头,以右中括号]结束

    正则以左中括号[开头,以右中括号]结束 /^\[([\s\S])*\]$/g var data = [hello]; data.replace( /^\[([\s\S])*\]$/g ,'哈哈哈'); alert(data)

  • 正则表达式匹配任意字符

    最开始以为.* 可以匹配任意字符,后来发现有问题,匹配不了换行符\n 查了下资料,用[\s\S]*匹配可以  解释:\s空白符,\S非空白符,所以[\s\S]是任意字符

  • [正则表达式]正则表达式(.*)和(.*?)的字符串匹配问题

    Java 正则表达式 正则表达式定义了字符串的模式。 正则表达式可以用来搜索、编辑或处理文本。 正则表达式并不仅限于某一种语言,但是在每种语言中有细微的差别。 Java正则表达式和Perl的是最为相似的。 java.util.regex包主要包括以下三个类: Pattern类: pattern对象是一个正则表达式的编译表示。Pattern类没有公共构造方法。要创建一个Pattern对象,

  • 正则表达式常用匹配

    //

  • JS正则表达式

    1       概述正则表达式(Regular Expression)是一种匹配模式,描述的是一串文本的特征。 正如自然语言中“高大”、“坚固”等词语抽象出来描述事物特征一样,正则表达式就是字符的高度抽象,用来描述字符串的特征。 正则表达式(以下简称正则,Regex)通常不独立存在,各种编程语言和工具作为宿主语言提供对正则的支持,并根据自身语言的特点,进行一定的剪裁或扩展。 正则入门很容易,...

  • 正则表达式匹配连续相同字符

    今天楼主偶遇一道题,下面分享给大家 /* 题目:找出字符串中连续出现最多的字符和个数 输入:'aaaavvvvabbbbbffff' 输出:{b: 5} */ 那么该怎么做呢?重点在连续上 /* 题目:找出字符串中连续出现最多的字符和个数 输入:'aaaavvvvabbbbbffff' 输出:{b: 5} */ var str = 'aaa...

  • 正则表达式的匹配字符

    正则表达式是由普通字符(例如字符a ~ z)及特殊字符(称为元字符)组成的匹配模式字符串。 普通字符 非打印字符 特殊字符 次数限定符 贪婪与非贪婪限定符 定位符 选择与分组 向后引用   普通字符          普通字符包括没有显式指定为元字符的所有可打印和不可打印字符。这包括所有

  • 正则表达式 入门 -- 简单字符匹配、元字符

    好的工具可以提高工作效率,正则表达式绝对是这其中一员。最近抽时间大概了解了一下这方面的知识,整理了一下自己的一些笔记,文中示例通过vim编辑器来演示,匹配到的字符为黄色高亮显示,并在下面注明了显示结果。 首先,正则表达式的定义:一些用来匹配和处理文本的字符串 主要用途:搜索,替换 在正式开始之前,有一点需要特别强调:正则表达式的语法很容易掌握,但是真正的挑战是如何运用那些语法把实际问...

  • 主要正则表达式元字符列表(待完善)

    类别 字符 含义 定位符 ^ 行首(默认) $ 行尾(默认) \b 字边界,是单词和空格之间的位置 \B 非字边界,除字边界之外的任何位置 限定符 ? 重复 [0,1] + ...

Global site tag (gtag.js) - Google Analytics