WidgetKit

RSS for tag

Show relevant, glanceable content from your app on iOS and iPadOS Home Screen and Lock Screen, macOS Desktop, Apple Watch Smart Stack and Complications, and in StandBy mode on iPhone.

Posts under WidgetKit tag

200 Posts
Sort by:

Post

Replies

Boosts

Views

Activity

Major regressions in Apple Watch development support with watchOS 10.5 and Xcode 15.4
I've reached a point where I can no longer make any progress diagnosing the issues that have popped up with Apple Watch development support. To hopefully help draw attention and focus to the severity of this problem, I'm gathering all related threads into this single thread. Summary of problems There are several, possibly related, issues at play: Xcode is not discovering Apple Watches. This means it's not possible to deploy apps to Apple Watches that aren't already provisioned with Xcode. I've confirmed this behavior with a watch running watchOS 10.0. The logging profile for watchOS has expired. It's no longer possible to pull logs via Console from Apple Watches. AppIntent-based complications on watchOS 10.5 no longer load, staying stuck in a "placeholder" state. This can be reproduced with the Backyard Birds demo app. It's no longer possible to debug widget extensions on Apple Watch hardware. Feedback submitted FB13758427: No longer able to connect to Apple Watch from Xcode I was attempting to test another regression related to AppIntents no longer working on watchOS 10.5. To confirm the behavior had regressed since earlier versions of watchOS, I set up one of my older Apple Watches that is still running watchOS 10.0. After wiping the watch and repairing it with one of my test devices (iPhone 11 Pro, iOS 17.4.1), I’m unable to get the Apple Watch to appear in Xcode’s Devices & Simulators manager. The phone is connected via USB cable, and the phone appears as a Connected phone, but the watch does not appear. My Apple Watch Ultra that I use as my daily driver does appear as a remote device (the globe icon is next to it), but the Apple Watch 10.0 does not appear. Details about the older watch: Version: 10.0 21R5341c Model: A2478 Not being able to test on other Apple Watches is severely limiting my ability to isolate and confirm the regression in AppIntent support that can be reproduced in the Backyard Birds demo app. Note that the 10.0 watch does actually appear in the Console app, but with a warning sign next to it. The 10.0 watch also appears twice. Clicking the warning sign does not reveal any information about why the warning is appearing, but after ~5 seconds I do get the following error in Console.app: “The user has not responded to the pairing request on 'Headless’ Respond to the Trust prompt on the device.” There is no trust prompt on the device. FB13756074: WatchOS logging profile is no longer valid https://developer.apple.com/bug-reporting/profiles-and-logs/?platform=watchos is no longer valid. See attached error that occurs when attempting to install the profile onto my Apple Watch Ultra. It seems that without this I’m unable to get any logs off of my Apple Watch, which is making testing/development quite difficult. FB13758450: AppIntent-based widgets no longer render on watchOS 10.5 AppIntent-based complications no longer get beyond a placeholder state on watchOS. This can be reproduced with the Backyard Birds demo app, which uses AppIntent-based widget configurations for the watchOS complications. AppIntent-based complications did appear to work in previous versions of watchOS 10, but I’m unable to confirm this with a 10.0 Watch I have due to FB13758427. To reproduce deploy the attached unmodified Backyard Birds app to a watch running watchOS 10.5. add a Backyard Birds complication to a watch face. Expected behavior: the widget shows live data Actual behavior: the complication never leaves a placeholder state. See the attached screenshot for the state the widget is stuck in. FB13758490: PacketLogger no longer logs packets PacketLogger used to log BTLE packets as they were received and transmitted on a macOS machine. Since updating to 14.5 Beta (23F5064f) however, PacketLogger no longer logs packets on macOS at all. Upon starting a new session, the interface remains empty. PacketLogger is still able to log packets from a connected iOS device. Related threads Apple Watch cannot reconnect WatchOS Sysdiagnose Profile is no longer XCode 15 can't run on iOS 17 devices. Previous preparation error: An error occurred while communicating with a remote process.. The connection was invalidated.
13
6
1.8k
May ’24
Configurable Widget not working in Swift Package
My app has two static widgets. In the widget extension, I have the following code: import WidgetKit import SwiftUI import ItemWidgetsKit @main struct ItemWidgetsBundle: WidgetBundle { var body: some Widget { RecentSavesWidget() RecommendationsWidget() } } the rest of the code, including the two Widget implementations, the TimelineProvider, etc, are in the imported ItemsWidgetKit, which is a library inside a Swift Package containing several libraries. These two widgets work as expected. Now I am adding a configurable widget, and the code above changes like so: import WidgetKit import SwiftUI import ItemWidgetsKit @main struct ItemWidgetsBundle: WidgetBundle { @WidgetBundleBuilder var body: some Widget { makeWidgets() } func makeWidgets() -> some Widget { if #available(iOS 17.0, *) { return WidgetBundleBuilder.buildBlock(RecentSavesWidget(), TopicRecommendationsWidget()) } else { return WidgetBundleBuilder.buildBlock(RecentSavesWidget(), RecommendationsWidget()) } } } TopicRecommendationsWidget is similar to RecommendationsWidget except that it lets you choose a topic to display recommendations for, by long pressing and selecting an intent. I followed the same approach of the other two widgets, and put the code inside ItemWidgetsKit This time, though, the widget does not work, and it only loads the placeholder; in fact, in the AppIntentTimelineProvider implementation (see below) only placeholder(in:) gets ever called @available(iOS 17.0, *) public struct TopicTimelineProvider: AppIntentTimelineProvider { public func placeholder(in context: Context) -> TopicEntry { return TopicEntry(date: Date(), content: TopicContent.sampleContent) } public func snapshot(for configuration: TopicIntent, in context: Context) async -> TopicEntry { return TopicEntry(date: Date(), content: configuration.topicEntity.topic) } public func timeline(for configuration: TopicIntent, in context: Context) async -> Timeline<TopicEntry> { let entry = TopicEntry(date: Date(), content: configuration.topicEntity.topic) return Timeline(entries: [entry], policy: .never) } } for more context, here's the code for the configurable Widget implementation (that resides inside ItemWidgetsKit @available(iOS 17.0, *) public struct TopicRecommendationsWidget: Widget { let kind: String public init() { self.kind = WidgetKind.topicRecommendations // a string stored elsewhere } public var body: some WidgetConfiguration { AppIntentConfiguration(kind: kind, intent: TopicIntent.self, provider: TopicTimelineProvider()) { entry in TopicWidgetContainerView(entry: entry) } .configurationDisplayName("New Recommendations") .description("Select a Topic") .supportedFamilies([.systemMedium, .systemLarge]) } } Any Idea why this happens and what would be the solution to this problem? Thank you
0
0
248
Apr ’24
How to prevent duplicate resource bundles from SPM dynamic framework in app extensions?
We use a local swift package in 6 of our app extensions. The product from the local package that we link to each app extension is a dynamic framework. And while the dynamic framework is copied into the final app bundle once, the resource bundles of each target that comprise the dynamic framework is copied into each app extension. I'd much rather have the bundles be copied into the dynamic framework once to prevent app bloat. Here is a visualization of the issue: . └── MyApp.ipa/ ├── MyApp (executable) ├── MyDynamicFramework_TargetA.bundle ├── MyDynamicFramework_TargetB.bundle ├── MyDynamicFramework_TargetC.bundle ├── Frameworks/ │ └── MyDynamicFramework.framework/ │ ├── TargetA │ ├── TargetB │ └── TargetC └── PlugIns/ ├── Widgets.appex/ │ ├── MyDynamicFramework_TargetA.bundle │ ├── MyDynamicFramework_TargetB.bundle │ └── MyDynamicFramework_TargetC.bundle ├── Intents.appex/ │ ├── MyDynamicFramework_TargetA.bundle │ ├── MyDynamicFramework_TargetB.bundle │ └── MyDynamicFramework_TargetC.bundle ├── IntentsUI.appex/ │ ├── MyDynamicFramework_TargetA.bundle │ ├── MyDynamicFramework_TargetB.bundle │ └── MyDynamicFramework_TargetC.bundle ├── NotificationContent.appex/ │ ├── MyDynamicFramework_TargetA.bundle │ ├── MyDynamicFramework_TargetB.bundle │ └── MyDynamicFramework_TargetC.bundle ├── RichPushContent.appex/ │ ├── MyDynamicFramework_TargetA.bundle │ ├── MyDynamicFramework_TargetB.bundle │ └── MyDynamicFramework_TargetC.bundle └── NotificationService.appex/ ├── MyDynamicFramework_TargetA.bundle ├── MyDynamicFramework_TargetB.bundle └── MyDynamicFramework_TargetC.bundle Notice that the resource bundles of Target A, B, and C are copied multiple times causing an unhealthy app size. I'd either like the resource bundles to be copied into MyDynamicFramework or copied once into the app bundle and let the app extensions reference them. Given the SPM + Xcode linking is a black box for the most part, how would I accomplish this?
2
0
535
2w
How do I get my widgets to work?
iOS app with Home Screen and Lock Screen widgets written in Swift/SwiftUI. I've never been able to get widgets to work properly. It's more pronounced on Lock Screen widgets, so let's try that method first... The app stores data in Core Data as an Event. They're read into my model and stored as WidgetEventDetails structs: struct WidgetEventDetails: AppEntity, Identifiable, Hashable { public var eventId: String public var name: String public var date: Date public var id: String { eventId } This all works absolutely fine in the iOS app, and each one is unique based on the eventId. When I go to add a Lock Screen widget, I customise the Lock Screen, tap in the section to add a widget, and my widgets appear correctly and are selectable: (bottom right, says "1y 28w 1d") So, I tap it and it appears in the widgets section: But it appears as "17w 6d", which is a different event entirely. Notice how the one in the selectable widgets has changed to "15w 5d", and the one I tapped (1y 28w 1d) is nowhere to be seen. So, I tap the one in the top row (17w 6d) to select an event, and this appears, suggesting that the event is the "Edinburgh & Glasgow 2024-02" event: But that event is actually only a day away (1d), so that's not the one I selected at all. I tap the list and see these events: I select "Las Vegas 2024", which is 17w 3d away, and this is shown: 17w 6d is a different event, not Las Vegas 2024. So, I tap it again and see this. The "Loading" text appears for ages, but occasionally does show the full list, as before: I select "Edinburgh & Glasgow 2024-02" which is 1d away, and I see this again: So, I resign myself to hoping it'll just figure itself out, and I tap "Done": "17w 6d" again :( I finish customising, and exit the customisation screen. I show the Lock Screen, and I see this: Why doesn't this work? Here's the code: @main struct WidgetExtensionBundle: WidgetBundle { @WidgetBundleBuilder var body: some Widget { WidgetExtension() } } struct WidgetExtension: Widget { var body: some WidgetConfiguration { AppIntentConfiguration(kind: kWidgetKind, intent: WidgetEventIntent.self, provider: WidgetEventTimelineProvider()) { entry in WidgetEntry(entry: entry) .environment(modelData) } .configurationDisplayName(NSLocalizedString("AddingWidget_Title", comment: "Adding the Widget")) .description(NSLocalizedString("AddingWidget_Description", comment: "Adding the Widget")) .supportedFamilies([.accessoryCircular, .accessoryInline, .accessoryRectangular, .systemSmall, .systemMedium]) .contentMarginsDisabled() } } struct WidgetEventIntent: WidgetConfigurationIntent { static let title: LocalizedStringResource = "AddingWidget_Title" static let description = IntentDescription(LocalizedStringResource("AddingWidget_Description")) @Parameter(title: LocalizedStringResource("Event")) var event: WidgetEventDetails? init(event: WidgetEventDetails? = nil) { self.event = event } init() {} static var parameterSummary: some ParameterSummary { Summary { \.$event } } } struct EventQuery: EntityQuery, Sendable { func entities(for identifiers: [WidgetEventDetails.ID]) async throws -> [WidgetEventDetails] { modelData.availableEvents.filter { identifiers.contains($0.id) } // availableEvents is just [WidgetEventDetails] } func suggestedEntities() async throws -> [WidgetEventDetails] { return modelData.availableEvents.filter { $0.type == kEventTypeStandard } } } If you think it's the TimelineProvider causing it, I can provide that code, too.
2
0
620
Jun ’24
Fetching location from iOS app's widget extension running on MacOS
I'm stuck fetching location inside iOS app's widget extension running on MacOS. locationManager.authorizationStatus == .notDetermined always returns true, meanwhile main app, running on MacOS has permission for location in MacOS system settings and doesn't have any problems with using geodata. Is it possible to fetch a location inside of iOS app's widget extension running on MacOS and if yes, what could I be doing wrong?
0
0
306
Mar ’24
XCode 15.3 WidgetKit Preview Problem
Hi all, I am trying to create a widget for my app but I cannot use the Preview feature of Xcode. Xcode enters a build loop and builds the project over and over. There is no error or message. There is only a loading spinner and lots of build. It doesn't matter how much time I wait, it never finishes. I tried to clean the build folder, delete all preview simulators, quit, and reopen the XCode but nothing helped.
3
0
578
Mar ’24
Live Activity Stops Updating after iPhone Lock
My background audio app stops updating its Live Activity after the iPhone locks, and doesn't resume updating the activity after tapping the screen or even after FaceID unlocks the device (without opening the lock screen). My live activity requests a ContentState update & iOS updates the content for the activity as below: Task{ log.debug("LiveActivityManager.updateLiveActivity() with new ContentState") await liveActivity.update( ActivityContent(state:contentState, staleDate:nil) ) } Below what my log looks like: <<<<SWIPE LOCK SCREEN DOWN>>>> DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState iOS: Updating content for activity 0A519263-1E46-4BB6-BA4F-F3DDBC081AB4 DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState iOS: Updating content for activity 0A519263-1E46-4BB6-BA4F-F3DDBC081AB4 <<<<PRESS LOCK BUTTON->Lock iPhone>>>> INFO: --------protectedDataWillBecomeUnavailableNotification-------- DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState iOS: Updating content for activity 0A519263-1E46-4BB6-BA4F-F3DDBC081AB4 DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState <<<<LOOK AT & TAP LOCK SCREEN->Unlock iPhone without swiping up>>>> INFO: --------protectedDataDidBecomeAvailableNotification----------- DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState DEBUG: LiveActivityManager.updateLiveActivity() with new ContentState As shown in the log, normally iOS updates the content for my activity after my liveActivity.update request. This works fine in the Dynamic Island and when after switching apps and swiping down to see the lock screen without locking the phone. However, once I lock the phone, iOS stops updating the Live Activity content, and doesn't resume updates until after the app regains the foreground at least once. Has anyone else encountered this behavior? Is this a setting that I'm missing, or a bug?
8
1
1.1k
2w
Create Widget for iOS 14 with Xcode 15.3
Hi all, I am experimenting with Widgets and I would like to add to my SwiftUI app a Widget that can be run on iOS 14. My Mac has macOS Sonoma 14.4, I am using Xcode 15.3. My SwiftUI app can target back to iOS 14. When adding a Widget with Xcode 15.3, the Widget can only target iOS 17. If I downgrade the minimum iOS version of the Widget extension, then my project doesn't compile anymore. I have tried multiple attempts to solve this problem. All of them have failed. If would be nice if someone could give me help on one or more of them: I have tried to install Xcode version 12.5.1, but apparently it is not possible on Sonoma. (It gets installed, but then I get an error on the first execution) I have tried to install a virtual machine in Parallels with macOS Big Sur, but I wasn't able to find the IPSW installation file from the Apple developer downloads. I have created a widget with Xcode 15.3, then replaced the files with the content of a new widget found in a YouTube video, and modified the project.pbxproj inside the xcodeproj as in the attached file (essentially I have added WidgetKit as a framework with an older version, that doesn't require iOS 17) Now: the full app compiles I can test the widget in the Xcode preview I can't deploy the app on both my iPhone with iOS 17.4, and on a Simulator with iOS 15. As I am not expert, probably I miss many steps or I have done many errors. Can anyone please help me in adding an iOS 14 Widget on Xcode 15.3 on Sonoma?
1
0
507
May ’24
WidgetKit Refresh Policy: onOverrideList == 1
I have an iOS app with widgetkit extension, and the widgets stopped updating. I attached the console, and saw these lines for widgets of my app: com.apple.widget.myApp::myWidgetKind::-6207022974507159915:417E34:[ {name: Widget Refresh Policy, policyWeight: 0.010, response: {Decision: Must Not Proceed, Score: 0.00, Rationale: [{onOverrideList == 1 AND IndividualBalance == -1}]}} ], FinalDecision: Must Not Proceed} The IndividualBalance == -1 apparently means that the app was updating widgets too often, but what about onOverrideList == 1? There seems to be no info online about this flag, and LLMs seem to suggest that the app got onto some kind of Apple's blacklist for updating too often, is that right?
0
0
336
Mar ’24
How long can widget be executed after being activated by the iOS system
Widgets are activated by the iOS system at regular intervals, and the task code defined in the TimelineProvider is executed. How long can this task code be executed at most? I don't think the system will allow tasks defined in the timeline to be executed continuously (looking like a background resident program), so there must be a time limit. If you know, or if there are related document links, please let me know Thank you.
0
0
189
Mar ’24
Widgets without timeline on WatchOS
TLDR; Can I have a widget without a Timeline? My previous watch app had a complication. Simply so it can be added to the watch face for a quick launch of the app. However now seeing that method is deprecated in favour of widgets. Can I add a widget without the need for all the Timeline as all I want is a button on the watch face to launch into my app. No data is updated over time so no need for all the extra timeline code.
1
0
596
Apr ’24
Single Radio Station Lock Screen Audio Card
I am working on a radio app. This is the first time and I have a problem with lock Screen Audio Card. According to docs It looks ok but could you please check why I can not display Audio Now Playing Card on lock Screen. 2 Code samples, 1. Now Playing and 2. Logic of current song and Album art. 1. Now Playing // Create a dictionary to hold the now playing information var nowPlayingInfo: [String: Any] = [:] // Set the title of the current song nowPlayingInfo[MPMediaItemPropertyTitle] = currentSong // If album art URL is available, fetch the image asynchronously if let albumArtUrl = albumArtUrl { URLSession.shared.dataTask(with: albumArtUrl) { data, _, error in if let data = data, let image = UIImage(data: data) { // Create artwork object let artwork = MPMediaItemArtwork(boundsSize: image.size) { _ in image } // Update now playing info with artwork on the main queue DispatchQueue.main.async { nowPlayingInfo[MPMediaItemPropertyArtwork] = artwork MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo } } else { // If there's an error fetching the album art, set now playing info without artwork MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo print("Error retrieving album art data:", error?.localizedDescription ?? "Unknown error") } }.resume() } else { // If album art URL is not available, set now playing info without artwork MPNowPlayingInfoCenter.default().nowPlayingInfo = nowPlayingInfo } } 2. Current Song, Album Art Logic let parts = currentSong.split(separator: "-", maxSplits: 1, omittingEmptySubsequences: true).map { $0.trimmingCharacters(in: .whitespaces) } let titleWithExtra = parts.count > 1 ? parts[1] : "" let title = titleWithExtra.components(separatedBy: " (").first ?? titleWithExtra return title } func updateSongInfo() { let url = URL(string: "https://live.heartfm.com.tr/listen/heart_fm/currentsong")! URLSession.shared.dataTask(with: url) { data, response, error in if let data = data, let songString = String(data: data, encoding: .utf8) { DispatchQueue.main.async { self.currentSong = songString.trimmingCharacters(in: .whitespacesAndNewlines) self.updateAlbumArtUrl(song: self.currentSong) } } }.resume() } private func updateAlbumArtUrl(song: String) { let parts = song.split(separator: "-", maxSplits: 1, omittingEmptySubsequences: true).map { $0.trimmingCharacters(in: .whitespaces) } let artist = parts.first ?? "" let titleWithExtra = parts.count > 1 ? parts[1] : "" let title = titleWithExtra.components(separatedBy: " (").first ?? titleWithExtra let artistAndTitle = artist.isEmpty || title.isEmpty ? song : "\(artist) - \(title)" let encodedArtistAndTitle = artistAndTitle.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? artistAndTitle albumArtUrl = URL(string: "https://www.heartfm.com.tr/ArtCover/\(encodedArtistAndTitle).jpg") }
0
0
445
Feb ’24