PyObjC ExternalAccessory Framework
PyObjC is a bridge between Python and the Objective-C runtime, allowing Python scripts to interact with macOS frameworks. The `pyobjc-framework-externalaccessory` package provides Python wrappers for the `ExternalAccessory` framework on macOS, enabling interaction with MFi (Made for iOS) accessories. The current version is 12.1, with releases tightly coupled to macOS SDK updates and Python version support cycles.
Warnings
- breaking PyObjC aggressively drops support for older Python versions. Version 12.0 dropped Python 3.9, and version 11.0 dropped Python 3.8. Ensure your Python environment meets the `requires_python` specification (currently `>=3.10` for v12.1).
- breaking The core bridge's Automatic Reference Counting (ARC) behavior for initializer methods (those in the 'init' family) was updated in `v11.1` to align with `clang`'s documentation. This means PyObjC now correctly models that `init` methods steal a reference to `self` and return a new reference, potentially affecting custom `init` methods in Python subclasses.
- gotcha PyObjC is a macOS-specific library. It binds directly to Objective-C frameworks available only on Apple's macOS operating system. Attempts to install or run PyObjC code on Linux, Windows, or other platforms will fail with import errors or linker issues.
- gotcha Behavior around `__init__` and `__new__` methods in Python subclasses of Objective-C objects changed in `v10.3` and was partially reverted in `v10.3.1`. While `__init__` can now be used when a user implements `__new__`, code relying on the PyObjC-provided `__new__` still cannot use `__init__` for custom initialization logic.
Install
-
pip install pyobjc-framework-externalaccessory
Imports
- ExternalAccessory
import ExternalAccessory
Quickstart
import ExternalAccessory
import objc
def list_accessories():
manager = ExternalAccessory.EAAccessoryManager.sharedAccessoryManager()
accessories = manager.connectedAccessories()
if accessories:
print(f"Found {len(accessories)} connected accessories:")
for acc in accessories:
print(f" - Name: {acc.name()}")
print(f" Model Number: {acc.modelNumber()}")
print(f" Manufacturer: {acc.manufacturer()}")
print(f" Serial Number: {acc.serialNumber()}")
print(f" Firmware Revision: {acc.firmwareRevision()}")
print(f" Hardware Revision: {acc.hardwareRevision()}")
print(f" Protocol Strings: {acc.protocolStrings()}")
else:
print("No MFi accessories connected.")
# Note: EAAccessoryManager typically requires an active runloop or
# an application context to correctly detect accessories and receive notifications.
# For simple scripting, you might need to run a console event loop.
# import PyObjCTools.AppHelper
# PyObjCTools.AppHelper.runConsoleEventLoop(installInterrupt=True, mode=objc.NSDefaultRunLoopMode, untilIdle=True)
if __name__ == '__main__':
# This part runs the list_accessories function immediately.
# In a full Cocoa app, this would be part of a delegate or controller.
# For a simple script, it will just check at startup.
list_accessories()