0

I am creating an app that contains a clock widget. I want to keep the widget updating preferable every second. I've had some luck creating a long timeline - but i'm still running into the throttling limition imposed by Apple

I've experimented with a fixed animation for the second hand "faking" the seconds. But the widget keeps getting "stuck" this is my c

Any tips or tricks to keep my widget running and "updating" every second?

I’ve seen multiple apps in the App Store do this. So it must be possible.

struct Provider: AppIntentTimelineProvider {     func placeholder(in context: Context) -> SimpleEntry {         SimpleEntry(date: Date(), configuration: ConfigurationAppIntent())     }     func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry {         SimpleEntry(date: Date(), configuration: configuration)     }          func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline<SimpleEntry> {         let currentDate = Date()         var entries: [SimpleEntry] = []                  // Create entries for the next 30 minutes, one every second         let numberOfEntries = 30 * 60  // 30 minutes * 60 seconds         for offset in 0..<numberOfEntries {             if let entryDate = Calendar.current.date(byAdding: .second, value: offset, to: currentDate) {                 let entry = SimpleEntry(date: entryDate, configuration: configuration)                 entries.append(entry)             }         }                  // Request new timeline 5 minutes before this one ends         let refreshDate = Calendar.current.date(byAdding: .minute, value: 25, to: currentDate)!         print("Created timeline at: \(currentDate), next refresh at: \(refreshDate)")                  return Timeline(entries: entries, policy: .after(refreshDate))     } } struct SimpleEntry: TimelineEntry {     let date: Date     let configuration: ConfigurationAppIntent          var selectedWatchFace: WatchFace? {         return configuration.selectedWatchFace?.watchFace     }          init(date: Date, configuration: ConfigurationAppIntent) {         self.date = date         self.configuration = configuration         print("Created entry for: \(date)")     } } struct WatchWidgetEntryView: View {     var entry: Provider.Entry     u/Environment(\.widgetFamily) var widgetFamily     var body: some View {         if let watchFace = entry.selectedWatchFace {             WatchPreview(                 background: watchFace.background,                 hourHand: watchFace.hourHand,                 minuteHand: watchFace.minuteHand,                 secondHand: watchFace.secondHand,                 currentTime: entry.date             )             .privacySensitive(false)         } else {             Text("Select a watch face")                 .font(.caption)         }     } } struct WatchWidget: Widget {     let kind: String = "WatchWidget"     var body: some WidgetConfiguration {         AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in             WatchWidgetEntryView(entry: entry)                 .frame(maxWidth: .infinity, maxHeight: .infinity)                 .containerBackground(for: .widget) {                     Color.clear                 }         }         .configurationDisplayName("Watch Face")         .description("Display your favorite watch face")         .supportedFamilies([.systemSmall])         .contentMarginsDisabled()     } } // Modified version of WatchPreview for the widget struct WatchPreview: View {     let background: UIImage?     let hourHand: UIImage?     let minuteHand: UIImage?     let secondHand: UIImage?     let currentTime: Date          private let calendar = Calendar.current     u/State private var secondRotation = 0.0     private var hourRotation: Double {         let hour = Double(calendar.component(.hour, from: currentTime) % 12)         let minute = Double(calendar.component(.minute, from: currentTime))         return (hour * 30) + (minute * 0.5)     }     private var minuteRotation: Double {         Double(calendar.component(.minute, from: currentTime)) * 6     }     var body: some View {         GeometryReader { geometry in             let size = min(geometry.size.width, geometry.size.height)             ZStack {                 if let background = background {                     Image(uiImage: background)                         .resizable()                         .aspectRatio(contentMode: .fill)                         .frame(width: size, height: size)                         .clipped()                 }                 if let hourHand = hourHand {                     Image(uiImage: hourHand)                         .resizable()                         .scaledToFit()                         .rotationEffect(.degrees(hourRotation))                 }                 if let minuteHand = minuteHand {                     Image(uiImage: minuteHand)                         .resizable()                         .scaledToFit()                         .rotationEffect(.degrees(minuteRotation))                 }                 if let secondHand = secondHand {                     Image(uiImage: secondHand)                         .resizable()                         .scaledToFit()                         .rotationEffect(.degrees(secondRotation))                 }             }             .frame(width: size, height: size)             .position(x: geometry.size.width / 2, y: geometry.size.height / 2)             .onAppear {                 // Set initial rotation based on current seconds                 let second = Double(calendar.component(.second, from: currentTime))                 secondRotation = second * 6                                  // Start continuous rotation animation                 withAnimation(.linear(duration: 60).repeatForever(autoreverses: false)) {                     secondRotation += 360                 }             }         }     } } 

Using timeline updates. Animation etc. Nothing seems to be reliable.

3
  • this thread suggests it is only possible with private api. Commented Jan 12 at 9:12
  • I saw that.. But Apple won’t approve these in the App Store, right? So there must be another way.. Commented Jan 12 at 9:20
  • You will get rejected if you get caught, but people sneak through. Your first review tends to be much more through than updates. I am not saying you should do this, simply how it might be possible that other apps do Commented Jan 12 at 21:51

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.