如何进行iOSWidget开发

北京白斑病医院 https://wapjbk.39.net/yiyuanfengcai/hj_bjzkbdfyy/

阿里妹导读:iOS14重磅推出了新功能Widget,可以在主屏上展示一些关键信息,如日程、待办事项、设备电量等。Widget的设计定位是什么?有哪些限制?如何进行Widget开发?本文基于一个小游戏——盒马小镇的Widget开发,分享在登录授权、数据更新、界面渲染以及审核上的实践经验。

文末福利:免费试用云服务器。

Widget简介

Widget是iOS14重磅推出的新功能,使得用户可以在主屏幕添加小组件,快速浏览app提供的重要信息。它的设计与旧版本macOS的Widget一脉相承,甚至连添加的动画也是去掉了拟物化的水波纹效果。

设计定位

用户可以通过Widget对主屏幕进行个性化定制,但是iOS14的Widget跟其他系统上的小组件有很大的区别。在Widget的设计上苹果也保持了一贯的克制,定位于轻量化、仅用作关键信息的展示。比如系统自带Widget中的股票、天气、电量、运动信息,他们的共同特征是更新频率高、提供的信息重要,让用户不用打开app就可以浏览关心的内容。苹果也不希望开发者将Widget仅仅当作app的一个快捷入口,这样的需求更适合用contextualmenu来实现。

限制

苹果基于上面的设计定位,同时也为了节省系统资源保证续航,对Widget的做了一些限制:

不支持动画,仅支持静态页面展示。更新频率由系统通过机器学习来动态分配。不支持拖拽、滚动等复杂的交互,不支持Switch等控件。用户点击Widget一定会跳转到app。

Widget开发实践

盒马小镇Widget设计

盒马小镇是盒马app内的一个小游戏,用户可以通过签到、购物、内容互动来获取盒花,用户最关心的就是有没有盒花可以收取,或者是否有盒花可以帮摘等信息。这正好可以契合Widget的设计初衷,我们期望能借此提升用户粘性。

要实现一个Widget首先要升级到Xcode12,然后在工程中增加一个新的WidgetExtension,Xcode会自动生成需要的模板文件。

我们现在要做的只有两件事:数据加载、渲染界面。

登录及授权

加载数据之前首先要解决的是授权问题。由于集团的登录SDK暂时不支持extension,加上全家桶依赖复杂、体积很大,我们不能使用MTOP来进行API调用,因此我们设计了一套认证机制,主app在登录后调用MTOP接口获取token,并且将token写入appgroup中,Widget通过HTTPS接口加上token来访问用户数据。

其中token通过UserDefaults来共享到Widget,因为开发过程中不同的证书打包的bundleid不同,因此我们将groupname设置成group.[bundleid]的形式,保证能正确读取token。

vartoken:String?{letbundleIdentifier=Bundle.main.bundleIdentifier!letdefaults=UserDefaults(suiteName:group.+bundleIdentifier)returndefaults?.object(forKey:widget.town.homeinfo.token)as?String}

Token的同步有几个时机:

App启动后,如果已经登录并且appgroup中没有token,则获取token。用户进入盒马小镇时获取token。用户登录时获取token。用户登出时删除token。

数据更新

这里苹果借用了timeline的概念,timeline里面包含了一个个entry,entry就是我们在特定时间需要展示的数据。系统先回调我们来获取timeline数据,再在特定时间来回调我们渲染界面。

我们在返回timeline时可以设置更新策略:

atEnd:在timeline中所有的entry都展示完之后更新。never:仅在主app触发更新。after:在特定时间后触发更新。

当然这些都只是我们建议系统的更新的时机,实际是否更新还是取决于系统。对于可以预测信息的,比如天气预报,可以在timeline中添加多个entry,并且选择atEnd作为更新时机;对于不可以预测信息的,比如股市,可以选择after策略,在一定时间后更新信息。

除此之外,我们还可以在主app中调用WidgetCenter的方法来触发更新,经我们测试使用这种方法每次调用都是能够真正触发数据更新的。更多信息可以参考官方文档[1]。

在盒马小镇的场景下,我们是无法预知到将来的数据的,因此每次返回的timeline中只包含一个entry,选取的策略是after,每20分钟更新一次数据。

值得注意的是,在getSnapshot方法中也要返回真实的数据,这样用户在Widget的添加过程中看到的就是正确的界面,真正做到所见即所得。

在用户在主app中收取盒花之后,我们还会主动触发一次数据的更新。

渲染界面

苹果为了推广SwiftUI,规定Widget只能使用SwiftUI来编写界面。SwiftUI与Flutter类似,是随iOS13推出一套声明式的UI框架。SwiftUI在这一年中有了很大的进步,补齐了很多能力上的不足。它使得跨平台(仅苹果生态)的界面开发变得非常简单。此外SwiftUI还支持preview(类似Flutter的hotreload),代码的改动可以近乎实时地反应在UI上,极大提高了开发效率和体验。

如果有Flutter开发经验,只要熟悉VStack、HStack、ZStack以及常见的几个modifier就可以轻松上手。

Bundle拆分

与集团的大多数app一样,我们的app工程也分为壳工程和业务bundle,我们不希望每次修改Widget都去修改壳工程,于是要把Widget的业务逻辑拆分开来。经过尝试发现一个可行的办法:

新建一个Swiftframeworkbundle,将Widget实现放在里面,并且将里面的类设置成public。

在壳工程中新建一个WidgetExtension,引入上面的framework,在里面保留

main方法。

mainstructHMTownWidget:Widget{letkind:String=HMTownWidgetvarbody:someWidgetConfiguration{StaticConfiguration(kind:kind,provider:Provider()){entryinHMTownWidgetEntryView(entry:entry)}.configurationDisplayName(盒马小镇).description(快速查看盒花动态,访问盒马小镇收盒花).supportedFamilies([.systemSmall,.systemMedium])}}

这种方法可以减少壳工程改动的风险,并且可以正常使用SwiftUI的preview和调试功能,缺点是Widget的配置信息仍在保留在壳工程中,暂时没有更好的办法在保证调试功能的同时完全分离壳工程和业务代码。

SwiftBridge

前面提到在用户摘取盒花之后,我们需要触发Widget的更新,这里需要调用WidgetCenter的API,而这个API仅提供了Swift版本,而我们的主app是纯OC写的,需要做一个bridge。要实现bridge必须开启DefineModules,而我们的工程由于历史原因在开启后无法编译通过,现在的解决方法是新建一个Swiftframework,里面调用WidgetCenterAPI,再由业务去引用这个bridge的framework。

埋点

Widget的曝光事件我们是无法感知的,由于点击Widget会直接跳转到主app,所以我们在跳转到主app的URL上增加了埋点参数,主app解析URL中的参数调用UT来埋点。

审核

在我们一开始打完包提交到TF审核时被拒了:

理由是我们使用了无效的字体,这个字体是我们在很早的版本就已经依赖的Flutter三方库引入的,之前的审核也一直没问题,在去掉了依赖之后成功过审,原因不明。Flutter官方issue[2]提到只有在增加了Widget之后才会遇到这个问题。

Swift的副作用

目前盒马app最低支持iOS9.0,而iOS直到12.2才将Swift基础库集成到系统中,因此我们需要在BuildSettings里面将“ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES”设置为“YES”才能在12.2及以下的系统上运行。

Swift虽然在5.0版本完成了ABI稳定,但是在低版本操作系统中(iOS12.2以下)仍旧会有一些不够完美的地方。在低于iOS12.2以下的操作系统会带来约有3MB的包大小问题,但幸运的是苹果放开了蜂窝数据网络下M的下载大小。在低于iOS12.2以下的操作系统会有-ms不等的启动耗时增加,但在团队同学的努力下上线了二进制重排,启动性能大幅度上升。具体分析请查看:手淘架构组最新实践

iOS基于静态库插桩的进制重排启动优化[3]。——《手淘Swift大事记》

好在iOS的升级率比较高,相信随着时间的推移Swift的应用会越来越多。

最后

目前新版本已经正式发布(4.54.1),欢迎下载体验,AppClip商品溯源也同步上线。现在的版本仍存在一些问题,比如用户如果已经打开小镇页面,通过点击Widget打开app仍然会再次打开小镇页面,需要从路由的层面优化;中尺寸的卡片相对于小尺寸也并没有透出更多的信息,与苹果的设计初衷相违背。不过也算是对新技术的一次尝试,后面会持续优化,期待能产生业务上的一些增量。

相关链接[1]


转载请注明:http://www.aierlanlan.com/grrz/5216.html