I have a launcher application in a bundle in /Applications that chooses a binary and fork/execs it. What I would like is for them to share a dock tile. I have tried a few approaches and none of them are satisfactory.
1. Keep the binary bundled with the app
If the binary is contained within the app bundle, this seems to work. However, it's generally considered bad practice for a bundle to modify itself, and I can't guarantee that a user has write access to /Applications. I tried putting a symlink to e.g. ~/Library/Application Support/MyBinaries/mybinary but this gives a separate dock tile.
2. Keep the binary outside the app bundle
If the binary is outside the app bundle, I get a separate dock tile. Why don't I set one of the processes to be an agent s.t. one of the tiles does not appear? This would have to be the launcher as the user should not be able to skip the launcher's logic as to which binary to run. Unfortunately this means that quit doesn't work properly, and you can't click the dock to restore the binary's window. It may be possible to get this to work by passing messages between the applications properly.
3. Massively hacky solution
There's a rather hacky way of doing this by adding an extra level of indirection, where the app at /Applications/MyLauncher.app launches another app in ~/Library/Application Support/Launcher2.app, which contains the binaries in its bundle. Only the second launcher has a dock icon.
This seems rather hacky, so I thought I would open this up to SO to see if anyone has a better solution?
EDIT
In option 2, I was keeping the binaries in bundles of their own. Don't do this. When I kept them in a regular folder everything worked correctly.
Answering my own question.
If you find yourself in this situation, go with option 2. Put the application at /Applications/MyApplication.app and keep the binaries in a folder named something like ~/Library/Application Support/MyApplication/Binaries/ and happily fork/exec them. Definitely do not put them in app bundles, as this was the source of my confusion. This solved all of my criteria:
Don't need root access to modify the binaries
Launcher and binaries share one dock tile
Pressing quit on the dock tile quits the binary.
App appears in Launchpad
Launching via Dock goes through the launcher app
Related
I have a cross platform need to open a gui application programmatically, but keep it hidden from the user. Effectively, I want a command line driven interface to act as a wrapper over this gui app, and insulate the end user from seeing or interacting with it. The program is from a third party, I did not write it, and I can't edit it.
I can do this one way or another on Windows, on Linux, and (in theory) on older versions of Mac, but not the most recent ones. On Windows, I can use the native api ShellEx with a hide window parameter. It's very easy and straight forward. In Linux, I can can render a gui app to a virtual frame buffer (using xvfb).
On macOS, the open command has a --hide and --background option, but they don't have any effect (at least on this app...)
I tried changing the plist file and found that LSUIElement will hide the app from the docker, but it still shows up on the screen. LSUIPresentationMode=4 or 3 OUGHT to work for exactly this, but apparently that doesn't do anything anymore as of a few os versions ago...
I tried the approach of moving the .app off of the screen with AppleScript. That works, but you have to manually grant permissions for such a thing to occur via System Preferences. In prior versions of Mac, those permissions could be twiddled on the fly via sqlLite (so long as you had sudo rights), but now they blocked that too. You can only pull that off apparently through a process of disabling "SIP" and forcing a reboot. That is totally outside the realm of what I want.
I've tried using the xvfb approach on Mac (jumping through hoops to acquire the binary they use to include stock, and now dropped), but I'm not having luck with that. I don't think it's possible to direct a mac .app to another display is it? A .app does not render on X11 by it's nature right?
What other clever ways might there be to hide a third party app on a mac? (and that still works in most recent os versions!)
I have a Mac desktop application developed using Xamarin.Mac and XCode. The application is loading views that should have a considerable amount of content as blank/white screens for a select few end users. While I've not been able to reproduce the issue locally and it doesn't appear to be impacting many people, it does happen consistently for a handful of users(6 out of over 4,000 at the moment). The app works just fine for the vast majority and uses a main window controller that sets the content view as needed by calling the applicable ViewController. When the views in question are loaded for the given users, it renders as a blank white area.
I did notice however that at least some of the objects in the views are actually there, just not visible. For instance, one view has buttons that are still "there" as you can click on them if you know where they are supposed to be positioned(and they also fire correctly) but they are not actually visible as the area is all white with no visible content. It's as if everything is loading properly but the UI just isn't cooperating in displaying objects that are actually there. The closest thing I could find was this Diagnosing run loop issue (partially frozen UI) in Cocoa application
However I'm not sure it's the same problem and there was no resolution for that either. Has anyone else ever encountered something like this?
Ok, got some new info. After doing a remote session with a user we had no luck with the hardware and the console didn't provide much insight, however we did stumble across a workaround that fixes the issue and may give some clues as to the real problem.
When the application is initially installed, we prompt the user to ask if they want it moved to the default Applications directory. They do not have to move it as it will work the same from pretty much anywhere but we do this for convenience. For the users having this problem, we noticed that they all had the app installed in the Applications folder. By sheer luck, one user accidentally chose to not move the app after reinstalling it per our support team. When the app was installed in his default Downloads directory, the problem vanished and the app worked as expected.
After testing various other directory locations(Downloads, Documents, etc.) we found that the issue only seemed to exist if the app was installed in the Applications directory. Furthermore, if the app was installed in the Applications directory, we could simply move it or copy/paste it to another directory outside Applications and when launching it from that new location the issue was resolved.
Seems like there is something specific to the default Applications directory that is causing this to happen(as odd as that sounds). Keep in mind that even when the app is installed in the Applications directory, this issue only happens to 7 people out of over 4,000.
Any ideas as to what might be special about that directory that could explain what we're seeing?
Ok. It is 2015. A lot of things have changed. And I would like to ask...
Does anyone know the way to detect how the application was launched on OSX ?
Because I still don't have the answer...
I am talking about these cases that are important to me:
Regular launch by user (via selecting app from Finder, Launchpad, etc.)
Launch at login (automatic launch by myHelperApp on startup)
Launch by user selecting item in services menu ("Do something in MyApp") assuming my app wasn't launched before.
Right now I am detecting the launch-at-login with outdated GetCurrentProcess function, obtaining current process id and then looking up for a parent process info. In case parent process info is obtained (!) and bundleId is not equal to some list of strings (myHelperApp bundleId, com.apple.loginwindow, com.apple.coreservices.uiagent) (!) - then this is not launch-at-login case.
Yes, it works for now, but c'mon people, this is a completely outdated, not stable way to solve the problem!
And what is important - there seems to be no way to tell that my app was launched via Services menu!
Has anyone found something new on this topic?
Apps in OS X that can open files to launch their respective applications often let the user choose the app that'll open the file. An example is the Finder.
I am still unclear about what's the best solution to implement this. The challenges are performance and showing the app's icon.
First, to get the list of apps, I found only LSCopyApplicationURLsForURL().
The major difficulty for me now is to get the app icons. All I have is the URLs (paths) to the apps. The only way I know of to get the icons would be to create a CFBundle object and then read the app's plist to get the icon data. But that appears to invole lots of disk access, and I could imagine it'll be quite inefficient if the app is located on a remote file server.
I believe that there's also a cached database about the apps, which includes icons and display names (without extension), and such. But where is the API for that?
Note: The app is Carbon based, but I can make use of Cocoa (NS...) functions if necessary. Also, Support for 10.5, even 10.4, would be appreciated.
Alright. I solved it eventually.
I now use the Carbon function GetIconRefFromFileInfo(), which still works in Lion, though it's marked deprecated/obsolete.
I had also tried to use QLThumbnailImageCreate(), but that didn't get me any results, oddly. No idea what I did wrong.
For Cocoa apps, [[NSWorkspace sharedWorkspace] iconForFile:path] can be used (thanks to C. Grunenberg of DevonTechnologies for this tip, where it's used with EasyFind).
I have a Mac app that can double as a screensaver (a minor functionality, but which I enjoy!). I don't want to have to distribute the app itself (a fractal viewer) and the screensaver separately, so I want to put the screensaver bundle inside the app bundle.
Questions: can I do that, and expect it to work? Do I have to "register" the screensaver somehow (using which API?), or will it be picked up automagically by the system?
I don't think the OSX screen saver host will acknowledge your .saver bundle unless it's in one of the Library/Screen Savers directories. So you can't just distribute the app and expect the saver to run with no further intervention.
You can still distribute them as a single bundle, of course, but you'll need to have some way of copying or symlinking the .saver into the right place from wherever it lives inside your app. For example, you could offer the user that option the first time they run your app, or you could add an "Install Screen Saver" menu item, or whatever.
I doubt you can do it without any user intervention at all -- as well as being rude, that would probably represent a bit of security hole...
You can do this without user intervention. At startup of your app, you can copy the .saver out of your bundle and into the "~/Library/Screen Savers" directory. The next time you run System Preferences and go to the screen saver settings, you should see your screensaver listed with the built in screensavers.
Beware that if the user doesn't expect that you are installing a screensaver, they might get irritated.
So, apparently no way around this.