You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用pushToStartTokens处理同类型多Live Activity实例?

问题:多同类型Live Activity的推送启动区分处理

我想让用户关注多场足球比赛,需要订阅多个同类型(相同FootballActivityAttributes)的Live Activity,但在监听pushToStartTokenUpdates序列时,无论调用多少次相关函数,始终得到同一个token。如何实现启动多个待启动的Activity并分别用推送触发?本地存储matchId,仅在推送id匹配时处理更新是否是最优方案?还是Apple没考虑这种场景?

补充代码示例(运行后两次打印相同token):

import ActivityKit
import SwiftUI

struct FootballActivityAttributes: ActivityAttributes {
    var eventId: String
    var homeTeam: String
    var awayTeam: String

    public struct ContentState: Codable, Hashable {
        var homeScore: Int
        var awayScore: Int
    }
}

func getPushToStartToken(eventID: String) async throws -> String? {
    print("Running Live Activity: Fetching pushToStartToken for event \(eventID)...")
    for await data in Activity<FootballActivityAttributes>.pushToStartTokenUpdates {
        let token = data.map {String(format: "%02x", $0)}.joined()
        print("Live Activity: Saved pushToStartToken for event \(eventID): \(token)")
        return token
    }
    print("Live Activity: Found no token")
    return nil
}

for eventId in ["12345", "67890"] {
    Task {
        try await getPushToStartToken(eventID: eventId)
    }
}

解决方案

核心结论

pushToStartToken是按Activity的Attributes类型生成的,同一类型的所有Live Activity共享同一个启动token,这是Apple的设计逻辑,并非代码问题。你需要通过推送payload携带唯一标识来区分不同的Activity实例。

标准实现方案

本地存储matchId与Activity实例ID的映射是官方预期的解决方案,只要做好映射的生命周期管理,就是高效合规的实现方式,具体步骤如下:

  1. 创建待启动的Activity并存储映射
    为每场比赛创建待启动的Live Activity实例,将赛事eventId与Activity的id关联存储,方便后续推送时匹配:

    func createPendingFootballActivity(eventId: String, homeTeam: String, awayTeam: String) async throws -> Activity<FootballActivityAttributes>? {
        let attributes = FootballActivityAttributes(eventId: eventId, homeTeam: homeTeam, awayTeam: awayTeam)
        let initialContentState = FootballActivityAttributes.ContentState(homeScore: 0, awayScore: 0)
        
        // 请求推送启动授权
        let authStatus = await Activity<FootballActivityAttributes>.requestPushToStartAuthorization()
        guard authStatus == .authorized else {
            print("推送启动授权失败")
            return nil
        }
        
        // 创建待启动的Activity实例
        let activity = try Activity.request(
            attributes: attributes,
            contentState: initialContentState,
            pushType: .token
        )
        
        // 存储eventId与Activity ID的映射(用UserDefaults示例,也可选用Keychain)
        var pendingMatches = UserDefaults.standard.dictionary(forKey: "PendingFootballMatches") as? [String: String] ?? [:]
        pendingMatches[eventId] = activity.id.uuidString
        UserDefaults.standard.set(pendingMatches, forKey: "PendingFootballMatches")
        
        return activity
    }
    
  2. 处理推送并启动指定Activity
    在推送回调中,从payload里取出eventId,匹配对应的Activity ID,再启动该实例:

    func handleLiveActivityPush(payload: [AnyHashable: Any]) {
        guard let aps = payload["aps"] as? [String: Any],
              let eventId = aps["event-id"] as? String, // 推送payload需携带该字段
              let pendingMatches = UserDefaults.standard.dictionary(forKey: "PendingFootballMatches") as? [String: String],
              let activityIdStr = pendingMatches[eventId],
              let activityId = UUID(uuidString: activityIdStr) else {
            return
        }
        
        Task {
            do {
                // 启动指定的待启动Activity
                try await Activity<FootballActivityAttributes>.request(options: .pushToStart, id: activityId)
                // 启动成功后移除映射,避免冗余数据
                var updatedMatches = pendingMatches
                updatedMatches.removeValue(forKey: eventId)
                UserDefaults.standard.set(updatedMatches, forKey: "PendingFootballMatches")
            } catch {
                print("启动Live Activity失败: \(error.localizedDescription)")
            }
        }
    }
    

额外注意事项

  • 推送payload必须包含event-id(或自定义的唯一标识),且需符合Apple的Live Activity推送格式要求。
  • 定期清理过期的映射关系(比如赛事结束后),避免存储冗余数据。
  • 若用户删除App或重置存储,需重新创建待启动的Activity并生成映射。

内容的提问来源于stack exchange,提问作者MatiasVian

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 00:02:41