From 6bcf63543665e6940b58d8cec9cb95484047d065 Mon Sep 17 00:00:00 2001 From: Erasmo Bellumat Date: Thu, 5 Feb 2026 22:16:03 -0300 Subject: [PATCH 1/2] feat: add support for scheduled Live Activities via startDate Adds support for Apple's Activity.request(startDate:) API, which allows scheduling a Live Activity to appear at a future date instead of immediately. This uses three reserved attribute keys prefixed with underscore: - _startDate: Unix timestamp (ms) for when the activity should appear - _alertTitle: Title for the notification shown when the activity starts - _alertBody: Body text for the notification When _startDate is present, the activity is scheduled using Activity.request(attributes:content:pushType:style:alertConfiguration:startDate:). When absent, the existing behavior is preserved (backward-compatible). Requires iOS 17.2+ (when Activity.request with startDate was introduced). Use case: Schedule state transitions for Live Activities without relying on background tasks or push notifications. For example, showing a countdown Live Activity immediately and scheduling a second "LIVE NOW" activity to appear automatically at the target time. Reference: https://developer.apple.com/documentation/activitykit/activity/request(attributes:content:pushtype:style:alertconfiguration:startdate:) --- .../ios/ActivityKitModule.swift | 24 +++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/react-native-activity-kit/ios/ActivityKitModule.swift b/packages/react-native-activity-kit/ios/ActivityKitModule.swift index 02a23ec..204c213 100644 --- a/packages/react-native-activity-kit/ios/ActivityKitModule.swift +++ b/packages/react-native-activity-kit/ios/ActivityKitModule.swift @@ -112,9 +112,14 @@ class ActivityKitModule: HybridActivityKitModuleSpec { pushType = nil } + let attributeDict = anyMapToDictionary(attributes) + let scheduledStartTimestamp = attributeDict["_startDate"] as? Double + let scheduledAlertTitle = attributeDict["_alertTitle"] as? String + let scheduledAlertBody = attributeDict["_alertBody"] as? String + let state = try ActivityKitModuleAttributes.ContentState(data: anyMapToDictionary(state)) - let attributes = try ActivityKitModuleAttributes(data: anyMapToDictionary(attributes)) + let attributes = try ActivityKitModuleAttributes(data: attributeDict) var activity: Activity @@ -125,7 +130,22 @@ class ActivityKitModule: HybridActivityKitModuleSpec { relevanceScore: options?.relevanceScore ?? 0, ) - if #available(iOS 18.0, *) { + if let startTimestamp = scheduledStartTimestamp { + let startDate = Date(timeIntervalSince1970: startTimestamp / 1000) + let alertConfig = ActivityKit.AlertConfiguration( + title: LocalizedStringResource(stringLiteral: scheduledAlertTitle ?? "Live Activity Started"), + body: LocalizedStringResource(stringLiteral: scheduledAlertBody ?? "Tap to open"), + sound: .default + ) + activity = try Activity.request( + attributes: attributes, + content: content, + pushType: pushType, + style: options?.style == .transient ? .transient : .standard, + alertConfiguration: alertConfig, + startDate: startDate + ) + } else if #available(iOS 18.0, *) { activity = try Activity.request( attributes: attributes, content: content, From 047bbaba6c883ce044bad850224abb20b0b19ea9 Mon Sep 17 00:00:00 2001 From: Erasmo Bellumat Date: Thu, 5 Feb 2026 22:27:58 -0300 Subject: [PATCH 2/2] Update Activity.request for iOS version compatibility Refactor Activity.request to handle iOS version differences. --- .../ios/ActivityKitModule.swift | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/packages/react-native-activity-kit/ios/ActivityKitModule.swift b/packages/react-native-activity-kit/ios/ActivityKitModule.swift index 204c213..7634357 100644 --- a/packages/react-native-activity-kit/ios/ActivityKitModule.swift +++ b/packages/react-native-activity-kit/ios/ActivityKitModule.swift @@ -137,14 +137,25 @@ class ActivityKitModule: HybridActivityKitModuleSpec { body: LocalizedStringResource(stringLiteral: scheduledAlertBody ?? "Tap to open"), sound: .default ) - activity = try Activity.request( - attributes: attributes, - content: content, - pushType: pushType, - style: options?.style == .transient ? .transient : .standard, - alertConfiguration: alertConfig, - startDate: startDate - ) + if #available(iOS 26.0, *) { + activity = try Activity.request( + attributes: attributes, + content: content, + pushType: pushType, + style: options?.style == .transient ? .transient : .standard, + alertConfiguration: alertConfig, + start: startDate + ) + } else { + activity = try Activity.request( + attributes: attributes, + content: content, + pushType: pushType, + style: options?.style == .transient ? .transient : .standard, + alertConfiguration: alertConfig, + startDate: startDate + ) + } } else if #available(iOS 18.0, *) { activity = try Activity.request( attributes: attributes,