PyObjC Framework: MultipeerConnectivity
The `pyobjc-framework-multipeerconnectivity` library provides Python bindings for Apple's Multipeer Connectivity framework on macOS, enabling Python applications to discover nearby devices and communicate via Wi-Fi, Peer-to-Peer Wi-Fi, and Bluetooth personal area networks. It is part of the larger PyObjC project, allowing Python developers to interact with Objective-C APIs directly. The current version is 12.1, and releases generally align with macOS SDK updates and Python version compatibility.
Warnings
- breaking PyObjC has dropped support for older Python versions in recent major releases. Version 12.0 dropped Python 3.9, and version 11.0 dropped Python 3.8. Ensure your Python environment meets the minimum `requires_python` requirement.
- breaking The automatic reference counting (ARC) behavior for `init` family methods in Objective-C was corrected in PyObjC 11.1. Methods in the 'init' family now correctly steal a reference to self and return a new reference, aligning with `clang`'s documentation. This can affect custom initializers in Python subclasses of Objective-C classes.
- gotcha When subclassing Objective-C classes in Python, there were changes in how `__init__` and `__new__` interact in PyObjC 10.3. If you provide a custom `__new__` in your Python class (or its superclasses), `__init__` can be used. However, if you rely on the `__new__` provided by PyObjC, `__init__` cannot be used directly to initialize the instance.
- gotcha PyObjC 11.0 introduced experimental support for Python 3.13's free-threading (PEP 703). While efforts have been made, users should be aware that this is an experimental feature and may not be fully stable or optimized. Earlier versions (e.g., PyObjC 10.3) explicitly did not support free threading.
- breaking Specific framework bindings can be removed from PyObjC if the underlying Apple framework is deprecated and removed from macOS SDKs. For example, the `IMServicePlugIn` bindings were removed in PyObjC 10.0 because the framework was removed in macOS 14. This applies to any `pyobjc-framework-*` package.
Install
-
pip install pyobjc-framework-multipeerconnectivity
Imports
- MultipeerConnectivity
from MultipeerConnectivity import *
- Foundation
from Foundation import *
- AppHelper
from PyObjCTools import AppHelper
Quickstart
import objc
from Foundation import *
from MultipeerConnectivity import *
from PyObjCTools import AppHelper
import sys
# Define a service type (must be 1-15 lowercase ASCII characters, no hyphens, no underscores)
SERVICE_TYPE = "my-p2p-app"
class BrowserDelegate(NSObject):
"""
Delegate for MCNearbyServiceBrowser to handle found and lost peers.
"""
def browser_foundPeer_withDiscoveryInfo_(self, browser, peerID, info):
print(f"[Browser] Found peer: {peerID.displayName()} (Info: {info})")
# In a real app, you'd now invite the peer to a session.
def browser_lostPeer_(self, browser, peerID):
print(f"[Browser] Lost peer: {peerID.displayName()}")
class AdvertiserDelegate(NSObject):
"""
Delegate for MCNearbyServiceAdvertiser to handle invitations.
"""
def advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(self, advertiser, peerID, context, invitationHandler):
print(f"[Advertiser] Received invitation from {peerID.displayName()} (Context: {context})")
# For this simple example, we decline any invitations.
invitationHandler(False, None)
# 1. Create a peer ID for this device
myPeerID = MCPeerID.alloc().initWithDisplayName_(NSHost.currentHost().name())
print(f"Starting MultipeerConnectivity as: {myPeerID.displayName()}")
# 2. Setup a browser to find other peers
browserDelegate = BrowserDelegate.alloc().init()
browser = MCNearbyServiceBrowser.alloc().initWithPeer_serviceType_(myPeerID, SERVICE_TYPE)
browser.setDelegate_(browserDelegate)
browser.startBrowsingForPeers()
print(f"Started browsing for peers using service type: '{SERVICE_TYPE}'")
# 3. Setup an advertiser to be discovered by other peers
advertiserDelegate = AdvertiserDelegate.alloc().init()
advertiser = MCNearbyServiceAdvertiser.alloc().initWithPeer_discoveryInfo_serviceType_(myPeerID, None, SERVICE_TYPE)
advertiser.setDelegate_(advertiserDelegate)
advertiser.startAdvertisingPeer()
print(f"Started advertising using service type: '{SERVICE_TYPE}'")
print("\n--- Running event loop. Press Ctrl+C to stop. ---")
try:
AppHelper.runConsoleEventLoop(installInterrupt=True)
except KeyboardInterrupt:
print("\nStopping...")
finally:
browser.stopBrowsingForPeers()
advertiser.stopAdvertisingPeer()
print("Stopped browsing and advertising.")
sys.exit(0)