© Radoslava Leseva Adams and Hristo Lesev 2016

Radoslava Leseva Adams and Hristo Lesev, Migrating to Swift from Flash and ActionScript, 10.1007/978-1-4842-1666-8_9

9. Communicating: E-mail, Text Messages, and Calls

Radoslava Leseva Adams and Hristo Lesev2

(1)London, UK

(2)Kazanlak, Bulgaria

In their early days mobile phones were used only for making calls and later on for sending short text messages. Today we don’t even call them phones any more: a mobile device is a computer that fits in your pocket. Still, communication is one of the core purposes of a mobile device and this is what we will focus on in this chapter by making an app that can make phone calls and send e-mail and text messages (SMS, or short message service).

In this chapter you will do the following:

  • Learn how to use the MessageUI framework for composing and sending e-mail and text messages.

  • Learn how to make a phone call from an app.

  • Learn how to work with the iOS address book, iterate through contacts, and read contact information with the AddressBookUI framework.

  • Build an app that does all of the above.

When you are done, you will have an app that can send e-mail and text messages, can make phone calls, lets you choose contact info from the address book, and assists you with message composition.

Setting Up the App and Designing the UI

The app you will develop has two main objectives. The first one is to help the user compose and send messages without leaving the app. The second objective is to make sending messages quicker by presenting the main bits of information already populated: the recipient’s address or phone number, a template for the message body, and so on.

Start by creating a Single View iOS application project (FileNewProject…, then iOSApplicationSingle View Application ) and naming it MessageComposer. We will design the user interface (UI) of the application as part of the setup, so we can focus on code in the rest of the chapter.

Figure 9-1 shows you what the UI will look like: on the left there is a mock-up with the UI elements you will need to place in the view on the storyboard and on the right is a screenshot of the storyboard with the elements already positioned on it.

A371202_1_En_9_Fig1_HTML.jpg
Figure 9-1. The app’s user interface

Open Main.storyboard and arrange the UI as shown in Figure 9-1 by adding three text fields, a text view, four buttons, and four labels. The text fields and the text view will be used for inputting a message and information about the recipient. Do not forget to add constraints, so that the app adapts its look to whatever device it runs on. If you need a reminder for how to set constraints and make an adaptive UI, have a look at Chapter 5 .

Next, open ViewController.swift and import the MessageUI framework to start with. Then create outlets for all the text fields you added to the storyboard (see Chapter 2 for how to create outlets). Your code should look like Listing 9-1.

Listing 9-1. Adding Outlets for the Text Fields to the ViewController Class
import UIKit
import MessageUI


class ViewController: UIViewController {

    @IBOutlet weak var recipientEmail: UITextField!
    @IBOutlet weak var phoneNumber: UITextField!
    @IBOutlet weak var messageSubject: UITextField!
    @IBOutlet weak var messageBody: UITextView!


    //The rest of the code goes here
}

With the UI of the app laid out we are ready to focus on writing code and adding functionality to the app.

Composing and Sending E-mail

Making it easy for the user to send an e-mail without leaving your app has two advantages: it is convenient for the user and allows you to spread the word about your app and brand by providing a custom template for the message body.

The MessageUI framework offers an easy way of doing that: it lets you show the standard iOS e-mail composer UI within your app with the help of a view controller class, called MFMailComposeViewController. We will see how to use it in a bit.

The e-mail interface will be shown when the user taps the E-mail button on the app’s screen, so let us first add a handler for that. On the storyboard select the button and create a Touch Up Inside action for it, called sendEmail, in ViewController.swift. (For details on how to create actions for storyboard elements see Chapter 2 .)

Listing 9-2 has the implementation you should put inside the action. First, we check if the device has been set up to send e-mail by calling canSendMail—a static method of the MFMailComposeViewController class. If sending e-mail is possible, we create an instance of MFMailComposeViewController, set it up, and present it on screen.

The setup includes providing initial values for the e-mail’s subject (setSubject), body (setMessageBody), and recipients (setToRecipients). To fill these in, we use the text that the user has provided in the text fields and the text view we added to the app earlier. Note that setToRecipients takes an array of String: this lets you specify more than one e-mail recipient. We get an array, containing all the recipients’ e-mails by dividing the original string into substrings using comma as the separator.

You can be creative with the message body and use HTML tags to make it prettier, include hyperlinks, and so on. To turn HTML on, you need to set the second parameter of setMessageBody to true. We will keep things simple in this example and only use plain text.

When all the setup is done, the e-mail composer is shown on screen with presentViewController.

Listing 9-2. Creating and Configuring an E-mail Composer Instance
@IBAction func sendEmail(sender: AnyObject) {
    //Check if the device is configured to send e-mail
    if MFMailComposeViewController.canSendMail() {
        let emailController = MFMailComposeViewController()
        //Set a delegate responsible for the dismissal of the view controller
        emailController.mailComposeDelegate = self


        //Extract recipients in an array of String items
        //by dividing the string using comma as a separator
        let recipientList =
                recipientEmail.text!.componentsSeparatedByString(",")
        //Use the resulting array to set the To field
        emailController.setToRecipients(recipientList)
        //Copy the subject from the messageSubject text field
        emailController.setSubject(messageSubject.text!)
        //Copy the message body from the messageBody text view
        emailController.setMessageBody(messageBody.text, isHTML: false)


        //Show emailController on the screen
        presentViewController(emailController, animated: true, completion: nil)
    }
    else {
        print("Cannot send e-mail.")
    }
}

You may have noticed that there is a line in Listing 9-2 I haven’t explained yet:

emailController.mailComposeDelegate = self

We talked about delegationin Chapter 5 . It is a design pattern, which is used a lot in the iOS SDK and lets an object delegate tasks to another object. In this case the mail composer will delegate to our ViewController class the task of handling what happens when the user is done composing an e-mail. For the delegation to work, ViewController needs to have an interface that the mail composer recognizes, so we will have it conform to the MFMailComposeViewControllerDelegate protocol, which is part of the iOS SDK. Let us add the protocol to ViewController’s inheritance list:

class ViewController: UIViewController, MFMailComposeViewControllerDelegate {
Note

For more information on protocols and conforming to them, see Chapter 21.

The protocol we have just added requires that any conforming type implement a method, named mailComposeController(_:didFinishWithResult:). This method serves as a callback and is executed when the user decides whether to send, save, or delete the e-mail by tapping one of the buttons in the mail composer: Send or Cancel. The user’s decision is delivered in one of the callback’s parameters, called result of type MFMailComposeResult. For simplicity, all our callback will do is print the result from the user’s choice and dismiss the mail composer (i.e., hide it from the screen). You can see the implementation in Listing 9-3.

Listing 9-3. Dismissing the E-mail Compose View Controller
func mailComposeController                              (controller: MFMailComposeViewController,
        didFinishWithResult result: MFMailComposeResult, error: NSError?) {


    //Print the result of the user's action
    switch (result) {
    case MFMailComposeResultCancelled:
        print("Cancelled.")
    case MFMailComposeResultSaved:
        print("Saved as a Draft.")
    case MFMailComposeResultSent:
        print("Sent.")
    case MFMailComposeResultFailed:
        print("Failed (error?.localizedDescription)")
    default:
        print("Result code: (result.rawValue)")
    }


    //Dissmiss the view controller from the screen
    controller.dismissViewControllerAnimated(true, completion: nil)
}

That’s it: you have an app that lets the user send e-mail with just a few lines of code. Now let us run it and test it by sending an e-mail or two.

Caution

At the time of this writing there is a bug in the iOS 9 simulator, which results in a crash when you try to use MFMailComposeViewController. Apple is aware of it and will likely provide a fix in the next simulator update. If you do get a crash in the simulator, you can test the app on a device instead. See Chapter 2 if you need a reminder for how to deploy apps on an iOS device.

Run the application; fill in the e-mail address, subject, and body fields; and tap the E-mail button. You should see the e-mail compose view controller modally presented on the screen (Figure 9-2) and be able to send an e-mail by tapping Send.

A371202_1_En_9_Fig2_HTML.jpg
Figure 9-2. Sending e-mail from your application

Composing and Sending SMS

Sending text messages from your app is so similar to sending e-mail, you are likely to have a déjà vu while writing the code.

To start with, create an action handler for the Touch Up Inside action of the SMS button you added to the storyboard earlier. Call the action handler sendSMS. Now look at Listing 9-4, which shows the implementation of sendSMS: does it look familiar?

Listing 9-4. Create and Configure SMS Compose View Controller
@IBAction func sendSMS(sender: AnyObject) {
    //Check if the device can send SMS
    if MFMessageComposeViewController.canSendText() {
        let smsController = MFMessageComposeViewController()
        //Set a delegate responsible for the dismissal of the view controller
        smsController.messageComposeDelegate = self
        //Extract recipients in an array of String items
        //by dividing phoneNumber using comma separator
        let recipientList = phoneNumber.text!.componentsSeparatedByString(",")
        //Use the resulting array to set the To field
        smsController.recipients = recipientList
        //Copy the message body from the messageBody text view
        smsController.body = messageBody.text


        //Show smsController on the screen
        presentViewController(smsController, animated: true, completion: nil)
    }
    else {
        print("Cannot send sms.")
    }
}

The iOS SDK has a class, called MFMessageComposeViewController, which we can use to show an SMS composer inside the app. The code first calls MFMessageComposeViewController.canSendText() to check if the device can send text messages. Then it creates an instance of MFMessageComposeViewController and sets it up with the information that the user typed in the app’s UI: the SMS content (body) and a list of recipients in the form of a String array. Finally, the SMS composer is presented on the screen.

The task of dismissing the SMS composer from the screen will be delegated to our ViewController class by the SMS composer, which is what this line is about:

smsController.messageComposeDelegate = self

To implement the interface for the delegation, make ViewController conform to the MFMessageComposeViewControllerDelegate protocol by first adding the protocol to ViewController’s inheritance list:

class ViewController: UIViewController, MFMailComposeViewControllerDelegate,  MFMessageComposeViewControllerDelegate {

Then add an implementation for the only method required by the protocol: messageComposeViewController(_:didFinishWithResult:). You can see the method implemented in Listing 9-5: again, it looks very similar to the callback method we implemented for handling e-mail sending in the previous section. In it we print the result from the user’s action and dismiss the SMS composer from the screen.

Listing 9-5. Dissimss the SMS Compose View Controller
func messageComposeViewController(controller: MFMessageComposeViewController,
                                didFinishWithResult result: MessageComposeResult) {


    //Print the result of the user's action
    switch (result) {
    case MessageComposeResultCancelled:
        print("Cancelled.")
    case MessageComposeResultSent:
        print("Sent.")
    case MessageComposeResultFailed:
        print("Failed.")
    default:
        print("Result code: (result.rawValue)")
    }


    //Dissmiss the view controller off the screen
    controller.dismissViewControllerAnimated(true, completion: nil)
}

When you run the app on your device and tap the SMS button, you should see the message compose view controller appear as shown in Figure 9-3.

A371202_1_En_9_Fig3_HTML.jpg
Figure 9-3. Compose SMS view controller
Note

In order to test sending text messages you will need to run the app on an iPhone with a SIM card. The simulator will not do in this case. If you try to run the app in the simulator or on a phone without a SIM card the MFMessageComposeViewController.canSendText() will always returns false.

Making a Call

Initiating a telephone call from an app is actually pretty easy and can be done with a single line of code. There is no dedicated iOS SDK framework specifically for making phone calls. Instead, to call a number, you need to treat it like a URL (uniform resource locator).

The same way that a URL scheme like http lets you open a web browser and navigate to a web page by doing http://mywebsite.com/mywebpage , defining a custom URL scheme for an app allows that app to be opened and to receive information from other apps.

Let us say, for example, that you are building a treasure-hunting app, which leads the user to discover a prize by following clues that you have hidden in the local park. You could encode the clues in QR codes and attach them to trees, benches, and posts in the park, which can be uncovered and scanned with a phone. Each QR code could contain a URL (for instance, myTreasureHuntingApp) and a piece of information (say, clue_1), which can be assembled in a string: myTreasureHuntingApp://clue_1. The first part of the string, the URL followed by //, tells iOS to look for an app that responds to this URL and start it.1 The second part is much a command-line parameter list that you can pass to an app when you start it.

Most of the standard applications and services that iOS comes with have custom URLs. The service for making phone calls uses the tel URL and this is what we are going to use: navigating to tel://some_phone_number should start the service and get it to call the given telephone number.

We will again first add an action for handling when the Call button has been tapped. Select the Call button on the storyboard and add a handler for its Touch Up Inside action it to the ViewController class.

Listing 9-6 shows the implementation of the action handler. First we extract the string that the user typed in the phoneNumber text edit and use it to create an instance of NSURL. The NSURL class is part of the iOS SDK, which helps with handling and parsing paths to resources—remote and local. The URL we obtain can be used to ask our application instance to navigate to it. We can get a reference to our app instance by calling iOS SDK’s UIApplication.sharedApplication(). Before we navigate to the telephone number URL, we check if it’s actually valid by calling UIApplication’s canOpenURL method.

Listing 9-6. Making a Call Using a URL Scheme
@IBAction func makeCall(sender: AnyObject) {

    if let phoneCallURL = NSURL(string: "tel://(phoneNumber.text!)") {
        let application = UIApplication.sharedApplication()


        if application.canOpenURL(phoneCallURL) {
            application.openURL(phoneCallURL)
        }
    }
}
Note

As was the case with sending text messages, testing phone calls in your app will require the app to run on a device with a SIM card, rather than in a simulator.

Run the app on your phone, enter a valid telephone number in the Phone Number text field, and tap Call. This should start the call service (Figure 9-4).

A371202_1_En_9_Fig4_HTML.jpg
Figure 9-4. Making a phone call

Using the Address Book

There is one more thing we could add to our app to make it even more convenient for making phone calls and sending messages. Instead of having the user input phone numbers and e-mail addresses by hand, we could grab the information from the device’s address book. You can think of the address book as a centralized database of contact information, which can be accessed by multiple applications.

iOS lets you access this information programmatically for reading and modifying contacts. If you choose to do that, your app will first need to ask the user’s permission.

If your app doesn’t need to browse through all of the contacts but just have them displayed on the screen for the user to select one, you can use a ready-made view controller, called CNContactPickerViewController, which is part of the AddressBookUI framework. It displays the standard iOS address book screen, where the user can browse through the contact list. In this case the app itself doesn’t have access to the whole address book but gets a copy of the selected contact, so it doesn’t need to ask for permission.

In this example we will have our app use CNContactPickerViewController to present an instance of it on the screen and let the user choose a contact. Then the app will auto-fill its text fields with the selected contact’s information.

We start by first importing the ContactsUI framework and then adding an action handler for one of the buttons on the screen: in this action handler we will present the contact picker view controller. Add a handler to ViewController for the Touch Up Inside action of the button titled Pick a contact from the address book and call it selectContact.

Inside selectContactfirst obtain an instance of CNContactPickerViewController and set it up for displaying a contact’s email address and phone number by setting the instance’s displayedPropertyKeys property as shown in Listing 9-7. Then show the view controller on the screen.

Listing 9-7. Create and Configure a Contact Picker View Controller
@IBAction func selectContact(sender: AnyObject) {
    let contactPicker = CNContactPickerViewController()
    //Tell contactPicker that we want to use e-mail and phone number
    contactPicker.displayedPropertyKeys = [CNContactEmailAddressesKey,
                                                         CNContactPhoneNumbersKey]
    //Set a delegate which will recieve the selected person's info
    contactPicker.delegate = self


    //Show contactPicker on the screen
    presentViewController(contactPicker, animated: true, completion: nil)
}

When the user selects a contact in the contact picker, the picker’s view controller will need to delegate the task of handling that contact’s information to our ViewController class. For that purpose we will make ViewController conform to yet another protocol, called CNContactPickerDelegate by adding it to ViewController’s inheritance list:

class ViewController: UIViewController, MFMailComposeViewControllerDelegate,  MFMessageComposeViewControllerDelegate, CNContactPickerDelegate {

In Listing 9-7 you can see the line that sets our ViewController as the delegate for the contact picker view controller:

contactPicker.delegate = self

Now let us implement the callback that CNContactPickerDelegate requires, in order to pass contact information back to us: contactPicker(_:didSelectContact). The second parameter of the callback is an instance of CNContact, a class, which represents a record in the address book. We will use that instance to read the selected contact’s e-mail address and telephone number and fill them in the main screen of our app (Listing 9-8).

An interesting thing to note here is how e-mail addresses and phone numbers are represented.

A contact in the address book can have multiple e-mail addresses (e.g., a work one and a personal one). We can access these e-mail addresses through CNContacts’s emailAddresses property, which is an array of CNLabeledValue instances. CNLabeledValue is very similar to a key-value pair in that it combines a value with a given label, for example, ‘06658907432’ and ‘Work’. In our example we will use the first available e-mail address from the array.

A contact can also have multiple phone numbers stored for it, again labeled ‘Work’, ‘Home’, and so on. CNContacts’s phoneNumbers property gives us access to them in the form of an array of CNPhoneNumber instances. We can get a phone number as a String by reading CNPhoneNumber’s stringValue property (Listing 9-8).

Listing 9-8. Reading Data from the Selected Contact
func contactPicker(picker: CNContactPickerViewController,
                                              didSelectContact contact: CNContact) {
    //Check if there are any e-mails for this contact
    if contact.emailAddresses.count > 0 {
        //Get the first e-mail entry
        let email = contact.emailAddresses.first?.value as! String
        //Show the e-mail address in the UI
        recipientEmail.text = email
    }


    //Check if there are any phone numbers for this contact
    if contact.phoneNumbers.count > 0 {
        //Get the first phone number entry
        let phone = contact.phoneNumbers.first?.value as! CNPhoneNumber
        //Extract a string from the phone number and show it in the UI
        phoneNumber.text = phone.stringValue
    }
}

Figure 9-5 shows you what you should see when you run your app with this last bit of functionality added to it. When you tap the Pick a contact from the address book button, the contact picker controller shows you all of your contacts. After you select one, you are taken back to the main screen of the app with the contact’s information filled in.

A371202_1_En_9_Fig5_HTML.jpg
Figure 9-5. Pick a person from the address book

Summary

In this chapter you saw how to use default iOS user interface to compose e-mails, send SMS, and make phone calls. You learned about the MessageUI framework and implemented a way of sending messages and making calls from within an app. As a bonus, you saw how to harness the AddressBookUI framework to read and display information about the user’s contacts.

In the following chapter we continue the topic of communication and look at how to compose and post messages on popular social networks. Let me just update my Facebook profile first . . .

Footnotes

1 For an app to be invoked with a custom URL, it needs to register this URL with iOS first. You can enable this in the app settings. For more information see “Using URL Schemes to Communicate with Apps” on Apple’s web site: https://developer.apple.com/library/ios/documentation/iPhone/Conceptual/iPhoneOSProgrammingGuide/Inter-AppCommunication/Inter-AppCommunication.html#//apple_ref/doc/uid/TP40007072-CH6-SW1 .

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset