把重复的操作交给 Workflow(3)——挖掘 Workflow 的能力

这是「流程和效率」系列之三

本文结构

  • 前文回顾
    • #1 Workflow 给我们带来什么
    • #2 Workflow 的创建步骤
    • #3 Workflow 调试工具
  • 挖掘内置动作的能力
    • #1 内置动作的 Workflow 实例
      • 例 1:订票提醒
      • 例 2:魔性闪图
    • #2 了解和用好内置动作
    • #3 了解数据的类型和传递
    • #4 Scripting
  • 利用无穷的外部接口——公开 API
    • 例 1:在线分词
    • 例 2:扫码查书

前文回顾

我们首先在《提高打开 App 的效率》中了解到 URL Schemes,然后在《创建简单的 Workflow》中以此为基础,尝试做了三个 Workflow。现在我们回头做一下整理。

#1 Workflow 给我们带来什么

我说「Workflow 是一种用流程来解决问题的思维模式」,也许有人因此觉得,这样的思维模式把生活都变成了数学题,毫无趣味可言。其实这是一种误解。

真正无趣的情形是遇到重复的困扰却不断选择忍受,它腐蚀人心,使我们变得麻木。流程化思考,不但是主动面对问题,而且是努力寻求一劳永逸的方法。相信自己能让事情变得更好,这让人感到更自由,这本就是一种乐趣。

回顾我们完成的三个 Workflow,一个实现了支付宝常用功能快速跳转,一个实现了搜索引擎随时切换、一个能帮助我们折算金额。它们所解决的困扰是微弱的,但依然让人获得改善的信心。

有个狂热爱好者说:「Workflow App 或许是无所不能的,限制我们的只是想象力。」这话显然是夸张的,Workflow App 不可能无所不能,但它的确令人惊叹。

你也许从未想到 Workflow 与订餐有什么联系,可是有选择困难症患者的确在用它订餐:他列了一份口味清单和相应的订餐电话,让 Workflow 帮他随机选择、自动拨号。

有很多问题 Workflow 可以帮我们解决,只是我们没有去想象。我们没有想让 Workflow 替我们解决,只是因为对它缺乏了解。

#2 Workflow 的创建步骤

遵循 Workflow 的思维模式,我们同样将创建 Workflow 的工作流程化:

  1. 确定目标

    Workflow 的功能是什么?它要适用于哪些情形?我们据此设置 Workflow 的名称、图标、类别,以及接受的数据类型。

  2. 确定核心步骤

    暂时无视条件判断和选项分支,先只管挑选实现功能的关键动作,构建 Workflow 的核心步骤。

  3. 补完流程

    扩充核心步骤,添加条件判断、运行分支或数据运算等等。

  4. 运行测试

    检查是否忽略了特殊符号的编码问题;在各种条件下试用 Workflow,看看是否出错。

#3 Workflow 调试工具

Workflow 提供了 Quick LookView Content Graph 两个动作,为我们测试提供了方便。

  • Quick Look 直译过来是瞥一眼,用于直接查看内容,让我们看到内容发生的变化。
  • View Content Graph 显示图表,用于查看数据构成。

比如说在 Select Contact 后面放 Quick Look 将显示联系人界面,放 View Content Graph 将用放射结构显示该联系人下包含哪些数据。

View Content Graph
联系人数据结构

如果一个动作修改了内容,那么用 Quick Look 直接查看改动;如果想要获得复合数据里的特定子项,则应该用 View Content Graph 了解它的结构。

View Content GraphQuick Look 可以帮助我们了解内置动作,或者在 Workflow 运行出错时查找问题所在。

在动手创建和调试 Workflow 的过程中,我们对它内在和外延能力的了解会不断加深。

挖掘内置动作的能力

不一定总要调用外在的 URL Schemes,使用 Workflow App 内置的动作就可以做出许多贴心的功能。

#1 内置动作的 Workflow 实例

这里举两个例子。

例 1:订票提醒

我打算过段时间出远门,需要订票。这时候有两个小小的烦恼,一是得花心思倒推订票日期,二是没到订票那天就把这事给忘了。这个问题用 Workflow 来解决很简单:

添加订票的日历事项

运行一下看看:

订票 Workflow 的运行效果
添加的日历事项

它的确忠实可靠地计算出应该订票的日期,并且在日历中添加了事件。

我们是不是还可以再懒一点?比如说订票有 App 订票、电话订票和去附近售票点购买三种方式,我们可以把相应的 URL Schemes 填写到日历事件的 Notes 中,届时点击 URL Schemes 立即启动订票 App、呼出订票电话,或是在地图中搜索附近的售票点。

例 2:魔性闪图

合成魔性闪图的 Workflow 可能更让人惊奇,但它其实更简单:

魔性闪图 Workflow

运行效果就不贴了,自己试试吧。

#2 了解和用好内置动作

Workflow App 被设计得极其易用,我们只需拖放动作卡片就可以拼装 Workflow。看了上述两个例子,你应该发现这话并不夸张。

在「魔性闪图」这个 Workflow 中,你需要做的调整仅是打开 Select Multiple 开关。

有些人习惯使用本子记录日程,在「订票提醒」的例子中,他可能发现了日历 App 在交互上的独特优势。Calendar 类的动作支持日历事件的添加、删除、查询,结合日期计算动作,用户在安排日程和调配时间时会更轻松。

Workflow App 的内置动作分为 12 类,除 Scripting 比较特殊,其他各类动作的作用均一目了然。

比如 Calendar 类的动作主要与日期计算、日程提醒相关;Contacts 类的动作能读取联系人的电话号码、地址、邮箱等数据……

动手尝试拼装 Workflow,是熟悉这些动作的最好方法。遇到看不明白的动作卡片时,我们为它新建一个临时、短小的 Workflow,并在后面放上 Quick LookView Content Graph,就能在运行时生动地看到动作卡片的运行效果。

#3 了解数据的类型和传递

在「Workflow 进阶」部分,我们创建的搜索引擎聚合必须接受数据传入,它可能是在网页或其他 App 中选中的内容,也可能是在 Ask for Input 界面中我们手动输入的文字。

在货币换算的 Workflow 中,它接受的数据只能是数字而不能是文字;在合成魔性闪图的 Workflow 中,Select Photos 动作选择的数据类型是 Image(图片)。

通过这些例子,我们意识到数据有类型之分。

  1. 数据类型

    Ask for Input 界面可以看到,基本的数据类型大致是 Text(文本)、Number(数字)、URL(网址)、Date(日期),除此之外还有一些常用文件类型,File(文件)、ImageMedia(视频、音频等媒体文件)、PDF 等。

    扩展类的 Workflow 有 Accepts 设置项,用于限定接受的数据类型,这里的许多类型和 Contact(联系人)一样,由多种基本的数据类型组合而成,我们可以用 View Content Graph 查看它们的组成结构。

    正如前文所说,Workflow 要区分数据类型是因为,当你输入「天哪!这么超值」,它就不应该试图将这段话折算成人民币。同样,你应该知道,用黄油相机给照片加的字,用 Get Text from Input 是弄不出来的。

    许多动作只能操作特定的数据类型,不过,基本的类型之间可以转换。

    在「我有 100 大洋」这句话中,「100」是文本而不是数字,用它进行运算,必须先把「100」单独抽出来,再用 Number 动作转换成数字;在「2017 年 12 月 12 日是我破产的日子」这句话中,「2017 年 12 月 12 日」必须用 Date 动作转换才能被 Workflow 视为日期。

  2. 数据传递

    许多动作都涉及数据的操作和转换,我们在动作列表中点击展开某个动作,可以看到相关资料。

    动作说明

    如图所见,Make HTML from Rich Text 动作只接受 Rich Text 类型的数据,并向后输出 HTML 源码(实际是 Text 类型)。

    无论是手动输入还是插件读取,数据将被某些动作卡片依次加工,不停向后传递。在支付宝快捷跳转的 Workflow 中,Choose from List 动作将词典中被选中的代码递给了 URL。

    有些动作不会对数据有任何改动(你可以看到它们的说明资料中写着「Result: The input」),比如 Set Variable,它只是保存当前数据,以便之后取用;而有些动作会截断之前的数据传递,比如 Get Variable

    运用 Set VariableGet Variable 组合,数据可以被“恢复”,动作卡片读取的数据不再限于“上一步”。前文搜索引擎的例子说到,Count 向后传递的是数值,这时就需要用 Set Variable 保存内容,之后再用 Get Variable 重新读取。

    Workflow 还支持「魔法变量」,让动作卡片直接读取前面某个卡片的输出结果,这省掉了大量使用 Set VariableGet Variable 组合的必要。

    选择**魔法变量**

#4 Scripting

在 12 个动作分类中,Scripting 是比较特殊的一个,里面的动作用于:

  • 存取变量;
  • 统计和运算;
  • 读写词典和列表;
  • 读写数据、设备的属性;
  • 控制 Workflow 的流程;
  • 通知交互;
  • ……

一般情况下,Scripting 中的动作跟功能目标无关,所以不会出现在核心步骤中,但它在将 Workflow 补充完整的阶段至关重要。

Workflow 被称为流程(Flow),是因为它能实现条件判断和运行分支,而相关的动作都位于 Scripting 分类中。

  1. Ask for Input 和 Ask When Run

    两者是用得比较多的动作/参数,当 Workflow 无法自动获得必要的数据,需要我们手动提供,这时就必须用到它们。

  2. If -(Otherwise)- End If

    这个动作是 Workflow 实现条件判断的关键。条件被满足时执行 If 部分,跳过 Otherwise 部分,到 End If 重新回到无条件执行的状态;反之,条件不被满足时跳过 If 部分而执行 Otherwise 部分。

    如果只需要管条件被满足的情况,Otherwise 下没有要执行的动作,则可以点它右侧的「X」号删掉。删除之后想找回来,可以点 If 右侧的齿轮图标,在弹出的窗口中点 Put Back "Otherwise"

    **If**

    很遗憾 Workflow App 不支持 Case,这导致条件复杂时只能用 If 层层相套。

  3. 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 分类下的 URLOpen URLs 动作调用,前面支付宝和 Vert 的 Workflow 就是这么做的。

除了调用 URL Schemes,利用 URLGet Contents of URL 动作组合,我们还可以调用在线接口,无限扩充功能。

许多大型网站会提供公开接口,以便第三方开发者接入,也有一些小型的、专门提供 API 服务的网站。

大型网站一般会用专门的开发平台来提供文档和示例,入口可以在网页顶部或底部的导航菜单中找到。

微博的开发平台入口

我们也可以通过搜索引擎用网站名加「开发平台」、「API」等关键字眼直接搜索到相应的页面。

搜索豆瓣的 API

网上也有专门的 API 商店,专门汇聚各方服务商提供的 API 接口:

例 1:在线分词

锤子科技在 2016 年为自有的系统加入了「Big Bang(大爆炸)」功能,其别致的交互受到了大量用户的追捧。

Big Bang。图片来自锤子官方论坛

「Big Bang」可以获取用户按压的文字片断(如果用户按压的是图片中的文字,则先调用 OCR API 来识别出文字),然后调用分词 API 来显示词语列表。

中文分词是机器实现中文语义识别的基础,中文语义识别可用于机器翻译和中文人机自然语言交互。Siri 等各种语音助手能和我们交谈,可能背后就使用了这些技术。

利用网上的 API,我们同样可以实现分词的功能(当然,「Big Bang」有系统级的支持,可以在任意界面即时弹出,这点是 Workflow 不可能做到的)。百度搜索「分词 API」,可以看到许多强大的中文语义平台,比如 BosonNLP、 哈工大语言云、NLPIR 等。为方便练手,我们选调用起来最简单的 PullWord。

☆ 第一步,查询 API 资料

http://api.pullword.com 可以查到 API 的使用说明:

  • 文本的输入必须使用 UTF8 编码;
  • 请求方式支持 GetPost 两种;
  • 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=清华大学是好学校&param1=0&param2=1

运行结果:

清华:0.604942 清华大学:1 华大:0.068537 大学:0.949906 好学:0.659566 学校:0.936925

☆ 第二步,拼装 Workflow

现在可以开始拼装了。新建 Workflow,将名称设为「分词」,为了方便使用,设为通知中心插件和分享面板扩展,接受的数据类型仅选择 Text

先把 Workflow 前半段写出来:

分词 Workflow 前半段

上图 URL 动作里的 API 显示不全,我将后面参数的值分别设为 1 和 0。

分词 Workflow 试运行

试着运行 Workflow,在 Quick Look 里看到,返回的结果是用空格相间的词语。我们根据这个返回结果补完 Workflow 的剩余部分。

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

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 的用法

☆ 第二步,拼装 Workflow

因为是扫码获得 ISBN 号码,所以 Workflow 的类型选择通知中心插件类。不像分享面板扩展需要做判断,Workflow 的前半段简单了很多:

扫码并调用 API

接下来处理返回的数据。API 返回的是 JSON 格式,我们用 Get Dictionary from Input 可以将其转换为词典,然后再用 Get Dictionary Value 获得不同关键词的值。

首先用 Get Dictionary Value 获得 msgcode 的值,如果返回这两个值,则表示请求失败,Workflow 在弹出相关提示后结束运行。

为了测试 API 请求失败的情况,先把 Scan QR/Bar Code 动作删掉,并把 URL 最后的 ISBN 设为固定的 12345。

当 API 请求失败

运行一下看看:

消息提示

接下来处理 API 请求成功时的返回数据,核心依然是用 Get Dictionary Value 获得关键词的值。

有一点需要留意,当 JSON 的层级较多时(从上面可以看到 rating 下面还有分项),转换得到的也会是多层的词典(即词典里包含词典),这时需要递次向内层取值。

比如要获得 ratingaverage 的值,得先用 Get Dictionary Value 获得 rating 的值(又是一个词典),再用 Get Dictionary Value 获得 average 的值。

为了在 End If 之后重新读取返回的数据,需要在 Get Contents of InputGet Dictionary from Input 后面用 Set Variable 将词典保存起来,然后在 End If 后用 Get Variable 重新读取。仅作示范,剩余部分就简单处理了:

显示图书信息页面
最终运行结果

通过分词和扫码查书两个例子,我们掌握了通过 Get Contents of URL 调用在线 API 的基本方法。

接下来说明一下 Get Contents of URLAdvanced 的设置方法。Method 指请求方式,以 GetPost 居多;使用 Post 方式可以递交 JSON、表单及文件数据。

运用网络调试工具,我们可以查获网站的一些接口,使原本需要手动完成的操作被自动化,比如自动登录某个网站签到,或检查最新动态。

网站自动登录

我们还可以监测云音乐的客户端,通过模拟它的请求行为来下载其中的 MV。

云音乐请求

这些就需要自己尝试和摸索了。


题图来自 Unsplash,作者 NeONBRAND

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容