xcode 当腕表应用中的数值更新时,如何更新腕表复杂功能?

nbnkbykc  于 2023-03-19  发布在  其他
关注(0)|答案(1)|浏览(119)

我使用Xcode 14为iOS 16.2和WatchOS 9.1创建了一个定制/学习型iOS应用和手表应用。这两个应用都有一个真实用户。这两个应用使用CoreData在本地存储活动。这两个应用使用WCSession transferUserInfo()将新活动的JSON表示传送到对方设备,然后对方将新活动保存到其CoreData DB中。这运行良好,应用程序视图动态更新。
使用Xcode,我添加了手表小部件扩展的目标,并稍微更新了样板代码,如下所示。
接下来,我想在新活动添加到手表应用程序时更新复杂功能(包括从iOS应用程序传输的活动)。用户每3到8小时添加一次活动,所以我认为设置未来输入日期的时间轴没有意义。复杂功能只需要最近活动的时间,这样它就可以显示自该活动以来经过的时间。
具体来说,当最近Activity的activityTime值更新时,如何将该值从手表应用发送到复杂功能?

import WidgetKit
import SwiftUI
import OSLog

struct Provider: TimelineProvider {
    let logger = Logger(subsystem: Bundle.main.bundleIdentifier ?? "", category: "Provider")
    
    func placeholder(in context: Context) -> mostRecentActivityEntry {
        mostRecentActivityEntry(date: Date(), activityTime: Date())
    }

    func getSnapshot(in context: Context, completion: @escaping (mostRecentActivityEntry) -> ()) {
        let entry = mostRecentActivityEntry(date: Date(), activityTime: Date())
        completion(entry)
    }

    func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        var mostRecentActivityTime: Date?
        
        var entries: [mostRecentActivityEntry] = []

        // Generate a timeline consisting of five entries an hour apart, starting from the current date.
        let currentDate = Date()
        for hourOffset in 0 ..< 5 {
            let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)!
            let entry = mostRecentActivityEntry(date: entryDate, activityTime: mostRecentActivityTime)
            entries.append(entry)
        }

        let timeline = Timeline(entries: entries, policy: .atEnd)
        completion(timeline)
    }
}

struct mostRecentActivityEntry: TimelineEntry {
    var date: Date
    var activityTime: Date?
}

struct MostRecentEntryView : View {
    var entry: Provider.Entry

    var body: some View {
        HStack {
            Text("Log")
                .font(.headline)
                .foregroundColor(.purple)
            if let time = entry.activityTime {  
                Text(time, style: .relative)
                    .font(.headline)
                    .foregroundColor(.accentColor)
            } 
            Spacer()
        }
    }
}

@main
struct ActivityLogWatchWidgetExtension: Widget {
    let kind: String = "ActivityLogWatchWidgetExtension"

    var body: some WidgetConfiguration {
        StaticConfiguration(
            kind: kind,
            provider: Provider()) { entry in
            MostRecentEntryView(entry: entry)
        }
        .configurationDisplayName("Time Since Last Activity")
        .description("Displays the time since the last activity.")
    }
}

struct ActivityLogWatchWidgetExtension_Previews: PreviewProvider {
    static var previews: some View {
        MostRecentEntryView(entry: mostRecentActivityEntry(date: Date(), activityTime: Date().addingTimeInterval(-1000)))
            .previewContext(WidgetPreviewContext(family: .accessoryRectangular))
        MostRecentEntryView(entry: mostRecentActivityEntry(date: Date(), activityTime: nil))
            .previewContext(WidgetPreviewContext(family: .accessoryRectangular))
   }
}
eivnm1vs

eivnm1vs1#

堆栈溢出响应

在为此工作了几天之后,对我来说,关键的信息是WidgetKit已经取代了ClockKit,手表应用程序及其复杂功能可以使用UserDefaults共享简单的数据。
我需要为手表应用和手表小工具扩展添加一个“应用组”功能(复杂化)。我使用的组名是“group.[MY PHONE APP BUNDLE IDENTIFIER]",不过最好避免超过40个字符的名称,因为它们在显示时会被截断,但在后台不会。这花了我一些时间。
在手表应用中直接创建新Activity或从手机应用传输新Activity时,我会将mostRecentActivityTime保存为UserDefaults,并通过WidgetCenter重新加载复杂功能的时间轴:

let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let dateString = formatter.string(from: mostRecentActivityTime)
UserDefaults(suiteName: "group.[MY PHONE APP BUNDLE IDENTIFIER]")?.set(dateString, forKey: "mostRecentEmptyTime")
WidgetCenter.shared.reloadAllTimelines()

在widget扩展中,我从UserDefaults获取mostRecentEmptyTime值,并向时间轴添加一个条目。当复杂功能仅在手表应用发送新值时发生变化时,.重载策略永远不起作用。

func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
    var entries: [mostRecentActivityEntry] = []

    let entryDate = Date()
    let dateString = UserDefaults(suiteName: "group.[MY PHONE APP BUNDLE IDENTIFIER]")?.string(forKey: "mostRecentActivityTime")
    if let dateString {
        let formatter = DateFormatter()
        formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
        if let mostRecentActivityTime = formatter.date(from: dateString) {
            let entry = mostRecentActivityEntry(date: entryDate, activityTime: mostRecentActivityTime)
            entries.append(entry)
            let timeline = Timeline(entries: entries, policy: .never)
            completion(timeline)
        }
    }
}

唯一剩下的问题是,手机应用使用transferUserInfo()将新活动传输到手表应用时,只有在手表应用打开后才会更新手表的复杂功能。我不认为使用sendMessage()会有所改善,因为苹果文档指出,“从iOS应用调用[sendMessage]不会唤醒相应的WatchKit扩展。”

相关问题