Send Text Message In-App – Using MFMessageComposeViewController with Swift

In a previous walkthrough on sending e-mails in-app, I explored how to use MFMailComposeViewController to allow a user to compose an e-mail without ever leaving your app. I then followed up with a proposal for better-segregating the responsibilities of composing an e-mail and responding to the delegate callbacks out of the View Controller.

I say all this because today, I’d like to walk you through sending a text message in-app using the same pattern as the second article. This walkthrough should be fairly straight-forward on its own, but if you’d like to reference my previous post on clean view controllers, it could be helpful in understanding why I’m not just shoving everything into the View Controller and calling it good.

The Gist

Here’s the gist of the components we’ll need in order to accomplish the task of using MFMessageComposeViewController to send text messages in-app. Presumably, you’d like to allow your users to send a text message to a pre-defined recipient, or maybe you want to pre-populate a message and allow your users to text it to whomever they desire. Any and all of this can be accomplished by implementing this general outline:

  • Create a class (I’ll call it MessageComposer) that will handle the responsibility of creating/configuring a text message composer.
  • MessageComposer will also handle the MFMessageComposeViewControllerDelegate callback method (
    messageComposeViewController:didFinishWithResult:).
  • Finally, I’ll program a View Controller to create an instance of this MessageComposer class and present it based upon some user action, such as tapping a button.
  • Note that to see the example in action, you’ll have to run it on an actual device, because the Simulator is unable to send text messages…

For those who just like to dive in and explore, feel free to head over to GitHub and grab the example project now!

The Details

With the general idea in mind, let’s jump in to discover how to implement the solution…

MessageComposer

While it’s possible to simply put all of this code inside the View Controller, I’d recommend doing your best to avoid it. While this simple example doesn’t add a ton of complexity if you just write it all into your View Controller, a real-world app will undoubtedly be more complex.

In my experience, it’s best to try and segregate out as many responsibilities of functionality from the View Controller where it’s possible. Thankfully, simple examples like this highlight the ease of segregating these responsibilities so that you can begin to employ the pattern for other components that you use within your app.

So in keeping with this idea of nurturing a clean View Controller, I’ve decided to create a new custom class called MessageComposer. Take a look:

Taking a close look through the comments, you’ll notice the following:

  • You need to import the MessageUI module.
  • Rather than hard-code the recipients list, I’ve declared a constant at a global scope for easy access/changeability in the future. It’s actually optional to even supply a recipients list to your composer… it’s just dependent on how you want to use it. Notice that it’s an array of Strings.
  • MessageComposer inherits from NSObject. This is a requirement of the MFMessageComposeViewControllerDelegate protocol, which MessageComposer conforms to.
  • There’s a function in there called canSendText that becomes important later on for testing whether or not sending a text message is even possible at the moment on the user’s device. It wraps MFMessageComposeViewController’s canSendText method to avoid needing to import the MessageUI module in other places (like the View Controller that uses instances of this class).
  • configuredMessageComposeViewController does what it says it does – it returns an instance of a MFMessageComposeViewController that’s been configured with a list of recipients and a body.
  • messageComposeViewController:didFinishWithResult: is what gets called with the user either sends the text, or cancels sending a text from the message composer. I’ve written code in that method’s body to simply dismiss the instance of the view controller that called the method.

We’re now ready to head to the View Controller and wire up the components allowing a user to display a MessageComposer!

View Controller

The View Controller is very simple for this example:

  • You’ll notice that I create an instance of MessageComposer (the custom class we just defined in previous steps). It’s declared at a scope that can be seen throughout the lifetime of the View Controller (so that the delegate callback can be invoked when appropriate).
  • sendTextMessageButtonTapped is wired up to a button on my storyboard, and will be executed when the user taps the button.
  • Checking to make sure the device can send a text message is critical – Note that running the example in the Simulator will execute the else block, because the Simulator cannot send text messages.
  • If the device can send texts, a configured MFMessageComposeViewController is obtained from the MessageComposer instance. It’s then displayed.
  • If the device can’t send texts, it’s probably a good idea to alert the user somehow… I’ve chosen a simple UIAlertView.

Summary

In this walkthrough, I’ve demonstrated the mechanics of configuring, displaying, and dismissing a MFMessageComposeViewController, which enables your users to send a text message in-app. Additionally, I’ve attempted to show how to keep the View Controller from handling more than it really should, by segregating out the MFMessageComposeViewController configuration and delegate protocol conformance to another class.

Happy texting!

  • Pingback: Send Email In-App – Using MFMailComposeViewController with Swift | Andrew Bancroft()

  • Pingback: Pick a Delegate… Any Delegate… On Clean View Controllers in Swift | Andrew Bancroft()

  • nukemhill

    Andrew.

    Thanks for the quick tutorial. Got it to run on the first try! I’m curious, though, if there is a way to send the texts automatically. I know there must be something for texts in general, as there are plenty of services that send automated texts (like weather forecasts, etc.). Those are server-based systems, whereas what we have here is app-based. I’d like to have my app send a text to a predefined recipient based on a set of rules.

    Is that possible? Or am I going to have to work on this at a lower level?

    • Andrew Bancroft

      Glad you got it working!

      Yes, what this post is demonstrating is the ability to use Apple’s pre-packaged user interface for sending text messages within an app. I don’t see a reason why you couldn’t grab the list of recipients from somewhere else (like a web service) – but with this implementation, you’d still be manually presenting Apple’s UI for the user to interact with.

      From the sounds of it, you’d prefer to have the text messages go out in the background, based on some rules or business logic, without the user needing to hit “send” on a user interface. If that’s the case, Twilio (http://www.twilio.com) is a service I’ve heard of, though I haven’t had the need to use it, personally.

      From the looks of it, several cloud service providers like Parse (https://parse.com/docs/cloud_modules_guide#twilio) and Azure (http://weblogs.asp.net/scottgu/windows-azure-mobile-services-new-support-for-ios-apps-facebook-twitter-google-identity-emails-sms-blobs-service-bus-and-more) integrate with Twilio to help the process along.

      Not sure if any of that info was particularly helpful, but feel free to reply and let me know if there’s anything I can clarify or help you research for your project!

      • nukemhill

        Thanks for the response. This seems to be more complicated than I anticipated. Twilio requires a subscription, and the messaging devices need to belong to their service. I can’t put that kind of restriction on the devices.

        I’d love to be able to operate in the background, and simply send a text without any interaction from the user. They’d have to enable the service, obviously, and supply the number(s) to which the texts would be going. But that’s it.

        The app is health-based, and the idea is that, for example, a child would have certain data points being measured on an ongoing basis. If specified boundaries were crossed, the data would be collected, and then texted to his/her parents. It seems simple, but maybe I’m just making too many assumptions.

        I’d love to be able to reverse engineer the MFMessageCompose* API to see how it works. There are probably private method calls that would allow me to do exactly what I’m talking about. Alas! :-(

        Thanks again. I’ll keep digging. If I learn anything new, I’ll let you know.

      • nukemhill

        Thanks for the response. This seems to be more complicated than I anticipated. Twilio requires a subscription, and the messaging devices need to belong to their service. I can’t put that kind of restriction on the devices.

        I’d love to be able to operate in the background, and simply send a text without any interaction from the user. They’d have to enable the service, obviously, and supply the number(s) to which the texts would be going. But that’s it.

        The app is health-based, and the idea is that, for example, a child would have certain data points being measured on an ongoing basis. If specified boundaries were crossed, the data would be collected, and then texted to his/her parents. It seems simple, but maybe I’m just making too many assumptions.

        I’d love to be able to reverse engineer the MFMessageCompose* API to see how it works. There are probably private method calls that would allow me to do exactly what I’m talking about. Alas! :-(

        Thanks again. I’ll keep digging. If I learn anything new, I’ll let you know.

        • Jassi Sikand

          There are private API calls but then you can’t put it on the App Store. Apple explicitly disallows what you’re attempting to do, unfortunately, but you can easily do it on Android. Twilio lets you make a server for which your app communicates to the server so that only your server sends the texts. The problem, however, is that then your users must be aware of your number so they don’t disregard it. A better way would be to implement networking and deliver the information via push notifications

    • Andrew Bancroft

      Glad you got it working!

      Yes, what this post is demonstrating is the ability to use Apple’s pre-packaged user interface for sending text messages within an app. I don’t see a reason why you couldn’t grab the list of recipients from somewhere else (like a web service) – but with this implementation, you’d still be manually presenting Apple’s UI for the user to interact with.

      From the sounds of it, you’d prefer to have the text messages go out in the background, based on some rules or business logic, without the user needing to hit “send” on a user interface. If that’s the case, Twilio (http://www.twilio.com) is a service I’ve heard of, though I haven’t had the need to use it, personally.

      From the looks of it, several cloud service providers like Parse (https://parse.com/docs/cloud_modules_guide#twilio) and Azure (http://weblogs.asp.net/scottgu/windows-azure-mobile-services-new-support-for-ios-apps-facebook-twitter-google-identity-emails-sms-blobs-service-bus-and-more) integrate with Twilio to help the process along.

      Not sure if any of that info was particularly helpful, but feel free to reply and let me know if there’s anything I can clarify or help you research for your project!

  • nukemhill

    Andrew.

    Thanks for the quick tutorial. Got it to run on the first try! I’m curious, though, if there is a way to send the texts automatically. I know there must be something for texts in general, as there are plenty of services that send automated texts (like weather forecasts, etc.). Those are server-based systems, whereas what we have here is app-based. I’d like to have my app send a text to a predefined recipient based on a set of rules.

    Is that possible? Or am I going to have to work on this at a lower level?

  • Jason Morcos

    Everything works except when I click cancel or send the text disappears but the message composer view stays active and then when I click cancel again the app crashes. For whatever reason, the view is never dismissed. The main view is embedded in a navigation controller. Could this be it? Is there a solution to this problem?

    • Andrew Bancroft

      Hey Jason,

      In playing with the example I have up on GitHub (https://github.com/andrewcbancroft/SwiftMFMessageComposeViewController), I’ve embedded my main view controller in a navigation controller, but everything sends and dismisses fine if I use that exact code.

      However, I -was- able to make one minor tweak to my GitHub code and get some pretty odd behavior:

      If I store a reference to the -configured- MFMessageComposeViewController instance as a property on my main view controller (ie, I set the return value of a call like messageComposerInstance.configuredMessageComposeViewController() to a property on my main view controller), and pass that reference to presentViewController:animated:completion:, things get really crazy. The text clears out like you say, and the view can never be dismissed by hitting send or cancel.

      By chance, is that similar to what you’re doing? If so, try just getting a configured instance and storing it locally in the method responding to the user’s interaction to bring up the MFMessageComposeViewController. If not, let me know and I’ll see if I can think up anything else.

      Thanks, Jason!

      • Jason Morcos

        Andrew,
        I found my error. I was creating the messageComposer within a UIAlertView and not within the main view. Working like a charm now!

        Thanks, Jason

        • just user

          but I want to create message by using UIAlertView, how possibly I could do that ?

  • Nadar Nevitz

    Thanks for building out a sane approach how to clean up a view controller from it’s message composer configuration and delegation. I’ve just been working this same problem, but your’s looks really good. But I have larger question. MFMailComposeViewController and MFMessageComposeViewController have really parallel functionality, methods and patterns. But MessageUI doesn’t have a single protocol or category that unifies them unless I’m mistaken. Perhaps delegate classes EmailComposer and MessageComposer could be combined and unify and handle both mail and sms functionality. I haven’t thought through how.

    • Andrew Bancroft

      Thanks for that feedback, Nadar!

      I believe you’re right about the lack of a unifying protocol in MessageUI. I definitely see the overlap you’re talking about. The “workflow” of checking whether or not the device can send, configuring the controller, presenting, and dismissing is similar.

      Creating a protocol as an abstraction layer probably wouldn’t be impossible (I’m like you – I haven’t thought through the how part), but one could wonder about the necessity. I’m thinking about why I’d need to be able to generalize this… when would I need to substitute one for the other? Would it be helpful for testing somehow? Questions like that come to mind, but I’m not sure I find a compelling reason to go more general.

      I’d be curious about a use-case for it if you’ve thought of any, where being able to substitute an e-mail controller for an sms controller (or vice-versa) would be helpful. That may end up driving the abstraction layer. But if there’s no real driver for it, I’d probably just leave them separate concrete classes and try to keep my View Controller as clean as possible.

      Did any of that make any sense? haha Thanks again for the comment – you got me thinking a bit more about the problem.

  • Brian Shultz

    I am able to call the message composer from a cell within my table view, however when I dismiss the message view (by send or cancel) the app crashes. It seems that I cannot set my tableview as the delegate for the message view. Is there a way around this so that it exits and returns to my table view?

    • Andrew Bancroft

      I’ll try and check into it and let you know Brian. If I get a working example together, I’ll point you to it.

  • Mark Wang

    Thanks for the tutorial! I also had an issue with dismissal and view delegates. I solved it by passing in the presenting view controller and setting that as the delegate.

  • Mehdi SILINI

    hi ! how do i can change the nav bar color and tint in my messagecomposer ? thanks !

    • Andrew Bancroft

      I really wish I knew the answer, Mehdi – Unfortunately I’ve not had the need to do this, so I haven’t explored the possibilities. If I have a chance to look into it more, I’ll definitely let you know!

      Thanks for your question!

    • http://www.worldcraze.com Louis Borlée

      Hi !
      I would also like to know if there is an answer =)

      If you find one, please keep me informed!

      Thanks

      • Andrew Bancroft

        Hi Louis!

        I haven’t found an answer yet, but certainly – if I get to experimenting and discover a solution, I’ll let everyone that’s expressed interest know.

  • just user

    hey , The code works just fine, but once I press “cancel” option , the app crashing

    notice that I run the app on my iPhone

    keep in mind that when the button is pressed , list options appear, once I press “Yes”, it creat the message