Issue
I'm trying to implement dynamically provided options for my iOS 15 widget. So far I successfully implemented static intent parameters, and now I wanted to extend it with dynamically provided ones.
The dynamic parameter in my .intentdefinition file is called HotspotList
and has type String
.
I have defined a struct where I have also saved a list of availableHotspots
:
struct Hotspot: Hashable, Identifiable, Codable {
...
static var availableHotspots = UserDefaults.standard.object(forKey: "hotspots") as? [String] ?? []
}
I have checked that this array is successfully saved with print(Hotspot.availableHotspots)
somewhere in my main View.
Now I want to use this array in my IntentHandler.swift file:
import Intents
class IntentHandler: INExtension, WidgetConfigurationIntentHandling {
override func handler(for intent: INIntent) -> Any {
return self
}
func provideHotspotListOptionsCollection(for intent: WidgetConfigurationIntent) async throws -> INObjectCollection<NSString> {
let hotspots: [NSString] = Hotspot.availableHotspots.map { element in
let nsstring = element as NSString
return nsstring
}
let collection = INObjectCollection(items: hotspots)
return collection
}
func defaultHotspotList(for intent: WidgetConfigurationIntent) -> String? {
return "thisIsJustATest"
}
}
I see that the intent is implemented correctly, because defaultHotspotList() returns the default parameter. But somehow provideHotspotListOptionsCollection() doesn't return the list of Strings. What am I doing wrong?
Note: I also tried the non-async option of the function:
func provideHotspotListOptionsCollection(for intent: WidgetConfigurationIntent, with completion: @escaping (INObjectCollection<NSString>?, Error?) -> Void) {
let hotspots: [NSString] = Hotspot.availableHotspots.map { element in
let nsstring = element as NSString
return nsstring
}
let collection = INObjectCollection(items: hotspots)
print(collection)
completion(collection, nil)
}
Solution
So with the hint of @loremipsum I was able to fix it by myself. For anyone interested, here's my solution:
I added the following lines in my MainView in the App target:
struct MainView: View {
@AppStorage("hotspots", store: UserDefaults(suiteName: "group.com.<<bundleID>>"))
var hotspotData: Data = Data()
...
save(hotspots: miners)
...
func save(hotspots: [String]) {
do {
hotspotData = try NSKeyedArchiver.archivedData(withRootObject: hotspots, requiringSecureCoding: false)
WidgetCenter.shared.reloadAllTimelines()
} catch let error {
print("error hotspots key data not saved \(error.localizedDescription)")
}
}
and then to retrieve the data in the IntentHandler.swift:
import Intents
import SwiftUI
class IntentHandler: INExtension, WidgetConfigurationIntentHandling {
@AppStorage("hotspots", store: UserDefaults(suiteName: "group.com.<<bundleID>>"))
var hotspotData: Data = Data()
func provideHotspotListOptionsCollection(for intent: WidgetConfigurationIntent) async throws -> INObjectCollection<NSString> {
var hotspots: [String] {
var hotspots: [String]?
do {
hotspots = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(hotspotData) as? [String]
} catch let error {
print("color error \(error.localizedDescription)")
}
return hotspots ?? []
}
let NSHotspots: [NSString] = hotspots.map { element in
let nsstring = element as NSString
return nsstring
}
let collection = INObjectCollection(items: NSHotspots)
return collection
}
Answered By - benialstrasz
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.