And lo, the first result was for a GitHub repo called AppleSimulatorUtils. A command line utility that controls many of the Simulator menu items, including biometrics. Better still, it uses simctl and not AppleScript.
The way it works is by spawning a notifyutil process within the simulator runtime, which is then used to send a distributed notification across the iOS system that the Simulator listens for and toggles biometrics on (or off):
xcrun simctl spawn 'iPhone X' notifyutil -s com.apple.BiometricKit.enrollmentChanged '1' && xcrun simctl spawn 'iPhone X' notifyutil -p com.apple.BiometricKit.enrollmentChanged
There are actually two commands here, one to 'set' the new value, and one to actually post it:
- xcrun simctl: runs a command using simctl.
- spawn 'iPhone X' notifyutil: tells the iPhone X Simulator to spawn a notifyutil process.
- -s com.apple.BiometricKit.enrollmentChanged '1': sets the value of 1 to the com.apple.BiometricKit.enrollmentChanged notification.
- -p com.apple.BiometricKit.enrollmentChanged: posts the notification using another spawn of notifyutil.
Note that this doesn’t enable the little checkmark in the Simulator menu, but it does recognise it as enabled when you run your app!
It gets better!
This is a pretty good solution that we can modify our biometric server to use instead of AppleScript, but we didn’t stop there!
Looking at notifyutil, we realised that it’s just sending a cross-process Darwin notification. Darwin notifications are similar to (NS)Notification but not restricted to only being sent and received within a sandboxed app; they’re broadcast across the whole system and any app can observe them, even on iOS.
The usual way of sending a Darwin notification doesn’t allow you to set a value, so we had to go even lower level and use a different set of APIs. Unfortunately, these APIs are only available in Objective-C, so we’re going to have to go back in time a bit and write some good old fashioned C: