如何在Mac OS X中监听应用程序启动事件?

时间:2010-11-29 14:23:50

标签: objective-c macos pyobjc

我写了AppleScript来装载SparseBundle图像,我希望它在Time Machine启动时完全执行。

现在,我使用AppleScript语句定期检查Time Machine是否与on idle一起运行:

on idle
    ....
    return <interval>
end idle

这不是一种强有力的方式。在我看来,为Application Launch事件添加事件触发器将是一种更好的方法。

你能帮忙吗?

Objective-CPython示例代码(我更喜欢Python)非常受欢迎。

3 个答案:

答案 0 :(得分:5)

您正在寻找的是NSDistributedNotificationCenterNSWorkspace,这些可可类会发布应用程序事件的通知,工作区,应用程序启动,驱动器安装等等。

要在python中执行此操作,您需要PyObjC,这基本上是apple的cocoa类的python绑定。文档在他们的网站上很少,而且有一个原因,因为文档基本上与Apple文档相同,所以它们只包含pyobjc api和cocoa API之间的差异。如果您了解目标c api如何转换为python,那么您就可以了。点击此处:http://pyobjc.sourceforge.net/documentation/pyobjc-core/intro.html

我在下面列出了一个使用python监听分布式通知的示例。下面的代码基本上添加了一个观察者并监听itunes通知。您可以遵循类似的结构,而是添加NSWorkspace的观察者。要弄清楚你应该听什么,有一个应用程序将显示通过你的系统的所有通知。它被称为notification watcher。用它来弄清楚你应该听什么。您还可以将目标c代码转换为python。

以下代码正在做什么

  1. 定义一个继承自NSObject的新类,由PyObjC
  2. 定义
  3. 定义一个方法,该方法将传递实际通知并将其打印出来
  4. 创建Foundation.NSDistributedNotificationCenter.defaultCenter
  5. 的实例
  6. 创建GetSongs的实例
  7. 注册观察者,向其传递类,在收到通知时调用的方法以及哪个应用程序&amp;要监视的事件,即“com.apple.iTunes.playerInfo”
  8. 运行事件循环,
  9. 有一件事会让你失望,访问属性(目标c属性)与访问python属性不同。即在python中你为python中的目标c做class_name.att,你必须把它称为函数,即我的例子如下:song.userInfo()

    import Foundation
    from AppKit import *
    from PyObjCTools import AppHelper
    
    class GetSongs(NSObject):
        def getMySongs_(self, song):
            print "song:", song
            song_details = {}
            ui = song.userInfo()
            print 'ui:', ui
            for x in ui:
                song_details[x] = ui.objectForKey_(x)
            print song_details
    
    nc = Foundation.NSDistributedNotificationCenter.defaultCenter()
    GetSongs = GetSongs.new()
    nc.addObserver_selector_name_object_(GetSongs, 'getMySongs:', 'com.apple.iTunes.playerInfo',None)
    
    NSLog("Listening for new tunes....")
    AppHelper.runConsoleEventLoop()
    

    以下是实际输出的示例...(YES BRITNEY ROCKS!,NOT!;)

    song NSConcreteNotification 0x104c0a3b0 {name = com.apple.iTunes.playerInfo; object = com.apple.iTunes.player; userInfo = {
        Album = Circus;
        "Album Rating" = 0;
        "Album Rating Computed" = 1;
        Artist = "Britney Spears";
        "Artwork Count" = 1;
        Genre = Pop;
        "Library PersistentID" = 8361352612761174229;
        Location = "file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3";
        Name = Circus;
        PersistentID = 4028778662306031905;
        "Play Count" = 0;
        "Play Date" = "2010-06-26 08:20:57 +0200";
        "Player State" = Playing;
        "Playlist PersistentID" = 7784218291109903761;
        "Rating Computed" = 1;
        "Skip Count" = 1;
        "Skip Date" = "2010-06-26 12:20:57 +0200";
        "Store URL" = "itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus";
        "Total Time" = 192444;
        "Track Count" = 16;
        "Track Number" = 2;
    }}
    ui {
        Album = Circus;
        "Album Rating" = 0;
        "Album Rating Computed" = 1;
        Artist = "Britney Spears";
        "Artwork Count" = 1;
        Genre = Pop;
        "Library PersistentID" = 8361352612761174229;
        Location = "file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3";
        Name = Circus;
        PersistentID = 4028778662306031905;
        "Play Count" = 0;
        "Play Date" = "2010-06-26 08:20:57 +0200";
        "Player State" = Playing;
        "Playlist PersistentID" = 7784218291109903761;
        "Rating Computed" = 1;
        "Skip Count" = 1;
        "Skip Date" = "2010-06-26 12:20:57 +0200";
        "Store URL" = "itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus";
        "Total Time" = 192444;
        "Track Count" = 16;
        "Track Number" = 2;
    }
    {u'Album Rating Computed': 1, u'Album': u'Circus', u'Rating Computed': True, u'Name': u'Circus', u'Artist': u'Britney Spears', u'Track Number': 2, u'Skip Date': 2010-06-26 12:20:57 +0200, u'Library PersistentID': 8361352612761174229L, u'Player State': u'Playing', u'Total Time': 192444L, u'Genre': u'Pop', u'Playlist PersistentID': 7784218291109903761L, u'Album Rating': 0, u'Location': u'file://localhost/Users/izze/Music/iTunes/iTunes%20Music/Britney%20Spears/Circus/02%20Circus.mp3', u'Skip Count': 1, u'Track Count': 16L, u'Artwork Count': 1, u'Play Date': 2010-06-26 08:20:57 +0200, u'PersistentID': 4028778662306031905L, u'Play Count': 0, u'Store URL': u'itms://itunes.com/link?n=Circus&an=Britney%20Spears&pn=Circus'}
    

答案 1 :(得分:3)

在Objc-C中这不太难。您可以通过NSWorkspace和NSNotificationCenter访问所有应用程序的通知。创建一个对象并为NSWorkspaceDidTerminateApplicationNotification类型的通知注册其中一个方法。类似的东西:

@interface NotificationObserver : NSObject { }
- (void) applicationDidLaunch:(NSNotification*)notification;
@end

@implementation NotificationObserver : NSObject
- (void) applicationDidLaunch:(NSNotification*)notification
{
  // Check the notification to see if Time Machine is being launched.
}
@end

void watch(void)
{
  NSNotificationCenter* notificationCenter
    = [[NSWorkspace sharedWorkspace] sharednotificationCenter];
  NotificationObserver* observer = [[NotificationObserver alloc] init];
  [notificationCenter addObserver:observer
                         selector:@selector(applicationDidTerminate:)
                             name:@"NSWorkspaceDidTerminateApplicationNotification"
                           object:nil];
}

答案 2 :(得分:0)

这不是您问题的答案,但它可以解决您的问题。

为什么不让AppleScript在安装磁盘映像后启动Time Machine?然后,不是直接启动Time Machine,而是始终通过脚本调用Time Machine。您甚至可以将Time Machine图标粘贴到AppleScript文件上,并将其命名为“Time Machine”以使幻觉完整。 : - )