跳转到主要内容
Live Activities 让您的 iOS 应用直接在锁屏和动态岛上显示实时更新。非常适合配送跟踪、体育比分或时效性交易更新,让用户无需打开应用即可保持了解。
Android 有一个类似的功能叫做 Android Live Notifications

要求


设置

这些步骤引导您快速设置 Live Activities。有关更多详情和设计自定义,请参阅 Apple 的 Live Activities 开发者文档

1. 添加 Widget 扩展

在 Xcode 中,转到 File > New > Target… > Widget Extension

在 Xcode 中为您的应用添加新的 Widget Extension 目标。

选择并按 Next 通过提供名称(示例:OneSignalWidget)配置 Widget Extension,并确保选中 Include Live Activity。然后点击 Finish

Live Activity 的 Widget Extension 选项。

Click Don’t Activate if prompted to activate the scheme.

Live Activity 的 Widget Extension 选项。

2. 更新 Info.plist

在您的主目标的 Info.plist 中,添加键 Supports Live Activities 作为 Boolean,并将其设置为 YES

将 Supports Live Activities 键添加到 Info 并将其值设置为布尔值 YES

如果您以编程方式设置它,应该如下所示:
info.plist
<key>NSSupportsLiveActivities</key>
<true/>
更新 Live Activities 时,您可以选择设置”优先级”,Apple 使用它来确定更新的紧急程度。Apple 有内部阈值,会对过于频繁使用高优先级标志的请求进行限制。如果您的 Live Activities 用例依赖于更频繁的高优先级更新,您可以按照 Apple 开发者文档的指示,将键 NSSupportsLiveActivitiesFrequentUpdates 作为布尔类型设置为 YES 添加到您的 Info.plist 中。当 Live Activity 超过其推送预算时,用户将看到一个对话框,如果他们允许 Live Activity 继续,预算将自动增加以提供无缝的用户体验。

3. 添加 SDK

  • 包管理器
  • Cocoapods
在您的 Widget Extension 目标中,在General > Frameworks, Libraries and Embedded Content下添加 OneSignalFramework

将 OneSignalFramework 添加到您的 Widget Extension 目标

4. 定义小组件属性和 UI

打开 your-nameLiveActivity.swift 文件(示例:OneSignalWidgetLiveActivity.swift)来定义结构的属性并对 widget UI 进行更改。
  • your-nameAttributes 描述您 Live Activity 的静态内容。
  • ContentState 描述您 Live Activity 的动态内容。
如果您遵循示例,请将下面的代码复制粘贴到您的 OneSignalWidgetLiveActivity.swift 文件中。
your-nameLiveActivity.swift
import ActivityKit
import WidgetKit
import SwiftUI
// 导入 OneSignalLiveActivities 模块
// 如果您收到关于找不到模块的错误,请返回步骤 3 并确保您已正确添加了 OneSignalLiveActivities pod。
import OneSignalLiveActivities

// 更新以继承 OneSignalLiveActivityAttributes
// 这将在您的 API 请求中用于启动 Live Activity
struct OneSignalWidgetAttributes: OneSignalLiveActivityAttributes  {
    // 更新以继承 OneSignalLiveActivityContentState
    public struct ContentState: OneSignalLiveActivityContentState {
        // 关于您活动的动态状态属性在这里!
        var emoji: String
        // 添加对 OneSignalLiveActivityContentStateData 的引用?
        var onesignal: OneSignalLiveActivityContentStateData?
    }
    // 关于您活动的固定不变属性在这里!
    var name: String
    // 添加对 OneSignalLiveActivityAttributeData 的引用
    var onesignal: OneSignalLiveActivityAttributeData
}

struct OneSignalWidgetLiveActivity: Widget {
    var body: some WidgetConfiguration {
      // 更新以使用 `for: the-name-of-your-attributes-struct`
      // 这将在您的 API 请求中用于启动 Live Activity
        ActivityConfiguration(for: OneSignalWidgetAttributes.self) { context in
            // 锁屏/横幅 UI 在这里
            // 更新以显示通过负载发送的属性
            VStack {
                Text("Hello \(context.attributes.name) \(context.state.emoji)")
            }
            .activityBackgroundTint(Color.cyan)
            .activitySystemActionForegroundColor(Color.black)

        } dynamicIsland: { context in
            DynamicIsland {
                // 展开的 UI 在这里。通过各种区域组成展开的 UI,
                // 如 leading/trailing/center/bottom
                DynamicIslandExpandedRegion(.leading) {
                    Text("Leading")
                }
                DynamicIslandExpandedRegion(.trailing) {
                    Text("Trailing")
                }
                DynamicIslandExpandedRegion(.bottom) {
                    Text("Bottom \(context.state.emoji)")
                    // 更多内容
                }
            } compactLeading: {
                Text("L")
            } compactTrailing: {
                Text("T \(context.state.emoji)")
            } minimal: {
                Text(context.state.emoji)
            }
            .widgetURL(URL(string: "http://www.apple.com"))
            .keylineTint(Color.red)
        }
    }
}

5. 允许主目标成员资格

将您的主应用目标添加到 your-nameLiveActivity.swift 文件中的 Target Membership 列表。 在 Xcode 中,打开屏幕右侧的 Inspector 面板。在 Target Membership 中,点击 + 按钮并选择包含 ContentView 和您的 OneSignal 初始化代码的主应用目标。

允许主目标成员资格

6. 将设置方法添加到您的 AppDelegate

在 OneSignal SDK 初始化后,在您的 AppDelegate 中调用 OneSignal.LiveActivities.setup OneSignalWidgetAttributes 替换为您的 Live Activity 属性结构的名称。
AppDelegate
// 导入 OneSignalLiveActivities 模块
import OneSignalLiveActivities

// 这应该在初始化 OneSignal SDK 后添加
if #available(iOS 16.1, *) {
	OneSignal.LiveActivities.setup(OneSignalWidgetAttributes.self)
  // 如果您有多个 Live Activities,您可以在这里使用 setup 方法添加它们
  // OneSignal.LiveActivities.setup(LiveActivityWidgetAttributes-2.self)
}
这使用 ActivityKit 异步序列管理和报告更新。
如果您在应用中也直接使用以下任何序列,可能会干扰 OneSignal Live Activity 行为:
  • activityStateUpdates
  • pushTokenUpdates
  • pushToStartTokenUpdates
  • activityUpdates

启动 Live Activity

在设备上启动 Live Activity 有 2 个选项:
  • 推送开始
  • 应用内触发
发送推送启动 API 请求。确保所有名称和 ID 与您的 widget 配置完全匹配(参数区分大小写)。如果有任何遗漏或错误添加,您在尝试启动 widget 时可能会遇到问题。这是一个适用于上述示例的示例请求。替换:
  • YOUR_APP_ID 为您的 OneSignal 应用 ID。
  • YOUR_APP_API_KEY 为您的 OneSignal API 密钥。
  • OneSignalWidgetAttributes 为您的 Widget Attributes 结构的名称。
    curl
    curl --location 'https://api.onesignal.com/apps/YOUR_APP_ID/activities/activity/OneSignalWidgetAttributes' \
    --header 'Authorization: key YOUR_APP_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{
        "event": "start",
        "activity_id": "push-to-start",
        "included_segments": [
            "Subscribed Users"
        ],
        "event_attributes": {
            "name": "World"
        },
        "event_updates": {
            "emoji":"🤩"
        },
        "name": "Live Activities Test",
        "contents": {
            "en": "A push started this Live Activity"
        },
        "headings": {
          "en": "Live Activity Started"
        }
      }'
    
如果您遵循提供的示例代码,您应该在设备的锁屏上看到 Live Activity。

锁屏上的 Live Activity

您已成功使用 push-to-start 启动了 Live Activity!用户需要选择”允许”以继续获取更新。

更新 Live Activity

使用更新 Live Activity API来更新活动的 widgets。 匹配启动活动时使用的 activity_id 此示例请求将更新 push-to-start widget,因为它具有我们定义的标题为 push-to-startactivity_id。 要更新 click-to-start widget,请更新请求路径以使用 click-to-start 而不是 push-to-start
curl
curl --location 'https://api.onesignal.com/apps/YOUR_APP_ID/live_activities/push-to-start/notifications' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: key YOUR_API_KEY' \
--data '{
    "event": "update",
    "event_updates": {
        "emoji": "😎"
    },
    "contents": {
        "en": "A push updated this Live Activity"
    },
    "name": "Live Activity Updated"
}'

Live Activity 已更新

您已成功更新了 Live Activity!查看更新 Live Activity API以获取有关更新 Live Activity 的更多信息。

结束 Live Activity

使用相同的更新 Live Activity API,我们可以通过设置 "event": "end" 来结束 Live Activity。
curl
curl --location 'https://api.onesignal.com/apps/YOUR_APP_ID/live_activities/my_activity_id/notifications' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'Authorization: key YOUR_API_KEY' \
--data '{
    "event": "end",
    "event_updates": {
        "emoji": "👋"
    },
    "contents": {
        "en": "A push ended this Live Activity"
    },
    "name": "Live Activity Ended"
}'
Live Activity 的其他结束方式:
  • 使用我们的 SDK exit() 方法
  • 用户手动滑动 Live Activity 使其消失。
  • 用户在 iOS 设置中撤销 Live Activities 权限。

Live Activity 已结束

您已成功结束 Live Activity 并完成了示例!

最佳实践和建议

设计考虑

  • 遵循 Apple 的 Live Activities 人机界面指南
    • 优先考虑重要信息,使其易于一目了然地理解。
    • 不要在您的应用中添加吸引对动态岛注意的元素。
    • 使用边距并保持元素之间的空间。
    • 为背景使用醒目的颜色。为浅色和深色模式进行设计。

功能性


常见问题

高优先级更新的预算是多少?

Apple 不为高优先级(priority: 10)更新提供固定限制,但他们确实执行动态系统级预算。在短时间内发送过多高优先级更新可能导致限制,更新被延迟或丢弃。 要降低限制风险:
  • 使用混合优先级:Apple 建议同时使用 priority: 5(标准)和 priority: 10(高)以取得平衡。
  • 仅为时效性或关键更新保留 priority: 10(如订单状态变化、游戏比分)。
如果您的用例需要频繁更新:
  • 将键 NSSupportsLiveActivitiesFrequentUpdates 添加到您应用的 Info.plist 文件中,设置为布尔值 YES
  • 当超过此预算时,iOS 可能会提示用户允许额外更新。如果用户同意,Apple 将自动扩展允许的更新限制以保持无缝体验。
有关更多详情,请参阅 Apple 开发者文档

我可以从主应用读取 Live Activity 更新吗?

是的。您可以观察更新以进行调试或 UI 同步:
Task {
    for await content in activity.contentUpdates {
        print("LA activity id: \(activity.id), content update: \(content.state)")
    }
}
// Example output:
// LA activity id: EFE6D54D-F7E1-45EF-9514-4C2598F8DED2, content update: ContentState(message: "My message from payload")
跟踪生命周期变化:
Task {
    for await state in activity.activityStateUpdates {
        print("LA state update: \(state)")
        //If you wanted to do something based on the state, you would use this:
      	if state != ActivityState.active {
            //Do something here
        }
    }
}

// Example output 1 - LA ended, but still visible
// LA state update: active

/* State can be equal to 4 possible values on the ActivityState enum
active, dismissed, ended, and stale
*/

API 返回 400 错误,提示我超过了订阅者限制。我该怎么办?

如果您的推送订阅者数量超过了您计划的推送订阅者限制,请将您的账户升级到下一个计划,或联系 support@onesignal.com。有关最新计划详情,请点击这里查看

如何避免同时发送推送和 Live Activities?

您的应用可能已经发送了一系列推送通知,而您设计的 Live Activity 替代了这些推送通知的需要。例如,如果您通过推送发送比分更新,您可以通过 Live Activity 来替代。 为了确保您的用户不会收到太多消息,我们建议当您的用户选择加入 Live Activity 时,添加一个数据标签。通过添加此数据标签,您可以从可能包含相同或类似内容的推送消息中排除具有此数据标签的用户。阅读更多关于数据标签细分的信息。

故障排除

无接收者

为了在尝试启动或更新 Live Activity 时找到您的用户,您必须确保活动类型、widget 和 cURL 请求都具有匹配的值。
  1. 检查请求中的路径参数,确保您向服务器发送的是格式正确的请求。应用 ID 必须与您在 OneSignal.Initialize 方法中使用的应用 ID 匹配,活动类型必须与您在 Live Activity 文件中定义的类型匹配。
  2. 推送启动 API 请求的主体中,您应该具有以下参数:
  • event: "start"
  • event_updates: 您在活动类型下的结构中定义的并在您的 widget 中使用的动态数据。确保请求、类型和 widget 之间的字母大小写和变量都匹配。
  • event_attributes: 静态数据遵循与事件更新相同的逻辑,必须包含使用中的所有变量,并且必须在 live activity 和请求的所有部分中匹配
  • activity_id: 这将为 widget 分配一个 ID,是在用户设备上启动活动后用于更新活动的 ID。
  • name: Live Activity 名称。
  • contents: 发送推送所需的消息内容。
  • headings: 发送推送所需的消息标题。
  • 定向参数,如 included_segments可用选项

活动已发送但未接收

  1. 确保请求格式正确。如果省略了 Widget 中使用的任何字段,活动可能无法按预期启动或更新。
  2. 在您的 API 请求中,确定您设置的 priority 级别。如果您将其设置为 10(最高优先级),请尝试将其降低到 5 并重新测试。Apple 会根据他们自己的内部速率限制对发送过于频繁的请求进行限制。
如果您的用例依赖于更频繁的更新,请按照 Apple 开发者文档的指示,将键 NSSupportsLiveActivitiesFrequentUpdates 作为布尔类型设置为 YES 添加到您的 Info.plist 中。当 Live Activity 超过其推送预算时,用户将看到一个对话框,如果他们允许 Live Activity 继续,预算将自动增加以提供无缝的用户体验。
需要帮助?与我们的支持团队聊天或发送邮件至 support@onesignal.com请包含以下信息:
  • 您遇到的问题详情以及复现步骤(如有)
  • 您的 OneSignal 应用 ID
  • 外部 ID 或订阅 ID(如适用)
  • 您在 OneSignal 控制台中测试的消息 URL(如适用)
  • 任何相关的日志或错误信息
我们很乐意为您提供帮助!

I