Pythonista-Issues icon indicating copy to clipboard operation
Pythonista-Issues copied to clipboard

Multipeer Connectivity example not working in 3.4

Open bbkiwi opened this issue 1 year ago • 4 comments

The example (mentioned in closed issue support #501)

System Information

  • Pythonista N/A (N/A), Default interpreter 3.10.4
  • iOS 16.5, model iPad7,5, resolution (portrait) 1536.0 x 2048.0 @ 2.0

When run multipeer.py and enter name get Message: MultipeerConnectivity framework error

bbkiwi avatar Jun 11 '23 07:06 bbkiwi

The actual error message is: The operation couldn’t be completed. (NSNetServicesErrorDomain error -72008.)

It looks like since iOS 14 there has been a new security requirement where multipeer (Bonjour) network usage must be declared in plist as follows:

<key>NSBonjourServices</key>
--
<array>
<string>_multipeertest._tcp</string>
</array>

… where multipeertest should match the service key provided to the multipeer framework.

This is a problem for Pythonista, since it is only one app from Apple’s point of view, with a singular plist.

In theory, there could be a known value set in plist, which would then be used for all multipeer Pythonista scripts. To ensure that you only connect peers expected by your script, you would need to add some additional validation to filter peers by initial data.

mikaelho avatar Jun 11 '23 11:06 mikaelho

Thanks for the info. With the 'help' of Chat GTP-3 I got understanding about what is required. Is the service key, that same as the server_type string in your MultipeerConnectivity class? (If so should the same restrictions eg 1-15 chars.. apply). Should a request for adding the key to the plist be made? Chat GTP-3 (with quite a bit of prompting) suggested code below to modify the plist but for me to discover that overwriting it is not permitted. Cheers, Bill

import objc_util
from plistlib import dumps, loads
bundle_id = objc_util.ObjCClass('NSBundle').mainBundle().bundleIdentifier()
main_bundle = objc_util.ObjCClass('NSBundle').bundleWithIdentifier_(bundle_id)
info_plist_path = str(main_bundle.pathForResource_ofType_('Info', 'plist'))
with open(info_plist_path, 'rb') as f:
    info_plist_data = f.read()
info_plist = loads(info_plist_data)
info_plist['NSBonjourServices'] = 'mptest-tcp'
modified_info_plist_data = dumps(info_plist)
with open(info_plist_path, 'wb') as f:
    f.write(modified_info_plist_data) ## fails

bbkiwi avatar Jun 12 '23 03:06 bbkiwi

Yes. Apple's iOS security will not allow the modification of any application's permissions except when digitally signed by the application's original author prior to Apple's review for submission into the App Store.

cclauss avatar Jun 12 '23 11:06 cclauss

import objc_util
from plistlib import dumps, loads
bundle_id = objc_util.ObjCClass('NSBundle').mainBundle().bundleIdentifier()
main_bundle = objc_util.ObjCClass('NSBundle').bundleWithIdentifier_(bundle_id)
info_plist_path = str(main_bundle.pathForResource_ofType_('Info', 'plist'))
with open(info_plist_path, 'rb') as f:
    info_plist_data = f.read()
info_plist = loads(info_plist_data)

-->

import plistlib
import sys
from pathlib import Path

info_plist = plistlib.loads((Path(sys.executable).parent / "Info.plist").read_bytes())

cclauss avatar Jun 12 '23 11:06 cclauss