先吐个槽:随着iOS14系统发布,新的小组件掀起了一股热潮,在距离十一假期还有3天的时候,领导看着App Store排行榜沉思了一秒钟就做出了决定:我们也要做小组件,并且要在十一假期前上架App Store,先抢占一波流量。但是对我而言,WidgetKit没看过、swiftUI没用过、swift不熟练,所以只能现学现卖了。领导动动嘴,我们累断了腰啊,没办法,Just Do IT吧
正文
widgetKit出来已经有段时间了,关于新小组件的说明和原理网上很多,苹果开发者网站也有详细的解释说明,这里就不赘述了,需要了解基础的同学可以去Developer查看官方文档,目前网上的说明和示例基本都是翻译的官方文档,今天主要说一下我自己在开发小组件中遇到的问题及解决方案(主要是原理和想法上的问题,不涉及具体方法的实现)。
一、小组件与主APP数据互通
由于小组件是一个extension,需要在项目中新建一个target,所以在小组件中无法获取到主APP的沙盒数据,但可以通过APP Groups的方式实现数据互通。
1.UserDefaults使用[[NSUserDefaults alloc] initWithSuiteName:@"group_id"]
来获取共享数据。
2.数据库可以使用[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group_id"]
笔者目前的做法是在主APP中设置完小组件内容后,生成plist文件再通过
[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group_id"]
的方式将plist文件保存到共享沙盒中,再在小组件中获取,图片同理。
ps:通过网络请求的方式,将配置信息上传到服务器,再在小组件中请求服务器信息应该也可以。
二、持续刷新问题
小组件的刷新在Provider的getTimeline 方法里有一个 policy
参数,表示刷新的时机,可以选择.never(不自动刷新)
、.atEnd(时间线中的数据显示完毕之后自动刷新)
、.after(date)(到达自己设置的时间后自动刷新)
。
然而在开发过程中发现,有时候即使到达刷新时间或者时间线中的数据显示完毕,小组件也不自动刷新,这是由于小组件有自己的刷新机制,记得好像是15分钟(不确定在哪里看到过),既然如此那就在时间线中添加更多的entry来保证小组件可以持续刷新。然而事与愿违,当添加的entry太多时运行小组件崩溃,显示内存不能超过30M。
由于组件中有图片及其他自定义属性,所以添加多个entry时内存太大,于是尝试使用单例的方式将entry中除Date之外的属性和图片全部放在单例中,这样entry中只包含Date一个属性,创建多个entry占用的内存也不会太大。
至此,问题貌似解决了,但每次添加和刷新小组件时需要更长的时间加载时间线中的内容,导致小组件一片空白。目前只能平衡一下,在时间线中添加300条即5分钟的数据。
ps:目前看了很多持续刷新的小组件(大多为时间显示类),发现都存在刷新停止的问题,只有《氢时钟》没有这个问题,不知道是怎么做到的
三、用户自定义配置的问题
用户自己选择小组件配置的方式是使用Configuration Intent配合Intent Extension来实现,这个倒是不难实现,只是产品经理要求我们只做小中大三个组件内容根据用户自己选择的配置来显示,且三个组件的内容是分开的,即假如有时间、天气、和健康三个组件,如果用户在小组件中添加了时间组件,则在手机中添加的组件中只有小号组件的配置中有天气选项,而中号和大号组件中不能有天气选项。
在网上找了好久也找不到解决方案,最后想到一个方案,使用3个Intent来实现,机智!
解决方式:
在Configuration.intentdefinition
中添加小、中、大三个Intent,如图:
再添加3个Intent Extension来处理这三个Intent中的数据,如图:
在Info.plist
中NSExtension
->NSExtensionAttributes
->IntentsSupported
数组中添加对应的Intent名称,如:SmallIntent
的Info.plist
中添加SmallConfigurationIntent
注意:
1、添加的值是SmallConfigurationIntent
而不是SmallConfiguration
,即SmallConfiguration
后需要加上Intent
2、如果修改了Configuration.intentdefinition
中的值(包括Configuration的Parameter
、ENUMS
和TYPES
中的值),在三个Info.plist
文件中会自动增加小中大三个ConfigurationIntent,需要将其他两个删除,只保留一个对应的ConfigurationIntent,坑啊!
3、如果需要与主APP数据互通,那么三个Intent Extension
中都需要添加App Groups
这里要吐槽一下XCode自动生成代码是真的恶心,配置完Configuration.intentdefinition后在IntentHandler
类中使用代理ConfigurationIntentHandling时总是提示找不到,开始我以为自己写错了,检查了半天也不知道咋回事,后来莫名其妙又好了,最后才知道需要Clean后再Build一下才行,有时候需要退出Xcode才行。