diff options
author | Ivan Solovev <ivan.solovev@qt.io> | 2023-04-21 16:17:36 +0200 |
---|---|---|
committer | Ivan Solovev <ivan.solovev@qt.io> | 2023-05-10 09:58:54 +0200 |
commit | 697f2dbb559966a0f7aeccdb5a905da39ebcfab6 (patch) | |
tree | 6ddc82c8a72fa9a47e6dd96f986cc48d68eed181 | |
parent | f5ca6f089ff19906184d788e78aecbf52de6ac8b (diff) |
CoreLocation plugin: introduce RequestAlwaysPermission parameter
Previously we were using NSLocationAlwaysAndWhenInUseUsageDescription
and NSLocationWhenInUseUsageDescription to distinguish the level of
permission that we want to request.
However, Apple now always requires *both* entries to present in the
Info.plist file.
[ChangeLog][Important Behavior Changes][Apple] Introduce an explicit
RequestAlwaysPermission parameter to the corelocation plugin.
When specified and set to true, this parameters enables the "Always"
location request. When not specified or set to false, only the
"When In Use" location permission is requested. By default this
parameter is not specified.
This patch is only applicable to Qt 6.5 and earlier versions, because
starting from Qt 6.6 the Qt Positioning library will no longer
request the permissions. Instead the new QPermission API must be
used at the user application level.
Fixes: QTBUG-109359
Pick-to: 6.2 5.15
Change-Id: Ib35f578a6459e84d2ff29c79416ae5ee9f104cc8
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Juha Vuolle <juha.vuolle@qt.io>
Reviewed-by: Alex Blasche <alexander.blasche@qt.io>
5 files changed, 123 insertions, 13 deletions
diff --git a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm index 173fdf2e..87972dfc 100644 --- a/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm +++ b/src/plugins/position/corelocation/qgeopositioninfosource_cl.mm @@ -7,6 +7,7 @@ #include <QtCore/qglobal.h> #include <QtCore/private/qglobal_p.h> #include <QtCore/qtimezone.h> +#include <QtCore/qvariantmap.h> #include "qgeopositioninfosource_cl_p.h" @@ -82,7 +83,9 @@ QT_BEGIN_NAMESPACE -QGeoPositionInfoSourceCL::QGeoPositionInfoSourceCL(QObject *parent) +static const auto alwaysPermissionKey = QStringLiteral("RequestAlwaysPermission"); + +QGeoPositionInfoSourceCL::QGeoPositionInfoSourceCL(const QVariantMap ¶meters, QObject *parent) : QGeoPositionInfoSource(parent), m_locationManager(0), m_updatesWanted(false), @@ -90,6 +93,7 @@ QGeoPositionInfoSourceCL::QGeoPositionInfoSourceCL(QObject *parent) m_updateTimeout(0), m_positionError(QGeoPositionInfoSource::NoError) { + m_requestAlwaysPermission = parameters.value(alwaysPermissionKey, false).toBool(); } QGeoPositionInfoSourceCL::~QGeoPositionInfoSourceCL() @@ -137,19 +141,30 @@ bool QGeoPositionInfoSourceCL::enableLocationManager() m_locationManager.delegate = [[PositionLocationDelegate alloc] initWithInfoSource:this]; } - // -requestAlwaysAuthorization requires both NSLocationAlwaysAndWhenInUseUsageDescription and - // NSLocationWhenInUseUsageDescription entries present in Info.plist (otherwise, - // while probably a noop, the call generates a warning). - // -requestWhenInUseAuthorization only requires NSLocationWhenInUseUsageDescription - // entry in Info.plist + // According to QTBUG-109359, Apple now requires both NSLocationWhenInUseUsageDescription + // and NSLocationAlwaysAndWhenInUseUsageDescription entries to present in Info.plist + // if the binary has capabilities to request both (symbols for that are present). + // This means that we cannot use the presence of permission keys to decide + // which authorization type to request (as both need to be present). + // Use an explicit plugin parameter instead. #ifdef Q_OS_IOS NSDictionary<NSString *, id> *infoDict = NSBundle.mainBundle.infoDictionary; const bool hasAlwaysUseUsage = !![infoDict objectForKey:@"NSLocationAlwaysAndWhenInUseUsageDescription"]; const bool hasWhenInUseUsage = !![infoDict objectForKey:@"NSLocationWhenInUseUsageDescription"]; - if (hasAlwaysUseUsage && hasWhenInUseUsage) - [m_locationManager requestAlwaysAuthorization]; - else if (hasWhenInUseUsage) + if (hasAlwaysUseUsage && hasWhenInUseUsage) { + if (m_requestAlwaysPermission) + [m_locationManager requestAlwaysAuthorization]; + else + [m_locationManager requestWhenInUseAuthorization]; + } else if (hasWhenInUseUsage) { + qWarning("Requesting \"When In Use\" location permission in fallback mode. " + "Your application is missing the NSLocationAlwaysAndWhenInUseUsageDescription " + "entry in the Info.plist file. It will be impossible to publish the application " + "into App Store without this entry. Please add both " + "NSLocationWhenInUseUsageDescription and " + "NSLocationAlwaysAndWhenInUseUsageDescription to your Info.plist file."); [m_locationManager requestWhenInUseAuthorization]; + } #endif // Q_OS_IOS return (m_locationManager != nullptr); diff --git a/src/plugins/position/corelocation/qgeopositioninfosource_cl_p.h b/src/plugins/position/corelocation/qgeopositioninfosource_cl_p.h index f49951d5..7e9774be 100644 --- a/src/plugins/position/corelocation/qgeopositioninfosource_cl_p.h +++ b/src/plugins/position/corelocation/qgeopositioninfosource_cl_p.h @@ -26,7 +26,7 @@ class QGeoPositionInfoSourceCL : public QGeoPositionInfoSource { Q_OBJECT public: - QGeoPositionInfoSourceCL(QObject *parent = 0); + QGeoPositionInfoSourceCL(const QVariantMap ¶meters, QObject *parent = 0); ~QGeoPositionInfoSourceCL(); QGeoPositionInfo lastKnownPosition(bool fromSatellitePositioningMethodsOnly = false) const override; @@ -57,6 +57,7 @@ private: Q_DISABLE_COPY(QGeoPositionInfoSourceCL); CLLocationManager *m_locationManager; bool m_updatesWanted; + bool m_requestAlwaysPermission = false; QGeoPositionInfo m_lastUpdate; diff --git a/src/plugins/position/corelocation/qgeopositioninfosourcefactory_cl.mm b/src/plugins/position/corelocation/qgeopositioninfosourcefactory_cl.mm index 0979422c..49d2c977 100644 --- a/src/plugins/position/corelocation/qgeopositioninfosourcefactory_cl.mm +++ b/src/plugins/position/corelocation/qgeopositioninfosourcefactory_cl.mm @@ -6,8 +6,7 @@ QGeoPositionInfoSource *QGeoPositionInfoSourceFactoryCL::positionInfoSource(QObject *parent, const QVariantMap ¶meters) { - Q_UNUSED(parameters) - return new QGeoPositionInfoSourceCL(parent); + return new QGeoPositionInfoSourceCL(parameters, parent); } QGeoSatelliteInfoSource *QGeoPositionInfoSourceFactoryCL::satelliteInfoSource(QObject *parent, const QVariantMap ¶meters) diff --git a/src/positioning/doc/src/plugins/corelocation.qdoc b/src/positioning/doc/src/plugins/corelocation.qdoc new file mode 100644 index 00000000..32e44382 --- /dev/null +++ b/src/positioning/doc/src/plugins/corelocation.qdoc @@ -0,0 +1,93 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! +\page position-plugin-corelocation.html +\title Qt Positioning Core Location plugin +\ingroup QtPositioning-plugins + +\brief Provides positioning information on Apple platforms + +\section1 Overview + +The plugin wraps iOS and macOS positioning subsystems. It is only available +on Apple platforms that support corelocation. The plugin provides only +positioning information. + +This plugin can be loaded by using the provider name \b corelocation. + +\section1 Parameters + +The following table lists parameters that \e can be passed to the corelocation +plugin. + +\table +\header + \li Parameter + \li Description +\row + \li RequestAlwaysPermission + \li Ask permissions for using location not only while using the + application, but also in background. The parameter is a \c bool, so + it accepts either \c {true} or \c {false}. If the parameter is not + specified, it is considered to be \c {false}. +\endtable + +On iOS, the application can ask for two levels of location permissions: + +\list + \li \b {When In Use} - makes location updates available only when someone + uses your app. + \li \b {Always} - makes location updates available at any time, and lets + the system launch your app quietly to handle some updates. +\endlist + +By default, only the \b {When In Use} permission is requested. +The \c RequestAlwaysPermission parameter is used to explicitly reqeust for +\b {Always} permission. + +\section1 Position source usage example + +The following examples show how to create a \b corelocation PositionSource +using different permission levels. + +\section2 QML + +\code +// default - When In Use permission. +PositionSource { + name: "corelocation" +} + +// RequestAlwaysPermission = false. Same as default. +PositionSource { + name: "corelocation" + PluginParameter { name: "RequestAlwaysPermission"; value: false } +} + +// RequestAlwaysPermission = true. Request Always permission. +PositionSource { + name: "corelocation" + PluginParameter { name: "RequestAlwaysPermission"; value: true } +} +\endcode + +\section2 C++ + +\code +// default - When In Use permission. +QGeoPositionInfoSource *defaultSource + = QGeoPositionInfoSource::createSource("corelocation", this); + +// RequestAlwaysPermission = false. Same as default. +params["RequestAlwaysPermission"] = false; +QGeoPositionInfoSource *whenInUseSource + = QGeoPositionInfoSource::createSource("corelocation", params, this); + +// RequestAlwaysPermission = true. Request Always permission. +params["RequestAlwaysPermission"] = true; +QGeoPositionInfoSource *alwaysSource + = QGeoPositionInfoSource::createSource("corelocation", params, this); +\endcode + +*/ diff --git a/src/positioning/doc/src/qtpositioning-plugins.qdoc b/src/positioning/doc/src/qtpositioning-plugins.qdoc index f650e3c3..24c62afb 100644 --- a/src/positioning/doc/src/qtpositioning-plugins.qdoc +++ b/src/positioning/doc/src/qtpositioning-plugins.qdoc @@ -18,7 +18,9 @@ Some plugins already ship with Qt. These are: \li Wraps Android positioning subsystem. Available only on Android. \row \li \b corelocation - \li Wraps iOS and macOS positioning subsystems. Available only on Apple platforms supporting corelocation. + \li A \l {Qt Positioning Core Location plugin}{Core Location} backend + wraps iOS and macOS positioning subsystems. Available only on Apple + platforms supporting corelocation. \row \li \b geoclue2 \li A \l {Qt Positioning GeoClue v2 plugin}{GeoClue v2} backend that |