谈谈OS X Sandboxed App开机自动运行的实现

这个其实是在去年我做的一个项目中第一次接触到为 Sandboxed App 添加开机自动运行的选项,中间走了不少弯路,所以今天就把实现的方法贴出来。(我的拖延症真的好严重请不要怪我 QAQ)

在 Apple 强制规定上架 Mac App Store 的 App 必须在沙盒 (Sandbox) 中运行之前,还是有挺多办法来为自己的 App 添加开机自动运行这个功能的,当然在这里就不多说了。这篇文章主要说说沙盒化的应用 (Sandboxed App) 实现开机自动运行的原理以及实现方法。

首先来看看苹果官方的开发文档 App Sandbox Design Guide,里面是这样说的:

To create a login item for your sandboxed app, use the SMLoginItemSetEnabled function (declared in ServiceManagement/SMLoginItem.h) as described in “Adding Login Items Using the Service Management Framework” in Daemons and Services Programming Guide.

(With App Sandbox, you cannot create a login item using functions in the LSSharedFileList.h header file. For example, you cannot use the function LSSharedFileListInsertItemURL. Nor can you manipulate the state of launch services, such as by using the function LSRegisterURL.)

然后再来看看这篇文档 Daemons and Services Programming Guide,里面告诉我们该如何来实现让 App 开机自动运行:

Applications can contain a helper application as a full application bundle, stored inside the main application bundle in the Contents/Library/LoginItems directory. Set either the LSUIElement or LSBackgroundOnly key in the Info.plist file of the helper application’s bundle.

Use the SMLoginItemSetEnabled function (available in Mac OS X v10.6.6 and later) to enable a helper application. It takes two arguments, a CFStringRef containing the bundle identifier of the helper application, and a Boolean specifying the desired state. Pass true to start the helper application immediately and indicate that it should be started every time the user logs in. Pass false to terminate the helper application and indicate that it should no longer be launched when the user logs in. This function returns true if the requested change has taken effect; otherwise, it returns false. This function can be used to manage any number of helper applications.

If multiple applications (for example, several applications from the same company) contain a helper application with the same bundle identifier, only the one with the greatest bundle version number is launched. Any of the applications that contain a copy of the helper application can enable and disable it.

也就是说,假设需要设置开机自动运行的 app 为 main app,这时候就需要为它创建一个 helper app,而 helper app 是可以在用户登录系统后由 launchd 来加载的,根据这个思路我们就可以通过这个 helper app 来 launch main app。

Ⅰ. 为 main app 添加 helper app

首先在 main app 的项目中添加一个 Target,我的主程序是 Now Playing Pro,那么新添加的 Target 我给它命名为 Now Playing Pro Helper,这个 Now Playing Pro Helper 也就是我们前面所说的 helper app。

New Target

Helper App Target

Ⅱ. 修改 main app

我们需要在主程序 (main app) 中添加一个 Build Phase 使 Now Playing Pro Helper (helper app) 成为主程序 (main app) bundle 的一部分。在主程序 (main app) Build Phases 选项卡中新建一个  Copy Files Build Phase,Destination 设置为 Wrapper,Subpath 中填上 Contents/Library/LoginItems,然后在 Navigator 中找到对应 helper app 的可执行文件 (Now Playing Pro Helper.app) 并拖拽到刚刚新建的 Copy Files Build Phase 列表中。

Build Phases

Copy Helper App

接下来在主程序 (main app) General 选项卡中添加 ServiceManagement.framework,并在 Capabilities 选项卡中把 App Sandbox 打开。

ServiceManagementFramework

App Sandbox

如下图修改 Build Settings 中的 Strip Debug Symbols During Copy 项。

Strip Debug Symbols During Copy

接着我们需要在主程序 (main app) 的 AppDelegate.[mh] 中添加如下代码。

在主程序 (main app) MainMenu.xib 中,添加一个 Check Box 并连接 AppDelegate.h 中刚刚新增加的 outlet 和 action,如下图。

Action & Outlet in XIB

Ⅲ. 修改 helper app

Helper app 的作用只是为了 launch main app,所以 helper app 是不需要运行界面的,删掉 MainMenu.xib,在 Info.plist 中如下图添加一行 Application is agent (UIElement) 并设置为 YES 让其在后台运行。

Application is agent

Target 切换到 helper app,跟主程序 (main app) 一样,在 Capabilities 选项卡中把 App Sandbox 打开,然后不一样的是 Build Settings 中 Skip Install 改为 Yes,否则最后安装应用时会出现签名无法验证的问题。

Skip Install

最后,修改 helper app 的 AppDelegate.m 内容,在 launch main app 后,helper app 也就没什么用了,过河拆个桥,终止 helper app 运行。

Ⅳ. 注意事项

在 main app 和 helper app 的 Entitlements 文件中都必须要加上这么一组 key – array。

Xcode 中 main app 和 helper app 的签名证书以及 Entitlements 设置。

Main App Code Signing

Helper App Code Signing

再啰嗦几句,最终生成的 app 必须要签名,并将其放到 /Applications 或是 ~/Applications 目录下才能正常工作。如果需要提交到 Mac App Store 审核默认不要勾选 Start at Login,说白了就是要用户自愿去决定你的 app 是否应该开机自动运行。关于如何保存 Start at Login 开启状态的,博主使用的方法是 NSUserDefaults,具体你应该知道怎么做。

 

Related post

  1. 2012.08.31

    ROT13加密算法
  1. Cleva_ 2014.02.27 5:09下午

    不明觉厉!

  2. 哪家的贼猫猫 2014.02.28 7:02下午

    哈啥哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈!我来玩儿啦

  3. 哪家的贼猫猫 2014.02.28 7:03下午

    我发现我的整个头在动!好神奇!

    • eli-lien 2014.02.28 7:09下午

      你难道没发现我的也在动吗!

  4. 无敌小白龙kaka 2015.07.11 10:24上午

    不明觉厉

Ads

About

#wtf