天道酬勤,学无止境

Get Data to Complication: ExtensionDelegate not Called

(It looks like this issue has been encountered by others in previous weeks, but there haven't been any solutions that I've found.)

I'm trying to do a really basic thing: Get data from either my iOS app or my Watch app to my Complication Controller.

I am turning out to be way less capable of getting this done than I thought. watchOS 2 Transition Guide indicates that I should "[fetch] the needed data from the extension delegate" using the following code:

ExtensionDelegate* myDelegate = [[WKExtension sharedExtension] delegate];  
NSDictionary* data = [myDelegate.myComplicationData objectForKey:ComplicationCurrentEntry];

Great. Except, I haven't been able to figure out how to get this to work on the extension side. Though even more importantly, I can't seem to even get the extension delegate code to run at all from a complication controller launch. When I run the complication, I get this message: "Extension received request to wake up for complication support." However, none of the code within any of the extension delegate's methods seems to run. I've also set breakpoints within every method and none of those breakpoints are hit.

It also looks like "transferCurrentComplicationUserInfo:" is also suggested to be used for complication updates, though it's unclear precisely how it's used. As much as I've gathered, it's used to wake up the watch extension so that ExtensionDelegate can store the new data for the next time the complication controller runs, but due to the previous issue I haven't been able to confirm.

I've got one maybe workaround (pinging the server from the complication controller and hoping that session variables persist so I can send relevant data), but there's every chance that if I can't get this worked out my complication work will be hosed. Any help here would be tremendous.

By the way, here's the code I have for "getCurrentTimelineEntryForComplication", if that's helpful at all.

- (void)getCurrentTimelineEntryForComplication:(CLKComplication *)complication withHandler:(void(^)(CLKComplicationTimelineEntry * __nullable))handler {  
    NSDate* entryDate = [NSDate date];  

    ExtensionDelegate* myDelegate = [[WKExtension sharedExtension] delegate];  
    NSString* data = [myDelegate.complicationData objectForKey:@"meow"];  
    NSLog(@"complication data: %@", data);  

    CLKComplicationTimelineEntry* entry = [self getTimelineEntry:@"2015-08-25 00:19:42" entryDate:entryDate complication:complication];  

    handler(entry);  
}

评论

I've been working with Complications in WatchOS2 since Xcode 7 Beta 4. I'm now on the latest, Xcode Beta 6. I've had a number of issues as in both Beta versions running on the Watch, running on the iPhone then installing to the Watch, and running on the simulator frequently give false negatives due to what appears to be buggy APIs and OS releases. I have been able to get data to show on complications in the following way.

  • Ensure that your primary Interface Controller implements the WCSessionDelegate protocol.
  • Implement both the didReceiveMessage and didReceiveApplicationContext methods in your Interface Controller.
  • In your iPhone app, attempt to send a message using the WCSession to the Watch.
  • If the message fails to send from the iPhone app, send the application context.
  • Back in the Interface Controller, when you receive a message -or- a context, update the values in your Extension Delegate.
  • Still in the Interface Controller and still after receiving a message -or- context, get a handle to the CLKComplicationServer and for each complication in activeComplications call reloadTimelineForComplication.
  • In your Complication Controller's getCurrentTimelineEntryForComplication grab the data you set in the Extension Delegate and set the values in your CLKComplicationTimelineEntry.
  • This will work usually when the App is already open on the Watch, the app is still resident in memory, but backgrounded on the Watch, or you start the app and their is context waiting which it consumes.
  • I have not been able to get the historical timeline entries to function (or the future ones). Nor, I have I been able to get the timeline to update independently of the Watch app.

If you are having trouble, here are some debugging things to try. As I stated above, the API and OS appears to be very buggy. The steps below do work (sometimes).

  • In the sim, use the Reset all Settings option on both the iPhone and Watch sim.
  • On the device, restart the Watch. If necessary, unpair and repair the Watch, although this takes a really long time to do.
  • On the iPhone, delete the app (which will also delete the Watch app if installed) and reinstall.

I hope that helps!

Justin

In order to make the ComplicationController respond to WCSession activity you must make the controller conform to WCSessionDelegate, then manage didReceiveUserInfo from within the ComplicationController. The ExtensionDelegate is not woken up for these updates when in the background. You can still update your delegate from the controller if necessary.

Also, as of right now, the simulator does not send transferCurrentComplicationUserInfo to the watch sim, you have to test on devices.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 调用ExtensionDelegate来创建/刷新用于并发症的数据(Call ExtensionDelegate to create/refresh data for Complication)
    问题 我所有的数据创建都在ExtensionDelegate.swift完成。 问题是我的ComplicationController.swift getCurrentTimelineEntryForComplication函数之前没有调用ExtensionDelegate.swift 。 有任何想法吗? 这是我的代码和详细信息: 因此,我的ComplicationController.swift数组extEvnts为空: func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) { let extEvnts = ExtensionDelegate.evnts } 因为尚未调用我的ExtensionDelegate.swift ,所以将为数组创建数据: class ExtensionDelegate: NSObject, WKExtensionDelegate, WCSessionDelegate { private let session = WCSession.defaultSession() var receivedData = Array
  • Call ExtensionDelegate to create/refresh data for Complication
    All my data creation is done in the ExtensionDelegate.swift. The problem is ExtensionDelegate.swift doesn't get called before the function getCurrentTimelineEntryForComplication in my ComplicationController.swift. Any ideas? Here is my code and details: So my array extEvnts is empty in my ComplicationController.swift: func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: ((CLKComplicationTimelineEntry?) -> Void)) { let extEvnts = ExtensionDelegate.evnts } Because my ExtensionDelegate.swift hasn't gotten called yet, which is what creates the data for
  • WatchKit Complication:从扩展委托获取并发症数据(WatchKit Complication: get Complication data from extension delegate)
    问题 我的 WatchKit 扩展中有我需要的所有数据(从 iOS 应用程序传递)。 我用WatchKit InterfaceController的数据填了一张表格,效果很好。 我试图找出在我的 WatchKit ComplicationController获取相同数据的最佳方法。 目前,在InterfaceController ,数据使用didReceiveUserInfo传入: func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) { if let beachValue = userInfo["Surf"] as? String { places.append(Place(dataDictionary: ["Surf" : surfValue])) } else { print("Something went wrong") } } 我是否需要在我的ComplicationController调用这个相同的WCSession方法并再次抓取整个数据,或者有没有更简单的方法让我访问在ComplicationController使用的相同数据? 任何帮助表示赞赏。 谢谢! 编辑: 我的表功能: func makeTable() { // Per SO let
  • WatchKit Complication: get Complication data from extension delegate
    I have all the data I need in my WatchKit Extension (passed from the iOS app). I used the data in the WatchKit InterfaceController to fill in a table, which works perfectly. I'm trying to figure out the best way to get that same data in my WatchKit ComplicationController. Currently, in the InterfaceController, the data gets passed in using didReceiveUserInfo: func session(session: WCSession, didReceiveUserInfo userInfo: [String : AnyObject]) { if let beachValue = userInfo["Surf"] as? String { places.append(Place(dataDictionary: ["Surf" : surfValue])) } else { print("Something went wrong") } }
  • WKURLSessionRefreshBackgroundTask isn't called when attempting to do background refreshes in watchOS
    I'm working on a complication to get scheduled data from a web service. Every 20-30 minutes (or manually), I am scheduling a WKRefreshBackgroundTask to do this. As suggested by Apple, I want the OS to handle the fetching of this data via a background NSURLSession. This is the function I use to download the data I need: func scheduleURLSession() { print("\nScheduling URL Session...") let backgroundSessionConfig:URLSessionConfiguration = URLSessionConfiguration.background(withIdentifier: NSUUID().uuidString) backgroundSessionConfig.sessionSendsLaunchEvents = true let backgroundSession =
  • 尝试在 watchOS 中进行后台刷新时不会调用 WKURLSessionRefreshBackgroundTask(WKURLSessionRefreshBackgroundTask isn't called when attempting to do background refreshes in watchOS)
    问题 我正在处理从 Web 服务获取预定数据的复杂功能。 每 20-30 分钟(或手动),我会安排一个 WKRefreshBackgroundTask 来执行此操作。 正如 Apple 所建议的,我希望操作系统通过后台NSURLSession处理这些数据的获取。 这是我用来下载我需要的数据的函数: func scheduleURLSession() { print("\nScheduling URL Session...") let backgroundSessionConfig:URLSessionConfiguration = URLSessionConfiguration.background(withIdentifier: NSUUID().uuidString) backgroundSessionConfig.sessionSendsLaunchEvents = true let backgroundSession = URLSession(configuration: backgroundSessionConfig) let downloadTask = backgroundSession.downloadTask(with: URL(string: "https://www.myserver.com/somedata")!) downloadTask.resume()
  • WCSession 尚未激活(WCSession has not been activated)
    问题 当我尝试发送某些内容时,出现 WCSession 未激活错误。 我不知道我做错了什么。 我已经测试了“必须”起作用的 serval 预制解决方案。 但它不适用于我的模拟器和物理设备。 一些代码: 我的应用程序委托: import UIKit import CoreData import WatchConnectivity @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate { var window: UIWindow? func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : String]) -> Void) { replyHandler(["message": "Hello Watch!"]) } func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { } func
  • Apple Watch Complication not updating in background
    I have an Apple Watch complication that initializes correctly and show the data I am expecting. However, when the NSDate returned in my getNextRequestedUpdateDateWithHandler method triggers a refresh, the only method in my delegate that gets called again is the getNextRequestedUpdateDateWithHandler method (I set breakpoints at every method to determine this). I would have expected requestedUpdateDidBegin to get called when the requested update date occurs, but that doesn't seem to be the case. Does anyone know what could be causing this? Here is my code: class ComplicationController: NSObject
  • Apple Watch 复杂功能未在后台更新(Apple Watch Complication not updating in background)
    问题 我有一个 Apple Watch 并发症,它可以正确初始化并显示我期望的数据。 但是,当我的 getNextRequestedUpdateDateWithHandler 方法中返回的 NSDate 触发刷新时,我的委托中唯一被再次调用的方法是 getNextRequestedUpdateDateWithHandler 方法(我在每个方法上设置断点来确定这一点)。 我本来希望在请求的更新日期发生时调用 requestsUpdateDidBegin,但情况似乎并非如此。 有谁知道是什么原因造成的? 这是我的代码: class ComplicationController: NSObject, CLKComplicationDataSource { /// Provide the time travel directions your complication supports (forward, backward, both, or none). func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) -> Void) { handler(
  • 何时何地获取手表并发症数据(Where and When to get data for Watch Complication)
    问题 在处理了几天的复杂性之后,我有信心说出以下有关在规定间隔内发生的更新的更新过程: 系统调用requestedUpdateDidBegin() 在这里,您可以确定数据是否已更改。 如果没有,则您的应用程序无需执行任何操作。 如果您的数据已更改,则需要调用以下任一方法: reloadTimelineForComplication如果需要重置所有数据)。 如果您只需要在复杂时间线的末尾添加新项目,则可以使用extendTimelineForComplication 。 注意:如果您当天花费了太多的并发症时间预算,则系统实际上可能会调用requestedUpdateBudgetExhausted()而不是requestedUpdateDidBegin() 。 这就是这个问题的原因。 如果您调用了reloadTimelineForComplication ,则系统将调用getCurrentTimelineEntryForComplication (以及将来和过去获取数组的变体,具体取决于您的时间旅行设置) 这是一个猜测,因为我尚未对其进行测试,但是我相信,如果您调用了extendTimelineForComplication ,则只会调用getTimelineEntriesForComplication(... afterDate date: NSDate ...) 。 然后
  • WCSession has not been activated
    I get the WCSession has not been activated error when I try to sent something. And I don't know what I'm doing wrong. I have tested serval pre-made solutions what "must" work. But it doesn't work at my simulator and physical devices. Some code: My app delegate: import UIKit import CoreData import WatchConnectivity @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate, WCSessionDelegate { var window: UIWindow? func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : String]) -> Void) { replyHandler(["message": "Hello Watch!"])
  • 如何正确实现从 iOS 应用程序到 watchOS2 并发症的设置传输(How to correctly implement transfer of settings from iOS app to watchOS2 complication)
    问题 我想要实现的是以下内容: 复杂功能每隔 30 分钟在后台更新一次每当手表应用程序运行并接收到自己的更新数据时,并发症就会更新每当 iOS 应用程序运行并且用户更改影响手表数据的设置(例如更改天气观测的位置或显示单位)时,并发症就会更新 第 1 项和第 2 项似乎很简单,在这里得到了很好的解决:更新 Apple Watch 复杂功能数据的流程是什么? 但是,对于第 3 项,在 iOS 应用程序中,我设置了一个 WCSession 实例并调用 transferCurrentComplicationUserInfo,将新设置作为 NSDictionary 发送。 在 watch 扩展中,这会调用 WCSessionDelegate 中的 didReceiveUserInfo。 - (void)session:(WCSession *)session didReceiveUserInfo:(NSDictionary<NSString *,id> *)userInfo { // Code here to apply the new settings // .... // Invoke a NSUSRLSession-based web query to get new data [self queryForNewDataWithCompletionHandler:^
  • WatchKit 中 UIApplication.sharedApplication().delegate 的等价物是什么?(What is the equivalent of UIApplication.sharedApplication().delegate in WatchKit?)
    问题 在 iOS 应用程序中,您可以通过以下方式获取对共享应用程序委托的引用: 迅速: let delegate = UIApplication.sharedApplication().delegate as! AppDelegate 目标-C: AppDelegate *delegate = [[UIApplication sharedApplication] delegate]; 在 WatchKit2 App Extension 中有一个类似的 App Delegate,我想在视图控制器中获取对它的引用,以访问应用程序中的共享资源,例如核心数据堆栈的 ManagedObjectModel 和 PersistentStoreCoordinator,我已在应用代理。 但是, UIApplication.sharedApplication().delegate as! AppDelegate UIApplication.sharedApplication().delegate as! AppDelegate报错, 使用未解析的标识符“UIApplication” 如何访问 WatchKit2 应用扩展中的应用委托? 回答1 WatchOS 2 中的WKExtension类自动为每个扩展提供一个扩展对象,以管理在所有应用程序界面控制器之间共享的行为。 Apple 文档指出,您
  • 结合 WatchConnectivity 和复杂功能(Combining WatchConnectivity and Complications)
    问题 我希望我的复杂功能通过 Watch Connectivity 从 iPhone 获取数据。 我正在使用sendMessage即时消息技术。 当我尝试获取数据时,我不希望我的 iPhone 应用程序打开,因此这需要在后台运行。 在我的 iPhone 上的 ViewController 中: import UIKit import WatchConnectivity class ViewController: UIViewController, WCSessionDelegate { var session: WCSession! override func viewDidLoad() { super.viewDidLoad() if WCSession.isSupported() { self.session = WCSession.defaultSession() self.session.delegate = self self.session.activateSession() } } func session(session: WCSession, didReceiveMessage message: [String : AnyObject], replyHandler: ([String : AnyObject]) -> Void) { if message
  • How to correctly implement transfer of settings from iOS app to watchOS2 complication
    What I want to achieve is the following: Complication(s) get updated in the background at intervals of 30 minutes Complication(s) get updated whenever the watch app runs and receives its own updated data Complication(s) get updated whenever the iOS app runs and the user changes a setting which affects the watch data (such as changing location of weather observations, or display units) Items 1. and 2. seem to be straightforward, and nicely addressed here: What is the flow for updating complication data for Apple Watch? However, for item 3, in the iOS app, I set up a WCSession instance and call
  • 如何检查iPhone和Apple Watch是否已连接(How to check whether iPhone and apple watch are connected)
    问题 是否有任何方法可以通知Apple Watch用户iPhone现在超出范围以及何时返回范围。 我们如何在手表扩展中做到这一点。 提前致谢。 回答1 因此,在WatchOS 2上可能! 您必须在iPhone方面: 第一的 : import WatchConnectivity 然后 : if WCSession.isSupported() { // check if the device support to handle an Apple Watch let session = WCSession.defaultSession() session.delegate = self session.activateSession() // activate the session if session.paired { // Check if the iPhone is paired with the Apple Watch // Do stuff } } 希望对您有所帮助:) 回答2 有了watchOS 2.0,您可以做到。 为此,如果希望Apple Watch收到通知,可以将它们添加到ExtensionDelegate中: func watchKitSetup() { if (WCSession.isSupported()) { let session = WCSession
  • 更新Apple Watch并发症数据的流程是什么?(What is the flow for updating complication data for Apple Watch?)
    问题 我一直在互联网上关注许多教程,以学习如何设置并发症。 我可以按预期设置并发症。 直到初始时间轴条目到期。 12小时后,我不知道如何对其进行更新以使并发症持续存在。 我将分享我下面的所有内容,希望有人可以帮助我填写。 在这里,我为要在复杂情况下显示的数据创建了变量。 struct data = { var name: String var startString: String var startDate: NSDate } 以下数组是此数据的容器。 var dataArray = [data] 这样可以在手表锁定时显示复杂情况。 func getPrivacyBehaviorForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationPrivacyBehavior) -> Void) { handler(.ShowOnLockScreen) } 这样就可以在复杂情况下进行时间旅行。 func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) ->
  • transferCurrentComplicationUserInfo是否更适合并发症更新?(Is transferCurrentComplicationUserInfo more suitable for complication update?)
    问题 transferCurrentComplicationUserInfo和transferUserInfo什么区别? 我想将数据从AppDelegate发送到时钟套件并发症。 transferCurrentComplicationUserInfo似乎做同样的事情transferCurrentUserInfo 。 我想念什么吗? 回答1 这两个WCSession方法之间的区别涉及何时发送数据以及是否唤醒了watchkit扩展。 transferCurrentComplicationUserInfo:专门用于传输要在表盘上立即显示的复杂用户信息。 复杂用户信息标记为“紧急”,并位于队列的最前面, 手表会在后台唤醒该扩展程序以接收信息,并且转移立即发生。 (其他排队的信息也可能会在此时转移。) transferUserInfo:将信息排队,在系统确定是处理队列的适当时机将要传输的信息: 用户信息位于队列的后面, 如果扩展名未唤醒,则存储已传输的信息, 转移不会立即发生,并且信息将按照其发送顺序进行传递。 有关更多详细信息,请参阅WWDC 2015介绍手表连接性的视频。 iOS 10更新: 在iOS 10中, WCSession添加了剩余的WCSession属性,该属性可能会影响iOS将使用哪种方法来传输用户信息:
  • Can't get WatchKit URLSession background to work
    I have a file for a BackgroundSession class class BackgroundSession: NSObject { static let shared = BackgroundSession() static let identifier = "com.***.bg" private var session: URLSession! var savedCompletionHandler: (() -> Void)? private override init() { super.init() let configuration = URLSessionConfiguration.background(withIdentifier: BackgroundSession.identifier) session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil) } func start(_ request: URLRequest) { session.downloadTask(with: request).resume() } } extension BackgroundSession: URLSessionDelegate { func
  • 从 HealthKit 监测心率 --> HKAnchoredObjectQuery 仅在 applicationDidBecomeActive 之后调用(BUG 或 FEATURE?)(Monitor heart rate from HealthKit --> HKAnchoredObjectQuery only called after applicationDidBecomeActive (BUG or FEATURE?))
    问题 我正在编写一个简单的应用程序,用于在将新的健康率值写入 HealthKit 时从 HealthKit 监控心率 (HKQuantityTypeIdentifierHeartRate)。 正如在 WWDC2015 (session 203) 上看到的,我正在使用HKAnchoredObjectQuery ,它应该可以用于添加和删除对象。 每当我启动应用程序时,我都会为最新的对象调用HKQuery并执行运行良好的查询!!! 但是即使样本在那里,我也没有得到新样本,但是如果我将应用程序带到后台并再次回到前台,我将获得所有新的心率。 这是一个错误吗? 或者我应该怎么做才能在不将应用程序置于后台和前台的情况下监测心率? 这是我正在使用的代码(所有内容都存储在 AppDelegate 中),我正在调用[self requestAccessDataTypes]; 来自didFinishLaunchingWithOptions : [healthStore enableBackgroundDeliveryForType:sampleType frequency:HKUpdateFrequencyImmediate withCompletion:^(BOOL success, NSError *error) {}]; HKQuery *query = [self