在 MacOS App 开发中, 有一些操作需要管理员权限, 需要弹出认证对话框让用户输入账号和密码, 这个过程就是 MacOS App 提权的过程, 主要有下面几种方式:
1. AuthorizationExecuteWithPrivileges()
使用这个接口最有代表的库是 STPrivilegedTask, 这是一个封装得很好得 App 提权库, 接口与 NSTask 十分像, 使用起来十分方便
可惜得是 AuthorizationExecuteWithPrivileges() 接口在 MacOS 10.7 开始 deprecated, 据说在 10.12 的版本该接口就关闭了
因此, 若要兼容 10.12 以后的 MacOS 版本, 就不得不放弃使用 STPrivilegedTask 库了
2. 使用 ServiceManagement.framework 注册 LaunchdDaemon
这是 Apple 官方目前推荐的提权方式, 官方有一个 SMJobBless 的 Demo, 是用来有点复杂, 具体请见另一篇文档 "SMJobBless 官方 Demo 笔记"
该方法有一个几个小缺点:
弹出认证对话框的提示内容是 "需要 Install Helper", 而且每次打开都是这样的提示, 对于小白用户来说, 会不会误导用户 App 老是在安装什么东西?
LaunchdDaemon 及其配置文件是需要安装到 / Library 下的, 当用户把 App 卸载后会不会存在 "残留问题"?
3. 使用 AppleScript
do shell script "..." with administrator privileges
省略号部分填入 shell 脚本, 任何可执行文件都需要写全路径, 如 / bin/ls
以上是 AppleScript 脚本, 通过这种方式提权有以下有点:
比上述 "注册 LaunchdDaemon" 方法实现起来简单很多
同时也不用担心卸载残留的问题, 因为全部东西都在. app 里
AppleScript 脚本在 objective-c 中有两种执行方式:
通过 NSTask 执行 "/usr/bin/osascript -e"do shell ...""
通过 NSAppleScript 执行
方法 1 有两个缺点:
do shell script 会在所有 shell 执行完成后再把所有 stdout 返回, 因此当启动的是 Daemon 进程, 就算使用 NSTask 的 fileHandle Notification, 也无法把 stdout 分次读取出来
这种方法的认证窗口提示信息是 "osascript wants to make changes.", 对于小白用户来说会不会有一种这样的感觉 "我明明安装的是 XXX.app, 怎么来了一个 osascript 让我输入账号密码? 会不会是恶意程序?"
而使用 NSAppleScript 方法时, 认证窗口的提示信息是 "APP_NAME wants to make changes.", 感觉这样的提示更加友好但也有一些缺点:
NSAppleScript 执行 Daemon 进程的话会直到 Daemon 退出才退出, 即会一直占用线程
解法: 建议在子线程使用 NSAppleScript, 以免 UI 无法响应
也存在 stdout 只能等待 Daemon 退出才全部打印的问题
Jacob Pan (jacobpan3g.github.io/cn)
来源: https://www.cnblogs.com/jacobpan/p/8515737.html