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

Post

Replies

Boosts

Views

Activity

Can't Widgetkit use lottie to implement the isOn state of toggle?
I introduced lottie to toggle in my widget to show a transition animation, but found that the.json file wouldn't load. The loading_hc.json file is validated and exists in the widget target. Ask for help, thank you! struct LottieView: UIViewRepresentable { let animationName: String func makeUIView(context: Context) -> LOTAnimationView { let lotAnimationView = LOTAnimationView(name: animationName, bundle: .main) lotAnimationView.contentMode = .scaleAspectFit lotAnimationView.play() return lotAnimationView } func updateUIView(_ uiView: LOTAnimationView, context: Context) { } func makeCoordinator() -> Coordinator { Coordinator() } } struct ControlToggleDisarmingStyle: ToggleStyle { func makeBody(configuration: Configuration) -> some View { if configuration.isOn { LottieView(animationName: "loading_hc.json").foregroundColor(.clear).frame(width: 24,height: 24) } else { Image("icon_disarm", bundle: Bundle.main).foregroundColor(.clear) } } }
2
0
439
Jan ’25
get location in app intent for interactive widgets
I have an app intent for interactive widgets. when I touch the toggle, the app intent perform to request location. func perform() async throws -> some IntentResult { var mark: LocationService.Placemark? do { mark = try await AsyncLocationServive.shared.requestLocation() print("[Widget] ConnectHandleIntent: \(mark)") } catch { WidgetHandler.shared.error = .locationUnauthorized print("[Widget] ConnectHandleIntent: \(WidgetHandler.shared.error!)") } return .result() } @available(iOSApplicationExtension 13.0, *) @available(iOS 13.0, *) final class AsyncLocationServive: NSObject, CLLocationManagerDelegate { static let shared = AsyncLocationServive() private let manager: CLLocationManager private let locationSubject: PassthroughSubject<Result<LocationService.Placemark, LocationService.Error>, Never> = .init() lazy var geocoder: CLGeocoder = { let geocoder = CLGeocoder() return geocoder }() @available(iOSApplicationExtension 14.0, *) @available(iOS 14.0, *) var isAuthorizedForWidgetUpdates: Bool { manager.isAuthorizedForWidgetUpdates } override init() { manager = CLLocationManager() super.init() manager.delegate = self } func requestLocation() async throws -> LocationService.Placemark { let result: Result<LocationService.Placemark, LocationService.Error> = try await withUnsafeThrowingContinuation { continuation in var cancellable: AnyCancellable? var didReceiveValue = false cancellable = locationSubject.sink( receiveCompletion: { _ in if !didReceiveValue { // subject completed without a value… continuation.resume(throwing: LocationService.Error.emptyLocations) } }, receiveValue: { value in // Make sure we only send a value once! guard !didReceiveValue else { return } didReceiveValue = true // Cancel current sink cancellable?.cancel() // We either got a location or an error continuation.resume(returning: value) } ) // Now that we monitor locationSubject, ask for the location DispatchQueue.global().async { self.manager.requestLocation() } } switch result { case .success(let location): // We got the location! return location case .failure(let failure): // We got an error :( throw failure } } // MARK: CLLocationManagerDelegate func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) { defer { manager.stopUpdatingLocation() } guard let location = locations.first else { locationSubject.send(.failure(.emptyLocations)) return } debugPrint("[Location] location: \(location.coordinate)") manager.stopUpdatingLocation() if geocoder.isGeocoding { geocoder.cancelGeocode() } geocoder.reverseGeocodeLocation(location) { [weak self] marks, error in guard let mark = marks?.last else { self?.locationSubject.send(.failure(.emptyMarks)) return } debugPrint("[Location] mark: \(mark.description)") self?.locationSubject.send(.success(mark)) } } func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) { locationSubject.send(.failure(.errorMsg(error.localizedDescription))) } } I found it had not any response when the app intent performed. And there is a location logo tips in the top left corner of phone screen.
2
0
596
Jan ’25
iOS 18 Button with accented image is broken(cannot tap) in desktop widget.
In iOS 18 widget, button is broken when it's has an accented desaturated image as content, the button's AppIntent will not trigger perform function. checkout the code below: ` struct WidgetExtEntryView : View { var entry: Provider.Entry var body: some View { VStack { Text("count:") Text("\(WidgetExtAppIntent.count)") HStack { // button can not be tapped Button(intent: WidgetExtAppIntent(action: "+1")) { VStack { Image(systemName: "plus.square.fill").resizable() .widgetAccentedRenderingMode(.accentedDesaturated) // <-- here .frame(width: 50, height: 50) Text("Broken") } }.tint(.red) // button can be tapped Button(intent: WidgetExtAppIntent(action: "+1")) { VStack { Image(systemName: "plus.square.fill").resizable() .widgetAccentedRenderingMode(.fullColor) // <-- here .frame(width: 50, height: 50) Text("OK").frame(width: 50, alignment: .center) } }.tint(.green) } .minimumScaleFactor(0.5) } } } ` check out the full demo project: ButtonInWidgetBrokenIOS18
2
0
299
Jan ’25
Xcode 16 beta 6 - Widget gallery doesn't show app in iOS 15
We have minimum deployments set to iOS 15 in one of the app for both application and widget target. When install app in simulator or real device using Xcode 15.4, it works fine in iOS15, iOS16, iOS17 and iOS18 beta. When install app in simulator or real device, using Xcode 16 beta 6, it works fine in iOS16, iOS17 and iOS18 beta but in iOS 15, our app doesn't show in widget gallery.
18
12
4.6k
Jan ’25
Live Activities - Missing Entitlement
I've built an app that supports live activities, but when trying to build and deploy I'm getting the error: Provisioning profile "iOS Team Provisioning Profile doesn't include the com.apple.developer.live-activity entitlement." Looking in Xcode - under signing and provisions, there is no "Live Activity" option to select. Looking in the developer portal, similarly under Certificates, Identifiers & Profiles, there is no "Live Activity" option. I've added com.apple.developer.live-activity to my entitlements file for both my widget and my main app target, and added NSSupportsLiveActivities to my info.plist files. I'm building on Xcode Version 16.0 Any ideas on how to fix this? Super confused! Thanks in advance!
3
2
745
Dec ’24
Timeline refresh issue for widget on ios 18.2
I use AppIntent to trigger a widget refresh, Appint is used on Button or Toggle,as follows var isAudibleArming = false struct SoundAlarmIntent: AppIntent { static var title: LocalizedStringResource = "SoundAlarmIntent" func perform() async throws -> some IntentResult { isAudibleArming = true return .result() } } func timeline( for configuration: DynamicIntentWidgetPersonIntent, in context: Context ) async -> Timeline { var entries: [Entry] = [] let currentDate = Date() let entry = Entry(person: person(for: configuration)) entries.append(entry) if isAudibleArming { let entry2 = Entry(person: Person(name: "Friend4", dateOfBirth: currentDate.adding(.second, value: 6))) entries.append(entry2) } return .init(entries: entries, policy: .never) } The timeline function fires, with entry corresponding to view1 and entry2 corresponding to view2. I expect to show view1 immediately and view2 6 seconds later. You get the correct response on iOS17. But the 6 second delay function on the discovery code in iOS18.2 takes effect immediately, view1 flashes, view2 appears immediately instead of waiting 6 seconds to appear.
7
0
637
Dec ’24
Widget Extension scheme causes "failed to find valid container bundle" errors when ran
I've got a macOS app with a Widget Extension. When I try to run the scheme attached to this extension, WidgetKit Simulator "unexpectedly quits" and I get plenty of errors such as the ones below, that do not seem to be at all linked with the purpose nor the functionalities explicitly used by the app (nor the extension). That's what I get in Xcode's console: com.apple.siri.AssistantSettingsControls failed to find valid container bundle for file:///System/Library/ExtensionKit/Extensions/AssistantSettingsControlsExtension.appex/ at /System/Library/ExtensionKit/Extensions/AssistantSettingsControlsExtension.appex com.apple.settings-intents.LoginItemsIntents failed to find valid container bundle for file:///System/Library/ExtensionKit/Extensions/LoginItemsIntentsExtension.appex/ at /System/Library/ExtensionKit/Extensions/LoginItemsIntentsExtension.appex com.apple.SoftwareUpdate.SoftwareUpdateSettingsWidget failed to find valid container bundle for file:///System/Library/ExtensionKit/Extensions/SoftwareUpdateSettingsWidgetExtension.appex/ at /System/Library/ExtensionKit/Extensions/SoftwareUpdateSettingsWidgetExtension.appex com.apple.settings-intents.PrinterScannerIntents failed to find valid container bundle for file:///System/Library/ExtensionKit/Extensions/PrinterScannerIntentsExtension.appex/ at /System/Library/ExtensionKit/Extensions/PrinterScannerIntentsExtension.appex com.apple.settings-intents.WallpaperIntents failed to find valid container bundle for file:///System/Library/ExtensionKit/Extensions/WallpaperIntentsExtension.appex/ at /System/Library/ExtensionKit/Extensions/WallpaperIntentsExtension.appex com.apple.settings-intents.ScreenSaverIntents failed to find valid container bundle for file:///System/Library/ExtensionKit/Extensions/ScreenSaverIntentsExtension.appex/ at /System/Library/ExtensionKit/Extensions/ScreenSaverIntentsExtension.appex In the error log (Console crash logs), the error description: Exception Type: EXC_BREAKPOINT (SIGTRAP) Exception Codes: 0x0000000000000001, 0x000000010428507c Termination Reason: Namespace SIGNAL, Code 5 Trace/BPT trap: 5 Terminating Process: exc handler [31252] I have observed that even if I try creating a new blank project and add a Widget Extension (keeping everything default) and try to run the scheme, I end up (after setting IDEPreferLogStreaming to YES in the environment variables) with the exact same errors. What is the issue? How can I fix it?
1
2
431
Dec ’24
photo album widget won’t work
for a while i had one photo widget (no special app, just the standard apple one) and it was set to shuffle to an album of pics of my bf. no problems at all. a few weeks later i added one to shuffle through an album of pics of my cat, and that one worked fine, but it made the one of my bf stop working, and it just showed a blank white widget, no error message or anything. so i removed the one of my cat hoping the one of my bf would go back to working, and it didn’t. i only have the widgets for find my, my bank, and then apps on my home screen otherwise.
1
0
632
Dec ’24
WidgetCenter.shared.reloadAllTimelines() doesnt work when app in background
I have an iOS app, watchOS app, and iOS Widget that shows the most recent data in the database. The watch app sends data to the iOS app over the WCSession and is received in session(didReceiveMessage, replyHandler). After that data is processed, reloadAllTimelines() is called. When running in Simulator or on device plugged in to debugger, it works, the widget updates when the app is closed (in background, even if force quit). But when running TestFlight or App Store build, the data is still processed and saved to Core Data (I open the app and it's there), but the widget doesn't update. It seems that reloadAllTimelines only works when the app is in foreground (at least in non debug builds). I dont have an iOS 17 device to check but I think this is a recent bug with iOS 18.
2
2
559
Dec ’24
Xcode 16.x project doesn’t build with (SiriKit / Widget) intent definition file + translations
If you add a (SiriKit / Widget) intent definition file to an Xcode project and then translate it into another language, the build of the iOS app only works until you close the project. As soon as you open the project again, you get the error message with the next build: Unexpected duplicate tasks A workaround for this bug is, that you convert the folder (where the intent file is located) in Xcode to a group. After that every thing works without problems. Steps to reproduce: Create a new iOS project Add a localization to the project (German for example) Add a SiriKit Intent Definition File Localize the SiriKit Intent Definition File Build the project (should work without errors) Close the project Open the project again Build the project again Expected result: The project builds without problems Current result: The project doesn’t build and returns the error: Unexpected duplicate tasks Is this a known problem? Is there a way to solve this without switching to Xcode groups (instead of folders)
3
1
768
Dec ’24
Widget link broken by `.desaturated` image rendering mode
Using desaturated mode on an image in a widget will break any links or buttons that use the image as their 'label'. Using the following will just open the app as if there was no link at all - therefore just using the fallback userActivity handler, or any .widgetURL() urls provided. Link(destination: URL(string: "bug://never-works")!) { Image("puppy") .widgetAccentedRenderingMode(.desaturated) } The same goes for buttons: Button(intent: MyDemoIntent()) { Image("puppy") .widgetAccentedRenderingMode(.desaturated) } I've tried hacky solutions like putting the link behind the image using a ZStack, and disabling hit testing on the image, but they don't work. Anything else to try? Logged as Feedback #15152620.
5
2
629
Dec ’24
Can't use Link in .systemLarge widget
I just added a .systemLarge widget to my app, but I can't get Links to work. I want the user to be able to tap one of the four rows in my widget - like the EmojiRangers example - but I can't get it to work. I watched a Developer video from WWDC20: https://developer.apple.com/videos/play/wwdc2020/10036?time=223 The guy, Izzy, 'simply' embeds an HStack in a Link, and hey presto! It all works. But that doesn't happen for me. There's clearly some code in the background that runs. I already have .widgetURL working for .systemSmall and .systemMedium widgets, and I don't need to use Links on those two types. Those work by sending a URL to .onOpenURL { incomingURL in ... All good there, no issues. I've wrapped each row in the large widget in a Link with the URL of something like myappurlscheme://widgetTapped/widgetId (it's the same url as that used in the small and medium widgets). I build & run. I tap a row. It doesn't act as though a row is tappable (it doesn't go slightly transparent), and just opens the app without hitting .onOpenURL or anything else. Nothing in my scene delegate is triggered. Is there a specific delegate method that gets called? Do I need to set up some awful intents? I'm not using any sort of NavigationStack here; that model doesn't fit my app. Any ideas? Thanks.
1
0
520
Dec ’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?
7
2
1.9k
Dec ’24
Slow bundle copy build phase from dependency
We have a dependency, Apollo iOS, that is managed by SwiftPM in an internal module Swift Package. That internal Swift Package is then linked and included in our iOS target. The iOS target has an associated WidgetKit extension app. When archiving the app, we're seeing extremely long "Copy Apollo_Apollo.bundle" build steps, on the magnitude of 15 minutes. This is only happening when copying the bundle for the Widget extension app. Builds are done with Xcode 15.2, but we've tried on 15.4 and 16.2, seeing a few minutes shaved off. How can we begin to debug this issue?
0
0
243
Dec ’24
Refreshing widgets - policy and background tasks?
I have widgets providing their timeline using the .atEnd reload policy, i.e.: // AppIntentTimelineProvider: return Timeline(entries: entries, policy: .atEnd) // TimelineProvider let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) I can't seem to find any information on what happens after the end of the timeline. So, let's say I've got two days worth of entries, the dev docs for the reload policy say, "A policy that specifies that WidgetKit requests a new timeline after the last date in a timeline passes." Great! But how does it request the new timeline? Does iOS launch my app in the background and simply re-run the timeline to generate another two days worth of entries? I doubt it. I figure I need to implement some sort of background task, and the dev docs say how to do it with an Operation, but then I read that this is an old way of doing it? I've found some info online saying to use something like this, so this is what I've implemented: let kBackgroundWidgetRefreshTask = "my.refresh.task.identifier" // This has been registered in the info.plist correctly class SchedulingService { static let shared = SchedulingService() func registerBackgroundTasks() { let isRegistered = BGTaskScheduler.shared.register(forTaskWithIdentifier: kBackgroundWidgetRefreshTask, using: nil) { task in print("Background task is executing: \(task.identifier)") // This does print "true" self.handleWidgetRefresh(task: task as! BGAppRefreshTask) } print("Is the background task registered? \(isRegistered)") } func scheduleWidgetRefresh() { let request = BGAppRefreshTaskRequest(identifier: kBackgroundWidgetRefreshTask) // Fetch no earlier than 1 hour from now - test, will be two days request.earliestBeginDate = Date(timeIntervalSinceNow: 60 * 60) do { try BGTaskScheduler.shared.submit(request) print("Scheduled widget refresh for one hour from now") } catch { print("Could not schedule widget refresh: \(error)") } } private func handleWidgetRefresh(task: BGAppRefreshTask) { // Schedule a new refresh task scheduleWidgetRefresh() // Start refresh of the widget data let refreshTask = Task { do { print("Going to refresh widgets") try await self.backgroundRefreshWidgets() task.setTaskCompleted(success: true) } catch { print("Could not refresh widgets: \(error)") task.setTaskCompleted(success: false) } } // Provide the background task with an expiration handler that cancels the operation task.expirationHandler = { refreshTask.cancel() } } func backgroundRefreshWidgets() async throws { print("backgroundRefreshWidgets() called") definitelyRefreshWidgets() } } As I've commented above, the line print("Background task is executing: \(task.identifier)") does print true so the task has been registered correctly. I've put the app into the background and left it for hours and nothing is printed to the console. I've implemented a logger that writes to a file in the app container, but that doesn't get anything either. So, is there something I'm misunderstanding? Should I change the reload policy to .after(date)? But what makes the timeline reload? As a second but linked issue, my widgets have countdown timers on them and the entire timeline shows that every entry is correct, but the widgets on the Home Screen simply fail to refresh correctly. For example, with timeline entries for every hour for the next two days from 6pm today (so, 7pm, 8pm...) every entry in the preview in Xcode shows the right countdown timer. However, if you put the widget on the Home Screen, after about five hours the timer shows 25:12:34 (for example). No entry in the timeline preview ever shows more than 24 hours because the entires are every hour, and the one that shows a timer starting at 23:00:00 should never get to 24:00:00 as the next entry would kick in from 0:00:00, so it should never show more than 23:59:59 on the timer. It's like the 23:00:00 timer is just left to run for hours instead of being replaced by the next entry. It's as though the widget isn't refreshing correctly and entries aren't loaded? Given this is the Simulator - and my development device - and both are set to Developer Mode so widget refresh budgets aren't an issue, why is this happening? How do you get widgets to refresh properly? The dev docs are not very helpful (neither is the Backyard Birds example Apple keep pushing). Thanks!
5
0
1k
Dec ’24
iOS Control Widget Crash
2024-12-12_15-10-54.4423_+0800-39bc42f42baee8f05378c4924bcac0ea28d49d67.crash we collect some device crash logs from the organizer window in Xcode. Thread 0 name: Thread 0 Crashed: 0 libsystem_platform.dylib 0x000000020eb8eb44 _platform_strlen + 4 1 libc++.1.dylib 0x000000019797c7f4 std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>>::append(char const*) + 32 (string:2845) 2 libswiftCore.dylib 0x00000001859283c0 _gatherGenericParameters(swift::TargetContextDescriptor<swift::InProcess> const*, __swift::__runtime::llvm::ArrayRef<swift::MetadataOrPack>, swift::TargetMetadata<swift::InProcess> const*, __swift:... + 144 (MetadataLookup.cpp:1218) 3 libswiftCore.dylib 0x0000000185927f5c swift::TypeLookupError::TypeLookupError<_gatherGenericParameters(swift::TargetContextDescriptor<swift::InProcess> const*, __swift::__runtime::llvm::ArrayRef<swift::MetadataOrPack>, swift::TargetMet... + 76 (TypeLookupError.h:134) 4 libswiftCore.dylib 0x00000001858f9ba0 swift_getAssociatedTypeWitnessSlowImpl(swift::MetadataRequest, swift::TargetWitnessTable<swift::InProcess>*, swift::TargetMetadata<swift::InProcess> const*, swift::TargetProtocolRequirement<swift::... + 772 (Metadata.cpp:6636) 5 libswiftCore.dylib 0x00000001858f7ab4 swift_getAssociatedTypeWitness + 92 (Metadata.cpp:6702) 6 SwiftUI 0x000000018c5090d0 static ControlWidgetConfigurationAdaptor._makeWidgetConfiguration(widget:inputs:) + 152 (<stdin>:0) 7 SwiftUI 0x000000018bd69170 TupleWidgetConfiguration.MakeList.visit<A>(type:) + 1124 (TupleWidget.swift:88) 8 SwiftUI 0x000000018c42e948 TypeConformance<>.visitType<A>(visitor:) + 120 (WidgetConfiguration.swift:132) 9 SwiftUI 0x000000018bd68768 static TupleWidgetConfiguration._makeWidgetConfiguration(widget:inputs:) + 1668 (TupleWidget.swift:59) 10 SwiftUI 0x000000018c628548 closure #1 in WidgetGraph.init<A>(rootBundle:) + 1168 (WidgetGraph.swift:53)
1
0
505
Dec ’24