MacBook Pro 系统上添加定时任务的几种方法
Mac OS X 的 Launch Daemon / Agent
Apple 官方文档:About Daemons and Services
Many kinds of tasks that do not require user interaction are most effectively handled by a process that runs in the background. You can use a daemon or service to:
-
Provide server functionality, such serving web pages.
-
Coordinate access to of a shared resource, such as a database.
-
Perform work for a foreground application, such as file system access.
Figure I-1 Daemons and services are started by launchd in two separate session contexts
Apple Launch
在Mac OS X 10.4以后,苹果开始使用launchd来管理所有的Process、Application 及 Script。
Launch管理的这些进程分为四种:
1)Launch Daemon:在开机时加载
2)Launch Agent:在用户登录时加载
3)XPC Service:设置服务启动任务
4)Login Items:用户登录启动项,可视化设置
本文先介绍前两种:Launch Daemon 和 Launch Agent
Launch Daemon 和 Launch Agents
这两个东西其实是相同的,不同的只是他们的加载时机。
Launchd是通过.plist来得知系统中有哪些东西需要被管理的。所以简单的来说,想要新增被管理项,本质上就是新增一个.plist放入苹果的管理文件夹下,然后使其被加载后执行。苹果根据用户的角色提供了不同的Launch存放位置:
~/Library/LaunchAgents # 当前用户定义的任务 /Library/LaunchAgents # 系统管理员定义的任务 /Library/LaunchDaemons # 管理员定义的系统守护进程任务 /System/Library/LaunchAgents # 苹果定义的任务 /System/Library/LaunchDaemons # 苹果定义的系统守护进程任务
很显然,我们是最好不要使用下面两个位置的(苹果定义的),而管理员权限比较大,这里我用到的是第一个位置。
只为当前用户定任务,进入该目录,创建一个com.hello.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.hello</string> <!-- 任务加载时就默认启动一次 --> <key>RunAtLoad</key> <true/> <!-- 任务内容 --> <key>ProgramArguments</key> <array> <!-- 执行一个脚本_(:зゝ∠)_脚本都可以执行了,基本上什么羞羞的事情都可以做了,脚本内容在最下面贴出 --> <string>/Users/chengliqing/Desktop/temp/test.sh</string> </array> <!-- 任务执行间隔,如果计算机进入休眠,在唤醒前有多个任务被执行,则这些时间会合并成一个事件再执行。 --> <key>StartInterval</key> <integer>60</integer> <!-- 日历的形式执行任务 Minute <integer> 分钟 Hour <integer> 小时 Day <integer> 哪天 Weekday <integer> 周几(0和7都表示周日) Month <integer> 几月 = = 感觉挺麻烦,在下面说几个例子方便理解 --> <key>StartCalendarInterval</key> <array> <dict> <key>Weekday</key> <!-- 周几 --> <integer>1</integer> <key>Hour</key> <!-- 小时 --> <integer>8</integer> <key>Minute</key> <!-- 分钟 --> <string>58</string> </dict> <dict> <key>Weekday</key> <integer>2</integer> <key>Hour</key> <integer>8</integer> <key>Minute</key> <string>52</string> </dict> </array> <!-- 输出日志路径 --> <key>StandardOutPath</key> <string>/Users/chengliqing/Desktop/temp/stdout.log</string> <!-- 异常日志路径 --> <key>StandardErrorPath</key> <string>/Users/chengliqing/Desktop/temp/stderr.log</string> </dict> </plist>
StartCalendarInterval 例子
<!-- 这个表示每个小时的0分钟会执行此任务 --> <key>StartCalendarInterval</key> <dict> <key>Minute</key> <integer>0</integer> </dict> <!-- 在每天的3:55会执行此任务 --> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>3</integer> <key>Minute</key> <integer>55</integer> </dict> <!-- 在每六的3:15会执行此任务 --> <key>StartCalendarInterval</key> <dict> <key>Hour</key> <integer>3</integer> <key>Minute</key> <integer>15</integer> <key>Weekday</key> <integer>6</integer> </dict>
写完后可以用 plutil -lint xxx.plist
验证一下,随意
Launchctl 基本使用
我们将我们的任务描述出来了,接下来就该使用了!
# 加载任务 launchctl load ~/Library/LaunchAgents/com.hello.plist # 强制加载任务, -w选项会将plist文件中无效的key覆盖掉 launchctl load -w ~/Library/LaunchAgents/com.hello.plist # (-w强制)移除任务 launchctl unload ~/Library/LaunchAgents/com.hello.plist launchctl unload -w ~/Library/LaunchAgents/com.hello.plist # 手动执行任务 launchctl start com.hello # 列出所有任务 launchctl list # 查看任务列表, 使用 grep '任务部分名字' 过滤 $ launchctl list | grep 'com.hello'
在使用launchctl list的时候回列出所有任务能够看到任务的状态(status),如果出现非0的状态码就表示任务出错了,可以使用:launchctl error [errorCode]
来查看。
test.sh
#!/bin/sh say hello mimvp.com
这个脚本的意思是让Mac说 hello mimvp.com
写完并保存后记得将其变为可执行的sh文件,使用
chmod a+x /Users/chengliqing/Desktop/temp/test.sh
到这里,你应该已经会基本的手动添加任务的操作了。接下来我们在代码中添加任务。
这里涉及到权限问题,cocoa application 访问了除沙盒之外的文件且想要在上架到AppStore,是需要授权的,这里先将沙盒关闭,就可以直接写文件到我们指定的路径了。注意这样是不能上架到AppStore的!
这里涉及到使用shell脚本的情况,所以先贴出执行shell脚本的代码。
func runCommand(launchPath: String, arguments: [String]) -> String { let pipe = Pipe() let file = pipe.fileHandleForReading let task = Process() task.launchPath = launchPath task.arguments = arguments task.standardOutput = pipe task.launch() let data = file.readDataToEndOfFile() return String(data: data, encoding: String.Encoding.utf8)! }
先说说步骤:
1)先将*.plist复制到指定路径
2)注册任务
然后准备好我们的plist文件,这里我们将文件写到~/Library/LaunchAgents/
,直接使用复制的形式,先把plist拖入项目,然后复制到指定路径。
// 文件拷贝如指定路劲 let fromPath = Bundle.main.path(forResource: "task01", ofType: "plist") let toPath = "/Users/chengliqing/Library/LaunchAgents/com.hello.plist" try! FileManager.default.copyItem(atPath: fromPath!, toPath: toPath)
执行 shell 注册
// 执行shell 注册 let result = runCommand(launchPath: "/Users/chengliqing/Desktop/temp/loadTask.sh", arguments: ["SPHardwareDataType"]) print(result)
接下来贴出loadTask.sh
的内容
# 进入到根路径(这里之所以要进入到根,是因为我们项目到时候启动的路径会发生变化, # 所以为确保最终查找路径的正确性所以从根路径开始查找) cd / cd Users/chengliqing/Library/LaunchAgents/ # 进入到某用户的任务路径 launchctl load clq.hello.plist # 注册
到这里,在不上架到AppStore的情况下,我们的App就可以随意创建任务了。
以上的方法是不能上架到AppStore的
MacOS 系统上添加定时任务
mac系统上的定时任务用launchctl来管理
1、先写要执行的脚本 run.sh:
#!/bin/bash echo `date` > $HOME/test_result.log
2、再写调度任务的plist文件task.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.xyz.test</string> <!-- 要运行的程序, 如果省略这个选项,会把ProgramArguments的第一个 元素作为要运行的程序 --> <key>Program</key> <string>/Users/xyz/test.sh</string> <!-- 命令, 第一个为命令,其它为参数--> <key>ProgramArguments</key> <array> <string>/Users/xyz/test.sh</string> </array> <!-- 运行时间 --> <key>StartCalendarInterval</key> <dict> <key>Minute</key> <integer>10</integer> <key>Hour</key> <integer>17</integer> </dict> <!-- 标准输入文件 --> <key>StandardInPath</key> <string>/Users/xyz/test-in.log</string> <!-- 标准输出文件 --> <key>StandardOutPath</key> <string>/Users/xyz/test-out.log</string> <!-- 标准错误输出文件 --> <key>StandardErrorPath</key> <string>/Users/xyz/test-err.log</string> </dict> </plist>
3、然后再添加到执行列表中
launchctl load task.plist
就可以了。
注意一点:系统在自动运行shell脚本时是不会加载任何环境变量的,所以可能出现自己手工运行脚本正常,但是在调度任务中出错。这种情况需要导入环境变量来解决,如果不知道需要导入哪些环境变量,最简单的方法是直接导入所有环境变量的配置文件,如果使用的shell是bash,可以在运行脚本中加入如下一句:
source ~/.bashrc
plist 文件的详细内容参考:
Mac 下添加定时任务 (CSDN)
参考推荐:
mac系统上添加定时任务 (简书)
Mac下添加定时任务 (CSDN)
版权所有: 本文系米扑博客原创、转载、摘录,或修订后发表,最后更新于 2020-07-13 05:11:42
侵权处理: 本个人博客,不盈利,若侵犯了您的作品权,请联系博主删除,莫恶意,索钱财,感谢!