今天做一个桌面小插件配置IntentConfiguration的小Demo,前面我们留下一个问题没有用的那个intentdefinition,这次我们就创建一个新的工程做一个动态配置数据。按照上上一篇的文章,先创建一个工程。做一个菜单小插件。
创建一个工程命名为IntentWidget,创建一个target命名为MenuConfig,这时候我们先创建一个菜单数据模型,创建一个文件,命名为MenuJson,并添加如下代码:
struct MenuJson: Codable {
let id: String
let name: String
let image: String
static func createMenuList() -> [MenuJson] {
var list = [MenuJson]()
list.append(.init(id: "1", name: "西红柿炒鸡蛋", image: ""))
list.append(.init(id: "2", name: "水煮肉片", image: ""))
list.append(.init(id: "3", name: "白菜粉条", image: ""))
list.append(.init(id: "4", name: "鱼香肉丝", image: ""))
return list
}
}
在MenuConfig.intentdefinition的文件里添加一个MenuList类型,显示名称改成菜单列表,如下图:
然后在添加一个type变量,选择类型为MenuList,并选中Options are provided daynamically,如下图:
然后再创建一个Intents Extension扩展,需要动态处理数据。可以命名为MenuHandle,会出现一个文件IntentHandler.swift,我们在这里实现ConfigurationIntentHandling这个协议。如下:
class IntentHandler: INExtension,ConfigurationIntentHandling {
func provideTypeOptionsCollection(for intent: ConfigurationIntent, with completion: @escaping (INObjectCollection<MenuList>?, Error?) -> Void) {
let list = MenuJson.createMenuList().map { (item) -> MenuList in
.init(identifier: item.id, display: item.name)
}
completion(.init(items: list), nil)
}
override func handler(for intent: INIntent) -> Any {
// This is the default implementation. If you want different objects to handle different intents,
// you can override this and return the handler you want for that particular intent.
return self
}
}
接下来修改实体类SimpleEntry,如下:
struct SimpleEntry: TimelineEntry {
let date: Date
let configuration: ConfigurationIntent
let menu: MenuList
}
Provider这个结构体修改为如下:
struct Provider: IntentTimelineProvider {
let list = MenuJson.createMenuList().map { (item) -> MenuList in
.init(identifier: item.id, display: item.name)
}
func placeholder(in context: Context) -> SimpleEntry {
SimpleEntry(date: Date(), configuration: ConfigurationIntent(), menu: list[0])
}
func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
var firstItem = list.filter { (item: MenuList) -> Bool in
item.identifier == configuration.type?.identifier
}
if firstItem.count == 0 {
firstItem = list
}
let entry = SimpleEntry(date: Date(), configuration: configuration, menu: firstItem[0])
completion(entry)
}
func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var firstItem = list.filter { (item: MenuList) -> Bool in
item.identifier == configuration.type?.identifier
}
if firstItem.count == 0 {
firstItem = list
}
var entries = [SimpleEntry]();
entries.append(.init(date: Date(), configuration: configuration, menu: firstItem[0]));
completion(Timeline(entries: entries, policy: .atEnd ))
}
}
视图我们可以修改成如下的代码:
struct MenuConfigEntryView : View {
var entry: SimpleEntry
var body: some View {
let item = MenuJson.createMenuList().first { (subItem: MenuJson) -> Bool in
subItem.id == entry.menu.identifier
}
return GeometryReader(content: { (geometry: GeometryProxy) in
VStack(alignment: .center){
Image(uiImage: UIImage(named: item!.image)!).frame(width: geometry.size.width - 40, height: geometry.size.height - 80, alignment: .center).aspectRatio(contentMode: .fit).clipped()
Text(item?.name ?? "")
}.frame(width: geometry.size.width, height: geometry.size.height, alignment: .center)
})
}
}
最后加上图片,运行效果图如下:
后记:如果没有出现选项框,需要我们添加App GoupID,并在MenuHandle的扩展里的plist里加上NSExtension这个字典如下图:
这个就是动态配置数据的方法。好了就到这里,成功的路上总不缺少努力的人。