how to pass parameters between cocoa applications - macos

I have a Cocoa application (.app) and I would like to launch it from another Cocoa application, no problem here, but is there any way to launch the second application passing it some parameters ? maybe using the argv[] array in the main function?

I did this using NSWorkspace to launch the app, and NSDistributedNotificationCenter to pass the data. This obviously isn't fully developed, but it worked. One caveat from the docs -- the dictionary I sent with the argument (just a string in this example) can't be used in a sandboxed app (the dictionary must be nil).
This is in the app that opens the other app:
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
ws = [NSWorkspace sharedWorkspace];
NSNotificationCenter *center = [ws notificationCenter];
[center addObserver:self selector:#selector(poster:) name:NSWorkspaceDidLaunchApplicationNotification object:nil];
[ws launchApplication:#"OtherApp.app"];
}
-(void)poster:(NSNotification *) aNote
{
NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
NSDictionary *dict = [NSDictionary dictionaryWithObject:#"theDataToSend" forKey:#"startup"];
[center postNotificationName:#"launchWithData" object:nil userInfo:dict];
NSLog(#"Posted notification");
}
And this is in the app that is opened:
-(void)awakeFromNib
{
NSDistributedNotificationCenter *center = [NSDistributedNotificationCenter defaultCenter];
[center addObserver:self selector:#selector(doStartup:) name:#"launchWithData" object:nil];
}
-(void)doStartup:(NSNotification *) aNote
{
NSLog(#"%#",aNote.userInfo);
}

How are you launching the second Cocoa app?
When I've done this, I usually communicate with the other app using AppleScript via NSAppleScript. You can launch apps that way too. Of course, the other app has to support AppleScript.
You could also use Distributed Objects if you have control over both apps, but it is more complex.
If you ever have to work with a command-line program, then NSTask is useful.

Related

gcdasyncsocket background file transfer

Having two devices that need to keep transferring data while in background or in LockScreen.
The main resource about backgrounding is available on https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/BackgroundExecution/BackgroundExecution.html
So far I'm looking forward to understand how is it expected to implement such above mentioned behaviour: in a scenario where a transfer is in progress and one of the apps (or both) goes into background. Obviously we have resumable transfer management working already.
I've been collecting stubs and answers about and I've ended up with the following:
Ensure every socket is backgroundable.
[socket performBlock:^{
[socket enableBackgroundingOnSocket];
}];
To keep backgrounding even when in Lock Screen, I read an answer saying that we should have something like at the end of didFinishLaunchingWithOptions but what code is in [self backgroundHandler] method?
BOOL backgroundAccepted = [[UIApplication sharedApplication]
setKeepAliveTimeout:600 handler:^{ [self backgroundHandler]; }];
if (backgroundAccepted)
NSLog(#"background handler accepted");
return YES;
The applicationDidEnterBackground delegate method of UIApplication shows
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(#"=== DID ENTER BACKGROUND ===");
if([[UIDevice currentDevice] respondsToSelector:#selector(isMultitaskingSupported)])
NSLog(#"Multitasking Supported");
else
return;
// Shall I remove my KVO observers when in background?? I guess NOT, right? :D
//[[NSNotificationCenter defaultCenter] removeObserver:self];
UIBackgroundTaskIdentifier bgTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
NSLog(#"End of tolerate time. Application should be suspended now if we do not ask more 'tolerance'");
// [self askToRunMoreBackgroundTask]; This code seems to be unnecessary. I'll verify it.
}];
if (bgTask == UIBackgroundTaskInvalid)
NSLog(#"This application does not support background mode");
else
NSLog(#"Application will continue to run in background");
// Start the long-running task and return immediately.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
});
I got it working following this tutorial but looks like GCDAsyncSocket is no longer maintained so it will work only on iOS7.
http://www.objc.io/issue-5/multitasking.html
To do background file transfer under iOS 8 I am using AFNetworking library (http://afnetworking.com)

How to detect when user opens the OS X Notification Center?

How do I detect when a user opens the OS X Mountain Lion Notification Center?
Is there an NSNotification (ugh, very similar term for a different thing) which I can observe?
I don't know of any officially documented solution or notification (let me know!), but this appeared to work (at least on OS X 10.10) when I tested it, so long as my application was in the foreground/had the frontmost window I believe.
Add your object as an observer:
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:#selector(notificationCenterOpened:) name:#"com.apple.HIToolbox.beginMenuTrackingNotification" object:nil];
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:#selector(notificationCenterClosed:) name:#"com.apple.HIToolbox.endMenuTrackingNotification" object:nil];
Add methods similar to the following to your object, making sure to check for the correct ToolboxMessageEventData number (4927), for example:
- (void)notificationCenterOpened:(NSNotification*)notification {
if ([notification.userInfo[#"ToolboxMessageEventData"] isEqual: #4927]) {
NSLog(#"Notification center opened");
}
}
- (void)notificationCenterClosed:(NSNotification*)notification {
if ([notification.userInfo[#"ToolboxMessageEventData"] isEqual: #4927]) {
NSLog(#"Notification center closed");
}
}
Let me know if that does or doesn't work for you.
Nevermind - upon restart/log-off + log back in, the ToolboxMessageEventData appears to change.

OS X: Show interface of application agent (UIElement)

How do I make the interface for an application that has 'Application is agent (UIElement)' set to yes reappear?
The interface shows up the first time I start the app, but if I close the window, and the click on the app's icon then nothing happens. I guess that it's because OS X is trying to start the app again, and there is some mechanism preventing that. What I would like is this:
The first click on the app's icon should launch the app and show the interface.
If the interface has been closed down (but the app is still running in the background) a subsequent click on the icon should just show the interface.
If the interface is already shown a click on the icon should simply move the window to the foreground.
Here is a way you can do it:
1) add + initialize method to your app delegate
+ (void)initialize
{
// check if there is a running instance of your app
NSArray * apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:[[NSBundle mainBundle] bundleIdentifier]];
if ([apps count] > 1)
{
//post notification to it to update inteface
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:#"updateInterface" object:nil];
//quit current instance of the app, coz you don't need two apps running continiously
exit(0);
}
}
2) Register your app for the notification
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
[[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:#selector(updateInterface:) name:#"updateInterface" object:nil];
}
3) Add updateInterface method
- (void)updateInterface:(NSNotification *)aNotification
{
// handle your interface here
// ....
// move your app forward
[NSApp activateIgnoringOtherApps:YES];
}
I found the answer here: Closing Mac application (clicking red cross on top) and reopening by clicking dock icon.
- (BOOL)applicationShouldHandleReopen:(NSApplication*)theApplication
hasVisibleWindows:(BOOL)flag
{
[self.window makeKeyAndOrderFront:self];
return YES;
}

How to hook the OS X dictionary

on osx lion, you can control-command-d or triple-tap on a word that your mouse is pointed to in any app to launch a popover dictionary. i want to make an app to track the words a user is looking up in the dictionary.
how do i observe the event where the user does control-command-d or triple-tap to launch the popover dictionary?
I understand that the specific API for this is HIDictionaryWindowShow.
You can use popoverDidShow:
- (void)awakeFromNib {
NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter addObserver:self selector:#selector(popoverDidShow:)
name:NSPopoverDidShowNotification object:nil];
}
// dictionary is shown or another NSPopover
- (void)popoverDidShow:(NSNotification*)notify {
//your code
}

How to hide window of UIAgent process with cocoa

I have an UIAgent application with one window. I want to hide/show it from another application.How do I do it with cocoa? Seems like hide/unhide methods of NSRunningApplication doesn't affect UIAgent processes.
Thanks in advance
I solved it with NSDistributionNotifications. In the UIAgent application I add an observer to a #"QuitProcessNotification" (any other name):
[[NSDistributedNotificationCenter defaultCenter]
addObserver:self selector:#selector(quit:)
name:#"QuitProcessNotification"
object:#"com.MyCompany.MyApp"
suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
The callback looks like that:
- (void) quit:(NSNotification *) notification
{
[NSApp terminate:nil];
}
In the main application:
Sending notification:
[[NSDistributedNotificationCenter defaultCenter]
postNotificationName:#"QuitProcessNotification"
object:#"com.MyCompany.MyApp"
userInfo: nil /* no dictionary */
deliverImmediately: YES];
Be sure, that the object parameter is indeed your sender application's bundle identifier.

Resources