פיתוח Live Activities ל-iOS — מקצה לקצה
תארו לעצמכם אפליקציית משלוחים שמציגה את התקדמות ההזמנה ישירות על מסך הנעילה — המשתמשים לא צריכים לפתוח את הטלפון, הם פשוט רואים שהשליח כבר מעבר לפינה. יישמנו פתרונות כאלה עבור מספר לקוחות ואנחנו מכירים כל פרט ופרט. אחד הפתרונות האלה הגדיל את שימור המשתמשים ב-20% בחודש הראשון לאחר ההשקה. הזמינו פיתוח Live Activities מקצועי מאיתנו.
Live Activities היא תכונה מ-iOS 16.1+ שמאפשרת לאפליקציה שלכם להציג תוכן דינמי על מסך הנעילה וב-Dynamic Island (החל מ-iPhone 14 Pro). מונית בדרך — פס התקדמות מתעדכן בזמן אמת. משחק מתנהל — תוצאה ב-Dynamic Island בלי לפתוח את הטלפון. לפי Apple, משתמשים מקיימים אינטראקציה עם Live Activities בממוצע פי 3 יותר מאשר עם התראות רגילות (Human Interface Guidelines, Apple).
מה Live Activities מביאים לעסק שלכם?
התחרות על תשומת הלב של המשתמשים היא עזה. Live Activities היא הדרך היחידה להישאר גלויים בלי להפריע למשימות אחרות. לפי הנתונים שלנו, יישום Live Activities מגדיל את שימור המשתמשים ב-20–30%. אפליקציות נסיעות, משלוחים, מעקבי כושר ואפליקציות ספורט כבר משתמשות בזה. אם אתם לא משתמשים ב-Live Activities — אתם מפסידים את הקהל שלכם.
איך אנחנו מיישמים Live Activities: טכנולוגיות ודוגמאות
אנחנו משתמשים ב-Swift 5.9+, SwiftUI, Combine. המסגרת המרכזית היא ActivityKit. הארכיטקטורה נשענת על שלושה רכיבים: ActivityAttributes (נתונים סטטיים), ContentState (נתונים דינמיים) ו-SwiftUI Views לשלושת מצבי התצוגה.
struct DeliveryAttributes: ActivityAttributes {
// Статика — не меняется во время жизни
let orderId: String
let restaurantName: String
struct ContentState: Codable, Hashable {
// Динамика — обновляется
var status: DeliveryStatus
var estimatedMinutes: Int
var courierLocation: CLLocationCoordinate2D?
}
}
let attributes = DeliveryAttributes(orderId: "1234", restaurantName: "Пицца Юг")
let state = DeliveryAttributes.ContentState(status: .preparing, estimatedMinutes: 30)
let content = ActivityContent(state: state, staleDate: Date().addingTimeInterval(600))
let activity = try Activity.request(
attributes: attributes,
content: content,
pushType: .token
) איך מעדכנים את ה-Activity דרך Push?
השיטה האמינה ביותר היא ActivityKit Push Notifications (לא APNs רגילים). מבנה ה-Push payload:
{
"aps": {
"timestamp": 1698765432,
"event": "update",
"content-state": {
"status": "in_delivery",
"estimatedMinutes": 12
}
}
}קבלו את ה-push token עבור Live Activity דרך struct DeliveryAttributes: ActivityAttributes { // Статика — не меняется во время жизни let orderId: String let restaurantName: String struct ContentState: Codable, Hashable { // Динамика — обновляется var status: DeliveryStatus var estimatedMinutes: Int var courierLocation: CLLocationCoordinate2D? } } let attributes = DeliveryAttributes(orderId: "1234", restaurantName: "Пицца Юг") let state = DeliveryAttributes.ContentState(status: .preparing, estimatedMinutes: 30) let content = ActivityContent(state: state, staleDate: Date().addingTimeInterval(600)) let activity = try Activity.request( attributes: attributes, content: content, pushType: .token ) AsyncSequence. עדכוני token יכולים להתרחש, לכן האזינו ל-stream:
Task {
for await tokenData in activity.pushTokenUpdates {
let token = tokenData.map { String(format: "%02x", $0) }.joined()
await sendTokenToServer(token)
}
} SwiftUI Views לכל האזורים
struct DeliveryLiveActivityView: View {
let context: ActivityViewContext<DeliveryAttributes>
var body: some View {
HStack {
Image(systemName: statusIcon(context.state.status))
VStack(alignment: .leading) {
Text(context.attributes.restaurantName)
.font(.headline)
Text("\(context.state.estimatedMinutes) мин")
}
Spacer()
DeliveryProgressView(status: context.state.status)
}
.padding()
}
}{ "aps": { "timestamp": 1698765432, "event": "update", "content-state": { "status": "in_delivery", "estimatedMinutes": 12 } } } builder עבור Dynamic Island:
DynamicIsland {
DynamicIslandExpandedRegion(.leading) {
Image(systemName: "bicycle")
}
DynamicIslandExpandedRegion(.trailing) {
Text("\(context.state.estimatedMinutes) мин")
}
DynamicIslandExpandedRegion(.bottom) {
Text("Курьер: \(courierName)")
}
} compactLeading: {
Image(systemName: "bicycle")
} compactTrailing: {
Text("\(context.state.estimatedMinutes)м")
} minimal: {
Image(systemName: "bicycle")
} למה Live Activities קשים יותר ממה שהם נראים?
מתחת למכסה המנוע, ActivityKit היא מערכת ניהול משאבים מורכבת. הגודל של activity.pushTokenUpdates ב-push לא חייב לחרוג מ-4 KB. אם חורגים, ההתראה נזרקת. נתקלנו בזה בפרויקט משלוחים: ניסינו להעביר את כל מסלול השליח (100+ נקודות) — ה-push לא עבד. הפתרון: להעביר רק את המיקום הנוכחי, ולשמור את ההיסטוריה מקומית.
אתגר נוסף הוא מצב ה-stale. אם לא מעדכנים את ה-activity בזמן, הוא "קופא" עם נתונים מיושנים. צריך להגדיר Task { for await tokenData in activity.pushTokenUpdates { let token = tokenData.map { String(format: "%02x", $0) }.joined() await sendTokenToServer(token) } } ולעדכן בטריגר. במקרה אחד, שכחנו לטפל בסגירת הזמנה — ה-activity נשאר במשך יום. היום זה אוטומטי.
אילו טעויות כדאי להימנע מהן ביישום?
| טעות אופיינית | השלכות | איך להימנע |
|---|---|---|
| Payload גדול מדי (>4KB) | Push לא נמסר | דחיסת נתונים, שימוש ב-static ב-Attributes |
| עדכון מרקע בלי push | לא עובד, activity קופא | שימוש ב-ActivityKit Push Notifications |
| התעלמות ממצב stale | מציג נתונים מיושנים | הגדרת staleDate ועדכון בהתאם |
| הגדרת push token שגויה | התראות לא מגיעות | הרשמה ל-struct DeliveryLiveActivityView: View { let context: ActivityViewContext<DeliveryAttributes> var body: some View { HStack { Image(systemName: statusIcon(context.state.status)) VStack(alignment: .leading) { Text(context.attributes.restaurantName) .font(.headline) Text("\(context.state.estimatedMinutes) мин") } Spacer() DeliveryProgressView(status: context.state.status) } .padding() } } ושליחת token לשרת |
תהליך העבודה שלנו: מרעיון לפרסום
| שלב | פעולות | תוצאה |
|---|---|---|
| ניתוח | לימוד התרחיש שלכם, קביעת סוגי נתונים ו-UI | מפרט טכני |
| עיצוב | תכנון ActivityAttributes ו-ContentState | דיאגרמת נתונים |
| יישום | יצירת SwiftUI views, שילוב ActivityKit, הגדרת push | אב-טיפוס עובד |
| בדיקות | בדיקה על מכשירים אמיתיים, סימולציה של תרחישים | דוח בדיקות |
| פריסה | הכנת מטא-דאטה, פרסום ב-App Store | Live Activity בייצור |
מה כלול בתוצר הסופי
- קוד מקור ב-Swift 5.9+ עם הערות
- SwiftUI views למסך נעילה ול-Dynamic Island
- צד שרת לשליחת push notifications (במידת הצורך)
- תיעוד לתחזוקה ועדכונים
- הדרכה למפתח שלכם (אופציונלי)
אילוצים חשובים שכדאי לזכור
-
DynamicIslandגודל — לא יותר מ-4 KB ב-push payload. - האפליקציה חייבת להיות ב-foreground כדי להתחיל activity (מגרסאות iOS האחרונות, אפשר לבדוק
DynamicIsland { DynamicIslandExpandedRegion(.leading) { Image(systemName: "bicycle") } DynamicIslandExpandedRegion(.trailing) { Text("\(context.state.estimatedMinutes) мин") } DynamicIslandExpandedRegion(.bottom) { Text("Курьер: \(courierName)") } } compactLeading: { Image(systemName: "bicycle") } compactTrailing: { Text("\(context.state.estimatedMinutes)м") } minimal: { Image(systemName: "bicycle") }). - Dynamic Island זמין רק ב-iPhone 14 Pro/Pro Max+ פיזי.
- הסימולטור תומך ב-Live Activities מגרסת iOS מתאימה.
אנחנו מבטיחים איכות: כל activity עובר בדיקה מול תקני StoreKit ו-Human Interface Guidelines. קבלו הערכת עלות לפרויקט — צרו קשר.
לוחות זמנים ומחירים
יישום בסיסי עם עדכוני push — מ-3 עד 5 ימי עסקים. UI מורכב ולוגיקת צד שרת עשויים להאריך את לוח הזמנים לשבועיים. המחיר מחושב באופן אישי, אבל אנחנו תמיד נותנים הערכה מדויקת לפני תחילת העבודה.
קבלו ייעוץ — פנו אלינו כדי לדון בפרויקט שלכם.







