首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >NSWorkspace的runningApplications有多可靠?

NSWorkspace的runningApplications有多可靠?
EN

Stack Overflow用户
提问于 2020-05-31 15:18:20
回答 1查看 588关注 0票数 3

经过一段时间后,我想终止一些应用程序的执行。我正在对NSWorkspace的runningApplications进行轮询,因为它缺少可以观察到的内容(如果应用程序正在运行,它会通知什么吗?)

我的问题是,应用程序有时只会被终止,有时会在应该关闭的时间(根据内部计时器)之后几秒钟完成,有时甚至根本不会终止!

我尝试使用终止方法和forceTerminate方法。

在代码片段中,_apps_是包含应用程序名称的字符串向量。它由另一个线程定期更新,并在运行以下代码之前接收其数据。它们都在_es_handler_block_t中运行

代码语言:javascript
复制
NSArray<NSRunningApplication *> *running_apps = [NSWorkspace sharedWorkspace].runningApplications;
for (const auto &app_ : apps_) {
    //std::cout << app_ << "\n";
    for (NSRunningApplication *app in running_apps) {
        if ([[NSString stringWithUTF8String:app_.c_str()] isEqualToString:[app.executableURL lastPathComponent]] ) {
            std::string app_name = [[app.executableURL absoluteString] UTF8String];
            std::cout << "Terminating app " << app_name << "\n";
            bool res_f = [app forceTerminate];
            bool res_t = [app terminate];
            LOG_DBG("Force terminate: %d", res_f);
            LOG_DBG("Terminate: %d", res_t);
            break;
        }
    }
}

我在runningApplications文档中看到,“只有在主运行循环以公共模式运行时,此属性才会更改”。什么意思?

我认为这与运行应用程序的轮询有关,因为在上面的代码中插入一个断点(在if检查之前),然后恢复执行会立即杀死本来仍在运行的应用程序。

我没有阻止主要功能。我只有一个端点安全类作为框架,网络是在其他线程上完成的,我使用returnNSApplicationMain(argc, argv);

有什么问题吗?谢谢。

编辑:我正在利用Cocoa创建一个只显示在系统托盘中并且具有根权限的代理。使用终结点安全框架( Endpoint Security )成功地阻止了应用程序的启动,但我没有找到一种可靠的方法来杀死已经在运行的应用程序,这些应用程序每次都能工作。

稍后编辑:我设法向[[NSWorkspace sharedWorkspace] notificationCenter]添加了一个观察者,但是对于正在运行的应用程序,我应该订阅什么通知呢?我尝试过隐藏,但如果用户只点击红色窗口按钮,只有当用户将应用程序隐藏在码头上时,它就无法工作。但是我仍然想关闭它,即使用户和运行中的应用程序之间没有交互。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-06-01 00:10:26

在macOS上可靠地终止应用程序取决于许多因素,例如:

  1. 权利
  2. 该应用程序是如何发布的
  3. 如果有任何后台应用程序使主应用程序在崩溃或被另一个进程退出时立即存活

例如,您的应用程序可能被允许终止一个应用程序,但是,例如,如果您使用像下面这样的plist来终止launchdKeepAlive命令启动的进程:

代码语言:javascript
复制
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>com.bundleidentifierOf.AnUnquitabbleApp</string>
    <key>ProgramArguments</key>
    <array>
        <string>/path/to/the/AnUnquitableApp</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
</dict>
</plist>

你会大吃一惊,因为当你试图这么做的时候,launchd会立即重新启动它,看起来这款应用程序似乎没有被杀,但它确实是。您可以看到,应用程序是重新启动,当它的PID变化,每次你试图杀死它。

您可以使用以下命令来检查:

代码语言:javascript
复制
ps -ax

在终端中列出在Mac上运行的所有进程。如果您想知道应用程序是否正在运行,请使用:

代码语言:javascript
复制
ps -ax | grep "AnUnquitableAppNameHere"

然后,您可以使用它的PID与

代码语言:javascript
复制
kill <PID>

这将帮助您确定哪些应用程序可以使用简单的退出信号来杀死,哪些应用程序需要使用更强的信号来终止它们,而这些应用程序是不可缺少的,因为要杀死这些应用程序需要您的应用程序可能没有的特权或权利。阅读pskill的手册页,了解更多关于目标应用程序的信息。

在macOS上有许多其他的方法来获得持久性,如果您想了解如何可靠地退出应用程序,首先需要了解它们是如何获得持久性的。

例如,如果用户拥有管理/超级用户权限,则可以通过在/Library/LaunchDaemons中安装守护进程来获得持久性。如果您的应用程序没有根权限,则不太可能终止该进程。

除了launchd plist之外,应用程序保持持久性的另一种方法是,例如,有一个后台应用程序,一旦主应用程序被迫退出,它就会重新启动。一个例子是,如果您使用kill来杀死最新版本的Microsoft Word,您将看到它将由这样一个助手重新启动,该助手会抱怨Word被迫退出。

杀死一个应用程序最好的方法实际上是发送一个退出苹果事件,这是我通常做的。

我不想让你灰心丧气,但你想要达到的目标似乎比最初看起来更困难。即使你成功了,也要记住,用户可能会杀了你的应用程序,这会挫败你想要达到的目标,除非它被一个启动程序或其他形式的坚持所维持。

现在,如果您想观察哪些应用程序在没有投票的情况下被杀死或启动,我绝对建议您阅读TN2050

现在回答你的具体问题:

“只有在主运行循环以公共模式运行时,此属性才会更改”

这意味着您需要一个运行循环来更新NSRunningApplication。如果您有一个GUI应用程序,那么已经为您安装了这样一个循环。如果您的应用程序是一个CLI,那么这是没有安装的,您需要自己安装这样一个运行循环。如果您使用的是Objective,那么您可以按照这个问题中的建议来做。

因此,你想要达到的目标有很多警告,你需要在继续之前意识到它们。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/62118302

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档