Many features of today’s devices and operating systems can have significant privacy, security, and performance implications, if misused. As a result, it’s increasingly common for platforms to require explicit consent from the user before accessing these features.
With Qt 6.5, we’ve added cross platform permission APIs, that allow the application to check or request permission for such features, with backend implementations for macOS, iOS, Android, and WebAssembly.
Usage
A feature that commonly requires user consent is access to the microphone of the device. An application for recording voice memos would perhaps look something like this initially:
void VoiceMemoWidget::onRecordingInitiated() { m_microphone->startRecording(); }
To ensure this application works well on platforms that require user consent for microphone access we would extend it like this:
void VoiceMemoWidget::onRecordingInitiated() { #if QT_CONFIG(permissions) QMicrophonePermission microphonePermission; switch (qApp->checkPermission(microphonePermission)) { case Qt::PermissionStatus::Undetermined: qApp->requestPermission(microphonePermission, this &VoiceMemoWidget::onRecordingInitiated); return; case Qt::PermissionStatus::Denied: m_permissionInstructionsDialog->show(); return; case Qt::PermissionStatus::Granted: break; // Proceed } #endif m_microphone->startRecording(); }
We first check if we already know the status of the microphone permission. If we don’t we initiate a permission request to determine the current status, which will potentially ask the user for consent. We connect the result of the request to the slot we’re already in, so that we get another chance at evaluating the permission status.
Once the permission status is known, either because we had been granted or denied permission at an earlier time, or after getting the result back from the request we just initiated, we redirect the user to a dialog explaining why we can not record voice memos at this time (if the permission was denied), or proceed to using the microphone (if permission was granted).
The use of the QT_CONFIG(permissions)
macro ensures that the code will work as before on platforms where permissions are not available.
Declaring Permissions
Some platforms require that the permissions you request are declared up front at build time.
On Apple platforms each permission you request must be accompanied by a so called usage description string in the application’s Info.plist
file. For example:
<key>NSMicrophoneUsageDescription</key> <string>The microphone is used to record voice memos.</string>
While on Android the permission you request must be accompanied by a uses-permission
entry in the application’s AndroidManifest.xml
file. For example:
<manifest ...> <uses-permission android:name="android.permission.RECORD_AUDIO"/> </manifest>
The relevant permission requirements are described in the documentation for each permission type.
Available Permissions
The following permissions types are available in Qt 6.5:
- QBluetoothPermission to access Bluetooth peripherals
- QCalendarPermission to access the user’s calendar
- QContactsPermission to access the user’s contacts
- QCameraPermission to access the camera for taking pictures or video
- QMicrophonePermission to access the microphone for monitoring or recording sound
- QLocationPermission to access the user’s location
Best Practices
To ensure the best possible user experience for the end user we recommend adopting the following best practices for managing application permissions:
- Request the minimal set of permissions needed. For example, if you only need access to the microphone, do not request camera permission just in case. Use the properties of individual permission types to limit the permission scope even further, for example QContactsPermission::setReadOnly() to request read only access.
- Request permissions in response to specific actions by the user. For example, defer requesting microphone permission until the user presses the button to record audio. Associating the permission request to a specific action gives the user a clearer context of why the permission is needed. Do not request all needed permission on startup.
- Present extra context and explanation if needed. Sometimes the action by the user is not enough context. Consider presenting an explanation-dialog after the user has initiated the action, but before requesting the permission, so the user is aware of what’s about to happen when the system permission dialog subsequently pops up.
- Be transparent and explicit about why permissions are needed. In explanation dialogs and usage descriptions, be transparent about why the particular permission is needed for your application to provide a specific feature, so users can make informed decisions.
- Account for denied permissions. The permissions you request may be denied for various reasons. You should always account for this situation, by gracefully degrading the experience of your application, and presenting clear explanations the user about the situation.
- Never request permissions from a library. The request of permissions should be done as close as possible to the user, where the information needed to make good decisions on the points above is available. Libraries can check permissions, to ensure they have the prerequisites for doing their work, but if the permission is undetermined or denied this should be reflected through the library’s API, so that the application in turn can request the necessary permissions.
Future work
For now this API are C++ only, but we’re investigating QML APIs that provide the same functionality. We are also looking into adding more permission types down the line.
Please try these APIs out in the Qt 6.5 betas, and let us know of any issues you might encounter!