我一直在尝试创建一种方法来告诉(正在运行的)macOS应用程序打开一些文件并为该命令提供一些其他参数。
对于冷启动应用程序,使用
$ open MyApp.app fileA.txt --args --foo-arg
将启动该应用程序,我将能够通过--foo-arg
/UserDefaults
/ CommandLine
检查ProcessInfo
。但是,如果应用程序已在运行,则--foo-arg
/UserDefaults
/ ProcessInfo
中缺少CommandLine
。
我一直在努力解决这个问题,因为我有一些要求,使事情变得有些困难。
XPC
有人建议我使用XPC,但在阅读了有关内容之后,我不确定该解决方案的外观如何?
Apple脚本
URL方案
我可以注册我的应用程序以拥有自己的URL方案,但是NSApplicationDelegate处理传入URL的方式分两批。首先,它可以打开的URL,然后是它无法打开的URL方案或文件路径。即:
open -a MyApp.app myapp:foo; open -a MyApp.app file.txt
我可能可以完成这项工作,但有点俗气,我真的想以正确的方式来做。
一个命令行工具可以提取其参数并将其转换为Apple Events。通过安装BBEdit命令行工具,然后在“终端”窗口中运行man bbedit
或man bbdiff
,您可以从用户的角度查看其工作方式。
从命令行工具的角度来看,“有趣的”部分是:
找出应用程序是否正在运行:+[NSRunningApplication runningApplicationsWithBundleIdentifier:]
将对此有所帮助。
如果应用程序正在运行[[not,则使用-[NSWorkspaceURLForApplicationWithBundleIdentifier:]
首先通过捆绑软件ID查找应用程序,然后使用-[NSWorkspace launchApplicationAtURL:options:configuration:error:]
启动应用程序。这将返回一个NSRunningApplication
实例,或者NIL和一个错误。 (确保处理错误情况。)
NSRunningApplication
实例,现在可以使用NSAppleEventDescriptor
API或低级AppleEvent C API构造事件。 (更高级的API可能更易于使用。)那会是这样:
processIdentifier
构造目标描述符:targetDesc = [NSAppleEventDescriptor descriptorWithProcessIdentifier: myRunningApplication.processIdentifier;
构造一个“打开文档”事件,发送给目标应用程序:
event = [NSAppleEventDescriptor appleEventWithEventClass: kCoreEventClass eventID: kAEOpenDocuments targetDescriptor: targetDesc returnID: kAutoGenerateReturnID transactionID: kAnyTransactionID];
注意:我以kCoreEventClass
/kAEOpenDocuments
为例-如果您要尝试打开一个或多个带有其他信息的文件,那很好。如果您正在做其他工作,则应该为应用程序特定的事件类创建一个四个字符的代码,并为您所请求的操作创建一个四个字符的事件ID。]将命令参数添加到事件中。对于每个参数,这包括根据参数的内在类型(布尔,整数,字符串,文件URL)创建适当的描述符,然后使用关键字参数将其添加到事件中。
AEDataModel.h
或AERegistry.h
中定义的合适的代码)满足您的需求)。对于您创建的每个描述符,请使用-[setParamDescriptor: forKeyword:]
将其添加到事件中:
myURLParamDesc = [NSAppleEventDescriptor descriptorWithFileURL: myFileURL];
[event setParamDescriptor: myURLParamDesc forKey: kMyFileParamKeyword];
将所有参数添加到事件后,发送它:
[event sendWithOptions: kAENoReply timeout: FLOAT_MAX error: &error];
在应用程序端,您需要使用-[NSAppleEventManager setEventHandler: andSelector: forEventClass: andID:]
。这将针对您在上面发明的自定义事件类和ID进行调用,此时您可以使用描述符API将事件拆开并运行您的操作。
沙箱会自行处理:您的应用程序会自动为通过Apple Events传递的文件获得沙箱扩展名。
您的命令行工具是
not
沙盒-不能,因为它是从Terminal和(可能)其他非沙盒应用程序运行的。但是,该工具必须使用强化的运行时进行签名,并使用com.apple.security.automation.apple-events = YES
和com.apple.security.temporary-exception.apple-events
命名应用程序的捆绑包标识符,以便该工具可以将Apple Events发送到您的应用程序。(该工具将需要一个带有NSAppleEventsUsageDescription
字符串的Info.plist。)
我为读者做了大量练习;但希望这会帮助您入门。