Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
How to Support Multipeer Connectivity ?
-
Pythonista can support iOS Multipeer Connectivity?
who can show some sample code? -
@wolf71 You'll have to elaborate a bit more on exactly what you want for those of us who aren't familiar
-
-
MCSession=ObjCClass('MCSession')
Error:
no objective-C class named 'MCSession' found -
@wolf71 You first need to load the
MultipeerConnectivity
Framework:NSBundle.bundle(Path="/System/Library/Frameworks/MultipeerConnectivity.framework").load()
-
Thanks @lukaskollmer, It's work.
-
how to set the MCNearByServiceBrowser Delegate,so can using pythonista handle callback ? I Try this,but not work.
!!crash!!Multipeer Connectivity Ref: https://developer.apple.com/library/ios/documentation/MultipeerConnectivity/Reference/MultipeerConnectivityFramework/index.html#//apple_ref/doc/uid/TP40013328
from objc_util import * import ctypes,time,os NSBundle.bundle(Path="/System/Library/Frameworks/MultipeerConnectivity.framework").load() MCPeerID=ObjCClass('MCPeerID') MCSession=ObjCClass('MCSession') MCNearbyServiceAdvertiser=ObjCClass('MCNearbyServiceAdvertiser') MCNearbyServiceBrowser=ObjCClass('MCNearbyServiceBrowser') def browser_foundPeer_withDiscoverInfo_(_self, _cmd, _browser, _peerID, _info): print '!!!!!!!!!!' #print 'Service found:', ObjCInstance(_info) BrowserDelegate = create_objc_class('BrowserDelegate',methods=[browser_foundPeer_withDiscoverInfo_],protocols=['MCNearbyServiceBrowserDelegate']) myID = MCPeerID.alloc().initWithDisplayName('Wolf_Audio') #mySession = MCSession.alloc().initWithPeer_(myID) #aSrv = MCNearbyServiceAdvertiser.alloc().initWithPeer_discoveryInfo_serviceType_(myID,None,'AudioSrv') # set delegate #aSrv.setDelegate_(MCDelegate.alloc().init()) #aSrv.startAdvertisingPeer() aBr = MCNearbyServiceBrowser.alloc().initWithPeer_serviceType_(myID,'AudioSrv') #aBr.setDelegate_(BrowserDelegate.alloc().init()) aBr.startBrowsingForPeers() time.sleep(10) aBr.stopBrowsingForPeers() #aSrv.stopAdvertisingPeer()
-
Are you using Python 2 or Python 3?
-
It is probably a bad idea to pass in alloc().init() into an objc method in the argument directly. objc_util does not retain arguments by default, so what happens is the ObjCInstance is created, a pointer to the class is sent to the objc side of the world, then the object is promptly destroyed in python as it falls out of scope. It sort of depends whether the reference counter gets incremented on the objc side, but basically it is a good idea to separately create a variable and pass it in.
So, just use mydelegate=BrowserDelegate.alloc().init(), and pass that into your other methods.
aBr.setDelegate_(mydelegate)
I could not get your code to crash after fixing this, but I also don't think I have a peer around to trigger the callback. There could be other issuex. If you have pythonista 3, you should install dgelessus's pythonista_startup's enable_fault_handler to tell you where the crash is occuring.
If you get this working, please do report back as others may find this useful.
-
@JonB I'm no Objective-C expert, but shouldn't the result of
XYSomeClass.alloc().init()
start out retained? I thought the Objective-C convention was that objects returned fromalloc...
,copy...
,mutableCopy...
ornew...
methods don't need to be retained by hand.Also
objc_util.ObjCInstance
automatically retains and releases the underlying object in the Python__new__
and__del__
methods, so as long as theObjCInstance
is alive in Python, the Objective-C instance is too. And Python functions keep their arguments alive for the duration of the function call (except in some VERY specially written function code), so anObjCInstance
should never be garbage-collected during a method call.By the way, if you only want to install the faulthandler and Objective-C exception handler, you can copy the code for that from this Gist. The rest of my
pythonista_startup
code can be found in the main repo. -
@JonB Thanks
using your method chage the program. but crash again.
I think it maybe this class delegate var problem.=============================
delegate
Property
The delegate object that handles browser-related events.Declaration
SWIFT
weak var delegate: MCNearbyServiceBrowserDelegate?
OBJECTIVE-C
@property(weak, nonatomic) id< MCNearbyServiceBrowserDelegate > delegateFatal Python error: Aborted
Thread 0x000000016e247000 (most recent call first):
Objective-C exception details:
NSInvalidArgumentException: Invalid serviceType passed to MCNearbyServiceBrowser
Stack trace:
0 CoreFoundation 0x0000000181f02dc8 <redacted> + 148
1 libobjc.A.dylib 0x0000000181567f80 objc_exception_throw + 56
2 CoreFoundation 0x0000000181f02cf8 <redacted> + 0
3 MultipeerConnectivity 0x000000019466a6fc <redacted> + 424
4 PythonistaKit 0x0000000101aa7044 ffi_call_SYSV + 68
5 PythonistaKit 0x0000000101aaca78 ffi_call_int + 1160
6 PythonistaKit 0x0000000101aac5e4 ffi_call + 56
7 PythonistaKit 0x00000001018af4a0 _ctypes_callproc + 820
8 PythonistaKit 0x00000001018b4374 PyCFuncPtr_call + 1048
9 PythonistaKit 0x0000000101419c04 PyObject_Call + 124
10 PythonistaKit 0x0000000101650304 PyEval_EvalFrameEx + 2032
11 PythonistaKit 0x000000010164f8c4 PyEval_EvalCodeEx + 1604
12 PythonistaKit 0x00000001013eb9f0 function_call + 152
13 PythonistaKit 0x0000000101419c04 PyObject_Call + 124
14 PythonistaKit 0x00000001014082c8 instancemethod_call + 180
15 PythonistaKit 0x0000000101419c04 PyObject_Call + 124
16 PythonistaKit 0x00000001013945f0 slot_tp_call + 68
17 PythonistaKit 0x0000000101419c04 PyObject_Call + 124
18 PythonistaKit 0x00000001016507b4 PyEval_EvalFrameEx + 3232
19 PythonistaKit 0x000000010164f8c4 PyEval_EvalCodeEx + 1604
20 PythonistaKit 0x000000010164f274 PyEval_EvalCode + 44
21 PythonistaKit 0x00000001016e02e8 run_mod + 60
22 PythonistaKit 0x00000001016e03bc PyRun_FileExFlags + 148
23 PythonistaKit 0x00000001016dfe34 PyRun_SimpleFileExFlags + 696
24 PythonistaKit 0x00000001016270c4 -[PythonInterpreter runWithOptions:] + 2008
25 PythonistaKit 0x00000001016275c4 -[PythonInterpreter doDispatchBlockOnInterpreterThread:] + 108
26 Foundation 0x00000001828d802c <redacted> + 340
27 CoreFoundation 0x0000000181eb909c <redacted> + 24
28 CoreFoundation 0x0000000181eb8b30 <redacted> + 540
29 CoreFoundation 0x0000000181eb6830 <redacted> + 724
30 CoreFoundation 0x0000000181de0c50 CFRunLoopRunSpecific + 384
31 Foundation 0x00000001827f0cfc <redacted> + 308
32 Foundation 0x0000000182811ad8 <redacted> + 96
33 Foundation 0x00000001828d7e4c <redacted> + 1000
34 libsystem_pthread.dylib 0x0000000181b67b28 <redacted> + 156
35 libsystem_pthread.dylib 0x0000000181b67a8c <redacted> + 0
36 libsystem_pthread.dylib 0x0000000181b65028 thread_start + 4End of exception details.
-
NSInvalidArgumentException: Invalid serviceType passed to MCNearbyServiceBrowser
Your service type
"AudioSrv"
is not valid - the documentation for-[MCNearbyServiceBrowser initWithPeer:serviceType:]
says the following aboutserviceType
:- Must be 1-15 characters long
- Can contain only ASCII lowercase letters, numbers and hyphens.
This means that
"audiosrv"
or"audio-srv"
would be valid service types, but"AudioSrv"
is not, because it contains an uppercaseA
andS
. -
@dgelessus I change it to 'audio-srv' ,it's also crash.
Objective-C exception details:
NSInvalidArgumentException: -[BrowserDelegate_2 browser:foundPeer:withDiscoveryInfo:]: unrecognized selector sent to instance 0x1499625a0
Stack trace:
0 CoreFoundation 0x0000000181f02dc8 <redacted> + 148
1 libobjc.A.dylib 0x0000000181567f80 objc_exception_throw + 56
2 CoreFoundation 0x0000000181f09c4c <redacted> + 0
3 CoreFoundation 0x0000000181f06bec <redacted> + 872
4 CoreFoundation 0x0000000181e04c5c _CF_forwarding_prep_0 + 92
5 libdispatch.dylib 0x000000018194d4bc <redacted> + 24
6 libdispatch.dylib 0x000000018194d47c <redacted> + 16
7 libdispatch.dylib 0x0000000181952b84 _dispatch_main_queue_callback_4CF + 1844
8 CoreFoundation 0x0000000181eb8d50 <redacted> + 12
9 CoreFoundation 0x0000000181eb6bb8 <redacted> + 1628
10 CoreFoundation 0x0000000181de0c50 CFRunLoopRunSpecific + 384
11 GraphicsServices 0x00000001836c8088 GSEventRunModal + 180
12 UIKit 0x00000001870c6088 UIApplicationMain + 204
13 Pythonista3 0x00000001000a81c8 Pythonista3 + 180680
14 libdyld.dylib 0x000000018197e8b8 <redacted> + 4End of exception details.
-
OK, it's a different error, we are making progress
:)
Now it's saying that it can't find the method
browser:foundPeer:withDiscoveryInfo:
on your delegate. It looks like you mistyped the name in your code (you wrotewithDiscoverInfo
, it should bewithDiscoveryInfo
, note they
inDiscovery
). -
@dgelessus Thank you very much.
edit the bug, but can you tell me how to process the browser:lostPeer: delegate?
======================================
Fatal Python error: AbortedThread 0x000000016e2d3000 (most recent call first):
Objective-C exception details:
NSInvalidArgumentException: -[BrowserDelegate_6 browser:lostPeer:]: unrecognized selector sent to instance 0x134eb9c40
Stack trace:
0 CoreFoundation 0x0000000181f02dc8 <redacted> + 148
1 libobjc.A.dylib 0x0000000181567f80 objc_exception_throw + 56
2 CoreFoundation 0x0000000181f09c4c <redacted> + 0
3 CoreFoundation 0x0000000181f06bec <redacted> + 872
4 CoreFoundation 0x0000000181e04c5c _CF_forwarding_prep_0 + 92
5 libdispatch.dylib 0x000000018194d4bc <redacted> + 24
6 libdispatch.dylib 0x000000018194d47c <redacted> + 16
7 libdispatch.dylib 0x0000000181952b84 _dispatch_main_queue_callback_4CF + 1844
8 CoreFoundation 0x0000000181eb8d50 <redacted> + 12
9 CoreFoundation 0x0000000181eb6bb8 <redacted> + 1628
10 CoreFoundation 0x0000000181de0c50 CFRunLoopRunSpecific + 384
11 GraphicsServices 0x00000001836c8088 GSEventRunModal + 180
12 UIKit 0x00000001870c6088 UIApplicationMain + 204
13 Pythonista3 0x00000001000b01c8 Pythonista3 + 180680
14 libdyld.dylib 0x000000018197e8b8 <redacted> + 4End of exception details.
-
That bug is saying that it tried to call broswe:lostPeer:, but your object did not implement it.
The protocol reference shows those as required.Simply create a method
def browser_lostPeer_(_self, _cmd, browser, peer): print ('lost peer')
and when you create the class pass both methods in the methods argument
... methods=[browser_lostPeer_, browser_foundPeer_withDiscoveryInfo_], ...
-
@JonB Thank you very much.
It's work !!! -
@JonB can you tell me how write this type delegate.
invitationHandler:(void (^)(BOOL accept,
MCSession *session))invitationHandlerdef advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,_advertiser,_peerID,_context,_invitationHandler): print 'ppppppp'
OBJECTIVE-C
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
didReceiveInvitationFromPeer:(MCPeerID *)peerID
withContext:(NSData *)context
invitationHandler:(void (^)(BOOL accept,
MCSession *session))invitationHandler
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
-
What you have looks right. Add it to the methods argument of your delegate, and also add the right protocol to your delegate class. MCNearbyServiceAdvertiserDelegate
You are requires to call the handler block with a boolean accept argument, and a MCSession initalized from the peer. StackOverflow gives me:
accept=true session = ObjCClass('MCSession').alloc().initWithPeer(peerID) session.delegate = YOURSERVICEADVERTISERDELEGATE ObjCInstance(handler).invoke(accept, session)
Disclaimer... I don't have anything to test out, you need o find a good end to end example written in ObjC or swift to port over... some of these frameworks are tricky to work with just from the docs alone.
-
@JonB you can using this test code.
Server side:# -*- coding: utf-8 -*- from objc_util import * import ctypes,time,os NSBundle.bundle(Path="/System/Library/Frameworks/MultipeerConnectivity.framework").load() MCPeerID=ObjCClass('MCPeerID') MCSession=ObjCClass('MCSession') MCNearbyServiceAdvertiser=ObjCClass('MCNearbyServiceAdvertiser') MCNearbyServiceBrowser=ObjCClass('MCNearbyServiceBrowser') # Session Delegate def session_peer_didChangeState_(_self,_cmd,_session,_peerID,_state): print 'session change',_peerID,_session,_state def session_didReceiveData_fromPeer_(_self,_cmd,_session,_data,_peerID): print 'Received Data',_data def session_didReceiveStream_withName_fromPeer_(_self,_cmd,_session,_stream,_streamName,_peerID): print 'Received Stream....',_streamName SessionDelegate = create_objc_class('SessionDelegate',methods=[session_peer_didChangeState_, session_didReceiveData_fromPeer_, session_didReceiveStream_withName_fromPeer_],protocols=['MCSessionDelegate']) SDelegate = SessionDelegate.alloc().init() # Advertiser Delegate def advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_(_self,_cmd,advertiser,peerID,context,invitationHandler): print 'ppppppp' #ObjCInstance(invitationHandler).invoke(True,mySession) AdvertiserDelegate = create_objc_class('AdvertiserDelegate',methods=[advertiser_didReceiveInvitationFromPeer_withContext_invitationHandler_],protocols=['MCNearbyServiceAdvertiserDelegate']) ADelegate = AdvertiserDelegate.alloc().init() # init PeerID myID = MCPeerID.alloc().initWithDisplayName('wolf_srv') # init Session and delegate mySession = MCSession.alloc().initWithPeer_(myID) mySession.setDelegate_(SDelegate) ''' Server ''' # Create Server and set delegate aSrv = MCNearbyServiceAdvertiser.alloc().initWithPeer_discoveryInfo_serviceType_(myID,ns({'player.name':'apple'}),'audio-srv1') aSrv.setDelegate_(ADelegate) # Start Server aSrv.startAdvertisingPeer() print 'Server start, ID is : ',myID try: while 1: time.sleep(0.1) except KeyboardInterrupt: print 'Server Stop...' aSrv.stopAdvertisingPeer() except: raise
=================================
Browser side# -*- coding: utf-8 -*- from objc_util import * import ctypes,time,os cnt = 0 NSBundle.bundle(Path="/System/Library/Frameworks/MultipeerConnectivity.framework").load() MCPeerID=ObjCClass('MCPeerID') MCSession=ObjCClass('MCSession') MCNearbyServiceAdvertiser=ObjCClass('MCNearbyServiceAdvertiser') MCNearbyServiceBrowser=ObjCClass('MCNearbyServiceBrowser') def session_peer_didChangeState_(_self,_cmd,_session,_peerID,_state): print 'session change',ObjCInstance(_peerID),_state def session_didReceiveData_fromPeer_(_self,_cmd,_session,_data,_peerID): print 'Received Data',_data def session_didReceiveStream_withName_fromPeer_(_self,_cmd,_session,_stream,_streamName,_peerID): print 'Received Stream....',_streamName SessionDelegate = create_objc_class('SessionDelegate',methods=[session_peer_didChangeState_, session_didReceiveData_fromPeer_, session_didReceiveStream_withName_fromPeer_],protocols=['MCSessionDelegate']) SDelegate = SessionDelegate.alloc().init() def browser_didNotStartBrowsingForPeers_(_self,_cmd,_browser,_err): print ('ERROR!!!') def browser_foundPeer_withDiscoveryInfo_(_self, _cmd, _browser, _peerID, _info): global aBr,mySession peerID = ObjCInstance(_peerID) aBr.invitePeer_toSession_withContext_timeout_(peerID,mySession,None,0) #mySession.connectPeer_withNearbyConnectionData_(peerID,None) print '#',peerID,ObjCInstance(_info) def browser_lostPeer_(_self, _cmd, browser, peer): print ('lost peer') BrowserDelegate = create_objc_class('BrowserDelegate',methods=[browser_foundPeer_withDiscoveryInfo_, browser_lostPeer_, browser_didNotStartBrowsingForPeers_],protocols=['MCNearbyServiceBrowserDelegate']) Bdelegate = BrowserDelegate.alloc().init() myID = MCPeerID.alloc().initWithDisplayName('wolf_client') mySession = MCSession.alloc().initWithPeer_(myID) mySession.setDelegate_(SDelegate) print 'my ID',myID aBr = MCNearbyServiceBrowser.alloc().initWithPeer_serviceType_(myID,'audio-srv1') aBr.setDelegate_(Bdelegate) aBr.startBrowsingForPeers() try: while 1: time.sleep(0.1) except KeyboardInterrupt: print 'Close...' aBr.stopBrowsingForPeers() except: raise