apple-watch watch-os-2 apple-watch-complication clockkit

¿Cuál es el flujo para actualizar los datos de complicaciones para Apple Watch?



apple-watch watch-os-2 (2)

He estado siguiendo muchos tutoriales en Internet para aprender cómo configurar la complicación. No tengo ningún problema para configurar la complicación como se esperaba.

Hasta que las entradas iniciales de la línea de tiempo expiren. Después de 12 horas, no sé cómo actualizarlo para mantener viva la complicación. Voy a compartir todo lo que tengo debajo y espero que alguien pueda ayudarme a informarme.

Aquí, creo las variables para mis datos que quiero mostrar en la complicación.

struct data = { var name: String var startString: String var startDate: NSDate }

La siguiente matriz es un contenedor para estos datos.

var dataArray = [data]

Esto permite mostrar la complicación cuando el reloj está bloqueado.

func getPrivacyBehaviorForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationPrivacyBehavior) -> Void) { handler(.ShowOnLockScreen) }

Esto permite adelantar el viaje en el tiempo en la complicación.

func getSupportedTimeTravelDirectionsForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimeTravelDirections) -> Void) { handler([.Forward]) }

Aquí, configuro la hora de inicio de la línea de tiempo para que sea igual a ahora.

func getTimelineStartDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) { handler(NSDate()) }

Aquí, configuro la hora de finalización de la línea de tiempo para que sea igual a 12 horas a partir de ahora.

func getTimelineEndDateForComplication(complication: CLKComplication, withHandler handler: (NSDate?) -> Void) { handler(NSDate(timeIntervalSinceNow: (60 * 60 * 12))) }

Aquí, creo la plantilla de la complicación. Esto es para mostrar datos de muestra para los usuarios cuando ven mi complicación mientras exploran todas las complicaciones en su reloj.

func getPlaceholderTemplateForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTemplate?) -> Void) { let headerTextProvider = CLKSimpleTextProvider(text: "Some Data") let body1TextProvider = CLKSimpleTextProvider(text: "Some Data Time") let template = CLKComplicationTemplateModularLargeStandardBody() template.headerTextProvider = headerTextProvider template.body1TextProvider = body1TextProvider handler(template) }

Esto crea la primera entrada de línea de tiempo para la complicación. Tan pronto como se habilite la complicación, este código se ejecutará y completará inmediatamente la complicación correspondiente.

func getCurrentTimelineEntryForComplication(complication: CLKComplication, withHandler handler: (CLKComplicationTimelineEntry?) -> Void) { createData() if complication.family == .ModularLarge { if dataArray.count != 0 { let firstData = dataArray[0] let headerTextProvider = CLKSimpleTextProvider(text: firstData.name) let body1TextProvider = CLKSimpleTextProvider(text: firstData.startString) let template = CLKComplicationTemplateModularLargeStandardBody() template.headerTextProvider = headerTextProvider template.body1TextProvider = body1TextProvider let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: template) handler(timelineEntry) } else { let headerTextProvider = CLKSimpleTextProvider(text: "No Data") let body1TextProvider = CLKSimpleTextProvider(text: "Create some data") let template = CLKComplicationTemplateModularLargeStandardBody() template.headerTextProvider = headerTextProvider template.body1TextProvider = body1TextProvider let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(), complicationTemplate: template) handler(timelineEntry) } } else { handler(nil) } }

Aquí es donde creo entradas de línea de tiempo para todos los datos que tengo actualmente.

func getTimelineEntriesForComplication(complication: CLKComplication, afterDate date: NSDate, limit: Int, withHandler handler: ([CLKComplicationTimelineEntry]?) -> Void) { createData() var entries = [CLKComplicationTimelineEntry]() for dataObject in dataArray { if entries.count < limit && data.startDate.timeIntervalSinceDate(date) > 0 { let headerTextProvider = CLKSimpleTextProvider(text: dataObject.name) let body1TextProvider = CLKSimpleTextProvider(text: dataObject.startString) let template = CLKComplicationTemplateModularLargeStandardBody() template.headerTextProvider = headerTextProvider template.body1TextProvider = body1TextProvider let timelineEntry = CLKComplicationTimelineEntry(date: NSDate(timeInterval: (-10*60), sinceDate: data.startDate), complicationTemplate: template) entries.append(timelineEntry) } } handler(entries) }

Esto le dice al reloj cuándo actualizar los datos de complicaciones.

func getNextRequestedUpdateDateWithHandler(handler: (NSDate?) -> Void) { handler(NSDate(timeIntervalSinceNow: 60 * 60 * 6)) }

Aquí es donde estoy teniendo problemas.

¿Cómo creo mis nuevos datos y recargo la línea de tiempo? ¿Qué es el flujo? No estoy tratando de extender la línea de tiempo, sino de reemplazarla por completo. Estoy en una pérdida completa. Los documentos de Apple son bastante vagos cuando se trata de este punto. Sé que necesito implementar los siguientes métodos, pero no sé cómo. ¿Puede alguien ayudarme a rellenar este código?

func requestedUpdateDidBegin() { createData() //I assume createData() goes here? If so, how do I populate the new timeline entries based on the results? } func requestedUpdateBudgetExhausted() { //This can''t possibly be the case as I haven''t gotten it to work once. } func reloadTimelineForComplication(complication: CLKComplication!) { //This method appears to do nothing. }

Actualizar:

Gracias a El Tea, lo tengo funcionando. Necesito agregar una instancia de CLKComplicationServer a requiredUpdateDidBegin y poner el método reloadTimeline dentro.

Aquí está el código actualizado:

func requestedUpdateDidBegin() { print("Complication update is starting") createData() let server=CLKComplicationServer.sharedInstance() for comp in (server.activeComplications) { server.reloadTimelineForComplication(comp) print("Timeline has been reloaded!") } } func requestedUpdateBudgetExhausted() { print("Budget exhausted") }


El flujo para una actualización de complicación que se realiza en un intervalo de tiempo sigue esta secuencia:

  • iOS llama a su función requestedUpdateDidBegin() o requestedUpdateBudgetExhausted() (Si su presupuesto se agota, nada de lo que haga causará una actualización hasta que se le otorgue más tiempo de ejecución).
  • Dentro de reloadTimelineForComplication() debe llamar a reloadTimelineForComplication() o extendTimelineForComplication() para especificar cuál de sus complicaciones desea que se vuelva a cargar o para agregar datos. Si no haces esto, ¡no pasa nada!
  • Dependiendo de si llamó a reload o extend , iOS realiza llamadas a uno o ambos de getCurrentTimelineEntryForComplication() y getTimelineEntriesForComplication()
  • Independientemente de si actualizó o no su complicación, iOS llama a getNextRequestedUpdateDateWithHandler() para saber cuándo desea repetir los pasos anteriores.

Nota: los dos últimos pasos no necesariamente tienen que suceder en ese orden.

El proceso funciona de esta manera para que iOS no le pida que regenere repetidamente los mismos datos. Le da la oportunidad en requestedUpdateDidBegin() para decidir si su complicación necesita actualizarse. Si no lo hace, su código debería regresar. (Esto reduce el tiempo de ejecución de su complicación y ayuda a evitar que iOS corte su aplicación de otras actualizaciones por haber utilizado su presupuesto diario). Pero si tiene datos nuevos, necesita avisar a iOS llamando a reloadTimelineForComplication() o extendTimelineForComplication()

Por lo que puedo decir, todo lo que ha escrito allí se ve bien, aparte de que no estaba solicitando una recarga o extensión dentro de requestedUpdateDidBegin() . Es posible que su complicación sea visible en la esfera del reloj en más de una posición, y que diferentes plantillas tengan diferentes comportamientos de visualización, por lo que tiene que invalidarlas todas. Aquí es como se ve mi código:

func requestedUpdateDidBegin() { //Not shown: decide if you actually need to update your complication. //If you do, execute the following code: let server=CLKComplicationServer.sharedInstance() for comp in (server.activeComplications) { server.reloadTimelineForComplication(comp) } }

Tenga en cuenta que, además de los intervalos de tiempo, existen otras formas de iniciar las actualizaciones, incluidas las alertas automáticas, la ejecución de recargas cuando se ejecuta la aplicación Watch, o el uso del marco Watch Connectivity con una WCSession para que la aplicación del teléfono envíe datos actualizados para que se muestren inmediatamente a través de transferCurrentComplicationUserInfo() . Consulte Actualización de sus datos de complicaciones en los documentos de Apple para obtener más información.

He tenido éxito en los intervalos de actualización de pruebas del simulador en tan solo diez minutos. Probablemente no debería actualizar esa frecuencia en el reloj real debido al presupuesto de tiempo de ejecución, pero esto le permitirá probar su código sin tener que esperar 12 horas.


La respuesta de El Tea entra en detalles sobre cómo actualizar una complicación para watchOS 2.

En watchOS 3, la forma recomendada de mantener su complicación actualizada consiste en utilizar las tareas de la aplicación de actualización en segundo plano . Puede usar una serie de tareas en segundo plano para schedule y handle la extensión de su aplicación que se está activando en segundo plano para:

Esto es mucho más funcional además de eficiente en el uso de la energía, ya que no utiliza el presupuesto de ejecución diaria de su complicación para obtener datos o actualizar el modelo.

También evita la complejidad de los enfoques no recomendados que intentaron obtener datos de forma asíncrona en una fuente de datos de complicaciones que solo estaba destinada a responder de forma inmediata a las solicitudes.

He proporcionado más información, así como enlaces a videos de WWDC y código de muestra, en una respuesta diferente .

Para resumir el cambio para watchOS 3

Use tareas programadas en segundo plano en lugar de getNextRequestedUpdateDateWithHandler() .

Vuelva a cargar o extienda su línea de tiempo en una tarea de aplicación, en lugar de dentro de requestedUpdateDidBegin() .