Can I store a screensaver inside my App bundle? - macos

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.

Related

On macOS how can I open a gui .app hidden or off screen?

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!)

Pros and cons of splitting Cocoa utility app into helper binary + main app binary?

I'm modernizing and sandboxing an old Cocoa utility and considering approaches. The app lives in the menu bar and works in the background, but shows a Dock icon and a configuration window when the icon is clicked.
There are two approaches:
A. A single binary with LSUIElement=YES, using TransformProcessType to show and hide the dock icon as necessary.
B. A helper tool performs the actual app functionality, manages the menu icon and always runs in LSUIElement mode in background. The main app presents the configuration UI and is only launched when necessary.
The app currently does A. I've noticed that many long-running utility apps have separate helper binaries and basically do B. Examples on my Mac include Paste Helper, TimingHelper, Discord Helper, CCC Helper (for Carbon Copy Cloner), 1Password Extension Helper.
I understand that having a separate helper app is conceptually more pure and potentially allows for better separation of sandbox privileges, but it's also harder to implement, so I doubt that's the sole reason why all these apps opted to have a separate helper binary.
So:
What are the pros and cons of A and B, i.e. why do some choose B over A? Is it required to get some functionality these days?
Is it even possible to have a helper tool outlive the main app in a sandboxed Mac App Store app?
What API does one use to make such a helper? The old-style authorisation APIs seem deprecated, and XPC does not seem like it allows a helper app to launch at startup (and even outliving the main app may be hacky)?
I suspect the reason so many developers choose option B is because this arrangement is now baked into macOS via the "Login Items" facility.
In a nutshell, your main application embeds a second (helper) app and that app is configured as a "Login Item". macOS detects this and automatically adds your helper app to the user's login items. You can control this, programmatically, using SMLoginItemSetEnabled(...).
You end up with a regular app users are familiar with, and a helper app that automatically starts at login and can run in the background. I'm also pretty sure this includes a free XPC connection you can take advantage of.
Read all about it in the Adding Login Items section of the infamous Daemons and Services Programming Guide.
I've never done this myself (I currently install background apps as user agents, which I can do because I don't have a sandboxed app), but I did research it for another project and I know a lot of apps do this.
One disadvantage of option A (based on user feedback from my own apps) is that the main app won't act like a regular app. Using the A approach, your users either can't quit the app (because it will need to automatically restart) or you need a way to hide it in the dock, and then there's no (obvious) way to launch it again. It just gets confusing. If you do let your users quit the app, then the background functionality goes away, and that creates other problems.

Logon-type wxpython app

I manage a number of Windows PCs which are used to control equipment. Each computer has a specific program installed which is what people launch to use that equipment. We want to require people to log in before they can access this program.
Currently, I have a wxpython app which just launches that executable when people log in with the correct credentials. However, you can just run the program directly and bypass logging on. I'd like to make a mock logon screen, ie, fullscreen and modal, which only goes away when you log in. Also it should not be able to be bypassed by alt-tab, windows key, etc. How might I accomplish this with wxpython?
There is no full proof way to do this on Windows. You can show a wx.Frame modally using its MakeModal() method. And you can catch EVT_CLOSE and basically veto it it they try to close the frame. However, if they have access to the Task Manager or even Run, they can probably get around the screen. Most users won't be that smart though. You can delete the shortcuts to the apps you want to launch with wx and that will force most normal users to use your login screen. It's only the smart ones who like to troll through the file system who will go around it.

How to make 2 applications shared the same dock tile

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

How do I automatically run an application on USB attach or CD insert on Mac OS X?

Is there any way to automatically launch an application on USB attach or CD insert on Mac OS X? it's easy on Windows, but I found that AutoRun.Inf does not work on the Mac at all.
You can't. Autostarting applications is impossible under Mac OS X.
The next-best thing, opening the CD folder and showing the installer icon, can be done by using (AutoOpen version 1.0) to make a .dmg which can then be burnt to a CD.
Basically, auto-run is considered a security problem and so is not supported in OSX. Sophie Alpert's answer is also a bit overkill. Most installers for OSX simply open up a folder to show the application and, possibly, a readme. Installing is done by dragging the app to your Applications folder.
For other kinds of apps on CDs (say, a slide show or something like that), the developer generally uses hidden folders to hide support data to ensure that the only thing the user will see when they open the CD is the single icon they're supposed to double click to start the app.
It is possible to install a background service that monitors whenever a USB device is plugged in and then launches an App. Google's "Android File Transfer Agent" is such a service that is running in the background and launches "Android File Transfer" whenever you plug in an Android device.
If you are looking for something for just yourself, you could write a small mac app that runs in the background and watches for a particular USB device (by id) to be attached and then run the program. Ideally a small XML plist could be used to map device IDs to the correct program to run. The XCode SDK has sample code that monitors for device additional and removal to get you started.
I agree with JavaCoderEx. I would crontab a task that looks for /Volumes/*/autorun.sh, then runs it once. Maybe touch a file in /tmp/ so you know its already been run, then remove it if the volume disappears.

Resources