A similar problem is mentioned in the [Apple Developer Forum](https://developer.apple.com/forums/thread/727984).
The way I found is to use `AXIsProcessTrusted` or `AXIsProcessTrustedWithOptions` as a queued callback *and* a minimum of 5-10ms delay.
This will run later on the main thread, but not block it waiting.
```obj-c
// Add monitor to the system list of apps with accessibility permissions.
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
selector:@selector(onAccessibilitySettingsChanged:)
name:@"com.apple.accessibility.api"
object:nil];
- (void) onAccessibilitySettingsChanged:(NSNotification*)note {
// Note 1: The notification does not specify what changed, it could be an unrelated app.
// Note 2: Directly querying returns an old result, therefore enqueue the check
// *and* add a slight delay. Empirically, both are needed.
// (sleeping the main thread for half a sec does not work and makes irresponsiveness)
// Note 3: consider dispatching a second check after a half a second to really
// confirm things. 10ms works most times, but clicking the setting fast will not.
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)( 10 * MSEC_PER_SEC)),
dispatch_get_main_queue(),
^{ /* read AXIsProcessTrusted() here */ }
);
}
```
I believe this happens because the app is not considered to be "the same".
It is really confusing, because in the settings it has the same name, same icon, permission looks on, and even turning it off and on again won't work (while deleting does). This leads both developers and users to rebuild and turn apps and computers off and on again in increasingly mystical ways :(
**From a user standpoint:**
1\. delete the app from the system permissions list. This ensures a clean slate.
(`tccutil reset SERVICE [BUNDLE_ID]` may not be enough)
2\. restart the app, which should prompt for the permission again.
3\. click to enable the permission in the settings list.
Now it's on, but depending on how the app is coded, it may not query for the setting again and have a cached value that it's off, so things may still not work.
4\. restart the app again.
**For developers not to have the app losing permissions while developing:**
1\. ensure there is a `Team` selected in Xcode. (generates a stable ID for `DEVELOPMENT_TEAM`)
2\. set `Signing Certificate` to `Development`, *not* Run Locally. (sets `CODE_SIGN_IDENTITY` to `Apple Development`)
This should be enough for rebuild and re-run to work locally.
Be aware that changing Team ID, Bundle ID, provisioning profile or certificates will cause the ID used in the permissions to change and people will need to delete the old setting and give permission again.
It would be lovely to see the ID used for the settings somewhere, but I don't know how.
[Here is more information from Apple about different kinds of IDs](https://developer.apple.com/forums/thread/811970)
My understanding is that Apple generates some kind of identifier for the app during the build & code-signing process. This is different than a signed build where a code change would rightfully invalidate the previous signing, since... well it changed the code :)
The settings identifier should be more stable across builds, including for end-users to receive an update for the app and not have to give it permission again, as long as it is "the same app". (I think!)
Changes to the app "identity" (bundle ID, team ID) will make it "not the same" for the settings, even when it visually looks the same.
More fun reading:
[Apple Forum - Code Signing Resources](https://developer.apple.com/forums/thread/707080)
**Good practice for the developed app:**
1. Use `AXIsProcessTrusted` or `AXIsProcessTrustedWithOptions` with `kAXTrustedCheckOptionPrompt` to check if the app has permissions with or without prompting the user with a dialog in case it has not.
The function returns immediately, it doesn't wait for users to click the settings.
The user may give/revoke permissions at any time, with the app running or not.
3. Install an observer for permission changes *and* read the value enqueued and with a slight timer delay.
[SO thread](https://stackoverflow.com/questions/63271532/call-to-axisprocesstrustedwithoptions-does-not-work-after-change-setting-value), [bug mentioned in Apple forum](https://developer.apple.com/forums/thread/727984)
```obj-c
// Add monitor to the system list of apps with accessibility permissions.
[[NSDistributedNotificationCenter defaultCenter] addObserver:self
selector:@selector(onAccessibilitySettingsChanged:)
name:@"com.apple.accessibility.api"
object:nil];
- (void) onAccessibilitySettingsChanged:(NSNotification*)note {
// Note 1: The notification does not specify what changed, it could be an unrelated app.
// Note 2: Directly querying returns an old result, therefore enqueue the check
// *and* add a slight delay. Empirically, both are needed.
// (sleeping the main thread for half a sec does not work and makes irresponsiveness)
// Note 3: consider dispatching a second check after a half a second to really
// confirm things. 10ms works most times, but clicking the setting fast will not.
dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)( 10 * MSEC_PER_SEC)),
dispatch_get_main_queue(),
^{ /* read AXIsProcessTrusted() here */ }
);
}
```