You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在macOS SwiftUI应用中实现不受睡眠影响的每日定时任务?

macOS SwiftUI 应用准点执行定时任务方案

针对你遇到的Mac睡眠导致Timer失效、无法准点执行任务的问题,最可靠的方案是结合Launchd(macOS原生系统调度工具)和应用内的任务校验逻辑,具体实现如下:

一、核心方案:使用Launchd调度任务

Launchd是macOS系统级的任务管理器,不受应用生命周期和系统睡眠影响,甚至可以唤醒系统执行定时任务(需配置系统权限),是实现准点任务的首选方案。

1. 创建Launchd配置文件

在~/Library/LaunchAgents/目录下创建一个名为com.yourcompany.warehouse-printer.plist的文件(替换为你的公司/应用标识),内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <!-- 唯一标识,必须唯一 -->
    <key>Label</key>
    <string>com.yourcompany.warehouse-printer</string>
    
    <!-- 应用启动路径,替换为你的App实际路径 -->
    <key>ProgramArguments</key>
    <array>
        <string>/Applications/WarehouseApp.app/Contents/MacOS/WarehouseApp</string>
        <string>--run-daily-task</string> <!-- 传递参数,让App识别是定时触发的任务 -->
    </array>
    
    <!-- 定时规则:每天5点0分执行 -->
    <key>StartCalendarInterval</key>
    <dict>
        <key>Hour</key>
        <integer>5</integer>
        <key>Minute</key>
        <integer>0</integer>
    </dict>
    
    <!-- 保证App全天运行:如果App意外退出(非正常退出码),自动重启 -->
    <key>KeepAlive</key>
    <dict>
        <key>SuccessfulExit</key>
        <false/>
    </dict>
    
    <!-- 日志路径,方便排查问题 -->
    <key>StandardOutPath</key>
    <string>~/Library/Logs/WarehousePrinter.log</string>
    <key>StandardErrorPath</key>
    <string>~/Library/Logs/WarehousePrinter.error.log</string>
</dict>
</plist>

2. 加载并启用Launchd任务

打开终端,执行以下命令:

# 加载配置文件
launchctl load ~/Library/LaunchAgents/com.yourcompany.warehouse-printer.plist

# 验证任务是否加载成功
launchctl list | grep com.yourcompany.warehouse-printer

如果需要更新配置,先卸载再重新加载:

launchctl unload ~/Library/LaunchAgents/com.yourcompany.warehouse-printer.plist
launchctl load ~/Library/LaunchAgents/com.yourcompany.warehouse-printer.plist

二、应用内逻辑调整

在SwiftUI应用中添加参数处理、任务执行标记和唤醒补执行逻辑,确保任务不重复、不遗漏。

1. 处理命令行参数

在App结构体中识别Launchd传递的--run-daily-task参数,触发任务执行:

@main
struct WarehouseApp: App {
    @State private var triggerDailyTask = false
    
    init() {
        // 检查是否是Launchd触发的任务
        if CommandLine.arguments.contains("--run-daily-task") {
            triggerDailyTask = true
        }
        // 启动时检查是否错过当天任务
        checkMissedDailyTask()
    }
    
    var body: some Scene {
        WindowGroup {
            ContentView()
                .onAppear {
                    if triggerDailyTask {
                        executeDailyTask()
                        // 可选:如果只是执行任务后退出,可调用exit(0);若需保持运行则忽略
                        // exit(0)
                    }
                }
        }
    }
    
    // 核心任务逻辑:调用API获取PDF并打印
    private func executeDailyTask() {
        // 替换为你的实际业务代码
        print("Executing daily PDF fetch and print task at \(Date())")
        
        // 标记当天任务已执行,避免重复执行
        let todayKey = "task_executed_\(Calendar.current.startOfDay(for: Date()))"
        UserDefaults.standard.set(true, forKey: todayKey)
    }
    
    // 检查是否错过当天5点的任务,若错过则补执行
    private func checkMissedDailyTask() {
        let calendar = Calendar.current
        let now = Date()
        let todayStart = calendar.startOfDay(for: now)
        let fiveAM = calendar.date(bySettingHour: 5, minute: 0, second: 0, of: todayStart)!
        
        let todayTaskKey = "task_executed_\(todayStart)"
        let hasExecutedToday = UserDefaults.standard.bool(forKey: todayTaskKey)
        
        // 当前时间已过5点且当天未执行任务,补执行
        if now >= fiveAM && !hasExecutedToday {
            executeDailyTask()
        }
    }
}

2. 监听系统唤醒通知,补执行任务

继续在App结构体中添加NSWorkspace的睡眠/唤醒监听,确保系统唤醒后立即检查任务:

import AppKit

@main
struct WarehouseApp: App {
    // ... 原有代码 ...
    
    private var notificationCenter: NotificationCenter {
        NSWorkspace.shared.notificationCenter
    }
    
    init() {
        // ... 原有初始化代码 ...
        
        // 监听系统唤醒通知
        notificationCenter.addObserver(
            forName: NSWorkspace.didWakeNotification,
            object: nil,
            queue: .main
        ) { _ in
            checkMissedDailyTask()
        }
    }
    
    // ... 原有方法 ...
}

三、系统配置注意事项

要让Launchd能唤醒系统执行任务,需在系统偏好设置中开启:

  1. 打开「系统设置」→「通用」→「节能」
  2. 勾选「唤醒以供网络访问」(部分机型可能显示为「唤醒以供Wi-Fi网络访问」)

四、方案优势

  • 不受睡眠影响:Launchd可唤醒系统执行任务,确保5点准点触发
  • 高可靠性:系统级调度,即使App意外退出也会被重启,保证全天运行
  • 避免重复执行:通过日期标记控制每天只执行一次
  • 补执行机制:系统唤醒后自动检查并补做错过的任务

内容的提问来源于stack exchange,提问作者Trey6

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 04:56:04