When I generate a dial through code, it prompts the following content:
code:
CLKWatchFaceLibrary * lib = [[CLKWatchFaceLibrary alloc] init];
[lib addWatchFaceAtURL:url completionHandler:^(NSError * _Nullable error) {
}];
result:
Complex functions are not available
How to fix it? Make it usable, Thank you~
ClockKit
RSS for tagDisplay app-specific data in the complications on the clock face using ClockKit.
Posts under ClockKit tag
11 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
Hi, I'm migrating ClockKit complications to WidgetKit. Everything works well except when I run the WidgetKit version, I see complications appear twice each in the complications list for my app when adding them.
If I restart the app from Xcode, it won't happen again, only for the first time. But on the actual device, only Watch restart or app reinstall fixes it which is frustrating and would not be ideal for live users.
I even tried Apple's example ClockKit project -> added complications to watch face -> added WidgetKit target, CLKComplicationWidgetMigrator and func widgetConfiguration(from complicationDescriptor: CLKComplicationDescriptor) code -> run the app -> new complications appear correctly replacing old ones -> when hold to add/change complications I see it doubled (screenshot attached) and it's even selected twice
If I add more complications, they will appear two times as well except one selected in two places almost like it's two same lists created.
class ComplicationController: NSObject, CLKComplicationDataSource, CLKComplicationWidgetMigrator {
@available(watchOSApplicationExtension 9.0, *)
var widgetMigrator: CLKComplicationWidgetMigrator {
self
}
@available(watchOSApplicationExtension 9.0, *)
func widgetConfiguration(from complicationDescriptor: CLKComplicationDescriptor) async -> CLKComplicationWidgetMigrationConfiguration? {
switch complicationDescriptor.identifier {
case "Coffee_Tracker_Caffeine_Dose":
return CLKComplicationStaticWidgetMigrationConfiguration(
kind: "WidgetKitComplications",
extensionBundleIdentifier: "com.example.apple-samplecode.Coffee-Tracker.watchkitapp.watchkitextension.WidgetKitComplications")
default:
return nil
}
}
Hi Apple Team,
Am seeing that in Apple's "share watch face" documentation that ClockKit APIs are still being used to share watch faces.
So my question is - will those ClockKit APIs (and therefore ClockKit complications) be supported in watchOS 11? Thank you.
I'm making an app where there are two widgets. Both widgets are supposed to get their timelines once per day, as all data for the day is known at midnight. I'm having an issue where when put on a development device, the widgets' timelines work correctly, but do not refresh the next day. I've tried both .atEnd and .after(Date) refresh policies and neither seems to work. Does anyone know why the widget isn't refreshing properly? I'm almost certain that I'm under the daily limit of refreshes (one timeline refresh and ~12 timeline entries per day). Thank you for any help! Dev device iPhone 15 Pro on 17.5.1 (21F90) with Xcode Version 15.4 (15F31d). Below is the timeline code for one of the widgets:
struct EndTimeProvider: TimelineProvider {
var currentHour: Int {
Calendar.current.component(.hour, from: .now)
}
var currentMinute : Int {
Calendar.current.component(.minute, from: .now)
}
var placeholderSixthPeriod: Period {
var endMinute: Int = 0
var endHour: Int = 0
if currentMinute > 60-14 {
endHour = currentHour + 1
endMinute = (currentMinute + 14) % 60
} else {
endHour = currentHour
endMinute = currentMinute + 14
}
return Period(name: "Period 6", start: "00:00", end: "\(endHour):\(endMinute)")
}
func placeholder(in context: Context) -> EndTimeEntry {
return EndTimeEntry(date: .now, displayPeriod: placeholderSixthPeriod, scheduleName: "Regular Day")
}
func getSnapshot(in context: Context, completion: @escaping (EndTimeEntry) -> ()) {
if context.isPreview {
completion(placeholder(in: context))
return
}
let entry = EndTimeEntry(date: .now, displayPeriod: placeholderSixthPeriod, scheduleName: "Regular Day")
completion(entry)
}
func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
var entries: [EndTimeEntry] = []
let context = PersistenceController.shared.backgroundContext
let scheduleFetch = StoredScheduleOnDate.fetchRequest()
do {
let storedSchedules = try context.fetch(scheduleFetch)
let currentDate = Date()
if let todaySchedule = storedSchedules.first(where: {
Calendar.current.isDate($0.date!, equalTo: currentDate, toGranularity: .day)
})?.schedule?.asDayType() {
// Have an entry at midnight when schedules are needed
let morningStart = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: .now)!
let morningPeriod = Period(name: "Good morning", start: "00:00", end: todaySchedule.periods.first!.start)
let morningEntry = EndTimeEntry(date: morningStart, displayPeriod: morningPeriod, scheduleName: todaySchedule.name)
entries.append(morningEntry)
// Passing periods should show the next full period's end time.
// This means that an entry's date should be the past period's end, or the start in the first period's case.
let firstPeriod = todaySchedule.periods.first!
let firstPeriodEntry = EndTimeEntry(date: firstPeriod.getStartAsDate(), displayPeriod: firstPeriod, scheduleName: todaySchedule.name)
entries.append(firstPeriodEntry)
for index in 1..<todaySchedule.periods.count {
let entry = EndTimeEntry(date: todaySchedule.periods[index-1].getEndAsDate(), displayPeriod: todaySchedule.periods[index], scheduleName: todaySchedule.name)
entries.append(entry)
}
// Have an entry at the end of the day to have the start time of the next day shown
if let tomorrowSchedule = storedSchedules.first(where: {
Calendar.current.isDate($0.date!, equalTo: Calendar.current.date(byAdding: .day, value: 1, to: currentDate)!, toGranularity: .day)
})?.schedule?.asDayType() {
// At EOD, show tomorrow's start
let endOfDay: Date = todaySchedule.periods.last!.getEndAsDate()
let overnightPeriod: Period = Period(name: "Good night", start: todaySchedule.periods.last!.end, end: "00:00")
let overnightEntry = EndTimeEntry(date: endOfDay, displayPeriod: overnightPeriod, scheduleName: tomorrowSchedule.name, overrideDisplayDate: tomorrowSchedule.periods.first!.getStartAsDate())
entries.append(overnightEntry)
}
}
} catch {
fatalError("Could not fetch from Core Data for widget timeline. \(error)")
}
let tomorrowMorning = Calendar.current.date(bySettingHour: 0, minute: 1, second: 0, of: Calendar.current.date(byAdding: .day, value: 1, to: .now)!)!
let timeline = Timeline(entries: entries, policy: .after(tomorrowMorning))
completion(timeline)
}
}
struct EndTimeEntry: TimelineEntry {
let date: Date
let displayPeriod: Period
let scheduleName: String
let overrideDisplayDate: Date?
init(date: Date, displayPeriod: Period, scheduleName: String, overrideDisplayDate: Date) {
self.date = date
self.displayPeriod = displayPeriod
self.scheduleName = scheduleName
self.overrideDisplayDate = overrideDisplayDate
}
init(date: Date, displayPeriod: Period, scheduleName: String) {
self.date = date
self.displayPeriod = displayPeriod
self.scheduleName = scheduleName
self.overrideDisplayDate = nil
}
}
...
Hello, fellow developers! How would you approach .watchface file to extract it's metadata? I need to know in which version of the app the face was created, to prompt the user to update the app if necessary.
Looking at binary I suppose that a .watchface file consists of a PNG previews and JSON metadata and it all packed in one file somehow. Probably archived with gzip.
When you use set an Alarm in clock app, you get to choose mutliple tones and even songs from Apple music.
However, when you set a Sleep|Wake up alarm using a sleep schedule, you are prompted to choose only limited tones.
This limits the Alarm tone options for sleep one. Hope, Apple lets users pick the full library of tones in next update.
I have an iPhone app, and added watch support, including a simple launcher complication. I can add the complication using the edit UI on the watch, but the complication is not visible using the watch app on the iPhone.
When I add my complication on the watch and then open the watch app on the iPhone, the complication slot shows as "Off".
What could I be doing wrong?
Suggestions on what is causing this? Where to look? Could it be related to having a CoreData 'abstract entity' that occurs in two configurations - one configuration for 'public' and one for 'private/shared'?
⌚️Hello,
I've noticed in watchOS 10 that when a complication is in the Smart Stack, the value of WCSession.isComplicationEnabled is false. I'm not sure if this is intentional or a bug. It seems trivial at first glance, but it actually affects the communication mechanism mentioned in Implementing Two-Way Communication Using Watch Connectivity.
In the following two scenarios, if the user has only added the app's complication to the Smart Stack, then the watch app will not be able to communicate properly with the iOS app.
Scenario 1 - WCSession.transferCurrentComplicationUserInfo()
// update complications from the iOS app
if WCSession.default.isComplicationEnabled {
let userInfoTransfer = WCSession.default.transferCurrentComplicationUserInfo(userInfo)
// ...
}
As described in Implementing Two-Way Communication Using Watch Connectivity, when the iOS app proactively updates the data of the watch app, since WCSession.isComplicationEnabled is false, WCSession will refuse to transfer any data. This causes the standalone complication in Smart Stack to not be updated.
Scenario 2 - WKApplicationRefreshBackgroundTask
When the watch app uses WKApplication.scheduleBackgroundRefresh() to periodically update data, as long as the user has added the app's complication to the watch face, the corresponding WKApplicationRefreshBackgroundTask can be executed periodically in the background to fetch data.
However, if the user has only added complication to the Smart Stack, then the watch app will be completely purged, and the background task will not be executed at all. Although WCSession.isComplicationEnabled is not directly used in this scenario, its behavior appears to be the same, that is, the complication in the Smart Stack is not considered a complication by the system.
Should I submit a bug report?
Whenever I try to put my choice of time zones on the MacBook clock widget, it won't show on the main widget. It will show the stock clock options. Such as Cupertino, Tokyo, Sydney, and Paris, Even though I change them inside the app the widget won't display the changes.
I’ve created a single-target watchOS app in Xcode 14, but I can’t seem to get ClockKit complications working.
I’ve added a CLKComplicationDataSource class to my watch target, and in the Info pane for my target I have set the CLKComplicationPrincipalClass key to MODULE-NAME.ComplicationController
I haven’t yet added Complication placeholder images to my Assets.xcassets, but as far as I am aware, that shouldn’t be a problem while I am still testing.
However, when I run it on a watchOS simulator, the complications never show up on the watch complications list when adding a complication.
All of the tutorials I can find for ClockKit complications reference older two-target WatchKit apps. Do the newer single target apps no longer support ClockKit? If so, how can I make a two-target WatchKit app with Xcode 14?
Unfortunately I cannot use WidgetKit for my complications because I need to support watchOS 7 at least, and WidgetKit only supports watchOS 9+
Thanks for your help