swift – DeviceActivityCenter startMonitoring hangs intermittently in iOS 18

0
24
swift – DeviceActivityCenter startMonitoring hangs intermittently in iOS 18


I am encountering a problem with DeviceActivityCenter the place my app generally will get hung up on the next traces:

middle.stopMonitoring()
middle.startMonitoring(.locked, throughout: defaultSchedule, occasions: occasions)
middle.startMonitoring(.unlocked, throughout: schedule, occasions: occasions)

This conduct happens inconsistently, roughly 50% of the time, and causes a delay earlier than the monitoring begins. Finally, the code does execute, however it could possibly cling for a number of seconds. This problem is new to iOS 18—it by no means occurred in iOS 17.

It hangs intermittently on the calls to stopMonitoring() and startMonitoring(). I added print() statements to substantiate that that is the place the delay happens.

Has anybody else skilled this with iOS 18? Any insights or ideas can be appreciated!

Extra Data:

Concern began after upgrading to iOS 18.
Occurs about 50% of the time, with no clear sample.
No modifications had been made to this a part of the code between iOS 17 and iOS 18.
This delay can final for as much as a minute earlier than it proceeds.

Right here is my code:

import DeviceActivity
import SwiftUI

extension DeviceActivityName {
    static let locked = Self("locked")
    static let unlocked = Self("unlocked")
}

extension DeviceActivityEvent.Identify {
    static let locked = Self("locked")
    static let unlocked = Self("unlocked")
}

class MySchedule {
    static let shared = MySchedule()
    let middle = DeviceActivityCenter()
    
    
    @AppStorage("unlockedStartDate", retailer: UserDefaults(suiteName: "group.com.Haplo.Barrier")) non-public var unlockedStartDateData: Knowledge?
    var unlockedStartDate: Date? {
        get {
            if let information = unlockedStartDateData {
                let decoder = JSONDecoder()
                if let decodedDate = strive? decoder.decode(Date.self, from: information) {
                    return decodedDate
                }
            }
            return nil
        }
        set {
            if let newDate = newValue {
                let encoder = JSONEncoder()
                if let encodedData = strive? encoder.encode(newDate) {
                    unlockedStartDateData = encodedData
                } else {
                    unlockedStartDateData = nil
                }
            } else {
                unlockedStartDateData = nil
            }
        }
    }
    
    @AppStorage("unlockedEndDate", retailer: UserDefaults(suiteName: "group.com.Haplo.Barrier")) non-public var unlockedEndDateData: Knowledge?
    var unlockedEndDate: Date? {
        get {
            if let information = unlockedEndDateData {
                let decoder = JSONDecoder()
                if let decodedDate = strive? decoder.decode(Date.self, from: information) {
                    return decodedDate
                }
            }
            return nil
        }
        set {
            if let newDate = newValue {
                let encoder = JSONEncoder()
                if let encodedData = strive? encoder.encode(newDate) {
                    unlockedEndDateData = encodedData
                } else {
                    unlockedEndDateData = nil
                }
            } else {
                unlockedEndDateData = nil
            }
        }
    }
    
    // Save schedule begin and finish occasions
    public func setSchedule(timeLimitMinutes: Int = 0) {
        print("middle.stopMonitoring().begin")
        middle.stopMonitoring([.locked, .unlocked])
        print("middle.stopMonitoring().full")
        
        if timeLimitMinutes == 0 {
            // Schedule to dam apps (locked state)
            let startTime = DateComponents(hour: 0, minute: 0)
            let endTime = DateComponents(hour: 23, minute: 59)
            let defaultSchedule = DeviceActivitySchedule(
                intervalStart: startTime,
                intervalEnd: endTime,
                repeats: true
            )
            
            unlockedStartDate = nil
            unlockedEndDate = nil
            
            let occasions: [DeviceActivityEvent.Name: DeviceActivityEvent] = [
                .locked: DeviceActivityEvent(
                    applications: MyModel.shared.selectionToDiscourage.applicationTokens,
                    categories: MyModel.shared.selectionToDiscourage.categoryTokens,
                    webDomains: MyModel.shared.selectionToDiscourage.webDomainTokens,
                    threshold: DateComponents(minute: timeLimitMinutes)
                )
            ]
            
            do {
                print("middle.startMonitoring(.locked).begin")
                strive middle.startMonitoring(.locked, throughout: defaultSchedule, occasions: occasions)
                print("middle.startMonitoring(.locked).full")
            } catch {
                print("Error beginning locked schedule: (error.localizedDescription)")
            }
        } else {
            // Schedule to unlock apps (unlocked state)
            let schedule = getUnlockedSchedule(forMinutes: timeLimitMinutes)
            
            let occasions: [DeviceActivityEvent.Name: DeviceActivityEvent] = [
                .unlocked: DeviceActivityEvent(threshold: DateComponents(minute: timeLimitMinutes))
            ]
            
            do {
                print("middle.startMonitoring(.unlocked).begin")
                strive middle.startMonitoring(.unlocked, throughout: schedule, occasions: occasions)
                print("middle.startMonitoring(.unlocked).full")
            } catch {
                print("Error beginning unlocked schedule: (error.localizedDescription)")
            }
        }
    }
    
    // Create a schedule primarily based on the present time and specified minutes
    func getUnlockedSchedule(forMinutes minutes: Int) -> DeviceActivitySchedule {
        let calendar = Calendar.present
        let currentDate = Date()
        
        // Begin is now
        let startComponents = calendar.dateComponents([.hour, .minute, .second], from: currentDate)
        
        // Finish is 'minutes' from now
        let intervalEnd = calendar.date(byAdding: .minute, worth: minutes, to: currentDate)!
        let endComponents = calendar.dateComponents([.hour, .minute, .second], from: intervalEnd)
        
        unlockedStartDate = currentDate
        unlockedEndDate = intervalEnd
        
        return DeviceActivitySchedule(
            intervalStart: startComponents,
            intervalEnd: endComponents,
            repeats: false
        )
    }
    
    // Examine if the present time is inside the schedule
    func isScheduleUnlocked() -> Bool {
        let now = Date()
        guard let intervalStartDate = unlockedStartDate, let intervalEndDate = unlockedEndDate else { return false }
        
        return now >= intervalStartDate && now <= intervalEndDate
    }
}

LEAVE A REPLY

Please enter your comment!
Please enter your name here