# iOS 实时活动

<Aside type="tip">
观看关于 iOS 实时活动 (Live Activities) 的视频
<YouTube id="jRrDh_pIZCE" playlabel="Youtube 视频：iOS 实时活动" /> 
</Aside>


[实时活动 (Live Activities)](https://developer.apple.com/design/human-interface-guidelines/live-activities) 会在 iPhone 或 iPad 的锁定屏幕和灵动岛上显示您应用的最新数据。此功能允许用户一目了然地查看实时信息，并执行与显示信息相关的快速操作。

以下是使用实时活动的一些示例：

*   在配送应用中显示订单状态；
*   在训练应用中提供实时倒计时；
*   在出租车应用中显示跟踪信息；
*   在体育应用中显示比赛统计数据和当前比分；
*   在天气应用中提供每小时预报。

您可以使用 Pushwoosh iOS SDK 启用实时活动，如下所述。要管理实时活动并更新其内容，请使用 [/updateLiveActivity](/zh/developer/api-reference/ios-live-activities-api#updateliveactivity) 方法。



## 设置
<Aside type="caution" title="重要提示" >
Pushwoosh 中的实时活动仅支持[基于令牌的配置](/zh/developer/first-steps/connect-messaging-services/ios-configuration/ios-token-based-configuration/)。不支持[基于证书的配置](/zh/developer/first-steps/connect-messaging-services/ios-configuration/ios-platform-configuration/)。
</Aside> 

### 添加小组件扩展 (Widget Extension)

1.  创建一个新目标

转到 **File > New > Target** 并选择 **Widget Extension**。

<img src="/ios-push-notifications-ios-live-activities-1.webp" alt=""/>

2.  小组件扩展配置
请输入一个名称，并确保选择 **Include Live Activity**，然后点击 **Finish**。

<img src="/ios-push-notifications-ios-live-activities-2.webp" alt=""/>

### Info.plist 配置
在主目标中找到 Info.plist 文件，插入 "Supports Live Activities" 键，并将其值设置为 YES。

```xml
	<key>NSSupportsLiveActivities</key>
	<true/>
```

### 从应用中启用实时活动
要启用实时活动，请将其代码添加到您现有的小组件扩展中，或者如果您的应用还没有，则创建一个新的。实时活动使用 [SwiftUI](https://developer.apple.com/documentation/SwiftUI) 和 [WidgetKit](https://developer.apple.com/documentation/WidgetKit) 功能来实现其用户界面。ActivityKit 处理每个实时活动的生命周期：其 API 用于请求、更新和结束实时活动，并接收 ActivityKit 推送通知。您可以在[苹果文档](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities)中了解更多关于实时活动的信息。

 1. 在 Xcode 中导航到您项目的 ContentView 文件并创建一个 Button

```swift
import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(spacing: 20) {

            Button(action: {
                LiveActivityManager.shared.startActivity()
            }, label: {
                Text("Start Live Activity")
                    .foregroundColor(.white)
                    .padding()
                    .background(Color.blue)
                    .cornerRadius(10)
            })
        }
        .padding()
    }
}

#Preview {
    ContentView()
}
```
<img src="/ios-push-notifications-ios-live-activities-4.webp" alt=""/>

 2. 创建一个 LiveActivityManager.swift 文件来管理实时活动

```swift
import Foundation
import ActivityKit
import UIKit
import PushwooshFramework
import PushwooshLiveActivities

class LiveActivityManager: NSObject, ObservableObject {
    public static let shared: LiveActivityManager = LiveActivityManager()

    private var currentActivity: Activity<FoodDeliveryAttributes>? = nil

    override init() {
        super.init()
    }

    func startActivity() {
        guard ActivityAuthorizationInfo().areActivitiesEnabled else {
            print("You can't start live activity.")
            return
        }
        do {
            let pushwooshData = PushwooshLiveActivityAttributeData(activityId: "activity_id")
            let atttribute = FoodDeliveryAttributes(orderNumber: "1234567", pushwoosh: pushwooshData)
            let initialState = FoodDeliveryAttributes.ContentState(
                status: "Preparing your meal",
                estimatedTime: "25 min",
                emoji: "👨‍🍳",
                pushwoosh: nil
            )
            let activity = try Activity<FoodDeliveryAttributes>.request(
                attributes: atttribute,
                content: .init(state:initialState , staleDate: nil),
                pushType: .token
            )
            self.currentActivity = activity

            Task {
                for await pushToken in activity.pushTokenUpdates {
                    let pushTokenString = pushToken.reduce("") {
                        $0 + String(format: "%02x", $1)
                    }
                    print("Activity:\(activity.id) push token: \(pushTokenString)")

                    // MARK: - Send Push Token to Pushwoosh
                    Pushwoosh.LiveActivities.startLiveActivity(
                        token: pushTokenString,
                        activityId: "activity_id"
                    )
                }
            }
        } catch {
            print("Start Activity Error: \(error.localizedDescription)")
        }
    }
}

```

 3. 就是这样，现在我们运行项目并按下“Start Live Activity”按钮。然后我们导航到锁定屏幕，看到已创建的实时活动。


<img src="/live-activities-1.webp" alt=""/>

### 通过远程推送通知启动实时活动

1.  要通过远程推送通知启动实时活动，您需要将 `pushToStartTokenUpdates` 令牌发送到 Pushwoosh。

```swift
func getPushToStartToken() {
    if #available(iOS 17.2, *) {
        Task {
            for await data in Activity<LiveActivityAttributes>.pushToStartTokenUpdates {
                let token = data.map {String(format: "%02x", $0)}.joined()
                print("Activity PushToStart Token: \(token)")

                // Send `pushToStartTokenUpdates` token to Pushwoosh
                try await Pushwoosh.LiveActivities.sendPushToStartLiveActivity(token: token)
            }
        }
    }
}
```
2.  通过远程推送通知启动实时活动

<Aside type="tip">
请遵循我们的 [Pushwoosh API 参考](/zh/developer/api-reference/ios-live-activities-api#startliveactivity)以获取有关发出请求以远程启动实时活动的说明和示例。
</Aside>

### 管理实时活动

Pushwoosh iOS SDK 提供了以下用于处理实时活动的方法：

```swift
// Send Live Activity Push To Start Token to Pushwoosh
static func sendPushToStartLiveActivity(token: String)
static func sendPushToStartLiveActivity(token: String, completion: @escaping (Error?) -> Void)

// Start Live Activity Methods with Activity ID
static func startLiveActivity(token: String, activityId: String)
static func startLiveActivity(token: String, activityId: String, completion: @escaping (Error?) -> Void)

// Stop Live Activity Methods
static func stopLiveActivity()
static func stopLiveActivity(completion: @escaping (Error?) -> Void)

static func stopLiveActivity(activityId: String)
static func stopLiveActivity(activityId: String, completion: @escaping (Error?) -> Void)

```

您还可以使用 `Activity ID` 参数按分段更新实时活动。创建活动时，您需要在方法中传递一个唯一的 `Activity ID` 参数，该参数将与特定用户分段相关。

例如，N 个用户在实时活动中订阅了同一个事件。`Activity ID` 参数对于所有这 N 个用户都必须是唯一的。

当您完成实时活动的工作时，请使用这些方法：
```swift
static func stopLiveActivity()
static func stopLiveActivity(completion: @escaping (Error?) -> Void)
```
<Aside type="note">
您可以通过 [Pushwoosh API](/zh/developer/api-reference/ios-live-activities-api) 管理 iOS 实时活动。
</Aside>

### `Setup()` 方法
Pushwoosh 通过引入 `PushwooshLiveActivities.setup` 函数简化了活动 ID 的传输，该函数处理应用内实时活动的整个生命周期。此函数会自动监听 `pushToStart` 和 `pushToUpdate` 令牌更新。通过使用此方法，应用不再需要手动跟踪实时活动的启动或管理活动更新的令牌更新。

我们建议使用此方法，因为它会处理我们这边的所有令牌管理，从而减少您需要维护的代码量。这简化了集成，并确保您的应用获得更流畅、更高效的体验。

在 AppDelegate 中，确保您导入 `PushwooshFramework` 和 `PushwooshLiveActivities`，并从 `Pushwoosh.LiveActivities` 模块调用 `setup` 方法。

**AppDelegate.swift**
```swift
if #available(iOS 16.1, *) {
    Pushwoosh.LiveActivities.setup(FoodDeliveryAttributes.self)
}
```
**FoodDeliveryAttributes**

```swift
import WidgetKit
import SwiftUI
import ActivityKit
import PushwooshFramework
import PushwooshLiveActivities

struct FoodDeliveryAttributes: PushwooshLiveActivityAttributes {
    public struct ContentState: PushwooshLiveActivityContentState {
        var status: String
        var estimatedTime: String
        var emoji: String
        var pushwoosh: PushwooshLiveActivityContentStateData?
    }

    var orderNumber: String
    var pushwoosh: PushwooshLiveActivityAttributeData
}
```
`FoodDeliveryAttributes`：此结构符合 `PushwooshLiveActivityAttributes` 协议。它用于定义应用内实时活动的属性。

<Aside type="note">
您可以使用 Pushwoosh API 的 /updateLiveActivity 方法管理实时活动并更新其内容。更多信息，请阅读[本指南](/zh/developer/api-reference/ios-live-activities-api)。
</Aside>

## 迁移指南

从 Pushwoosh iOS SDK 6.8.0 版本开始，我们更新了 SDK 结构。现在通过 `PushwooshLiveActivities` 模块访问实时活动方法。

如果您使用的是早于 6.8.0 版本的 Pushwoosh iOS SDK 并调用了下面列出的方法，并且此后已更新到 6.8.0 或更高版本，请注意以下更改：

```swift
static func setup<Attributes: PushwooshLiveActivityAttributes>(_ activityType: Attributes.Type)
static func defaultSetup()
static func defaultStart(_ activityId: String, attributes: [String: Any], content: [String: Any])
```

现在，要访问这些方法，您应该使用 LiveActivity 模块。

```swift
import PushwooshFramework
import PushwooshLiveActivities

```

```swift
Pushwoosh.LiveActivities.setup(FoodDeliveryAttributes.self)
Pushwoosh.LiveActivities.defaultSetup()
Pushwoosh.LiveActivities.defaultStart("activity_id",
                            attributes: ["key_attribute": "value_attribute"],
                            content: ["key_content": "value_content"])
```

我们还通过 `Pushwoosh.sharedInstance()` 维持了对下面列出方法的支持，但请注意，这些方法将在未来版本中被弃用。

``` swift
// Send Live Activity Push To Start Token to Pushwoosh
static func sendPushToStartLiveActivity(token: String)
static func sendPushToStartLiveActivity(token: String, completion: @escaping (Error?) -> Void)

// Start Live Activity Methods with Activity ID
static func startLiveActivity(token: String, activityId: String)
static func startLiveActivity(token: String, activityId: String, completion: @escaping (Error?) -> Void)

// Stop Live Activity Methods
static func stopLiveActivity()
static func stopLiveActivity(completion: @escaping (Error?) -> Void)

static func stopLiveActivity(activityId: String)
static func stopLiveActivity(activityId: String, completion: @escaping (Error?) -> Void)
```