【问题标题】:MAC OS X difference between "open APP.app" and "APP.app/content/MacOs/APP" shell scriptsMAC OS X “open APP.app”和“APP.app/content/MacOs/APP”shell 脚本的区别
【发布时间】:2017-09-23 21:34:24
【问题描述】:

如果我调用一个应用程序两次或多次但只有一个实例应该在运行(这是理想的),我会遇到问题。

首先一些(可能是必要的)背景信息:

  • 在 MAC OS X El Capitan (10.11.6) 上工作
  • 我有一个由 node.js、electron 和“npm build -m”构建的应用程序(我们称之为 APP.app)
  • 我通过打开构建的 dmg 文件并将其移动到程序文件夹中,将应用程序 App.app 安装到程序文件夹中
  • 然后我通过单击程序文件夹中的 App.app-icon 来启动应用程序 App.app
  • 应用程序以可见窗口启动,并且还有一个隐藏的后台进程正在运行
  • 如果我关闭可见窗口,App.app-Icon 仍保留在 Dock 中(这没关系,因为后台进程仍在运行)
  • 现在(这是 Windows 构建和在 Windows 中运行的区别),如果我再次单击程序文件夹中的 App.app-Icon,我只会关注已经运行的应用程序而不是打开窗口并关闭旧应用程序(我可以通过屏幕顶部苹果徽标旁边的切换菜单名称看到焦点切换/激活;它变成了“应用程序”)
  • 之前运行实例的关闭在init-method中的electron代码中定义如下:

        var shouldQuit = app.makeSingleInstance(function (commandLine, workingDirectory) {
        console.info('starting new instance');
        initInternal(commandLine);
        // Someone tried to run a second instance, we should focus our window.
        var windows = options.closeWindowsOnRestart ? Browser.getAllWindows() : appWindows.slice();
        windows.forEach(function (val, index) {
            val.close();
        });
        readyCallback();
    });
    

所以,我做了一些功课,可以弄清楚以下内容:

  • 我的 App.app-icon-click 应该类似于 open /Applications/App.app
  • 这样,如果我再次调用它,我会遇到与上述相同的问题(它只关注已经打开的窗口)
  • 现在是有趣的部分。如果我通过直接调用 /Applications/App.app/content/MacOS/App.app 打开应用程序,旧的应用程序实例将关闭并启动新的 App.app-application
  • 我通读了open-manual,发现如果我使用-n-flag,应用程序也会成功启动一个新实例。 (open /Applications/App.app -n)

我想知道为什么?你有什么线索吗?应用的打开和直接调用有什么区别?

我建议 App.app-package 中的 info.pklist 使 open-call 与 App.app 的直接调用不同。

顺便说一句: 不幸的是,我已经尝试添加 try-catch-blocks 来调试问题,但是open 没有向终端提供输出,它只是打开调用,而直接调用不会引发错误并且一切正常。 无论如何,我相信这更像是一个 MAC OS X 问题而不是 App.app 问题。

希望有人遇到同样的问题并为我提供解决方案

如有需要,请随时询问更多详情。

【问题讨论】:

  • 没有人能告诉我打开和只调用 app/Content/MacOS/app 中的应用程序的区别?

标签: node.js macos shell terminal electron


【解决方案1】:

短版:

  • open 使用 LaunchService 启动应用程序(并且可能 在 info.plist 中添加了启动参数)
  • 而直接调用 应用程序只是自己启动应用程序,没有任何其他 启动选项

*加长版*

我通读了打开的手册(man open;来源:https://developer.apple.com/legacy/library/documentation/Darwin/Reference/ManPages/man1/open.1.html),如果您单击一个项目,可以发现“通过 LaunchServices 确定的默认应用程序用于打开指定的文件”。

所以我通读了 LaunchService 文档,并可以弄清楚以下内容:

"通过文件系统引用打开项目 [...] 默认方式: 如果指定项目是应用程序:[...] 如果应用程序已经在运行,它会被激活(带到屏幕前面)并发送一个“rapp”(“reopen 应用程序”) Apple 事件。”

(来源:https://developer.apple.com/library/content/documentation/Carbon/Conceptual/LaunchServicesConcepts/LSCTasks/LSCTasks.html#//apple_ref/doc/uid/TP30000999-CH203-TP9

这完全反映了我的观察,即如果我第二次单击该图标,该应用程序就会被聚焦/激活。

因此我需要告诉应用程序打开一个新实例(oapp-event)而不是激活已经打开的应用程序(rapp-event)

进一步阅读将我带到以下信息:

"启动选项打开应用程序时(无论是单独还是 打开一个或多个文档或 URL),您可以指定各种启动 控制启动或激活方式的选项。 这些可以包括:[...] 是否启动一个新的实例 应用程序,即使另一个实例已经在运行”

(来源:https://developer.apple.com/library/content/documentation/Carbon/Conceptual/LaunchServicesConcepts/LSCConcepts/LSCConcepts.html#//apple_ref/doc/uid/TP30000999-CH202-BABBJHID

因此我只需要添加“启动选项”来定义,应该创建一个新实例而不是激活现有实例。但是没有写它的启动选项是什么以及它们将如何应用于应用程序(我建议它属于 info.plist 文件)。

所以至少这是我最初问题的答案,所以我把它贴在这里。

open - 使用 Launch-Service(以及 info.plist 中定义的选项参数)启动应用程序 而直接调用应用程序只是启动应用程序本身而没有任何其他启动选项

【讨论】: