找回密码
 会员注册
查看: 16|回复: 0

iOS14新特性-WidgetKit开发与实践

[复制链接]

7

主题

0

回帖

22

积分

新手上路

积分
22
发表于 2024-10-9 15:53:49 | 显示全部楼层 |阅读模式
iOS14新特性-WidgetKit开发与实践 iOS14新特性-WidgetKit开发与实践 张凯凯@贝壳找房 贝壳产品技术 贝壳产品技术 “贝壳产品技术公众号”作为贝壳官方产品技术号,致力打造贝壳产品、技术干货分享平台,面向互联网/O2O开发/产品从业者,每周推送优质产品技术文章、技术沙龙活动及招聘信息等。欢迎大家关注我们。 242篇内容 2020年10月29日 14:12 iOS14新特性-WidgetKit小部件 通过桌面编辑添加,将小部件放在iOS主屏幕或macOS通知中心上,使用户可以随时访问应用中的内容。同时小部件也可以保持更新,因此用户始终可以一目了然地获得最新信息,同时点击区域可以Deep Link跳转到主APP任意界面中。在2020年苹果发布会推出Widget之后,贝壳就第一时间做出了尝试, 期间苹果中国提供了很多支持与帮助,目前已在贝壳和链家APP上线。小部件具有三种不同的大小(小,中和大),可以显示各种信息。用户可以个性化小部件以查看特定于其需求的详细信息,并以最适合他们的方式安排其小部件。不同分辨率机型,三种卡片的尺寸也不同:1 如何开发WidgetKit前期准备:Xcode 12 及Bate版, iOS 14 及Bate版, 了解SwiftUI控件1.1 创建Widget首先,File->New->Target:有两种配置可供选择:StaticConfiguration: 对于一个没有用户可配置属性的Widget。例如,显示一般市场信息的股票市场Widget,或显示趋势的新闻Widget。IntentConfiguration: 对于一个具有用户可配置属性的Widget来说,你可以使用SiriKit自定义意图来定义属性。您使用 SiriKit 自定义意图来定义属性。例如,一个天气Widget需要一个城市的邮政编码或邮政编码,或者一个包裹跟踪Widget需要一个跟踪号码。下图中「Include Configuration Intent」复选框决定了Xcode使用哪种配置。选择Include Configuration Intent 表示支持用户配置;不需要,则不勾选。1.2 Widget初始化配置对象解析kind:识别Widget的字符串。如果包含多个widget后可作为唯一的标识符。Provider:符合TimelineProvider的对象。一个符合TimelineProvider的对象,它能产生一个时间线,告诉WidgetKit何时渲染Widget。时间线包含一个你定义的自定义TimelineEntry类型。时间线条目标识了你希望WidgetKit更新Widget内容的日期。在自定义类型中包含你的Widget的视图需要渲染的属性。Placeholder:一个 SwiftUI 视图,WidgetKit 用来在第一次渲染Widget。占位符是您的Widget的通用表示,没有特定的配置或数据。Content Closure(内容闭合):一个包含SwiftUI视图的封闭。WidgetKit调用它来渲染Widget的内容,从提供者那里传递一个TimelineEntry参数。函数解析1)placeholder占位视图,在数据加载前展示,在xcode12 bate3和bate4中有所有所变化:funcplaceholder(incontext:Context)->SimpleEntry{SimpleEntry(dateate(),modelJWidgetModel.preview_widget)}2)getSnapshot快照,在添加组件库中展示funcgetSnapshot(incontext:Context,completionescaping(SimpleEntry)->()){letentry=SimpleEntry(dateate(),modelJWidgetModel.preview_widget)completion(entry)}3)getTimeline时间轴,控制刷新时机funcgetTimeline(incontext:Context,completionescaping(Timeline)->()){letdate=Calendar.current.date(byAdding:.hour,value:12,toate())Date()LJWidgetAPI.loadData{(model,error)inguardletmodel=modelelse{lettimeline=Timeline(entries:[SimpleEntry(date:date,modelJWidgetModel.preview_widget)],policy:.after(date))completion(timeline)return}lettimeline=Timeline(entries:[SimpleEntry(date:date,model:model)],policy:.after(date))completion(timeline)}}4)SimpleEntry数据模型,类似modelstructSimpleEntry:TimelineEntry{letdateateletmodelJWidgetModel}5)WidgetEntryView主内容,展示区分小中大卡片 ,可根据family来区分structLJWidgetEntryView:View{varentryrovider.Entry@Environment(\.widgetFamily)varfamily@ViewBuildervarbody:someView{switchfamily{case.systemSmall:letsmall=entry.model.smallLJWidgetSmall(small).previewLayout(.sizeThatFits)case.systemMedium:letmedium=entry.model.mediumLJWidgetMedium(medium).previewLayout(.sizeThatFits)case.systemLarge:letlarge=entry.model.largeLJWidgetLarge(large).previewLayout(.sizeThatFits)@unknowndefault:Text("unknown")}}}6)Widget主界面控制器。kind为标识符structLJWidget:Widget{letkind:String="LJWidget"varbody:someWidgetConfiguration{StaticConfiguration(kind:kind,providerrovider()){entryinLJWidgetEntryView(entry:entry)}.configurationDisplayName("MyWidget").description("Thisisanexamplewidget.").supportedFamilies([.systemSmall,.systemMedium,.systemLarge])}}Widget_PreviewsstructLJWidgetLarge_PreviewsreviewProvider{staticvarpreviews:someView{Group{LJWidgetLarge(LJWidgetLargeModel.preview).frame(width:329.0,height:345.0).previewLayout(.sizeThatFits).colorScheme(.light)LJWidgetLarge(LJWidgetLargeModel.preview).frame(width:329.0,height:345.0).previewLayout(.sizeThatFits).colorScheme(.dark)}}Preview 预览界面开发是SwiftUI (Apple要求),可参考:https://developer.apple.com/documentation/widgetkit/creating-a-widget-extension 1.3 Widget刷新机制自动刷新如下图,本身维护一个时间轴,在创建时填充不同时间节点,当到达时间节点位置时,触发刷新。after会在消耗完时间点后,再次填充,保持循环运行。手动刷新一种是push notification推送来更新widget,另一种则是客户端内通过调用接口主动 reload。2 OC项目和Swift混编如果原有老项目为OC项目,想要实现和Swift的相互调用,需用到桥接文件,另外针对引入Swift依赖库,会引起包体积增加,大小大概7~8M左右,可以在ipa包内查看:2.1 Swift引用OC代码创建xxx(工程名)-Bridging-Header头文件, 并在Build Setting -> Objective-C Bridging Header 设置其路径这样我们在桥接文件内,通过 import “xxx.h”引用OC的组件库,就可以在Swift使用了。2.2 OC引用Swift代码桥接文件不需要手动创建,系统帮我创建好了,可以查看xxx-swift,在文件夹查找不到,但是引用头文件后,可以点击进入查看:3 主APP和Widget间通信因为Widget为新的Target项目,和之前主项目是两个进程的关系,所以如果想要资源共享,比如登录状态值token, 网络配置等,就需要用到共享区域来实现通信。苹果提供的共享方式有:方式一:APPGroup 方式1)配置好证书,是Gourp功能正常使用中,主APP和Widget保持统一key当我们配置完以后,会在文件目录下多出来一个.entitlements的文件。2)主APP写下数据//MainApp通过TextField来向共享文件appGroup.txt中写入数据-(void)textFieldDidEndEditingUITextField*)textField{//获取AppGroup的共享目录NSURL*groupURL=[[NSFileManagerdefaultManager]containerURLForSecurityApplicationGroupIdentifier"group.com.simon.app.test"];NSURL*fileURL=[groupURLURLByAppendingPathComponent"appGroup.txt"];//写入文件[textField.textwriteToURL:fileURLatomically:YESencoding:NSUTF8StringEncodingerror:nil];}3)Widget 内读取App Group的共享目录NSURL*groupURL=[[NSFileManagerdefaultManager]containerURLForSecurityApplicationGroupIdentifier"group.com.simon.app.test"];NSURL*fileURL=[groupURLURLByAppendingPathComponent"appGroup.txt"];//读取文件NSString*str=[NSStringstringWithContentsOfURL:fileURLencoding:NSUTF8StringEncodingerror:nil];self.shareLabel.text=str;方式二:KeyChain SharingKeyChain可将用户信息加密存储在钥匙串中,保证用户信息的安全性;另外多个应用可通过keyChain共享用户信息。1)同样我们需要配置keychan的key, 保持和主APP一致,省事的是少了证书的配置2)通过对钥匙串的读写来操作 (一般由SAKeychain库管理)比较方便,注意一点:实现共享的只是在钥匙串的缓存数据,如果一旦加载到内存中,它的修改不受主APP的影响了。4 常见问题问题1.选择Intent (widget配置),会出现configtion查找不到解决:方法一:若不使用Inetent, 在生成widget时不勾选即可,避免这类问题;方法二:见https://developer.apple.com/forums/thread/653910(在官网提出后,目前没有官方人员回答,不过有其他答案,未验证)问题2. Xcode 12 bate3运行贝壳的widget未显示preview解决:Build systems: 选择新的编译方式问题3.由于WidgetKit使用一些Swift的新特性,所以版本需要修改成Swift5.0问题4. Swift桥接OC组件库解决:1) 生成LJShell-Bridging-Header.h桥接文件,2)在 Build setting中找到Objective-C Bridging Header 设置对应路径$(SRCROOT)/LianJiaShell/LJShell-Bridging-Header.h3)将Build Settings中的Defines Module选项设置为YES问题5. 引入OC组件库报查找不到解决:在podfile中在LJWidget的target引入对应 pod xxx问题6. 使用Widget Preview功能bate版本目前发现在OC工程下混编情况,prview无法使用,可以尝试新建个swift工程来编写swiftUI,使用preview功能问题7.Error: Multiple commands produce解决:方法一:不使用New Build System,在File > Project/Workspace Settings中的Share Project/Workspace Settings 里build system 将New Build System(Default)切换成Legacy build system。方法二:在 target -> Build phase > Copy Bundle Resource 中找到info.plist,移除问题8. dyld: Library not loaded:dyldibrarynotloaded:/System/Library/Frameworks/WidgetKit.framework/WidgetKitReferencedfrom:/var/containers/Bundle/Application/EA42E025-6CFA-4C90-950E-50D28255B4DA/LJShell.app/LJShellReason:imagenotfound解决:https://developer.apple.com/forums/thread/1265065 参考文献WidgetKit:https://developer.apple.com/documentation/widgetkitSwiftUI:https://developer.apple.com/tutorials/swiftui/creating-and-combining-views 预览时标签不可点 移动端37大前端69移动端 · 目录#移动端上一篇iOS内存管理之Tagged Pointer下一篇如何进行网络框架的学习和设计关闭更多小程序广告搜索「undefined」网络结果
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2024-12-31 04:23 , Processed in 0.523794 second(s), 26 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表