How to deal with Mac OS X Helper/Main app architecture regarding core data, shared preferences and notifications? - macos

I'm having some architectural doubts about a project (Mac OS X app) I'm working on. It basically consists of two elements: a daemon that runs in the background gathering some data and a viewer used to represent the gathered data.
The daemon should be visible in the status bar (no dock icon) and includes a small menu accessible via the status bar. It saves data in a core data store. One of the menu items is a link which opens the viewer. When this viewer is opened, a normal GUI application should start including a dock icon and menubar. The viewer is also opened when opening the application itself (by double-clicking on the icon).
After some experimenting, I figured out the best way to achieve this functionality is by creating two applications, the main application representing the viewer and a helper utility representing the daemon. One of the reasons I did it this way is that it isn't possible to switch between LSUIElement values instantly to force the daemon/viewer state.
Now I have some questions about this architecture:
Both the daemon and viewer application uses the same core data store to save and retrieve data. When having a multi-threaded application I know multiple NSManagedObjectContext objects are needed to correctly synchronize data. What about having multiple applications using the same core data store simultaneously? Is this even possible without having the risk of conflicts, locks, etc.? How do I guarantee consistency?
The daemon should always start when the viewer starts. I achieved this by simply looping through all open processes and checking if the bundle identifier of the daemon is listed. If not, the daemon is started using NSWorkspace's launchApplication. This works fine. Now when the user quits the daemon, the viewer should also stop. What is the best way for the viewer to be notified of the daemon stopping? I can periodically check active processes and quit the viewer if the daemon is gone but that sounds a bit odd. I would rather choose some kind of notification that I'll send when the viewer is about to close. But since this notification should be sent and captured between apps I don't know which simple notification service is available. Any thoughts?
The application is sandboxed as it will be distributed on the Mac App Store. Starting apps with NSWorkspace's launchApplication causes the target app to run in the same sandboxed environment as the source which I think is not a problem at all because running both applications in the same sandbox feels better and probably is. But imagine this scenario: the daemon is started automatically at login (using SMLoginItemSetEnabled) and the user double-clicks Viewer.app. As the daemon is already running (again, this is checked by looping through active processes) it won't be started. Now we have the daemon and the viewer running in different sandboxes right? Will this cause any problems regarding preferences, core data store, etc.?
I would like to use NSUserDefaults for basic configuration, can I somehow interchange this data between the daemon and the viewer? Again, both applications will have different bundle identifiers.
Thanks in advance for your help, appreciated!

There isn't one right answer to this problem, but here's how I'd approach it:
Both the daemon and viewer application uses the same core data store to save and retrieve data.
Because sharing a Core Data store between processes isn't supported (as far as I know), I'd have the daemon expose an XPC Service. Instead of opening the Core Data store itself, the viewer would use an NSXPCConnection to access the data via the daemon.
Assuming the viewer never runs without the daemon, it can use SMLoginItemSetEnabled, like you mentioned in the question, to register a mach service for the daemon, and then connect to that service.
There's sample code that goes over the details of setting that up here on Apple's website (summary: the daemon needs to be at App.app/Contents/Library/LoginItems/daemon.bundle.id.app), and you might also want to read this blog post that discusses some extra requirements imposed by sandboxing (summary: make extra sure that your Team ID is in the daemon's bundle identifier).
The daemon should always start when the viewer starts.
All set: once you register the daemon with SMLoginItemSetEnabled, launchd will start it (if necessary) when the viewer connects to its XPC Service.
Now when the user quits the daemon, the viewer should also stop.
The viewer can use the NSXPCConnection to find out when the daemon quits. The daemon can also use SMLoginItemSetEnabled to un-register itself before it quits, so that it doesn't get relaunched.
I would like to use NSUserDefaults for basic configuration, can I somehow interchange this data between the daemon and the viewer? Again, both applications will have different bundle identifiers.
Use a suite for this:
// To read or write:
NSUserDefaults* suiteDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"com.example.app.shared"];
[suiteDefaults setObject:[NSDate date] forKey:#"launchTime"];
// Add the suite to -standardUserDefaults to make reading easier:
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
[defaults addSuiteNamed:#"com.example.app.shared"];
To work with sandboxing, the viewer and the daemon must share an App Group. You can even use KVO to observe changes to shared keys.

Related

User preferences are not saved from XPC service

In my main app bundle I have supporting XPC service included. App is sandboxed and everything works quite fine, except that when I call [[NSUserDefaults standardUserDefault] setObject:forKey:] method and than - synchronize method from the XPC service app, preferences are not written and data cannot be retrieved next time I need it.
I didn't find anything related to this problem in Apple's documentation, except that the sandboxed app cannot access preferences of other apps. That's all right, I don't need it. XPC service has its own container in ~/Library/Containers, where it should be able to store its own data, I'd suppose. But obviously it's not the case for some reason.
I probably missed something, but cannot find what. Is there anything special which needs to be done (adding some entitlement or so) in order to make this work?
Thanks for any tips.
I believe you'll need to use Group Containers to share the preferences and I have achieved something similar (a non-UI LSUIElement app sharing preferences with its conventional Preferences app countpart) using RMSharedPreferences.

windows phone app running in the background

Is it possible to create an app the runs in the background? If so is there any samples out there for this?
In Windows Phone OS 7.1 you can actually use Background Agents now to perform tasks in the background.
from MSDN:
Scheduled Tasks and background agents allow an application to execute
code in the background, even when the application is not running in
the foreground. The different types of Scheduled Tasks are designed
for different types of background processing scenarios and therefore
have different behaviors and constraints.
You can use a PeriodicTask or ResourceIntensiveTasks. Read more about it in the MSDN article above.
And here's some sample code for you to integrate background agents into your existing app.
Sample Code: Background Agents in Mango
An application in the foreground can continue to run when the phone screen is locked(not background but...) by setting the PhoneApplicationService.ApplicationIdleDetectionMode property. By setting up your application to run when the phone screen is locked, a user is able to access the application quickly upon unlock. However, when your application runs under a locked screen, it could consume power outside of the user's control. For this reason, your application must minimize power usage when running under a locked screen
At the moment there is no way to create application that runs in background.
True multitasking for 3rd party Windows Phone 7 apps will come as an OS upgrade later this year. However, unless the app has to absolutely run in the background (like Pandora etc.), we as developers share some responsibility in making our apps feel at home with the rest of the OS.
Windows Phone OS offers app developers chances to save state of their applications to give the end users the feeling that it never stopped running; this is essentially the same as in other mobile platforms. As your app is being deactivated/closed, you have the option to "Tombstone" your state so that your users can come back to just where they left with BackStack navigation or future launches. Channel 9 had a nice set of demos & labs around tombstoning, found here.
Hope this helps!

How to make an Invisible / Hidden Cocoa Application

I want to develop a application like http://orbicule.com/undercover/ or
http://hiddenapp.com/.
I know how I could do that for windows but I have totally no clue, what kind
of approach I would need for mac os x, cocoa/xcode.
Is there anything I should be aware of when building applicatons / background services
with no GUI for mac os x?
The service will post data to the webpage with the usual data like geo location & IP
information about the machine so it should be able to access the internet too.
Please lead me to the right path.
It's fairly straightforward.
Go to:
Information Property List Key Reference
http://developer.apple.com/library/ios/#documentation/general/Reference/InfoPlistKeyReference/Introduction/Introduction.html
in the Launch Services Keys, you will see one called "LSBackgroundOnly" simply define this in your Info.plist and set it to true.
<key>LSBackgroundOnly</key>
<true/>
From the documentation:
LSBackgroundOnly (Boolean - Mac OS X)
specifies whether this application
runs only in the background. If this
key exists and is set to “1”, Launch
Services runs the application in the
background only. You can use this key
to create faceless background
applications. You should also use this
key if your application uses
higher-level frameworks that connect
to the window server, but are not
intended to be visible to users.
Background applications must be
compiled as Mach-O executables. This
option is not available for CFM
applications.
Your application will be a background application.
Give System Startup Programming Topics a read. Create a command line tool project, not a Cocoa Application nor a Cocoa Document-Based application. To provide a GUI to interface with it you'll want to use a separate application (ideally one you don't have to install with the "hidden" app, since you seem not to want it to be easily discoverable).
With the exception of AppKit (UI) stuff, the rest of the basic Cocoa frameworks is still available to you via the command line. This means you'd write the main logic of your app (the non-GUI parts) the same as you would otherwise.

Alternative to SendKeys that does NOT require an unlocked session

Situation:
A GUI app contains functionality (off a menu option) that produces a frequently updated image to a directory.
A logged-in, running instance of the app is the ONLY source for this image (functionality 'reliant' on display device). I have researched this to death - it is a sad fact.
The GUI application offers COM interfaces, but none that generate the image.
GUI code cannot be change in the least (big surprise).
Requirement:
These current images are needed by other processes at various times.
Obvious solution:
A process that creates an instance of the GUI app and uses SendKeys to manipulate the controls to produce the image.
Roadblocks (do I need to elaborate)
Aside from the flakiness of Sendkeys - assuming that Sendkeys WAS reliable....
Sendkeys can't work when console session is locked (locked is production requirement)
SendMessage API can't send key combinations like 'shift/letter' (required to invoke menu option).
Questions
Is there any other way to programatically interact with the app when the session is locked?
Can a windows service unlock/lock the sesion at predetermined times - long enough to allow an image generation to occur.
I know, I know, its crap. ANY high level ideas and MOST opinions are appreciated ;)
Virtual PC.
Lock the host, not the virtual machine.
But to actually answer your question: i don't think you can send keys to a locked computer. Why? What if there are multiple logged in sessions; which one would it send the keys to?

Seeing the windows of a process running as System account or as a service

Suppose you have a process which run as as service as the System Account, is it possible to view the content of the windows created by the processes created by the service.
Suppose for example, that you have a service running as a kind of wrapper which starts Excel.
Microsoft Spy++
Select Spy/Processes and find your process there
If some of it's threads had created any windows, you'll see them as subtrees.
A process that creates and fills windows should never be run as a service. That being said, if this is on Win2K3 or earlier set the service to interact with the desktop and you can see the contents yourself. If it is on Vista or later there is no way to examine the contents of an arbitrary window.
If it is a specific type of window (i.e. EDIT control) that supports retrieving its contents you may be able to run another service that sends a windows message to the first service to get what you want.
Services will (under normal circumstances) be associated with a different window station to the interactive desktop, and they cannot interact -- you can read up more on Window Stations on MSDN

Resources