近期在做Widget小组件相关的开发,于是整理和记录在iOS14 Widget小组件开发过程中用到的知识点。
1、与APP数据同步
首先你得有个AppGroup,添加AppGroup,选择Target,点击Signing & Capability,再点击+Capability,找到AppGroup并双击。然后在AppGroups列表找到要使用ID,如果没有的话可以通过+新增即可。
NSUserDefault方式:
//OC
NSUserDefault *store = [[NSUserDefaults alloc] initWithSuiteName:@"group.yourgroupid"];
[store setObject:@"yourvalue" forKey:@"yourkey"];
[store synchronize];
//Swift
let store = UserDefaults(suiteName: "group.yourgroupid")
store.setValue(@"yourvalue", forKey: @"yourkey")
store.synchronize()
let store = UserDefaults(suiteName: "group.yourgroupid")
let obj = store.value(forKey: "yourkey")
if obj == nil {
} else {
}
NSFileManager文件方式:
NSURL *yourFileURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:@"group.yourgroupid"];
yourFileURL = [yourFileURL URLByAppendingPathComponent:@"your_file_name"];
//TODO: 拿到file url后就可以做你想做的事了,如果用sqlite,记得在pods中添加target widgetXXX,在里面加入FMDB,然后install
2、强制刷新Widget
当需要触发刷新Widget时,可通过WidgetCenter.shared.reloadAllTimelines()刷新全部,或者通过kind string刷新某一个WidgetCenter.shared.reloadTimelines(ofKind: “your_kind_string”)
WidgetKit只存在于Swift中,所以使用Objective-C的需要引入Swift混编,通过OC调用Swift来刷新Widget,至于OC和Swift混编的相关知识请各位自行查找。
import Foundation
import WidgetKit
public class MyWidget: NSObject {
@objc
public func reloadWidget() {
if #available(iOS 14.0, *) {
WidgetCenter.shared.reloadAllTimelines()
} else {
// Fallback on earlier versions
};
}
}
3、显示一张图片
针对不同尺寸的Widget进行处理,通过添加Image控件进行显示。
struct PPPasswordWidgetEntryView : View {
var entry: Provider.Entry
//针对不同尺寸的 Widget 设置不同的 View
@Environment(\.widgetFamily) var family // 尺寸环境变量
var body: some View {
switch family {
case.systemSmall:
Image.init("AppBgImage")
.resizable()
.frame(minWidth: 141, maxWidth: 200, minHeight: 141, maxHeight: 200, alignment: .center)
.scaledToFit()
.edgesIgnoringSafeArea(.all)
case.systemMedium:
Image.init("AppBgImage")
.resizable()
.frame(minWidth: 141, maxWidth: 200, minHeight: 141, maxHeight: 200, alignment: .center)
.scaledToFit()
.edgesIgnoringSafeArea(.all)
default:
Image.init("AppBgImage")
.resizable()
.frame(minWidth: 141, maxWidth: 400, minHeight: 141, maxHeight: 400, alignment: .center)
.scaledToFit()
.edgesIgnoringSafeArea(.all)
}
}
}
4、显示图片+文字
通过设置VStack的background来实现背景图片,通过在VStack中添加Text实现文本显示。
struct GYWidgetEntryView : View {
var entry: Provider.Entry
var body: some View {
let themeBgName = entry.themeBgName//主题背景图片
let textColor = entry.textColor//要显示文字内容
GeometryReader{ geo in
VStack {
Text(entry.content)
.font(.system(size: 24))
.padding(12)
.minimumScaleFactor(0.2)
.foregroundColor(textColor)
}.frame(width: geo.size.width, height: geo.size.height)
.background(Image(themeBgName)
.resizable()
.scaledToFill())
.padding(0)
}
}
}
5、文字自适应
Text(entry.content)
.font(.system(size: 24))
.padding(12)
.minimumScaleFactor(0.2)
.foregroundColor(textColor)
6、日期转字符串
//日期 -> 字符串
func date2String(date:Date, dateFormat:String = "yyyy-MM-dd HH:mm:ss") -> String {
let formatter = DateFormatter()
formatter.locale = Locale.init(identifier: "zh_CN")
formatter.dateFormat = dateFormat
let date = formatter.string(from: date)
return date
}
7、增加多组Widget
删除原Widget的@main声明,增加WidgetBundle
@main
struct Widgets: WidgetBundle {
@WidgetBundleBuilder
var body: some Widget {
BJXX2Widget();
BJXXWidget()
}
}
8、设置只显示小组件,中号和大号组件不显示
通过supportedFamilies方法进行设置,参数为支持的WidgetFamily数组,共包含了.systemSmall、.systemMedium、.systemLarge。
struct BJXX2Widget: Widget {
let kind: String = "BJXX2Widget"//北京限行日历小组件
var body: some WidgetConfiguration {
StaticConfiguration(kind: kind, provider: Provider()) { entry in
BJXX2WidgetEntryView(entry: entry)
}
.configurationDisplayName("一周限行")
.supportedFamilies([.systemSmall])
.description("限行号码一目了然")
}
}
9、自定义View
如何实现尾号限行日历小组件中一天的布局呢?自定义DayItemView,通过VStack包裹日期和限行尾号即可。
struct DayItemView : View {
let day: String
let number: String
init(day: String, number:String) {
self.day = day
self.number = number
}
var body: some View {
VStack {
Spacer()
Text(day)//那一天,例如:16
.font(.system(size: 12))
Text(number)//限行尾号,例如2和7
.font(.system(size: 9)).foregroundColor(.gray)
Spacer()
}
.frame(width: 32, height: 32, alignment: .center)
}
}
10、审核相关
小组件内容应该丰富的个性化的动态的,避免提供静态内容。要不很容易就审核人员4.4拒绝了。
如果你的小组件不包含Siri快捷键指令,请在提交审核时在备注中写上:不包含Siri快捷指令。如不不填写的话可能会被打回补充信息,询问是否包含Siri快捷键指令或如何操作等等,之前我增加Widget后首次提交审核审就是被这样打回的。