No microphone permission prompt on MacOS after upgrade to Qt 6.8.3
-
Hi! I have a bit of a mystery to solve and I am running out of ideas - perhaps someone has faced similar issues or will have any ideas on a possible solution.
My setup:
- Qt 6.8.3 (Desktop)
- MacOS 15.X (Intel) and MacOS 26.X (arm) with XCode 15.6
- local builds and Azure Pipelines builds with Microsoft-hosted agents (macos-latest / macos-15-arm64)
I have recently migrated from Qt 6.5.3 to Qt 6.8.3 and proceeded with application build / deployment as usual and noticed that the new build of my program does not request microphone access permission on application startup. Interestingly, this only happens when the program is an app bundle built in the remote pipeline, but does not occur with local builds.
The pipeline uses the aqtintall tool to get Qt and all required components for each build. I build my application with an additional QMAKE_POST_LINK step and the following configuration (simplified):
macx:CONFIG(release, debug|release) { plist.input = $$PWD/Info_template.plist plist.output = $$PWD/Info.plist QMAKE_SUBSTITUTES += plist QMAKE_INFO_PLIST = $$PWD/Info.plist DEPLOY_ENTITLEMENTS = $${QMAKE_COPY} \ $${PWD}/Entitlements.entitlements $$shell_quote($${DESTDIR}/$${TARGET}.app/Contents/Resources) DEPLOY_COMMAND = $$(QTDIR)/bin/macdeployqt DEPLOY_TARGET = $${TARGET}.app QMAKE_POST_LINK = $${DEPLOY_ENTITLEMENTS} \ && cd $${DESTDIR} \ && $${DEPLOY_COMMAND} $${DEPLOY_TARGET} -appstore-compliant -sign-for-notarization=<ident> -dmg }I do have an Info.plist file generated from a template and it contains the required NSMicrophoneUsageDescription key with a description. I also do deploy the required .entitlements file which has the com.apple.security.device.audio-input key. The application is built remotely, signed with macdeployqt and notarized in a further step.
I am trying to identify the culprit and to do that I have verified various possibilities:
- arm vs Intel builds --> not an issue, happens on both arm and Intel Macs, regardless of the build architecture, whenever the program is build with my pipeline setup
- checked the .plist and .entitlements are correctly deployed with the app bundle --> yes, they are and contain the correct keys
- the CFBundleIdentifier of the application is correct
- inspected the permissions and reset them correctly with tccutil --> I always start the program with no microphone permissions granted and stored in the OS
- verified the code signature of the program --> no issues reported upon inspection
- manual recursive codesign without using the -sign-for-notarization option --> does not fix the problem
- excluded that notarization is the issue --> regardless of whether performed, no microphone permission prompt appears
- built my application on a clean MacOS with exactly the same steps as performed in the pipeline
I have followed whatever was posted in these threads:
Qt application is not requesting microphone access
macOS->Microphone Permission (request permission Message won't popup)
Qt application is not requesting microphone accessI have even tried explicitly requesting microphone permissions in code of a class initialized at application startup, but it does not resolve the issue:
void MyAudioClass::initialize() { QMicrophonePermission microphonePermission; switch (qApp->checkPermission(microphonePermission)) { case Qt::PermissionStatus::Undetermined: qApp->requestPermission(microphonePermission, this, &AudioManager::microphonePermissionGranted); return; case Qt::PermissionStatus::Denied: qDebug() << "Microphone permission denied."; return; case Qt::PermissionStatus::Granted: return; } } void MyAudioClass::microphonePermissionGranted() { qDebug() << "Microphone permission granted."; }Regardless of what I do, when the program is built with my pipeline, the app bundle never prompts me to grant microphone access, while a local build, signed, even notarized works as expected. Due to the way I distribute my program, I am tied to the pipeline logic and I need to continue using it. Perhaps someone from this community has had similar issues or can come up with additional steps for debugging. Any input will be greatly appreciated. Should we find a solution, I will gladly document it here for future generations :)
-
Hi! I have a bit of a mystery to solve and I am running out of ideas - perhaps someone has faced similar issues or will have any ideas on a possible solution.
My setup:
- Qt 6.8.3 (Desktop)
- MacOS 15.X (Intel) and MacOS 26.X (arm) with XCode 15.6
- local builds and Azure Pipelines builds with Microsoft-hosted agents (macos-latest / macos-15-arm64)
I have recently migrated from Qt 6.5.3 to Qt 6.8.3 and proceeded with application build / deployment as usual and noticed that the new build of my program does not request microphone access permission on application startup. Interestingly, this only happens when the program is an app bundle built in the remote pipeline, but does not occur with local builds.
The pipeline uses the aqtintall tool to get Qt and all required components for each build. I build my application with an additional QMAKE_POST_LINK step and the following configuration (simplified):
macx:CONFIG(release, debug|release) { plist.input = $$PWD/Info_template.plist plist.output = $$PWD/Info.plist QMAKE_SUBSTITUTES += plist QMAKE_INFO_PLIST = $$PWD/Info.plist DEPLOY_ENTITLEMENTS = $${QMAKE_COPY} \ $${PWD}/Entitlements.entitlements $$shell_quote($${DESTDIR}/$${TARGET}.app/Contents/Resources) DEPLOY_COMMAND = $$(QTDIR)/bin/macdeployqt DEPLOY_TARGET = $${TARGET}.app QMAKE_POST_LINK = $${DEPLOY_ENTITLEMENTS} \ && cd $${DESTDIR} \ && $${DEPLOY_COMMAND} $${DEPLOY_TARGET} -appstore-compliant -sign-for-notarization=<ident> -dmg }I do have an Info.plist file generated from a template and it contains the required NSMicrophoneUsageDescription key with a description. I also do deploy the required .entitlements file which has the com.apple.security.device.audio-input key. The application is built remotely, signed with macdeployqt and notarized in a further step.
I am trying to identify the culprit and to do that I have verified various possibilities:
- arm vs Intel builds --> not an issue, happens on both arm and Intel Macs, regardless of the build architecture, whenever the program is build with my pipeline setup
- checked the .plist and .entitlements are correctly deployed with the app bundle --> yes, they are and contain the correct keys
- the CFBundleIdentifier of the application is correct
- inspected the permissions and reset them correctly with tccutil --> I always start the program with no microphone permissions granted and stored in the OS
- verified the code signature of the program --> no issues reported upon inspection
- manual recursive codesign without using the -sign-for-notarization option --> does not fix the problem
- excluded that notarization is the issue --> regardless of whether performed, no microphone permission prompt appears
- built my application on a clean MacOS with exactly the same steps as performed in the pipeline
I have followed whatever was posted in these threads:
Qt application is not requesting microphone access
macOS->Microphone Permission (request permission Message won't popup)
Qt application is not requesting microphone accessI have even tried explicitly requesting microphone permissions in code of a class initialized at application startup, but it does not resolve the issue:
void MyAudioClass::initialize() { QMicrophonePermission microphonePermission; switch (qApp->checkPermission(microphonePermission)) { case Qt::PermissionStatus::Undetermined: qApp->requestPermission(microphonePermission, this, &AudioManager::microphonePermissionGranted); return; case Qt::PermissionStatus::Denied: qDebug() << "Microphone permission denied."; return; case Qt::PermissionStatus::Granted: return; } } void MyAudioClass::microphonePermissionGranted() { qDebug() << "Microphone permission granted."; }Regardless of what I do, when the program is built with my pipeline, the app bundle never prompts me to grant microphone access, while a local build, signed, even notarized works as expected. Due to the way I distribute my program, I am tied to the pipeline logic and I need to continue using it. Perhaps someone from this community has had similar issues or can come up with additional steps for debugging. Any input will be greatly appreciated. Should we find a solution, I will gladly document it here for future generations :)
@szumial Can you please try Qt 6.10.1 and use the example project at https://qt-project.atlassian.net/browse/QTBUG-143510 ? (Change QLocationPermission to QMicrophonePermission)
-
@JKSH Before I try, do you have any experience with this permission system? I see a comment in the bug you linked:
The permissions rely on callbacks driven by GCD/CF, so you’ll need to run with the CoreFoundation event dispatcher. Set the QT_EVENT_DISPATCHER_CORE_FOUNDATION env var to 1.
And the discussion mentions having to use QGuiApplication for the permission prompts to appear. I do in fact use it and I have just tried starting my app with the above mentioned env var set. Unfortunately no success.
What worked when testing is a rebuild with Qt 6.5.3 again which works flawlessly with the same codebase.
-
@JKSH Before I try, do you have any experience with this permission system? I see a comment in the bug you linked:
The permissions rely on callbacks driven by GCD/CF, so you’ll need to run with the CoreFoundation event dispatcher. Set the QT_EVENT_DISPATCHER_CORE_FOUNDATION env var to 1.
And the discussion mentions having to use QGuiApplication for the permission prompts to appear. I do in fact use it and I have just tried starting my app with the above mentioned env var set. Unfortunately no success.
What worked when testing is a rebuild with Qt 6.5.3 again which works flawlessly with the same codebase.
@szumial said in No microphone permission prompt on MacOS after upgrade to Qt 6.8.3:
@JKSH Before I try, do you have any experience with this permission system?
I have a limited amount of experience with the permission system on macOS. Not enough to troubleshoot/fix the issue if it still persists with Qt 6.10.1.
I'm just trying to help find the smallest reproducer possible, which could help the relevant folks find a fix more quickly.
I see a comment in the bug you linked:
The permissions rely on callbacks driven by GCD/CF, so you’ll need to run with the CoreFoundation event dispatcher. Set the QT_EVENT_DISPATCHER_CORE_FOUNDATION env var to 1.
And the discussion mentions having to use QGuiApplication for the permission prompts to appear. I do in fact use it and I have just tried starting my app with the above mentioned env var set. Unfortunately no success.
The environment variable is not needed if you have a QGuiApplication.
The report that I linked described issues with
(QCoreApplication AND (QLocationPermission OR QBluetoothPermission)). There are no issues with(QGuiApplication OR QBluetoothPermission), which is why I suggested testing that.What worked when testing is a rebuild with Qt 6.5.3 again which works flawlessly with the same codebase.
It sounds like a regression (which receive more urgent attention from the Qt Company's engineers).
If you can confirm that the simple project works fine with Qt 6.5.3 but not 6.10.1, then you have a good basis for opening a bug report (please include details of how to reproduce your pipeline for investigations)
-
I need to stick to LTS versions, hence 6.8.3 is the Qt version of choice. I have noticed that in my Qt dir, there is a Plugins directory with a subdirectory named permissions. This catalog contains static libraries such as libdarwinmicrophonepermission. Since these are static, macdeployqt will not distribute them with my app bundle. Do you think there might be some linking issue with these?
-
Hi,
The suggestion of testing with 6.10.1 is not that you move your current production to that version, just that you build your application with it to see if the regression is still there.
AFAIK, these static plugins should get linked into your application automatically.
If you are using qmake, you can try setting:QTPLUGINS += permissionsand if cmake:
qt_import_plugins(myapp INCLUDE_BY_TYPE permissions )(mainly taken from the documentation as I haven't had to fiddle with these permissions for a long time).
-
Hi,
The suggestion of testing with 6.10.1 is not that you move your current production to that version, just that you build your application with it to see if the regression is still there.
AFAIK, these static plugins should get linked into your application automatically.
If you are using qmake, you can try setting:QTPLUGINS += permissionsand if cmake:
qt_import_plugins(myapp INCLUDE_BY_TYPE permissions )(mainly taken from the documentation as I haven't had to fiddle with these permissions for a long time).
@SGaist thanks for the reply! I am glad that you somehow always pop up with useful hints in any thread I post :)
I will rebuild it adding QTPLUGINS += permissions in my pipeline. I can test it with Qt 6.10.1 as well, since aqtinstall does list this version as available. I will report back once I have the results.
Let's consider other possible issues I should track:
- the CI uses a provisioning profile from Apple - could it be that 6.8.3 needs it somehow updated?
- the app bundle built with 6.8.3 comes with frameworks which include Info.plist files, but also PrivacyInfo.xcprivacy files, while 6.5.3 does not distribute them - I don't use one for my app, but unless I am wrong (because locally-built / VM-build apps work fine), it should not affect the permissions.
- I am explicitly using the native multimedia backend (darwin) and I opt to not distribute ffmpeg with my app (old compatibility reasons) - don't know if that could affect if (it does not with 6.5.3)
Edit:
Testing with Qt 6.10.1 proved the microphone permissions is not requested, same as with 6.8.3.
Adding QTPLUGINS += permissions does not change anything, microphone permission prompt still missing.I have browsed the documentation on Qt 6.6 changes in the Multimedia module and found out the following:
The Qt Multimedia library no longer requests audio or video permissions, but only checks if they are provided or not. The client applications must request the permissions using the C++ or QML permissions API.
I came to a conclusion that my app works when built with Qt 6.5.3 because it is the audio input configuration which touches the microphone at startup which automatically requests microphone permissions and shows the prompt. Since the Qt 6.6 change, there is need to use the permissions API. Hence I have coded the following logic called in the constructor of my audio management class:
void AudioClass::requestMicrophonePermission() { QMicrophonePermission microphonePermission; switch (qApp->checkPermission(microphonePermission)) { case Qt::PermissionStatus::Undetermined: qApp->requestPermission(microphonePermission, this, &AudioManager::microphonePermissionGranted); return; case Qt::PermissionStatus::Denied: qDebug() << "Microphone permission denied."; return; case Qt::PermissionStatus::Granted: return; } } void AudioClass::microphonePermissionGranted() { qDebug() << "Microphone permission granted."; }I have tried calling it both before and after initializing the audio input in Qt 6.8.3 and unfortunately it never displays the microphone permission prompt on MacOS. Since using QPermissions did not fix the issue I have resorted to integrating a small objective-C++ helper into my application and it does work when I opt to use the following native imports:
#import <AppKit/AppKit.h> #import <AVFoundation/AVFoundation.h> #import <ApplicationServices/ApplicationServices.h> #import <CoreGraphics/CoreGraphics.h>@SGaist do you think it is possible there is a bug in the permissions API of Qt that does not allow MacOS's TCC to handle permission prompts correctly?