Closed jwoodmansey closed 10 months ago
This indeed makes no sense, as denied
is returned when the status is ATTrackingManagerAuthorizationStatusNotDetermined
, and it should not be possible after a request.
My colleague has patched this, which seems to bring our analytics back in line with what we'd expect. After this patch we are now back to only getting blocked
or granted
returned from request
, at the ratio we would expect. I'm not entirely how this fixed it, but sharing their code below...
diff --git a/node_modules/react-native-permissions/ios/AppTrackingTransparency/RNPermissionHandlerAppTrackingTransparency.m b/node_modules/react-native-permissions/ios/AppTrackingTransparency/RNPermissionHandlerAppTrackingTransparency.m
index c492b3f..46f3e8b 100644
--- a/node_modules/react-native-permissions/ios/AppTrackingTransparency/RNPermissionHandlerAppTrackingTransparency.m
+++ b/node_modules/react-native-permissions/ios/AppTrackingTransparency/RNPermissionHandlerAppTrackingTransparency.m
@@ -50,13 +50,22 @@ - (void)requestWithResolver:(void (^ _Nonnull)(RNPermissionStatus))resolve
}
if ([[UIApplication sharedApplication] applicationState] == UIApplicationStateActive) {
- [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(__unused ATTrackingManagerAuthorizationStatus status) {
- [self checkWithResolver:resolve rejecter:reject];
+
+ [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
+ switch (status) {
+ case ATTrackingManagerAuthorizationStatusNotDetermined:
+ return resolve(RNPermissionStatusNotDetermined);
+ case ATTrackingManagerAuthorizationStatusRestricted:
+ return resolve(RNPermissionStatusRestricted);
+ case ATTrackingManagerAuthorizationStatusDenied:
+ return resolve(RNPermissionStatusDenied);
+ case ATTrackingManagerAuthorizationStatusAuthorized:
+ return resolve(RNPermissionStatusAuthorized);
+ }
}];
} else {
_resolve = resolve;
_reject = reject;
-
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onApplicationDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
@@ -71,10 +80,18 @@ - (void)onApplicationDidBecomeActive:(__unused NSNotification *)notification {
[[NSNotificationCenter defaultCenter] removeObserver:self
name:UIApplicationDidBecomeActiveNotification
object:nil];
-
if (@available(iOS 14.0, *)) {
- [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(__unused ATTrackingManagerAuthorizationStatus status) {
- [self checkWithResolver:self->_resolve rejecter:self->_reject];
+ [ATTrackingManager requestTrackingAuthorizationWithCompletionHandler:^(ATTrackingManagerAuthorizationStatus status) {
+ switch (status) {
+ case ATTrackingManagerAuthorizationStatusNotDetermined:
+ return self->_resolve(RNPermissionStatusNotDetermined);
+ case ATTrackingManagerAuthorizationStatusRestricted:
+ return self->_resolve(RNPermissionStatusRestricted);
+ case ATTrackingManagerAuthorizationStatusDenied:
+ return self->_resolve(RNPermissionStatusDenied);
+ case ATTrackingManagerAuthorizationStatusAuthorized:
+ return self->_resolve(RNPermissionStatusAuthorized);
+ }
}];
}
}
For that patch to be effective, either the "ios14 is not available" branch is taken in checkWithResolver
resulting in nothing but authorized or denied:
or the ios14-is-available branch is taken and the dynamic call for tracking status is somehow returning something different then the status sent in via the callback sent in with the request?
Here's the dynamic callback: https://github.com/zoontek/react-native-permissions/blob/63b695a609c1fb00b7611d98e7b4658e816d8788/ios/AppTrackingTransparency/RNPermissionHandlerAppTrackingTransparency.m#L26
...because the result of that callback is doing the same switch you've effectively inlined in the callback definition
It would be very interesting to know which of the ios14-is-available conditional branches were used and to know if the dynamic call for status was somehow different then the status provided as a parameter to the callback.
You have a working solution which you likely don't want to mess with and possibly cause a regression, but it could be possible to maybe call check
instead of request
in addition to see what check says - emulating the dynamic call. Is it safe to assume ios14-is-available is returning the correct value? I think so
That all seems unexpected though, I'm pretty confused how this is happening, doesn't seem like it should unless the request status vs the dynamic check status is racy somehow in ios17 with check providing a stale value for some unknown amount of time while the callback status is fresh 🤷
Closed as v4.0.0 is out.
Bug summary
We are calling
request(PERMISSIONS.IOS.APP_TRACKING_TRANSPARENCY)
and immediately logging the result for tracking purposes. Since iOS 17 we are seeing a large increase in these logs returning denied. According to the flowchart in this repo the request call should only return granted/blocked?Library version
3.10.1
Environment info
Steps to reproduce
Reproducible sample code