Running tests on Catalina - How to avoid permissions prompts?

Does anyone know how to deal with these? As it is I have to wait for them to happen, which obviously isn’t a very effective use of time. I’ve been searching but can’t find much information on it so I must be missing something.

*Edited… thought it was missing “entitlements” file but that’s not looking quite right now.

You can’t avoid them (at least to my knowledge). They can’t be added programmatically, can be reset using “tccutil reset” command, though. On Catalina user must add permissions manually.

Thanks, zabukowski. I’m actually able to change the behaviour by messing with the signing options, but so far only reduce the prompts not eliminate them. But it also seems if I create a default app with JUCE 6 projucer I don’t get any prompts at all, even with the same signing options. An obvious difference is that my app is based on JUCE 5 and the project is generated via FRUT, so I’m guessing the answer to this is lying somewhere in the differences there.

Fwiw, I’m using the following snippet to test the prompt for the microphone. It will prompt for my project but not the JUCE 6 one.

juce::String err = mgr->initialise(2, 2, nullptr, true, "Aggregate Device");
...
///juce_mac_CoreAudio.cpp.  This line immediately triggers the prompt
if (OK (AudioDeviceStart (deviceID, audioIOProc)))

Poking around some more:

1.) The default JUCE 6 app wasn’t prompting for microphone because it wasn’t configured to. I was aware of this need and forgot about it. Makes sense.

2.) JUCE doesn’t seem to support handling permission requests?. Apple article can be found here. Oddly the article suggests if you try to open input without permission your app will terminate and a reason will be included in the debug console. In my testing this does not happen. It just silently fails.

3.) One of the issues on my end has been that FRUT/Cmake (or something I did in the process of using it) doesn’t seem to handle Info-app.plist correctly. Internally the project does use it, but instead of Info-app.plist showing up in the Resources dir in Xcode, a different file called Info.plist is there and doesn’t contain any or much of the actual configuration.

For those following along from home, I’ve ended up with the following changes:

1.) Changed my signing configuration to be Automatic with Team specified and Signing Certification set to Development. This changes the behaviour such that the first run after making these changes will still prompt for permissions, but subsequent code changes will not.

2.) Implemented the code from the linked article as a helper method on an existing “mac helper” type class. I call this method on startup and log the result. From that I can inform the user of the authorization status and start the audio system. This will evolve but here’s what it looks like at the moment.

void MacHelper::requestMicrophone(std::function<void (bool canAccess)> & func) {
        
    // Request permission to access the camera and microphone.
    if (@available(macOS 10.14, *)) {
        
        switch ([AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo])
        {
            case AVAuthorizationStatusAuthorized:
            {
                func(true);
                break;
            }
            case AVAuthorizationStatusNotDetermined:
            {
                // The app hasn't yet asked the user for camera access.
                [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio completionHandler:^(BOOL granted) {
                    func(granted);
                }];
                
                break;
                
            }
            case AVAuthorizationStatusDenied:
            {
                // The user has previously denied access.
                func(false);
                break;
                
            }
            case AVAuthorizationStatusRestricted:
            {
                // The user can't grant access due to restrictions.
                func(false);
            }
        }
        
    } else {
        func(true);
    }
    
}

3.) Update/Fix my automated tests to skip initializing the real audio device. The tests were already setup to work with a virtual test device but the base loading code was still hitting a normal default device initialization which is what was triggering this.