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.
Send SMS from Pythonista
-
How do I do this now in the year 2020? The link to simplesms.py doesn't work.
-
@frakman1, this is how far I quickly got, but frustratingly I do not seem to get the sending UI dismissed, so it is unusable right now.
import objc_util import ui objc_util.load_framework('MessageUI') MFMessageComposeViewController = objc_util.ObjCClass( 'MFMessageComposeViewController') SUIViewController = objc_util.ObjCClass('SUIViewController') v = ui.View() b = ui.Button( title='Send SMS', background_color='#0e45cd', tint_color='white', flex='TBLR', ) b.frame = b.frame.inset(-8,-8) b.center = v.bounds.center() RESULTS = ('Cancelled', 'Sent', 'Failed') def messageComposeViewController_didFinishWithResult_( _self, _cmd, _controller, _result): """ Required to be able to dismiss the controller. """ controller = objc_util.ObjCInstance(_controller) #result = objc_util.ObjCInstance(_result) #print(RESULTS[result]) controller.dismissModalViewControllerAnimated_completion_(True, None) MessageSenderDelegate = objc_util.create_objc_class( 'MessageSenderDelegate', methods=[ messageComposeViewController_didFinishWithResult_, ], protocols=['MFMessageComposeViewControllerDelegate'] ) def send_sms(sender): composer = MFMessageComposeViewController.alloc().init() composer.setRecipients_(['12345678']) composer.setBody_('Message content') delegate = MessageSenderDelegate.alloc().init() composer.setDelegate_(delegate) vc = SUIViewController.viewControllerForView_( sender.superview.objc_instance) vc.presentModalViewController_animated_(composer, True) b.action = send_sms v.add_subview(b) v.present('fullscreen')
-
@mikael perhaps I forgot something but I get
Traceback (most recent call last): File "/private/var/mobile/Containers/Shared/AppGroup/1B829014-77B3-4446-9B65-034BDDC46F49/Pythonista3/Documents/a.py", line 49, in send_sms composer.setRecipients_(['12345678']) AttributeError: 'NoneType' object has no attribute 'setRecipients_'
-
@mikael sorry, I'm on an iPad, no sms
-
@cvp, thanks for trying.
-
@cvp, hmm, but shouldn’t iPads have iMessage, even if no SMS?
Here’s a version that checks for availability:
import objc_util import ui objc_util.load_framework('MessageUI') MFMessageComposeViewController = objc_util.ObjCClass( 'MFMessageComposeViewController') SUIViewController = objc_util.ObjCClass('SUIViewController') v = ui.View() b = ui.Button( tint_color='white', flex='TBLR', ) if MFMessageComposeViewController.canSendText(): b.title = 'Send Message' b.background_color = '#0e45cd' else: b.title = 'No messaging available' b.background_color = '#c35757' b.enabled = False b.size_to_fit() b.frame = b.frame.inset(-8,-8) b.center = v.bounds.center() RESULTS = ('Cancelled', 'Sent', 'Failed') def messageComposeViewController_didFinishWithResult_( _self, _cmd, _controller, _result): """ Required to be able to dismiss the controller. """ controller = objc_util.ObjCInstance(_controller) #result = objc_util.ObjCInstance(_result) #print(RESULTS[result]) controller.dismissModalViewControllerAnimated_completion_(True, None) MessageSenderDelegate = objc_util.create_objc_class( 'MessageSenderDelegate', methods=[ messageComposeViewController_didFinishWithResult_, ], protocols=['MFMessageComposeViewControllerDelegate'] ) def send_sms(sender): composer = MFMessageComposeViewController.alloc().init() composer.setRecipients_(['12345678']) composer.setBody_('Message content') delegate = MessageSenderDelegate.alloc().init() composer.setDelegate_(delegate) vc = SUIViewController.viewControllerForView_( sender.superview.objc_instance) vc.presentModalViewController_animated_(composer, True) b.action = send_sms v.add_subview(b) v.present('fullscreen')
-
Very annoying that I seem to remember we have done this before, but can’t find the post.
-
@mikael said:
hmm, but shouldn’t iPads have iMessage, even if no SMS?
You're right but iMessage is/was off on my iPad...
-
Via printing to file I think I have confirmed that the delegate method is not reached at all, but cannot see why.
-
Ok, you need to set the
messageComposeDelegate
instead ofdelegate
, which is for the inheritedUINavigationViewController
. Will post a working version later today. -
@frakman1, here’s a reusable version, with usage sample in the end. Note the option to provide a callback if you want control the closing of the message composer.
import objc_util objc_util.load_framework('MessageUI') MFMessageComposeViewController = objc_util.ObjCClass( 'MFMessageComposeViewController') SUIViewController = objc_util.ObjCClass('SUIViewController') CANCEL, SEND, FAIL = range(3) def default_callback(result): if result == FAIL: return True def messageComposeViewController_didFinishWithResult_( _self, _cmd, _controller, _result): """ Required to be able to dismiss the controller. """ controller = objc_util.ObjCInstance(_controller) # 0 is returned as None result = _result or 0 # Stay in the composer if callback returns True if controller.callback and controller.callback(result): return else: controller.dismissViewControllerAnimated_completion_(True, None) MessageSenderDelegate = objc_util.create_objc_class( 'MessageSenderDelegate', methods=[ messageComposeViewController_didFinishWithResult_, ], protocols=['MFMessageComposeViewControllerDelegate'] ) def send_message( superview, to='', body='', callback=None ): """ Open a message composer with the recipient and message already filled. Optional callback gets the result of the sending. Composer stays open if callback returns True. By default, composer stays open if sending fails. """ composer = MFMessageComposeViewController.alloc().init() composer.setRecipients_(['12345678']) composer.setBody_('Message content') composer.callback = callback or default_callback delegate = MessageSenderDelegate.alloc().init() composer.messageComposeDelegate = delegate vc = SUIViewController.viewControllerForView_( superview.objc_instance) vc.presentModalViewController_animated_(composer, True) if __name__ == '__main__': import ui v = ui.View() b = ui.Button( tint_color='white', flex='TBLR', ) if MFMessageComposeViewController.canSendText(): b.title = 'Send Message' b.background_color = '#0e45cd' else: b.title = 'No messaging available' b.background_color = '#c35757' b.enabled = False b.size_to_fit() b.frame = b.frame.inset(-8,-8) b.center = v.bounds.center() def send_message_action(sender): send_message(sender.superview, to='1234566', body='Message') b.action = send_message_action v.add_subview(b) v.present('fullscreen')
-
@mikael this app (Pythonista) and you are both amazing