# أنشطة iOS المباشرة (Live Activities)

<Aside type="tip">
شاهد فيديو حول iOS Live Activities
<YouTube id="jRrDh_pIZCE" playlabel="فيديو يوتيوب: iOS Live Activities" /> 
</Aside>


[Live Activities](https://developer.apple.com/design/human-interface-guidelines/live-activities) تعرض أحدث بيانات تطبيقك على شاشة القفل لجهاز iPhone أو iPad وفي Dynamic Island. تتيح هذه الميزة للمستخدمين رؤية المعلومات المباشرة بلمحة سريعة وتنفيذ إجراءات سريعة تتعلق بالمعلومات المعروضة.

فيما يلي بعض الأمثلة على استخدام Live Activities:

* إظهار حالة الطلب في تطبيق توصيل؛
* توفير عد تنازلي في الوقت الفعلي في تطبيق تدريب؛
* إظهار معلومات التتبع في تطبيق سيارات الأجرة؛
* عرض إحصائيات اللعبة والنتائج الحالية في تطبيق رياضي؛
* توفير توقعات الطقس كل ساعة في تطبيق الطقس.

يمكنك تمكين Live Activities باستخدام Pushwoosh iOS SDK كما هو موضح أدناه. لإدارة Live Activities وتحديث محتواها، استخدم دالة [/updateLiveActivity](/ar/developer/api-reference/ios-live-activities-api#updateliveactivity).



## الإعداد
<Aside type="caution" title="هام" >
تدعم Live Activities في Pushwoosh فقط [الإعداد القائم على الرمز (token-based configuration)](/ar/developer/first-steps/connect-messaging-services/ios-configuration/ios-token-based-configuration/). [الإعداد القائم على الشهادة (Certificate-based configuration)](/ar/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. إعداد ملحق الواجهة المستخدم (Widget Extension)
الرجاء إدخال اسم والتأكد من تحديد **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/>
```

<Aside type="tip" title="تحديثات متكررة">
إذا كان يتم تحديث Live Activity الخاص بك بشكل متكرر (على سبيل المثال، نتائج المباريات الرياضية المباشرة)، أضف أيضًا `NSSupportsLiveActivitiesFrequentUpdates` مع ضبط قيمته على `true`. تحد Apple من عدد تحديثات الدفع ذات الأولوية العالية التي يمكن للتطبيق إرسالها في الساعة. يرفع هذا المفتاح تلك الميزانية. راجع المعلمة `apns_priority` في [مرجع واجهة برمجة تطبيقات Live Activities](/ar/developer/api-reference/ios-live-activities-api/#time-sensitive-push-and-delivery-priority) لمعرفة كيفية التحكم في أولوية التسليم لكل تحديث.

```xml
	<key>NSSupportsLiveActivitiesFrequentUpdates</key>
	<true/>
```
</Aside>

###  تمكين الأنشطة المباشرة من التطبيق
لتمكين Live Activities، أضف الكود الخاص بها إلى ملحق الواجهة المستخدم الحالي لديك أو أنشئ واحدًا جديدًا إذا لم يكن لدى تطبيقك واحد بالفعل. تستخدم Live Activities وظائف [SwiftUI](https://developer.apple.com/documentation/SwiftUI) و [WidgetKit](https://developer.apple.com/documentation/WidgetKit) لواجهة المستخدم الخاصة بها. يتعامل ActivityKit مع دورة حياة كل Live Activity: يتم استخدام واجهة برمجة التطبيقات (API) الخاصة به لطلب وتحديث وإنهاء Live Activity واستلام إشعارات الدفع من ActivityKit. يمكنك معرفة المزيد حول Live Activities في [توثيق Apple](https://developer.apple.com/documentation/activitykit/displaying-live-data-with-live-activities).

 1. انتقل إلى ملف ContentView لمشروعك في Xcode وأنشئ 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 لإدارة Live Activities

```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'. ثم ننتقل إلى شاشة القفل ونرى Live Activity الذي تم إنشاؤه.


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

### بدء Live Activity بإشعار دفع عن بعد

1. لبدء Live Activity عبر إشعار دفع عن بعد، تحتاج إلى إرسال رمز 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. بدء Live Activity بإشعار دفع عن بعد

<Aside type="tip">
 اتبع [مرجع واجهة برمجة تطبيقات Pushwoosh](/ar/developer/api-reference/ios-live-activities-api#startliveactivity) للحصول على إرشادات وأمثلة حول كيفية تقديم طلب لبدء Live Activity عن بعد.
</Aside>

### إدارة Live Activities 

يوفر Pushwoosh iOS SDK الدوال التالية للعمل مع Live Activities:

```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)

// Schedule a Live Activity to start at a future date (iOS 26.0+)
static func schedule<Attributes: PushwooshLiveActivityAttributes>(attributes: Attributes, contentState: Attributes.ContentState, at startDate: Date, alertTitle: String, alertBody: String) throws -> Activity<Attributes>

// Cancel a scheduled or running Live Activity by its Activity ID (iOS 16.2+)
static func cancel<Attributes: PushwooshLiveActivityAttributes>(_ activityType: Attributes.Type, activityId: String)

```

يمكنك أيضًا تحديث الأنشطة المباشرة حسب الشرائح باستخدام معلمة Activity ID. عند إنشاء نشاط، تحتاج إلى تمرير معلمة Activity ID فريدة في الدالة، والتي ستكون ذات صلة بشريحة مستخدمين معينة.

على سبيل المثال، اشترك N من المستخدمين في نفس الحدث في Live Activity. من الضروري أن تكون معلمة Activity ID فريدة لجميع هؤلاء المستخدمين N.

عند الانتهاء من العمل مع Live Activity، استخدم هذه الدوال:
```swift
static func stopLiveActivity()
static func stopLiveActivity(completion: @escaping (Error?) -> Void)
```
<Aside type="note">
 يمكنك إدارة iOS Live Activities عبر [Pushwoosh API](/ar/developer/api-reference/ios-live-activities-api).
</Aside>

### جدولة Live Activity ليبدأ في تاريخ مستقبلي

<Aside type="note">
يتطلب iOS 26.0+.
</Aside>

بدلاً من بدء Live Activity على الفور، يمكنك جدولته ليبدأ في تاريخ مستقبلي. يتم عرض `alertTitle` و `alertBody` للمستخدم في تنبيه الإشعار المحلي الذي يتم إطلاقه عند بدء النشاط المجدول بالفعل:

```swift
if #available(iOS 26.0, *) {
    let startDate = Date().addingTimeInterval(3600) // starts in 1 hour

    do {
        let activity = try Pushwoosh.LiveActivities.schedule(
            attributes: atttribute,
            contentState: initialState,
            at: startDate,
            alertTitle: "Game starting!",
            alertBody: "The match is about to begin"
        )
        self.currentActivity = activity
    } catch {
        print("Schedule Activity Error: \(error.localizedDescription)")
    }
}
```

يجب أن يكون `startDate` في المستقبل، وإلا فإن الاستدعاء يطرح خطأ. استدعِ `schedule` على الخيط الرئيسي أثناء وجود التطبيق في المقدمة. لا يوجد طلب وقت جدولة إلى Pushwoosh: يتعرف الخادم على النشاط بمجرد أن يبدأ بالفعل ويتلقى رمز الدفع الخاص به من خلال نفس مراقب الرمز الذي تم تثبيته بواسطة دالة `setup()` (انظر أدناه).

### إلغاء Live Activity بواسطة Activity ID

<Aside type="note">
يتطلب iOS 16.2+.
</Aside>

استخدم `cancel(_:activityId:)` لإلغاء Live Activity بواسطة Activity ID الخاص به دون الاحتفاظ بمرجع إلى مثيل `Activity`:

```swift
if #available(iOS 16.2, *) {
    Pushwoosh.LiveActivities.cancel(FoodDeliveryAttributes.self, activityId: "activity_id")
}
```

ينهي `cancel` النشاط على الجهاز على الفور ويخطر خادم Pushwoosh. يختلف هذا عن `stopLiveActivity(activityId:)`، الذي يخطر الخادم فقط ولا ينهي النشاط على الجهاز مباشرة. يعمل `cancel` أيضًا مع Live Activity الذي تم جدولته باستخدام `schedule` ولكنه لم يبدأ بعد — يتم إلغاؤه قبل أن يبدأ.

### دالة `Setup()`
يبسط Pushwoosh نقل معرفات الأنشطة من خلال تقديم دالة `PushwooshLiveActivities.setup`، التي تتعامل مع دورة حياة Live Activity بأكملها داخل التطبيق. تستمع هذه الدالة تلقائيًا إلى تحديثات رموز pushToStart و pushToUpdate. باستخدام هذه الدالة، لم يعد التطبيق بحاجة إلى تتبع بدء Live Activities يدويًا أو إدارة تحديثات الرموز لتحديثات النشاط.

نوصي باستخدام هذه الدالة لأنها تتعامل مع كل إدارة الرموز من جانبنا، مما يقلل من كمية الكود التي تحتاج إلى صيانتها من جانبك. هذا يبسط التكامل ويضمن تجربة أكثر سلاسة وكفاءة لتطبيقك.

في AppDelegate، تأكد من استيراد `PushwooshFramework` و `PushwooshLiveActivities` واستدعاء دالة `setup` من وحدة `Pushwoosh.LiveActivities`.

**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">
 يمكنك إدارة Live Activities وتحديث محتواها باستخدام دالة /updateLiveActivity لواجهة برمجة تطبيقات Pushwoosh. لمزيد من المعلومات، يرجى قراءة [هذا الدليل](/ar/developer/api-reference/ios-live-activities-api)
</Aside>

## دليل الترحيل

بدءًا من الإصدار 6.8.0 من Pushwoosh iOS SDK، قمنا بتحديث بنية SDK. يتم الآن الوصول إلى دوال Live Activities من خلال وحدة `PushwooshLiveActivities`.

إذا كنت تستخدم إصدارًا من Pushwoosh iOS SDK أقدم من 6.8.0 وكنت تستدعي الدوال المدرجة أدناه، وقمت بالتحديث إلى الإصدار 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)
```