diff --git a/ios/app/VoltraModule.swift b/ios/app/VoltraModule.swift index 219b90d..0625e7c 100644 --- a/ios/app/VoltraModule.swift +++ b/ios/app/VoltraModule.swift @@ -2,6 +2,7 @@ import ActivityKit import Compression import ExpoModulesCore import Foundation +import os import WidgetKit public class VoltraModule: Module { @@ -10,7 +11,7 @@ public class VoltraModule: Module { private let TIMELINE_WARNING_SIZE = 100_000 // 100KB per timeline private let liveActivityService = VoltraLiveActivityService() private var wasLaunchedInBackground: Bool = false - private var monitoredActivityIds: Set = [] + private let monitoredActivityIds = OSAllocatedUnfairLock>(initialState: []) enum VoltraErrors: Error { case unsupportedOS @@ -55,7 +56,7 @@ public class VoltraModule: Module { OnStopObserving { VoltraEventBus.shared.unsubscribe() - monitoredActivityIds.removeAll() + monitoredActivityIds.withLock { $0.removeAll() } } OnCreate { @@ -608,32 +609,38 @@ private extension VoltraModule { /// Set up observers for an activity's lifecycle (only once per activity) private func monitorActivity(_ activity: Activity) { + guard activity.activityState != .ended else { return } + let activityId = activity.id + let activityName = activity.attributes.name + let pushEnabled = pushNotificationsEnabled - // Skip if we're already monitoring this activity - guard !monitoredActivityIds.contains(activityId) else { return } - monitoredActivityIds.insert(activityId) + // Thread-safe check-and-insert + let shouldMonitor = monitoredActivityIds.withLock { ids -> Bool in + guard !ids.contains(activityId) else { return false } + ids.insert(activityId) + return true + } + guard shouldMonitor else { return } - // Observe lifecycle state changes (active → dismissed → ended) Task { for await state in activity.activityStateUpdates { VoltraEventBus.shared.send( .stateChange( - activityName: activity.attributes.name, + activityName: activityName, state: String(describing: state) ) ) } } - // Observe push token updates if enabled - if pushNotificationsEnabled { + if pushEnabled { Task { for await pushTokenData in activity.pushTokenUpdates { let pushTokenString = pushTokenData.hexString VoltraEventBus.shared.send( .tokenReceived( - activityName: activity.attributes.name, + activityName: activityName, pushToken: pushTokenString ) )