I don't have any definitive answers here, but I can answer one of your questions: Always use multiple timeline entries if the exact timing of when a widget shows up is important. When you refresh your widget, if you add a timeline entry for a given date/time it will show up within a second or two of that time. On the other hand, the system can be very unpredictable about when it will activate your extension to run your reload logic. My suggestion is to generate timeline entries well past the time when you want to refresh with your best guess as to what it should look like then, and let those get replaced whenever your timeline does get refreshed.
Post
Replies
Boosts
Views
Activity
For parameters that have a known set of options (boolean, String, enum, etc) you specify the default in the intent definition file when you specify the parameter in the first place. When a snapshot is generated for preview or when the user initially installs a widget on their homes screen, the default value is the way the intent is initialized, and that is the value you will receive in the configuration that is sent to your snapshot(...) and timeline(...) implementations. The one wrinkle here is that if the widget was installed using an older version of your app (ie you add a new configuration option in a later release) that value will not get initialized and will be nil until the user opens the configuration. I believe this is a bug (filed as FB8754457 if anyone at Apple is listening). The way to deal with that is to look for that nil value and replace it with whatever you want the default to be. I do this in an extension to the intent like the following:
extension MyIntent {
public func me_showThing() -> Bool {
return self.showThing?.boolValue ?? true
		}
}
If you are trying to specify the default value for a dynamic parameter then you do that in the same place you specify the list of possible values. Once you specify that a parameter values are dynamic then a protocol is generated that is something like MyIntentHandling which has two relevant methods: one is for specifying all the options of the form provideMyThingOptionsCollectionForMyIntent:withCompletion: and one to specify the default that is something like defaultMyThingForMyIntent:
You are definitely not alone in seeing this issue. I am constantly struggling against it. Unfortunately, I also don't have any real solution for you. I have a few different widgets and I have done a far bit of testing to try to figure out what is going on. I can provide a few notes in case that helps you or anyone else get closer to a solution.
The preview view is generated one time and then seems to be cached forever. Although I haven't tested this, I believe you would have to completely delete the app to get the preview to refresh. This is relevant because if you happen to have had a blank preview initially it will continue to be blank even if you have changed the preview since then.
The less my widgets need to do while generating the timeline entries, the more likely they are to succeed. One widget is only pulling a few user configured values from the main application and it works nearly 100% of the time. Other widgets need to retrieve a significant amount of data from a database. Logging tells me that those widgets are always completing the timeline generation work, but then the data often just completely fails to show up in the widget itself.
While the widget will appear blank if your extension crashes in some way, it does not appear to be the only reason it can be blank. I have seen it be blank many times without any sign that it had crashed and plenty of evidence to the contrary.
For whatever it is worth, I am testing on a real device (iPhone X) and not the simulator.
I haven't tried to use the API myself, but what you are seeing feels like a bug to me. I am certainly not from Apple so I don't know what they expect, but I would expect it to give you up-to-date information about all the currently active widgets along with a valid family type. If you aren't seeing that I would recommend submitting feedback and hope it gets addressed before the release.
I don't know if you can get exactly what you are looking for, but I think you can achieve the same end results using getcurrentconfigurations(_:). It will allow you to query what widget configurations are currently in use from the main application. This should allow you to periodically poll for the current widgets and then record whatever you need.
https://developer.apple.com/documentation/widgetkit/widgetcenter/getcurrentconfigurations(_:)
Another thing to be aware of, is that the system has a floor to how frequently it will allow you to refresh the widget. I have no idea what all might go into the decision process but I did some testing with my widgets and on Beta 4 it seems like with a configured refresh rate of 5 seconds (this is way too short, never actually do this) the actual refresh rates is roughly every 5 minutes when the screen is active and the widget is visible or every 15 minutes with the phone screen turned off.
var weekday = Calendar.current.component(.weekday, from: Date())
var weekDayString = Calendar.current.shortWeekdaySymbols[weekday - 1]
Note that the value in weekday is 1-based (1-7) while the symbols array is 0-based (0-6). There are several different arrays to choose from depending on the exact usage you are looking for.
Everything looks correct in your code. It should be working as you expect. A single timeline entry is generated with a single random number and then after 15 minutes your timeline should be regenerated.
As you update to beta 4, be aware that several of the things you have copied are now deprecated and I have found it acts a little strange with the old methods. The placeholder logic is now handled in a placeholder(in:) alongside snapshot and timeline, which have respectively been changed to getSnapshot(with:in:completion:) and getTimeline(with:in:completion:)
The way that I am dealing with this is to generate the same array for all widgets and then limit it on the view side where the @Environment(\.widgetFamily) does work. In your case, you can have your timeline always generate 9 items in the array, then in your view you can do something like the following:
func getArray(array: [String]) -> [String] {
	 if (family == .systemSmall) {
			return Array(array.prefix(3))
	 } else if (family == .systemMedium) {
			return Array(array.prefix(6))
	 } else {
			return array
	 }
}
Depending on what you want to do, you don't even have to do that. The simplest way to handle light/dark mode is to define any color you want switch in the asset catalog (something like "Assets.xcassets")and set "Appearances" for the color to "Any, Dark". You can do this for as many colors as you need. You can then use those colors by name using something like: Color("WidgetBackground"). The widget will then automatically switch when the system theme changes.
It is definitely a daytime/nighttime indicator for that location. I can't tell exactly but it is something like white from 7 AM - 7PM and dark from 7PM - 7 AM
The .time and .date styles do not update over time. Using "Text(Date(), style: .time)" will display the time when the widget timeline was refreshed with a call to getTimeline(for:in:completion:) and will remain static until the next time the timeline is regenerated. The relative styles (.relative, .offset, .timer) are special in that they update in real-time between refreshes of the timeline which allows you to show a relative time without having to generate a timeline entry for each change in the value.
As a side note, I will mention that .relative shows the difference in time but without any indication of if it is positive or negative. Exactly 15 minutes before the given time will return "15 min, 0 sec" and exactly 15 minutes after the given time will also return "15 min, 0 sec"
If I might state this question slightly differently, some of Apple's widgets (Shortcuts, battery) use a background which appears to be something like .systemThinMaterial, but none of the ways I have tried to apply it to the background have worked.
Is there a way for non-Apple widgets to do this?
If so, how?
I am also having problems with getting Swift views to preview correctly. The error I am seeing is:
”Remote Human Readable Error: PreviewAgentError: Statically rendering previews is not supported on iOS Simulators”
I don't have any problems at all with previews in small, toy apps, but inside my real, actual project views don't render. Widgets can generate previews most of the time, but plain, non-widget views will not ever render. I have to develop my views in a separate project and them copied them over to the main project once they are mostly done.