8f3d3f4d56f8340781a7296b3731d6aa
WWDC20 10036 - 《Widgets 边看边写》第三部分:Timelines的进阶使用

本篇是WWDC20 Widgets 系列Session的第三部分,可以在这里观看

文中涉及的demo在这里

本系列的其他部分:
第一部分
第二部分

开始之前,我们先介绍下面三个对象(在本系列之前的session中已经提到过,但因为它们相对抽象,且能体现Widget的设计思想,为了方便理解,我们用简单的语言再描述一下)

  • Timeline:时间线,是一个关于更新策略的封装,里面包装了若干TimelineEntry
  • TimelineEntry:时间线策略的控制点,主要用来控制,更新的具体时间点(会结合Timeline的其他属性)
  • TimelineProvider:提供Timeline的那个对象,系统通过它拿到Widget的Timeline

TimelineEntry是最本质的那个对象,用来控制Widget更新时机

按苹果一贯控制且克制的风格,关键事情要拿在自己手里,在整个iOS系统中进行平衡——对于Widget来说,“关键的事情”是电量 & 流量的开销

这种机制确保了一个Widget不能随意刷新自己的内容,而是要通过有计划,有规律的方式来更新

特别注意:
TimelineEntry里面的Date不是一个精确的时间,只是一种给系统的建议,系统根据自身情况来决定是否需要更新,极端情况下,比如低电,甚至不能保证更新

本篇讲动态配置,如果没有看之前部分,可以把demo下载下来直接从第三部分开始

本篇widget:Leadbard Widget——一个将角色按health 排列的Widget,同时点击每个角色头像能够唤起主app,并进入该角色的详情页面,先整体看一下:

主App Widget

URL Session

Widget可以通过网络请求来获取数据——TimelineProvider 是通过回调工作的,这样会让网络处理比较简单

直接看代码(入口 CharacterDetail.loadLeaderboardData)

主旨是:

  • 2这里把fauxResponse(其实就是个字符串,没啥神秘的)写入了一个在临时目录的文件“userData.json”
  • 1这里其实就是一个普通的URLSession,利用dataTask的方式请求这个URL,然后在回调里处理返回的数据

Q:但这是什么操作?!写个文件,然后请求文件URL,然后在回调里处理文件数据?!
A:这里没问题,且说明了一件事:Widget里可以调用URLSession系列的API,间接证明了Widget是有网络能力的

说到这里,我们仔细想一下,为啥要在demo里证明Widget有哪些能力?

了解过Extension开发的同学应该明白,苹果有好多extension类型:

ShareExtension 点击“信息”

时间上先有虎嗅App进程,然后才有“信息”界面,我们合理推论一下

  • 低成本:“信息”的界面运行在“虎嗅”进程里了
  • 高成本:“信息”也是独立进程和“虎嗅”跨进程通讯
    • 从安全角度考虑,利用进程间的页表隔离,彻底隔离两个进程的数据(符合苹果一贯的谨慎)

无论哪种,都说明extension的进程和他的属主app的进程并不一定是同一个
之所以不一定,看Extension的类型,反例是NotificationExtension

回到主题,Widget也是Extension,它有自己的运行时环境,且在iPhone/iPad这样的用电池的设备上,在能用的API集合上必然是受限的!

Demo刚刚说明了,URLSession的API是可以放心使用的

理解了这些,后面很多内容就比较make sense了!

Background Session

用过后台下载特性的同学都知道,background session在完成的时候,可选后台唤起主app,从AppDelegate的这两个回调

不理解Background Session的同学去看看这里,这里我们不展开

对于Widget来说,Widget(进程)同样有能力处理Background session回调

在没有AppDelegate的情况下,Widget要怎么做呢?

答案是:在StaticConfiguration中,有一个配置“onBackgroundURLSessionEvents”,可以注册一些回调,可以用来代替AppDelegate的角色

比如,注册一个处理回调

Widget唤起宿主App

想要做到这样的效果,应该怎么做?

该SwiftUI Link API出场了,从AllCharactersView讲起(我们Leaderboard Widget的主要视图)

这里嵌入了一个Link(角色的url)

Q:就是Deeplink而已,有什么特殊的?
A:是Deeplink,但不是通过URLScheme做的

感兴趣的读者可以去工程里求证

看这里(注意这是主App的视图,不是Widget)

链接匹配则上面的NavationLink会通过SwiftUI的数据绑定,显示对应的界面

关于数据绑定的细节,可以参考这篇

Widget Bundle

目前,我们在Widget Gallery里还只能看到一个Widget

就是被 @main 标识的那个Widget

但一个Widget Bundle可以容纳多个Widget,@main可以移动到bundle这里

⚠️:从这里开始,我们看的是Demo里Game Status Final目录下的工程

现在能看到多个Widget了

动态配置Widget

此Target主要是给Widget提供配置项目,下面详细说

Widget可以有一些静态配置,在part2里介绍过

top Created with Sketch.