首页 > 解决方案 > macOS:检测所有应用程序启动,包括后台应用程序?

问题描述

新手来了 我正在尝试为应用程序启动创建一个小型侦听器,并且我已经有了这个:

// almon.m

#import <Cocoa/Cocoa.h>
#import <stdio.h>
#include <signal.h>

@interface almon: NSObject {}
-(id) init;
-(void) launchedApp: (NSNotification*) notification;
@end

@implementation almon
-(id) init {
  NSNotificationCenter * notify
    = [[NSWorkspace sharedWorkspace] notificationCenter];

  [notify addObserver: self
          selector:    @selector(launchedApp:)
          name:        @"NSWorkspaceWillLaunchApplicationNotification"
          object:      nil
  ];
  fprintf(stderr,"Listening...\n");
  [[NSRunLoop currentRunLoop] run];
  fprintf(stderr,"Stopping...\n");
  return self;
}

-(void) launchedApp: (NSNotification*) notification {
  NSDictionary *userInfo = [notification userInfo]; // read full application launch info
  NSString* AppPID = [userInfo objectForKey:@"NSApplicationProcessIdentifier"]; // parse for AppPID
  int killPID = [AppPID intValue]; // define integer from NSString
  kill((killPID), SIGSTOP); // interrupt app launch
  NSString* AppPath = [userInfo objectForKey:@"NSApplicationPath"]; // read application path
  NSString* AppBundleID = [userInfo objectForKey:@"NSApplicationBundleIdentifier"]; // read BundleID
  NSString* AppName = [userInfo objectForKey:@"NSApplicationName"]; // read AppName
  NSLog(@":::%@:::%@:::%@:::%@", AppPID, AppPath, AppBundleID, AppName);
}
@end

int main( int argc, char ** argv) {
  [[almon alloc] init];
  return 0;
}
// build: gcc -Wall almon.m -o almon -lobjc -framework Cocoa
// run: ./almon

注意:当我构建它时,它会运行良好,但是如果您在 High Sierra 上使用 Xcode 10 进行构建,您会收到ld警告,但是您可以忽略这些警告。

我的问题:有没有办法检测后台应用程序的启动,例如菜单栏应用程序,如粘度等?苹果这么说

系统不会为后台应用程序或文件中包含LSUIElement密钥的应用程序发布 [NSWorkspaceWillLaunchApplicationNotification] Info.plist。如果您想知道所有应用程序(包括后台应用程序)何时启动或终止,请使用键值观察来监控该runningApplications方法返回的值。

这里:https ://developer.apple.com/documentation/appkit/nsworkspacewilllaunchapplicationnotification?language=objc

我至少会尝试向侦听器添加对后台应用程序等的支持,但我不知道该怎么做。有任何想法吗?

标签: objective-cmacoscocoacommand-line-interfacensworkspace

解决方案


正如文档所建议的,您使用 Key-Value Observing 来观察runningApplications共享工作区对象的属性:

static const void *kMyKVOContext = (void*)&kMyKVOContext;


[[NSWorkspace sharedWorkspace] addObserver:self
                                forKeyPath:@"runningApplications"
                                   options:NSKeyValueObservingOptionNew // maybe | NSKeyValueObservingOptionInitial
                                   context:kMyKVOContext];

然后,您将实现观察方法(使用 Xcode 的现成代码段):

- (void) observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
    if (context != kMyKVOContext)
    {
        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
        return;
    }

    if ([keyPath isEqualToString:@"runningApplications"])
    {
        <#code to be executed when runningApplications has changed#>
    }
}

推荐阅读