Making phone calls in Swift with Twilio

March 29, 2018
Written by
Sam Agnew
Twilion

Screen Shot 2018-03-29 at 5.10.30 PM

Programmatically making phone calls is awesome, but doing so from an iOS app can be dangerous because it requires you to store your Twilio credentials in the app. With Swift’s ability to run on the server, you can avoid the risks of using Twilio client-side!

Let’s learn how to make phone calls with Twilio from our server using Swift.

If you just want to skip right to the point, here is all the code you need:

import Foundation
import Alamofire

if let accountSID = ProcessInfo.processInfo.environment["TWILIO_ACCOUNT_SID"],
   let authToken = ProcessInfo.processInfo.environment["TWILIO_AUTH_TOKEN"] {

  let url = "https://api.twilio.com/2010-04-01/Accounts/\(accountSID)/Calls"
  let parameters = ["From": "YOUR_TWILIO_NUMBER", "To": "YOUR_PERSONAL_NUMBER", "Url": "YOUR_TWIML_URL"]

  Alamofire.request(url, method: .post, parameters: parameters)
    .authenticate(user: accountSID, password: authToken)
    .responseJSON { response in
      debugPrint(response)
  }

  RunLoop.main.run()
}

Read ahead to learn how to get this code working. You’ll need to create a Twilio account if you haven’t already, and make sure you have Swift 4 installed.

What is this Alamofire thing?

In order to make a phone call with Twilio, we will need to make an HTTP request to Twilio’s REST API. We will be using a library called Alamofire to do this. Check out this other tutorial for more general info on sending HTTP requests in Swift.

We are going to use Swift Package Manager to handle dependencies. Start by initiating a Swift package in the directory where you want to run the code (I named my directory “SwiftCalls”):

swift package init --type executable

This will generate a Package.swift file for you, where we can add dependencies. Open Package.swift and make sure it has the following code:

// swift-tools-version:4.0
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "SwiftCalls",
    dependencies: [
        .package(url: "https://github.com/Alamofire/Alamofire.git", from: "4.0.0")
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages which this package depends on.
        .target(
            name: "SwiftCalls",
            dependencies: ["Alamofire"]),
    ]
)

Keep in mind that in the targets section you may need to modify the name to fit your package.

Now that we are good to go with dependencies, it’s time to get started with some code.

Creating a TwiML Bin

To define what happens during the phone call, we will need to write some TwiML, which is a set of instructions that tells Twilio what to do with a phone call or how to respond to a text message. In other programming languages, there are Twilio helper libraries you can use to avoid writing XML by hand, but that is not currently the case with Swift.

You would typically respond to a webhook request sent by Twilio to your server-side application with TwiML. This can be done using something like Vapor, but that’s not necessary right now. For this example we’ll use TwiML Bins, Twilio’s hosted solution for TwiML. TwiML Bins are awesome because you don’t have to write a bunch of extra code or host a web application just to make a simple phone call.

Let’s start by doing a basic redirect to another phone number. Click here to create a TwiML Bin. Name it whatever you want, add the following code to it, and click save when you are done:

<!--?xml version="1.0" encoding="UTF-8"?-->

    +13142026521

This TwiML will connect your phone call to another Twilio number that I created. Before moving on, take note of the URL for your TwiML Bin. We will need to use it later.

Making a phone call in Swift

In order to make a call, you’ll need a Twilio phone number. You can buy a phone number here (it’s free if you’re using the number to test your code during development).

You’ll also need to send your Twilio account SID and auth token as part of the request for the phone call. You can find those in your Twilio Console. Store them in environment variables with the following command:

export TWILIO_ACCOUNT_SID='YOUR_ACCOUNT_SID'
export TWILIO_AUTH_TOKEN='YOUR_AUTH_TOKEN'

Now open the file main.swift in your Sources/SwiftCalls/ folder (replace “SwiftCalls” with whatever you named your project) and add the following code:

import Foundation
import Alamofire

if let accountSID = ProcessInfo.processInfo.environment["TWILIO_ACCOUNT_SID"],
   let authToken = ProcessInfo.processInfo.environment["TWILIO_AUTH_TOKEN"] {

  let url = "https://api.twilio.com/2010-04-01/Accounts/\(accountSID)/Calls"
  let parameters = ["From": "YOUR_TWILIO_NUMBER", "To": "YOUR_PERSONAL_NUMBER", "Url": "YOUR_TWIML_URL"]

  Alamofire.request(url, method: .post, parameters: parameters)
    .authenticate(user: accountSID, password: authToken)
    .responseJSON { response in
      debugPrint(response)
  }

  RunLoop.main.run()
}

Remember to enter your Twilio phone number and personal phone number as the From and To values as well as the URL to your TwiML Bin as the Url value. Run it with this command, and you should receive a call!

swift build && ./.build/debug/SwiftCalls

To change the behavior of this phone call all you need to do is edit the code in your TwiML Bin. There are a bunch of things you can do with TwiML like creating conference calls or playing music over the phone.

Now what?

You can make calls from the server using Swift now. Congrats!

You might want to add this to an actual web application using a back end web framework for Swift such as Vapor. You also might want to try implementing this without using Alamofire if you don’t want to rely on dependencies. Check this post out to learn how to send HTTP requests in Swift 3 or 4.

If you want to do more with Swift and Twilio, you can check out these other posts:

If you have any other cool ideas, feel free to reach out and let me know or ask any questions: