Why my widget is not refreshing properly?

26 Views Asked by At

Hey I created a widget where I get the user location and with that coordinate I call an API request to get a near location on my getTimeline.

First Issue: Sometimes when the timeline refresh automatically (after the 1h 30m) the request is not done and the widget refresh with an empty state, even that the data have been save on UserDefaults(suiteName: ) in the widget request and in the app.

@available(iOS 17.0, *)
struct NearLocationWidget: Widget {
    let kind: String = "{name}"

    var body: some WidgetConfiguration {
        StaticConfiguration(kind: kind, provider: Provider()) { entry in
            NearLocationWidgetEntryView(entry: entry)
                .invalidatableContent()
        }
        .supportedFamilies([.systemSmall])
    }
}

@available(iOS 17.0, *)
struct Provider: Provider {
    private let locationManager: WidgetLocationManager = .init()

    func getTimeline(in context: Context, completion: @escaping (Timeline<WidgetEntry>) -> ()) {

        self.locationManager.fetchLocation { coordinate in

            Task {
                // Prepare entry
                let currentDate = Date()

                // Get saved values
                let savedCoordinate: CLLocationCoordinate2D? = UserDefaultsStorage.shared.getObjectFromGroup(for: .widgetCoordinates)
                let savedNearLocation: LocationObject? = UserDefaultsStorage.shared.getObjectFromGroup(for: .widgetNearLocationData)

                // Start first entry
                var entry: WidgetEntry = .init(date: currentDate, isLogIn: true, isLocationEnabled: self.locationManager.isAuthorizedForWidgetUpdates, nearestLocation: savedNearLocation)

                // If coordinates are not empty, request the nearest location
                if let coordinate = coordinate ?? savedCoordinate  {
                    let nearLocation = await NetworkService.shared.getNearestLocation(coordinate: coordinate)
                    entry.nearestLocation = nearLocation

                }

                // Next fetch happens in 1h and 30min later
                let nextUpdate = Calendar.current.date(byAdding: DateComponents(hour: 1, minute: 30), to: currentDate)!
                let timeline = Timeline(entries: [entry], policy: .after(nextUpdate))
                completion(timeline)
            }
        }
    }
}

Second Issue: My widget have a button to refresh the widget (See below), which Intent just return the .result() to produce the timeline refresh, but it has the same issue that above, sometimes it works properly, but when is been a while since the app is closed or in background I just have an empty state on my widget.

@available(iOS 17, *)
struct RefreshWidgetIntent: AppIntent {

    static var title: LocalizedStringResource = "Widget"

    static var description = IntentDescription("Refresh Widget")

    func perform() async throws -> some IntentResult {
        return .result()
    }
}

@available(iOS 17.0, *)
struct RefreshIconView: View {
    var body: some View {
            Button(intent: RefreshWidgetIntent()) {
                Image(systemName: "arrow.clockwise")
                    .resizable()
                    .aspectRatio(contentMode: .fit)
                    .foregroundStyle(Color.Inverted.surface)
                    .frame(height: 20)
                    .padding(12)
                    .background(Color.Surface.cutout)
                    .clipShape(Circle())
            }
            .buttonStyle(PlainButtonStyle())
            .frame(width: 44, height: 44)
    }
}

I have all the location permissions need it on the info plist. Tested on Simulator and Physical Device (Most on physical device: iPhone 13, iOS 17.3.1).

  • Is that the best way to reload a widget?
  • May that be the issue of why is not reloading properly?
0

There are 0 best solutions below