gpt4 book ai didi

objective-c - 全局事件、Mac App Store 和沙盒

转载 作者:太空狗 更新时间:2023-10-30 03:43:27 26 4
gpt4 key购买 nike

我正在开发一个应用程序,其中使用全局按键事件将是其操作的要求。此外,我计划通过 App Store 严格分发它。 (这是一个 Mac 应用程序,而不是 iOS。)我得到了一个通过 addGlobalMonitorForEventsMatchingMask 监听全局事件的示例,但有一些警告。

注意:我正在选择使用现代 API 而不是依赖早期的 Carbon 热键方法。如果它们最终被弃用,我不想以后再解决这个问题。

主要问题是必须信任该应用程序才能检测到全局事件。否则,必须为所有应用程序启用辅助功能。当我启用辅助功能时,会成功检测到事件。此要求记录在此处,https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/EventOverview/MonitoringEvents/MonitoringEvents.html .

我希望我的用户不必启用辅助功能。根据我所做的其他研究,您可以通过调用 AXMakeProcessTrusted 然后重新启动应用程序来使应用程序受信任。

在我使用的代码中,我没有收到身份验证提示。该应用程序将重新启动,但仍然不受信任(可能是因为我没有收到身份验证提示)。这是我这部分的代码:

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
if (!AXAPIEnabled() && !AXIsProcessTrusted()) {

NSString *appPath = [[NSBundle mainBundle] bundlePath];
AXError error = AXMakeProcessTrusted( (CFStringRef)CFBridgingRetain(appPath) );

[self restartApp];
}
}

- (void)restartApp{

NSTask *task = [[NSTask alloc] init];
NSMutableArray *args = [NSMutableArray array];
[args addObject:@"-c"];
[args addObject:[NSString stringWithFormat:@"sleep %d; open \"%@\"", 3, [[NSBundle mainBundle] bundlePath]]];
[task setLaunchPath:@"/bin/sh"];
[task setArguments:args];
[task launch];
[NSApp terminate:nil];
}

此外,我在此处查看了授权服务任务的文档 https://developer.apple.com/library/archive/documentation/Security/Conceptual/authorization_concepts/03authtasks/authtasks.html#//apple_ref/doc/uid/TP30000995-CH206-BCIGAIAG .

首先让我担心的是弹出这个信息框,“重要的是应用沙箱不支持授权服务 API,因为它允许权限升级。”

如果在重新启动应用程序之前需要此 API 来获取身份验证提示,那么我可能无法在未启用辅助功能的情况下获取全局事件。

总而言之,我的具体问题是:

  1. 我的示例代码中关于如何获取出现身份验证提示?

  2. 为了让身份验证提示出现,我是否需要使用授权服务 API?

  3. 是否有可能,或者不可能,有一个沙盒应用程序有访问全局事件?

最佳答案

首先,您无法自动允许应用程序使用可在沙盒环境和应用商店中运行的辅助功能 API。推荐的方法是简单地指导用户,以便他们自己轻松启用它。新的 API 调用 AXIsProcessTrustedWithOptions 正是为此:

        NSDictionary *options = @{(id) kAXTrustedCheckOptionPrompt : @YES};
AXIsProcessTrustedWithOptions((CFDictionaryRef) options);

现在,对于您的第一个和第二个问题(只是为了完整起见 - 同样,它在沙盒中不起作用):AXMakeProcessTrusted 背后的想法是您实际上创建了一个新的 auxiliary application您从主应用程序以 root 身份运行。然后该实用程序调用传入主应用程序可执行文件的 AXMakeProcessTrusted。最后你必须重新启动主应用程序。 API 调用已在 OSX 10.9 中弃用。

要以 root 身份生成新进程,您必须使用 launchdSMJobSubmit。这将通过身份验证提示提示用户说应用程序正在尝试安装帮助工具以及是否应该允许它。具体来说:

    + (BOOL)makeTrustedWithError:(NSError **)error {
NSString *label = FMTStr(@"%@.%@", kShiftItAppBundleId, @"mktrusted");
NSString *command = [[NSBundle mainBundle] pathForAuxiliaryExecutable:@"mktrusted"];
AuthorizationItem authItem = {kSMRightModifySystemDaemons, 0, NULL, 0};
AuthorizationRights authRights = {1, &authItem};
AuthorizationFlags flags = kAuthorizationFlagInteractionAllowed | kAuthorizationFlagPreAuthorize | kAuthorizationFlagExtendRights;
AuthorizationRef auth;

if (AuthorizationCreate(&authRights, kAuthorizationEmptyEnvironment, flags, &auth) == errAuthorizationSuccess) {
// this is actually important - if from any reason the job was not removed, it won't relaunch
// to check for the running jobs use: sudo launchctl list
// the sudo is important since this job runs under root
SMJobRemove(kSMDomainSystemLaunchd, (CFStringRef) label, auth, false, NULL);
// this is actually the launchd plist for a new process
// https://developer.apple.com/library/mac/documentation/Darwin/Reference/Manpages/man5/launchd.plist.5.html#//apple_ref/doc/man/5/launchd.plist
NSDictionary *plist = @{
@"Label" : label,
@"RunAtLoad" : @YES,
@"ProgramArguments" : @[command],
@"Debug" : @YES
};
BOOL ret;
if (SMJobSubmit(kSMDomainSystemLaunchd, (CFDictionaryRef) plist, auth, (CFErrorRef *) error)) {
FMTLogDebug(@"Executed %@", command);
ret = YES;
} else {
FMTLogError(@"Failed to execute %@ as priviledged process: %@", command, *error);
ret = NO;
}
// From whatever reason this did not work very well
// seems like it removed the job before it was executed
// SMJobRemove(kSMDomainSystemLaunchd, (CFStringRef) label, auth, false, NULL);
AuthorizationFree(auth, 0);
return ret;
} else {
FMTLogError(@"Unable to create authorization object");
return NO;
}
}

至于重新启动,这通常也使用外部实用程序来完成,等待主应用程序完成并再次启动它(通过使用 PID)。如果你使用 sparkle framework您可以重用现有的:

     + (void) relaunch {
NSString *relaunch = [[NSBundle bundleForClass:[SUUpdater class]] pathForResource:@"relaunch" ofType:@""];
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *pid = FMTStr(@"%d", [[NSProcessInfo processInfo] processIdentifier]);
[NSTask launchedTaskWithLaunchPath:relaunch arguments:@[path, pid]];
[NSApp terminate:self];
}

另一种选择是破解 /Library/Application Support/com.apple.TCC/TCC.db sqlite 数据库,使用辅助助手手动添加权限:

    NSString *sqlite = @"/usr/bin/sqlite3";
NSString *sql = FMTStr(@"INSERT or REPLACE INTO access values ('kTCCServiceAccessibility', '%@', 1, 1, 1, NULL);", MY_BUNDLE_ID);
NSArray *args = @[@"/Library/Application Support/com.apple.TCC/TCC.db", sql];
NSTask *task = [NSTask launchedTaskWithLaunchPath:sqlite arguments:args];
[task waitUntilExit];

然而,这将取消该应用程序作为应用程序商店的资格。更重要的是,它实际上只是一个 hack,db/schema 可以随时更改。一些应用程序(例如 Divvy.app 曾经这样做)在应用程序安装程序安装后脚本中使用了这个 hack。这样可以防止对话框告知应用正在请求安装辅助工具。

关于objective-c - 全局事件、Mac App Store 和沙盒,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12419988/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com