这是「流程和效率」系列之三
本文结构:
- 前文回顾
- #1 Workflow 给我们带来什么
- #2 Workflow 的创建步骤
- #3 Workflow 调试工具
- 挖掘内置动作的能力
- #1 内置动作的 Workflow 实例
- 例 1:订票提醒
- 例 2:魔性闪图
- #2 了解和用好内置动作
- #3 了解数据的类型和传递
- #4 Scripting
- #1 内置动作的 Workflow 实例
- 利用无穷的外部接口——公开 API
- 例 1:在线分词
- 例 2:扫码查书
前文回顾
我们首先在《提高打开 App 的效率》中了解到 URL Schemes,然后在《创建简单的 Workflow》中以此为基础,尝试做了三个 Workflow。现在我们回头做一下整理。
#1 Workflow 给我们带来什么
我说「Workflow 是一种用流程来解决问题的思维模式」,也许有人因此觉得,这样的思维模式把生活都变成了数学题,毫无趣味可言。其实这是一种误解。
真正无趣的情形是遇到重复的困扰却不断选择忍受,它腐蚀人心,使我们变得麻木。流程化思考,不但是主动面对问题,而且是努力寻求一劳永逸的方法。相信自己能让事情变得更好,这让人感到更自由,这本就是一种乐趣。
回顾我们完成的三个 Workflow,一个实现了支付宝常用功能快速跳转,一个实现了搜索引擎随时切换、一个能帮助我们折算金额。它们所解决的困扰是微弱的,但依然让人获得改善的信心。
有个狂热爱好者说:「Workflow App 或许是无所不能的,限制我们的只是想象力。」这话显然是夸张的,Workflow App 不可能无所不能,但它的确令人惊叹。
你也许从未想到 Workflow 与订餐有什么联系,可是有选择困难症患者的确在用它订餐:他列了一份口味清单和相应的订餐电话,让 Workflow 帮他随机选择、自动拨号。
有很多问题 Workflow 可以帮我们解决,只是我们没有去想象。我们没有想让 Workflow 替我们解决,只是因为对它缺乏了解。
#2 Workflow 的创建步骤
遵循 Workflow 的思维模式,我们同样将创建 Workflow 的工作流程化:
-
确定目标
Workflow 的功能是什么?它要适用于哪些情形?我们据此设置 Workflow 的名称、图标、类别,以及接受的数据类型。
-
确定核心步骤
暂时无视条件判断和选项分支,先只管挑选实现功能的关键动作,构建 Workflow 的核心步骤。
-
补完流程
扩充核心步骤,添加条件判断、运行分支或数据运算等等。
-
运行测试
检查是否忽略了特殊符号的编码问题;在各种条件下试用 Workflow,看看是否出错。
#3 Workflow 调试工具
Workflow 提供了 Quick Look 和 View Content Graph 两个动作,为我们测试提供了方便。
- Quick Look 直译过来是瞥一眼,用于直接查看内容,让我们看到内容发生的变化。
- View Content Graph 显示图表,用于查看数据构成。
比如说在 Select Contact 后面放 Quick Look 将显示联系人界面,放 View Content Graph 将用放射结构显示该联系人下包含哪些数据。
如果一个动作修改了内容,那么用 Quick Look 直接查看改动;如果想要获得复合数据里的特定子项,则应该用 View Content Graph 了解它的结构。
View Content Graph 和 Quick Look 可以帮助我们了解内置动作,或者在 Workflow 运行出错时查找问题所在。
在动手创建和调试 Workflow 的过程中,我们对它内在和外延能力的了解会不断加深。
挖掘内置动作的能力
不一定总要调用外在的 URL Schemes,使用 Workflow App 内置的动作就可以做出许多贴心的功能。
#1 内置动作的 Workflow 实例
这里举两个例子。
例 1:订票提醒
我打算过段时间出远门,需要订票。这时候有两个小小的烦恼,一是得花心思倒推订票日期,二是没到订票那天就把这事给忘了。这个问题用 Workflow 来解决很简单:
运行一下看看:
它的确忠实可靠地计算出应该订票的日期,并且在日历中添加了事件。
我们是不是还可以再懒一点?比如说订票有 App 订票、电话订票和去附近售票点购买三种方式,我们可以把相应的 URL Schemes 填写到日历事件的 Notes 中,届时点击 URL Schemes 立即启动订票 App、呼出订票电话,或是在地图中搜索附近的售票点。
例 2:魔性闪图
合成魔性闪图的 Workflow 可能更让人惊奇,但它其实更简单:
运行效果就不贴了,自己试试吧。
#2 了解和用好内置动作
Workflow App 被设计得极其易用,我们只需拖放动作卡片就可以拼装 Workflow??戳松鲜隽礁隼?,你应该发现这话并不夸张。
在「魔性闪图」这个 Workflow 中,你需要做的调整仅是打开 Select Multiple 开关。
有些人习惯使用本子记录日程,在「订票提醒」的例子中,他可能发现了日历 App 在交互上的独特优势。Calendar 类的动作支持日历事件的添加、删除、查询,结合日期计算动作,用户在安排日程和调配时间时会更轻松。
Workflow App 的内置动作分为 12 类,除 Scripting 比较特殊,其他各类动作的作用均一目了然。
比如 Calendar 类的动作主要与日期计算、日程提醒相关;Contacts 类的动作能读取联系人的电话号码、地址、邮箱等数据……
动手尝试拼装 Workflow,是熟悉这些动作的最好方法。遇到看不明白的动作卡片时,我们为它新建一个临时、短小的 Workflow,并在后面放上 Quick Look 或 View Content Graph,就能在运行时生动地看到动作卡片的运行效果。
#3 了解数据的类型和传递
在「Workflow 进阶」部分,我们创建的搜索引擎聚合必须接受数据传入,它可能是在网页或其他 App 中选中的内容,也可能是在 Ask for Input 界面中我们手动输入的文字。
在货币换算的 Workflow 中,它接受的数据只能是数字而不能是文字;在合成魔性闪图的 Workflow 中,Select Photos 动作选择的数据类型是 Image(图片)。
通过这些例子,我们意识到数据有类型之分。
-
数据类型
在 Ask for Input 界面可以看到,基本的数据类型大致是 Text(文本)、Number(数字)、URL(网址)、Date(日期),除此之外还有一些常用文件类型,File(文件)、Image、Media(视频、音频等媒体文件)、PDF 等。
扩展类的 Workflow 有 Accepts 设置项,用于限定接受的数据类型,这里的许多类型和 Contact(联系人)一样,由多种基本的数据类型组合而成,我们可以用 View Content Graph 查看它们的组成结构。
正如前文所说,Workflow 要区分数据类型是因为,当你输入「天哪!这么超值」,它就不应该试图将这段话折算成人民币。同样,你应该知道,用黄油相机给照片加的字,用 Get Text from Input 是弄不出来的。
许多动作只能操作特定的数据类型,不过,基本的类型之间可以转换。
在「我有 100 大洋」这句话中,「100」是文本而不是数字,用它进行运算,必须先把「100」单独抽出来,再用 Number 动作转换成数字;在「2017 年 12 月 12 日是我破产的日子」这句话中,「2017 年 12 月 12 日」必须用 Date 动作转换才能被 Workflow 视为日期。
-
数据传递
许多动作都涉及数据的操作和转换,我们在动作列表中点击展开某个动作,可以看到相关资料。
如图所见,Make HTML from Rich Text 动作只接受 Rich Text 类型的数据,并向后输出 HTML 源码(实际是 Text 类型)。
无论是手动输入还是插件读取,数据将被某些动作卡片依次加工,不停向后传递。在支付宝快捷跳转的 Workflow 中,Choose from List 动作将词典中被选中的代码递给了 URL。
有些动作不会对数据有任何改动(你可以看到它们的说明资料中写着「Result: The input」),比如 Set Variable,它只是保存当前数据,以便之后取用;而有些动作会截断之前的数据传递,比如 Get Variable。
运用 Set Variable 和 Get Variable 组合,数据可以被“恢复”,动作卡片读取的数据不再限于“上一步”。前文搜索引擎的例子说到,Count 向后传递的是数值,这时就需要用 Set Variable 保存内容,之后再用 Get Variable 重新读取。
Workflow 还支持「魔法变量」,让动作卡片直接读取前面某个卡片的输出结果,这省掉了大量使用 Set Variable 和 Get Variable 组合的必要。
#4 Scripting
在 12 个动作分类中,Scripting 是比较特殊的一个,里面的动作用于:
- 存取变量;
- 统计和运算;
- 读写词典和列表;
- 读写数据、设备的属性;
- 控制 Workflow 的流程;
- 通知交互;
- ……
一般情况下,Scripting 中的动作跟功能目标无关,所以不会出现在核心步骤中,但它在将 Workflow 补充完整的阶段至关重要。
Workflow 被称为流程(Flow),是因为它能实现条件判断和运行分支,而相关的动作都位于 Scripting 分类中。
-
Ask for Input 和 Ask When Run
两者是用得比较多的动作/参数,当 Workflow 无法自动获得必要的数据,需要我们手动提供,这时就必须用到它们。
-
If -(Otherwise)- End If
这个动作是 Workflow 实现条件判断的关键。条件被满足时执行 If 部分,跳过 Otherwise 部分,到 End If 重新回到无条件执行的状态;反之,条件不被满足时跳过 If 部分而执行 Otherwise 部分。
如果只需要管条件被满足的情况,Otherwise 下没有要执行的动作,则可以点它右侧的「X」号删掉。删除之后想找回来,可以点 If 右侧的齿轮图标,在弹出的窗口中点 Put Back "Otherwise"。
很遗憾 Workflow App 不支持 Case,这导致条件复杂时只能用 If 层层相套。
-
List 和 Dictionary
两者都是数据列表,后跟 Choose from List 都可以显示选单。但通过前文支付宝的 Workflow 可以看到它们的不同,Dictionary 的各项数据都有关键词和实际值两部分(就像词典的每个词条有词语和解释两部分),当用 Choose from List 选择“词典”里的项目时,向后传递的只是实际值,不包括关键词。
利用无穷的外部接口——公开 API
Workflow App 内置的动作有名为 App 的分类,封装了许多第三方 App 的 URL Schemes,但是前面说到的微信、支付宝、Vert,以及大量第三方 App 所提供的 URL Schemes 都不在其中。
这很正常,作者不可能把大量的精力用在打包 URL Schemes 这件事件上。那些外在的 URL Schemes,我们可以通过 Web 分类下的 URL 和 Open URLs 动作调用,前面支付宝和 Vert 的 Workflow 就是这么做的。
除了调用 URL Schemes,利用 URL 和 Get Contents of URL 动作组合,我们还可以调用在线接口,无限扩充功能。
许多大型网站会提供公开接口,以便第三方开发者接入,也有一些小型的、专门提供 API 服务的网站。
大型网站一般会用专门的开发平台来提供文档和示例,入口可以在网页顶部或底部的导航菜单中找到。
我们也可以通过搜索引擎用网站名加「开发平台」、「API」等关键字眼直接搜索到相应的页面。
网上也有专门的 API 商店,专门汇聚各方服务商提供的 API 接口:
- 聚合数据:https://www.juhe.cn
- 百度 API Store:http://apistore.baidu.com
例 1:在线分词
锤子科技在 2016 年为自有的系统加入了「Big Bang(大爆炸)」功能,其别致的交互受到了大量用户的追捧。
「Big Bang」可以获取用户按压的文字片断(如果用户按压的是图片中的文字,则先调用 OCR API 来识别出文字),然后调用分词 API 来显示词语列表。
中文分词是机器实现中文语义识别的基础,中文语义识别可用于机器翻译和中文人机自然语言交互。Siri 等各种语音助手能和我们交谈,可能背后就使用了这些技术。
利用网上的 API,我们同样可以实现分词的功能(当然,「Big Bang」有系统级的支持,可以在任意界面即时弹出,这点是 Workflow 不可能做到的)。百度搜索「分词 API」,可以看到许多强大的中文语义平台,比如 BosonNLP、 哈工大语言云、NLPIR 等。为方便练手,我们选调用起来最简单的 PullWord。
☆ 第一步,查询 API 资料
在 http://api.pullword.com 可以查到 API 的使用说明:
- 文本的输入必须使用 UTF8 编码;
- 请求方式支持 Get 和 Post 两种;
- Source 参数用于填写文字片断;
- Param1 参数用于指定分词的严格性,可填 0~1 之间的值(如 0.5),为 0 时最宽松,为 1 时最严谨;
- Param2 参数用于切换模式,为 0 时关闭调试,为 1 时显示每个词对应的划分合理程度。
因为页面上特别注明,超过 30 个汉字的分词请求,用 Post 方法会低效且出错,所以我们使用 Get 方法。在使用 Get 方法时,Get Contents of URL 动作不需要理会 Advanced 设置,保持默认即可。
通过页面上的「点击使用 Get 方式」链接可以得到 API 的格式:
http://api.pullword.com/get.php?source=清华大学是好学校¶m1=0¶m2=1
运行结果:
清华:0.604942 清华大学:1 华大:0.068537 大学:0.949906 好学:0.659566 学校:0.936925
☆ 第二步,拼装 Workflow
现在可以开始拼装了。新建 Workflow,将名称设为「分词」,为了方便使用,设为通知中心插件和分享面板扩展,接受的数据类型仅选择 Text。
先把 Workflow 前半段写出来:
上图 URL 动作里的 API 显示不全,我将后面参数的值分别设为 1 和 0。
试着运行 Workflow,在 Quick Look 里看到,返回的结果是用空格相间的词语。我们根据这个返回结果补完 Workflow 的剩余部分。
测试完毕删掉 Quick Look 动作。
说明:
- Split Text:以空格(Space)为界将返回结果分割为词语列表(List);
- Choose from List:显示选单;
- Copy to Clipboard:将选择的项目(词语)复制到剪贴板。
再次试用查看运行情况:
咦,怎么选单最后有一项「Text」?并且选择不同文段反复试用,选单最后一项总是「Text」,即使文中并没有这个单词,仍然会是这个结果。
☆ 第三步,纠错
在 Get Contents of URL 后重新添加 Quick Look 动作,再次运行,在查看器中长按并全选,此时发现最后一个词语后面还有一个空格。
因为 Split Text 用空格分项,这导致列表最后有一个空项。怎样把列表最后的这个空项去掉呢?用 Replace Text 动作可以做到。
Replace Text 的设置说明:
-
Find Text:要查找的文本。
这里的
\s*$
是正则表达式,\s
匹配空白字符,包括空格、制表符、换页符;*
表示匹配任意个;$
匹配文本结尾的位置。即\s*$
匹配文本结尾的任意个空白字符。 -
Replace With:替换为……
因为是要删除文段尾部的空格,所以这里留空。
-
Case Sensitive:区分大小写。
空格不存在大小写,这里是开是关无所谓。
-
Regular Expression:正则表达式。
必须打开这个开关,上面 Find Text 项才可以使用正则表达式。
例 2:扫码查书
PullWord 的分词 API 直接返回文本,而豆瓣图书 API 返回的是 JSON 格式,我们用它做扫码查书的 Workflow 来进一步了解返回数据的处理。
☆ 第一步,查询 API 资料
在豆瓣 API v2 和豆瓣图书 API v2 的页面查看相关说明:
-
API 的返回格式:数据返回格式统一使用 JSON。
-
成功时返回查询到的数据;
{ "rating":{ "max":10, "numRaters":2538, "average":"9.3", "min":0 }, ... }
-
失败时返回错误码。
{ "msg":"book_not_found", "code":6000, "request":"GET \/v2\/book\/isbn\/:9887301215692" }
错误码列表可以在豆瓣图书 API v2 页面上看到,稍有点长这里就不转贴了。
-
-
「根据 ISBN 获取图书信息」API 的用法:
- 请求方式为 Get
- 格式为 https://api.douban.com/v2/book/:id
☆ 第二步,拼装 Workflow
因为是扫码获得 ISBN 号码,所以 Workflow 的类型选择通知中心插件类。不像分享面板扩展需要做判断,Workflow 的前半段简单了很多:
接下来处理返回的数据。API 返回的是 JSON 格式,我们用 Get Dictionary from Input 可以将其转换为词典,然后再用 Get Dictionary Value 获得不同关键词的值。
首先用 Get Dictionary Value 获得 msg 或 code 的值,如果返回这两个值,则表示请求失败,Workflow 在弹出相关提示后结束运行。
为了测试 API 请求失败的情况,先把 Scan QR/Bar Code 动作删掉,并把 URL 最后的 ISBN 设为固定的 12345。
运行一下看看:
接下来处理 API 请求成功时的返回数据,核心依然是用 Get Dictionary Value 获得关键词的值。
有一点需要留意,当 JSON 的层级较多时(从上面可以看到 rating 下面还有分项),转换得到的也会是多层的词典(即词典里包含词典),这时需要递次向内层取值。
比如要获得 rating 下 average 的值,得先用 Get Dictionary Value 获得 rating 的值(又是一个词典),再用 Get Dictionary Value 获得 average 的值。
为了在 End If 之后重新读取返回的数据,需要在 Get Contents of Input 和 Get Dictionary from Input 后面用 Set Variable 将词典保存起来,然后在 End If 后用 Get Variable 重新读取。仅作示范,剩余部分就简单处理了:
通过分词和扫码查书两个例子,我们掌握了通过 Get Contents of URL 调用在线 API 的基本方法。
接下来说明一下 Get Contents of URL 内 Advanced 的设置方法。Method 指请求方式,以 Get、Post 居多;使用 Post 方式可以递交 JSON、表单及文件数据。
运用网络调试工具,我们可以查获网站的一些接口,使原本需要手动完成的操作被自动化,比如自动登录某个网站签到,或检查最新动态。
我们还可以监测云音乐的客户端,通过模拟它的请求行为来下载其中的 MV。
这些就需要自己尝试和摸索了。