Software Development

In System Preferences > Sound > Sound Effects, users have the choice to turn off user interface sound effects (as an example, that might be a “tick” sound when adjusting a slider, or a “lock/unlock” sound when clicking a Lock button).

But how do you respect that setting? NSSound surely doesn’t.
Well, I found two ways to do it:

The “Easy” Way

macOS has a key in the standard UserDefaults object

com.apple.sound.uiaudio.enabled

If it is present and set to true, it’s safe to play the ui sound.

The “Safe” Way

What if the UserDefaults key isn’t present? Or you just want to be absolutely certain that your sound respects the user’s setting?

Use the AudioToolbox APIs. It offers

AudioServicesSetProperty(kAudioServicesPropertyIsUISound,...)

which marks sounds as UI sounds, thus not playing if the user wishes them not to.

It’s a bit more work, but might be the safer way to do it.

Read more

I’m happy to announce the release of a new freeware app: BackLog.

The premise is simple:
It’s complicated, or at least cumbersome, to get logs that predate you clicking “Start streaming” in Console.app – Apple’s recommendation for it is to *create an entire system diagnostics report* and look for files in there. Madness.
I wanted a quick and easy way to, for example, get all log entries from all processes that happened from boot time to 5 minutes after. And that’s what this app lets me – and now, you – do.

Hello BackLog
BackLog, showing all log entries from boot-time to 4 seconds after boot-time.

Using BackLog is pretty straight-forward. Select the process you’re interested in, specify a time-range and an optional text-filter and hit Load Logs.
You can then select it all and copy-paste it somewhere, or hit the little Share button at the lower left to share it as a file.

For convenience, right-click the ‘from’ or ‘to’ date pickers and select a time from the contextual menu, like Boot time.
What makes it a Developer Tool?

While diagnostic logs might appear to be of interest mostly to developers, a simple logging-app is not a developer tool to me, per-se.
What really makes BackLog such a tool, in my opinion, is that developers can create backlog:// links which they can send to their customers, and, when they have the app installed and click that link, all the options (like process, date range and message type) will be set for them beforehand – no hassle. All the customer has to do is hit Load Logs and send the results back to the developer.

Numerous times I’ve had to deal with obscure app-sandbox or keychain access issues in Yoink, and having to tell customers to please open Console, filter for Yoink, and then (hopefully) reproduce the issue is just bad UX.
Now, I can send them this app with a backlog:// link, with a time range pre-defined, and all they have to do is copy-paste the results into a response to my mail. And best of all – they don’t have to reproduce anything, the logs already contain all the info I need from the last time the issue occurred.

You can either copy only the backlog:// link, or have it include pre-written instructions for your customers.
Links and Further Info

BackLog is and will be Freeware. If you like it, however, I’d like to ask you to take a look at my other apps I offer for purchase on the App Stores – thank you 🙂

The app requires macOS 10.15 or newer and is localized – for now – in English and German.
It’s sadly not sandboxed, because the OSLogStore APIs won’t work in the sandbox environment 🤦‍♂️.
But Hardened Runtime is enabled, and it’s been notarized by Apple.
Naturally, it runs natively on both Apple Silicon and Intel Macs.

For BackLog to work reliably, the app must be run from an admin account, or using ‘sudo’ (user-discretion advised)

Website
Direct Download (801KB, zipped)

It’s also my first app completely written in Swift. That doesn’t make the app any better or worse. It’s just a fun fact.

If you have any feedback or questions, you can reach me any time by eMail. I’m looking forward to hearing from you.



Enjoy 🤗


Read more

Just a quick update on SiriMote, as I’ve been putting out a few updates for it over the last few weeks.

The app now has improved support for controlling the following apps with the Apple TV Siri Remote:
– Boinx Software’s FotoMagico
– Kodi
– Apple’s Keynote
– Apple’s TV App
– Infuse 7

SiriMote is freeware, and you can download it here.

Enjoy 🤗

Read more

In an effort to support macOS Monterey’s new Shortcuts in Transloader‘s Link– and File Actions, I decided to run all the necessary CLI commands and AppleScripts in an external XPC service, mostly to separate privileges (running Apple Scripts (which aren’t precompiled and reside in the Application Scripts folder) in a sandboxed Mac app requires specific sandbox entitlements, which Transloader itself just doesn’t need).

I didn’t start with an XPC service, though. For testing and debugging purposes, I began with a new app in Xcode and ran all the Apple Scripts from there, which, after a bit of tweaking because I’m not “fluent” in Apple Script, worked just fine.

After subsequently moving them into an XPC service and thinking it would “just work”, I found that it didn’t. At least not reliably. Maybe every 8th or 9th time, yes, it did all it was asked to do, but every other time, it outright refused to execute Apple Scripts.

After two days of desperate attempts to get it working correctly, and almost giving up on the XPC privilege separation entirely for this, I figured I’d check to see if the Apple Scripts were being executed on the main thread.
I did recall reading quite some time ago (I don’t know where, sorry) that Apple Scripts on background threads are iffy in their execution. Lo and behold, the methods weren’t run on the main thread. One quick dispatch_async to the main queue later, and everything worked as I expected it to.

So, the takeaway of all this, and the TLDR, is this post’s title: An XPC service’s methods aren’t necessarily run on the main thread. Go figure.

Addendum

If you’re wondering what my configuration for the XPC service is:

RunLoopType = NSRunLoop
ServiceType = Application

I did try dispatch_main as RunLoop as well, which worked too, but I just figured, for Apple Scripts, NSRunLoop would be required, but I don’t know for sure.

Read more