I have an application that is a VOIP application of sorts that needs access to the microphone. I am using the Mac (Designed for iPad) support to not have to do huge amounts of conditional building and support for all the many iOS specific things my app includes.
I never get prompted to allow microphone permissions and I never see my app name appear in Privacy & Security -> Microphone permissions setup.
So is it that Mac is just a dead end for any form of an application that needs a microphone and is running under Mac (Designed for iPad) compatibility mode?
Why doesn't TCC have some mechanism to notice and grant access to mic use?
And again, this is "Mac (Designed for iPad)" build
Ah, yeah, I got mixed up with the terminology. A “Mac (Designed for iPad)” build takes you down the iOS apps on Mac path, which is definitely not Mac Catalyst. Sorry about the confusion.
iOS apps on Mac should follow iOS conventions, so:
- There’s no hardened runtime or App Sandbox, so no need for
com.apple.security.device.audio-inputorcom.apple.security.device.microphone. - You do still need
NSMicrophoneUsageDescription.
With that in mind, I sat down to try this out. Here’s what I did:
- Using Xcode 26.4 on macOS 26.4.1, I created a new test project.
- I wired up two buttons to some basic recording code (see below).
- In the Info tab of the target settings, I added a
NSMicrophoneUsageDescriptionproperty. - I ran the app on my iPhone.
- I tapped the Start button.
- iOS presented the microphone permission prompt. I tapped Allow.
- I spoke some words.
- I tapped the Stop button.
- Using Devices and Simulators I downloaded the app’s container.
- And looked in the container to confirm that there way a
tmp-xyz.wavfile and that it recorded the words I spoke in step 7. - I stopped the app.
IMPORTANT I know very little about audio recording, so no one should view the code below as a recommend for how to do it. Rather, I cobbled together just enough code for me to run this test.
I then repeated the test on my Mac:
- I changed the run destination to My Mac (Designed for iPad).
- I ran the app.
- I clicked the Start button.
- macOS presented the microphone permission prompt. I clicked Allow.
- I spoke some words.
- I clicked the Stop button.
- I used the Finder to preview the recording. It contained the words I spoke in step 5.
- I stopped the app.
Finally, I checked that my app was present in System Settings > Privacy & Security > Microphone.
Please try repeating my steps to see if you get the same result. Specifically, I’m curious as to whether this works with a new app whereas it fails with your main app. That’s not uncommon on the Mac, because macOS is much more complex than iOS, so it can end up caching state about an app that then causes problems in the future. So your main app may well work on a ‘clean’ machine, even though it fails on your main work Mac.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
final class MyViewController: UIViewController {
… other stuff …
var recordQ: AVAudioRecorder? = nil
func start() {
guard self.recordQ == nil else { return }
do {
print("will start")
let session = AVAudioSession.sharedInstance()
try session.setCategory(.record, options: [])
try session.setActive(true)
let tempURL = FileManager.default.temporaryDirectory
let fileURL = tempURL.appendingPathComponent("tmp-\(UUID()).wav")
let settings: [String: Any] = [
AVFormatIDKey: Int(kAudioFormatLinearPCM),
AVLinearPCMIsNonInterleaved: false,
AVSampleRateKey: 44_100.0,
AVNumberOfChannelsKey: 1,
AVLinearPCMBitDepthKey: 16
]
let recorder = try AVAudioRecorder(url: fileURL, settings: settings)
let didStart = recorder.record()
guard didStart else {
throw NSError(domain: NSOSStatusErrorDomain, code: Int(ENOTTY))
}
self.recordQ = recorder
print("did start, file: \(fileURL.path)")
} catch {
print("did not start, error: \(error)")
}
}
func stop() {
guard let recorder = self.recordQ else { return }
print("will stop")
recorder.stop()
self.recordQ = nil
print("did stop")
}
}