我需要在系统启动时启动我的应用程序,但问题是:它已经在 App Store 中,所以我必须遵循一些规则,比如使用沙盒。这会导致所需功能(如LSSharedFileListInsertItemURL和SMLoginItemSetEnabled )失败。在这种情况下我应该如何处理?
4 回答
我最近经历了同样的过程,不幸的是,使用沙盒它并不像以前那么容易。我制作了一个带有非常详细说明的测试应用程序,现在在 Github 上
笔记
此演示应用程序和您的应用程序只有在它们最好部署在Xcode 调试文件夹中时才能工作,/Applications/MyGreat.app
并且不能可靠地工作。
项目设置
这些是我的项目的设置,与此实现完美配合。
- 创建启用 ARC 的新项目
- 沙箱你的主应用程序和帮助应用程序(如果你还没有创建一个帮助程序,我们很快就会得到它)我还启用了代码签名
- 由于这只是一个测试应用程序,因此我对主应用程序或助手都没有有效的权利
- 如果您还没有,请创建一个帮助应用程序。转到您的项目设置并单击“添加目标”选择一个 Cocoa 应用程序。将其命名为 MyAwesomeProjectHelper 也启用了 ARC。(我将其“App Store 类别”留空)
- 现在选择主应用程序的目标。转到构建阶段 -> 添加构建阶段 -> 添加复制文件。
- 将目标更改为包装器。使子路径
Contents/Library/LoginItems
仅在未选中安装时保留复制。将您的助手应用程序从左侧的 Products 拖到 tableview 中。
主要应用程序代码设置
- 将 ServiceManagement.framework 导入您的主应用程序(不是您的助手)并包含
#import <ServiceManagement/ServiceManagement.h>
在您的 .h 文件中 - 从 Github获取 StartAtLoginController。这是 Alex Zielenski 的一个易于使用的类,用于处理添加、删除和查询登录项的复杂性。导入
StartAtLoginController.h
您的 h 文件。 - 创建您想要控制此设置的任何界面。如果您的应用程序自动启用此功能,它将被 Mac App Store 拒绝(根据指南 #2.26)
- 实现一个方法,例如
- (IBAction)checkChanged:(id)sender
我制作了一个与 StandardUserDefaults 绑定的简单复选框。(如果您选择做其他事情,您的实现可能会有所不同。)我还将复选框绑定到IBOutlet NSButton *loginCheck;
以确定它的状态。这也可以通过[[NSUserDefaults standardUserDefaults] boolForKey:YourKey]
在您的 .m 文件中实现与此类似的代码。
StartAtLoginController *loginController = [[StartAtLoginController alloc] init]; [loginController setBundle:[NSBundle bundleWithPath:[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"Contents/Library/LoginItems/HelperApp.app"]]]; // Change "HelperApp.app" to the name of your helper if ([loginCheck state]) { if (![loginController startAtLogin]) { [loginController setStartAtLogin: YES]; } } else { if ([loginController startAtLogin]) { [loginController setStartAtLogin:NO]; } }
而已。正如您在此项目中看到的,您可能还需要使用其他一些方法,例如:
if ([loginController startAtLogin]) { NSLog(@"Error"); }
用于在启用或禁用设置后检查以确保其正常工作。或这个:
BOOL startsAtLogin = [loginController startAtLogin]; if (startsAtLogin) { // Do stuff }
如果启用了登录助手,则执行某些操作。
助手应用程序代码设置
确保在您的实现中大力测试此代码。
- 默认情况下,导航到位于 Supporting Files 组中的 HelperApp.plist,使您的帮助应用程序成为 UIElement。在底部添加一行键
Application is agent (UIElement)
和YES
值(这将禁止应用程序在每次用户启用登录时启动时闪烁停靠图标)我还删除了界面构建器中除了 App Delegate 之外的所有内容 - 删除默认方法
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
并将其替换为- (void)applicationWillFinishLaunching:(NSNotification *)aNotification
在此方法中实现与此类似的代码。
NSString *appPath = [[[[[[NSBundle mainBundle] bundlePath] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent] stringByDeletingLastPathComponent]; // This string takes you from MyGreat.App/Contents/Library/LoginItems/MyHelper.app to MyGreat.App This is an obnoxious but dynamic way to do this since that specific Subpath is required NSString *binaryPath = [[NSBundle bundleWithPath:appPath] executablePath]; // This gets the binary executable within your main application [[NSWorkspace sharedWorkspace] launchApplication:binaryPath]; [NSApp terminate:nil];
此代码找到您的主应用程序,确定它是二进制可执行文件(在沙箱中启动应用程序所需)打开您的应用程序,然后退出
- 而已。
部署
在为自己或 Mac App Store 部署应用程序时,您应该做的最后一件事是从存档项目中删除您的 Helper 应用程序。通过导航到 HelperApp 的 Target -> Build Settings -> Skip Install 并为 Release 设置 Yes。Apple 在 (http://developer.apple.com/library/ios/#documentation/ToolsLanguages/Conceptual/Xcode4UserGuide/000-About_Xcode/about.html) 提供了更多信息
对于沙盒应用程序,您需要创建特殊的登录项帮助应用程序(位于 Contents/Library/LoginItems 内)。在这里查看更多。另请注意,您的应用程序必须从 /Applications 文件夹启动才能正确工作登录项。
我刚刚为我自己的应用程序实现了一个 LoginItem,并发现这些链接中的信息很有用:
如何为 Mac App 创建一个帮助应用程序以在用户登录时启动它?
https://github.com/tcurdt/TCLoginItemHelper
http://www.delitestudio.com/2011/10/25/start-dockless-apps-at-login-with-app-sandbox-enabled/
让您的沙盒应用程序在登录时启动的设置非常耗时,而且很容易出错。这就是为什么我制作了一个 Swift 包来自动化它。使用我的LaunchAtLogin
包,您所要做的就是在 Xcode 中添加一个构建步骤,然后编写两行代码:
import LaunchAtLogin
LaunchAtLogin.isEnabled = true