8#include <CoreLocation/CoreLocation.h>
10@interface QDarwinLocationPermissionHandler () <CLLocationManagerDelegate>
11@property (nonatomic, retain) CLLocationManager *manager;
14Q_STATIC_LOGGING_CATEGORY(lcLocationPermission,
"qt.permissions.location");
18void warmUpLocationServices()
28 qCDebug(lcLocationPermission) <<
"Warming up location services";
29 [[CLLocationManager
new] release];
32Q_CONSTRUCTOR_FUNCTION(warmUpLocationServices);
34struct PermissionRequest
36 QPermission permission;
37 PermissionCallback callback;
42@implementation QDarwinLocationPermissionHandler {
43 std::deque<PermissionRequest> m_requests;
48 if ((self = [super init])) {
60- (Qt::PermissionStatus)checkPermission:(QPermission)permission
62 const auto locationPermission = *permission.value<QLocationPermission>();
64 auto status = [self authorizationStatus:locationPermission];
65 if (status != Qt::PermissionStatus::Granted)
68 return [self accuracyAuthorization:locationPermission];
71- (Qt::PermissionStatus)authorizationStatus:(QLocationPermission)permission
73 NSString *bundleIdentifier = NSBundle.mainBundle.bundleIdentifier;
74 if (!bundleIdentifier || !bundleIdentifier.length) {
75 qCWarning(lcLocationPermission) <<
"Missing bundle identifier"
76 <<
"in Info.plist. Can not use location permissions.";
77 return Qt::PermissionStatus::Denied;
80#if defined(Q_OS_VISIONOS)
81 if (permission.availability() == QLocationPermission::Always)
82 return Qt::PermissionStatus::Denied;
85 auto status = [self authorizationStatus];
87 case kCLAuthorizationStatusRestricted:
88 case kCLAuthorizationStatusDenied:
89 return Qt::PermissionStatus::Denied;
90 case kCLAuthorizationStatusNotDetermined:
91 return Qt::PermissionStatus::Undetermined;
92#if !defined(Q_OS_VISIONOS)
93 case kCLAuthorizationStatusAuthorizedAlways:
94 return Qt::PermissionStatus::Granted;
96#if defined(Q_OS_IOS) || defined(Q_OS_VISIONOS)
97 case kCLAuthorizationStatusAuthorizedWhenInUse:
98 if (permission.availability() == QLocationPermission::Always)
99 return Qt::PermissionStatus::Denied;
100 return Qt::PermissionStatus::Granted;
104 qCWarning(lcPermissions) <<
"Unknown permission status" << status <<
"detected in" << self;
105 return Qt::PermissionStatus::Denied;
108- (CLAuthorizationStatus)authorizationStatus
111 return self.manager.authorizationStatus;
113 return QT_IGNORE_DEPRECATIONS(CLLocationManager.authorizationStatus);
116- (Qt::PermissionStatus)accuracyAuthorization:(QLocationPermission)permission
118 auto status = self.manager.accuracyAuthorization;
121 case CLAccuracyAuthorizationFullAccuracy:
122 return Qt::PermissionStatus::Granted;
123 case CLAccuracyAuthorizationReducedAccuracy:
124 if (permission.accuracy() == QLocationPermission::Approximate)
125 return Qt::PermissionStatus::Granted;
127 return Qt::PermissionStatus::Denied;
130 qCWarning(lcPermissions) <<
"Unknown accuracy status" << status <<
"detected in" << self;
131 return Qt::PermissionStatus::Denied;
134- (
QStringList)usageDescriptionsFor:(QPermission)permission
136#if defined(Q_OS_MACOS)
137 return {
"NSLocationUsageDescription" };
139 QStringList usageDescriptions = {
"NSLocationWhenInUseUsageDescription" };
140 const auto locationPermission = *permission.value<QLocationPermission>();
141 if (locationPermission.availability() == QLocationPermission::Always)
142 usageDescriptions <<
"NSLocationAlwaysAndWhenInUseUsageDescription";
143 return usageDescriptions;
147- (
void)requestPermission:(QPermission)permission withCallback:(PermissionCallback)callback
149 const bool requestAlreadyInFlight = !m_requests.empty();
151 m_requests.push_back({ permission, callback });
153 if (requestAlreadyInFlight) {
154 qCDebug(lcLocationPermission).nospace() <<
"Already processing "
155 << m_requests.front().permission <<
". Deferring request";
157 [self requestQueuedPermission];
161- (
void)requestQueuedPermission
163 Q_ASSERT(!m_requests.empty());
164 const auto permission = m_requests.front().permission;
166 qCDebug(lcLocationPermission) <<
"Requesting" << permission;
169 self.manager = [[CLLocationManager
new] autorelease];
170 self.manager.delegate = self;
173 const auto locationPermission = *permission.value<QLocationPermission>();
174 switch (locationPermission.availability()) {
175 case QLocationPermission::WhenInUse:
178 switch ([self authorizationStatus]) {
179 case kCLAuthorizationStatusNotDetermined:
180 [self.manager requestWhenInUseAuthorization];
183 [self deliverResult];
186 case QLocationPermission::Always:
187#if defined(Q_OS_VISIONOS)
188 [self deliverResult];
193 switch ([self authorizationStatus]) {
194 case kCLAuthorizationStatusNotDetermined:
195 [self.manager requestAlwaysAuthorization];
198 case kCLAuthorizationStatusAuthorizedWhenInUse:
204 qCWarning(lcLocationPermission) <<
"QLocationPermission::WhenInUse"
205 <<
"can not be upgraded to QLocationPermission::Always on iOS."
206 <<
"Please request QLocationPermission::Always directly.";
210 [self deliverResult];
217- (
void)locationManager:(CLLocationManager *)manager didChangeAuthorizationStatus:(CLAuthorizationStatus)status
219 qCDebug(lcLocationPermission) <<
"Processing authorization"
220 <<
"update with status" << status;
222 if (m_requests.empty()) {
223 qCDebug(lcLocationPermission) <<
"No requests in flight. Ignoring.";
227 if (status == kCLAuthorizationStatusNotDetermined) {
235 qCDebug(lcLocationPermission) <<
"Ignoring delegate callback"
236 <<
"with status kCLAuthorizationStatusNotDetermined";
240 [self deliverResult];
245 auto request = m_requests.front();
246 m_requests.pop_front();
248 auto status = [self checkPermission:request.permission];
249 qCDebug(lcLocationPermission) <<
"Result for"
250 << request.permission <<
"was" << status;
252 request.callback(status);
254 if (!m_requests.empty()) {
255 qCDebug(lcLocationPermission) <<
"Still have"
256 << m_requests.size() <<
"deferred request(s)";
257 [self requestQueuedPermission];
263#include "moc_qdarwinpermissionplugin_p_p.cpp"
QList< QString > QStringList
Constructs a string list that contains the given string, str.