App Tracking Transparency Framework for PyObjC

12.1 · active · verified Tue Apr 14

pyobjc-framework-AppTrackingTransparency provides Python wrappers for Apple's App Tracking Transparency framework on macOS. This framework enables applications to request user authorization for tracking across apps and websites, a critical privacy feature introduced in iOS 14 and macOS 11. It is part of the larger PyObjC project, which offers Python bindings for many macOS (Cocoa) frameworks. The current version is 12.1, with releases typically aligning with macOS SDK updates and Python compatibility.

Warnings

Install

Imports

Quickstart

This example demonstrates how to request app tracking authorization and check its status. For the authorization prompt to appear, you *must* add the `NSUserTrackingUsageDescription` key with a purpose string to your application's `Info.plist` file (an Xcode project setting, not Python code). The completion handler for `requestTrackingAuthorization_` is asynchronous and requires a running `NSRunLoop` to execute.

import objc
from Foundation import NSObject, NSLog, NSRunLoop, NSDefaultRunLoopMode, objc_object
from AppTrackingTransparency import ATTrackingManager, ATTrackingManagerAuthorizationStatus

class TrackingDelegate(NSObject):
    def init(self):
        self = objc.super(TrackingDelegate, self).init()
        if self is None: return None
        return self

    def requestTrackingPermission(self):
        current_status = ATTrackingManager.trackingAuthorizationStatus()
        NSLog(f"Initial tracking status: {current_status}")

        if current_status == ATTrackingManagerAuthorizationStatus.notDetermined:
            NSLog("Requesting tracking authorization...")
            # Objective-C method with completion handler translates to PyObjC with underscore suffix
            ATTrackingManager.requestTrackingAuthorization_(self.trackingAuthorizationCompletionHandler_)
        else:
            NSLog("Authorization already determined or restricted.")
            self.checkTrackingStatus()

    def trackingAuthorizationCompletionHandler_(self, status: ATTrackingManagerAuthorizationStatus) -> None:
        # This handler might not be called on the main thread; dispatch UI updates if any.
        NSLog(f"Tracking authorization completion handler called with status: {status}")
        self.checkTrackingStatus()

    def checkTrackingStatus(self):
        status = ATTrackingManager.trackingAuthorizationStatus()
        if status == ATTrackingManagerAuthorizationStatus.authorized:
            NSLog("Tracking authorized!")
        elif status == ATTrackingManagerAuthorizationStatus.denied:
            NSLog("Tracking denied.")
        elif status == ATTrackingManagerAuthorizationStatus.notDetermined:
            NSLog("Tracking not determined.")
        elif status == ATTrackingManagerAuthorizationStatus.restricted:
            NSLog("Tracking restricted by parental controls or MDM.")
        else:
            NSLog("Unknown tracking status.")

def main():
    delegate = TrackingDelegate.alloc().init()
    delegate.requestTrackingPermission()

    # For the completion handler to be called, an NSRunLoop must be active.
    # In a full AppKit application, this is handled automatically.
    # For a console script, run a short loop.
    NSLog("Running runloop for 5 seconds to allow async callback...")
    NSRunLoop.currentRunLoop().runUntilDate_(objc.NSTimeIntervalToBeDateTime(objc.current_time() + 5.0))
    NSLog("Runloop finished.")

if __name__ == '__main__':
    main()

view raw JSON →