How to observe notifications from a different application? - objective-c

I'd like to get notified when a certain application triggers an event. I'm not an Objective-C developer nor do I know the OS X APIs—so I hope this question is not too basic.
My goal is to write the meta info of the currently playing song to a log file. For iTunes, I got this working with the following Objective-C line:
[[NSDistributedNotificationCenter defaultCenter]
addObserver: myObserver selector: #selector(observeNotification:)
name: #"com.apple.iTunes.playerInfo" object:nil];
However, I also need this for AirServer (which is an software AirPlay receiver). Unfortunately, the following doesn't work—the observer never gets called:
[[NSDistributedNotificationCenter defaultCenter]
addObserver: myObserver selector: #selector(observeNotification:)
name: #"com.pratikkumar.airserver-mac" object:nil];
So apparently, AirServer does not send these type of notifications. However, there's a notification in the Notification Center when a new song starts playing.
My next step would be to periodically check for new notifications in the OS X Notification Center (as described here: https://stackoverflow.com/a/25930769/1387396). This is not too clean though—so my questions is: is there another option in this particular case?

Catalina silently changed the addObserver behavior - you can no longer use a nil value for the name to observe all notifications - you have to pass in a name. This makes discovery of event names more difficult.
Firstly, you have to understand that while the NSDistributedNotificationCenter has the word Notification in it; it's not related. From the About Local Notifications and Remote Notifications, it does state:
Note: Remote notifications and local notifications are not related to broadcast notifications (NSNotificationCenter) or key-value observing notifications.
So, at that point, I'm going to answer from the perspective of NSDistributedNotificationCenter, and not about Remote/Local notifications - you already have a potential solution in the answer you linked for observing the DB file that contains a record of the notifications in that way.
This example code will not work on Catalina (10.15) because of API behavior changes
The first thing you need to do is listen for the correct notification. Creating a simple application that listens for all events; e.g. using:
NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
[center addObserver:self
selector:#selector(notificationEvent:)
name:nil
object:nil];
-(void)notificationEvent:(NSNotification *)notif {
NSLog(#"%#", notif);
}
It indicates that the notifications are:
__CFNotification 0x6100000464b0 {name = com.airserverapp.AudioDidStart; object = com.pratikkumar.airserver-mac; userInfo = {
ip = "2002:d55e:dbb2:1:10e0:1bfb:4e81:b481";
remote = YES;
}}
__CFNotification 0x618000042790 {name = com.airserverapp.AudioDidStop; object = com.pratikkumar.airserver-mac; userInfo = {
ip = "2002:d55e:dbb2:1:10e0:1bfb:4e81:b481";
remote = YES;
}}
This indicates that the name parameter in the addObserver call should be com.airserverapp.AudioDidStart and com.airserverapp.AudioDidStop.
You can use code like that to determine all notifications, which will allow you to add the relevant observers when you want the particular observer. This is probably the easiest way to observe notifications of this type.

Related

Unable to receive NSWorkspaceActiveSpaceDidChangeNotification specifically, but other notifications work

-(void)monitor {
NSNotificationCenter *notcenter;
notcenter = [[NSWorkspace sharedWorkspace] notificationCenter];
[notcenter addObserver:self selector:#selector(activeSpaceDidChange:) name:NSWorkspaceActiveSpaceDidChangeNotification object:[NSWorkspace sharedWorkspace]];
- (void) activeSpaceDidChange:(NSNotification *)notification
{
NSLog(#"%#", notification.name);
}
Hey guys, does anyone have any info on this specific notification? For some reason, I seem to be able to get all other notifications, and if I put in nil for the name and receive all NSWorkspace messages, I can get all of them except NSWorkspaceActiveSpaceDidChangeNotification. All code snippets I have seen from people don't seem to be doing anything specific or different than what I have, so I have no idea why I wouldn't be able to get these notifications specifically.

Detecting AUv3 invalidations in a host app (iOS)

I'm working on a AUv3 host app, and I want the users to be notified when a loaded audio unit crashes (gets invalidated) for some reason. I looked at Apple's documentations about AUAudioUnit, but couldn't find any information about how to detect an invalidation of an audio unit (AUv3) from the host app.
Does anyone know how to do this?
Thanks
when setting up your AudioEngine you can observe kAudioComponentInstanceInvalidationNotification to figure out if its audio component instance was invalidated later on.
[[NSNotificationCenter defaultCenter] addObserverForName:kAudioComponentInstanceInvalidationNotification object:nil queue:nil usingBlock:^(NSNotification *note) {
AUAudioUnit *auUnit = (AUAudioUnit *)note.object;
NSValue *val = note.userInfo[#"audioUnit"];
AudioUnit auAddress = (AudioUnit)val.pointerValue;
NSLog(#"AudioComponent Invalidation of Unit:%# with Address:%p", auUnit, auAddress);
}];
keep in mind that you may have got the notification but the component ended up in a deadlock. So when trying to recover from that you may have to turn down the whole host app.

After IORegisterForSystemPower failing to call IODeregisterForSystemPower

I have an application, written in Objective-C for MacOS 10.10+ which registers for sleep/wake notifications (code sample below, but the code isn't the question). What I am wondering is, if I call IORegisterForSystemPower at App initialisation, but during debugging I kill the app before it has a chance to call IODeregisterForSystemPower, what are the implications? Does the app get de-registered automatically when it dies in any case? Is there a system dictionary I need to clear out (a plist somewhere, etc.)? Thanks in advance for any help.
io_object_t root_notifier = MACH_PORT_NULL;
IONotificationPortRef notify = NULL;
DebugLog(#"App: Logging IORegisterForSystemPower sleep/wake notifications %#", [NSDate date]);
/* Log sleep/wake messages */
powerCallbackPort = IORegisterForSystemPower ((__bridge void *)self, &notify, sleepWakeCallback, &root_notifier);
if ( powerCallbackPort == IO_OBJECT_NULL ) {
DebugLog(#"IORegisterForSystemPower failed");
return;
}
self.rootNotifierPtr = &(root_notifier); // MARK: deregister with this pointer
if ( notify && powerCallbackPort )
{
CFRunLoopAddSource(CFRunLoopGetCurrent(),IONotificationPortGetRunLoopSource(notify), kCFRunLoopDefaultMode);
}
To be honest, I don't know the exact answer. But it may help you.
First of, if you call IORegisterForSystemPower, you need to make two calls in this order: - Call IODeregisterForSystemPower with the 'notifier' argument returned here. - Then call IONotificationPortDestroy passing the 'thePortRef' argument returned here (Please visit apple's document for more detail).
In case of port binding, if I use CFSocketSetAddress, before releasing this socket no other can use this port for binding. But in case of app terminate/closed without releasing this socket this port is available. That means after terminated the app system automatically releasing this.
Does the app get de-registered automatically when it dies in any case?
I think it will automatically de-registered by system.
I also used similar code as you in one of my project. But recently replaced with below codes:
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self selector: #selector(receiveWakeNotification:) name: NSWorkspaceDidWakeNotification object: nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self selector: #selector(receiveSleepNotification:) name: NSWorkspaceWillSleepNotification object: nil];

NSNotificationCenter has a maximum speed?

Using NSNotificationCenter , it worked well till i have started to send very fast messages to other class.
What is fast ? its about 30-40 notifications in second. and i dont get even 1 of them .
is there other way to do that ?
should i update a global instead ?
//post data out .
- (void)post:(NSString*)string
{
NSLog(#"done"); //the log is printing
NSDictionary *userInfo = nil;
[[NSNotificationCenter defaultCenter] postNotificationName:#"connector"
object:string
userInfo:userInfo];
}
I know the observer is good cause same code worked before .
Thanks a lot .
If you're sending 30-40 notifications a second you should really think about your implementation again.
Heres some alternatives:
Creating your own delegates for callbacks
Using a block
The problem with NSNotificationCentre is that it sends the message to every observer - this can get slow and is generally used for updating views on state change (Login/Logout).
It looks like you setting the wrong object, Which should be the object that posts the notification (or nil). What I think you should be doing adding the string to userInfo:
NSDictionary *userInfo = #{#"somekey" : string };
[[NSNotificationCenter defaultCenter] postNotificationName:#"connector"
object:self
userInfo:userInfo];

How to verify network connectivity in objective-c

I was looking over the Reachability sample project on developer.apple.com and found that it was a large project just to verify you had network connectivity.
First part of the question is "What is the minimum code required to find out if the device can reach a 3G or wifi network?"
And next should this be done inside the appDelegate (on start) or inside the first View Controller that is launched?
Thank you in advance
It's not large, it really does what you want. If it is too big for you, you can extract what you need only like reachabilityForLocalWiFi. But I'm afraid that it will not be much smaller.
Yes, you can use reachability in your application delegate or inside the first view controller.
Reachability notification registration ...
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(networkReachabilityDidChange:)
name:kReachabilityChangedNotification
object:nil];
__reachability = [[Reachability reachabilityWithHostName:#"www.google.com"] retain];
[__reachability startNotifier];
... callback method example ...
- (void)networkReachabilityDidChange:(NSNotification *)notification {
Reachability *reachability = ( Reachability * )[notification object];
if ( reachability.currentReachabilityStatus != NotReachable ) {
// Network is available, ie. www.google.com
} else {
// Network is not available, ie. www.google.com
}
}
... do not forget to stop notifications, remove observer and release rechability object.