Senden einer SMS über iOS in Swift

November 02, 2016
Autor:in:

Senden einer SMS über iOS in Swift


Hallo und Danke fürs Lesen! Dieser Blogpost ist eine Übersetzung von How to Send an SMS from iOS in Swift. Während wir unsere Übersetzungsprozesse verbessern, würden wir uns über Dein Feedback an help@twilio.com freuen, solltest Du etwas bemerken, was falsch übersetzt wurde. Wir bedanken uns für hilfreiche Beiträge mit Twilio Swag :)

Das Versenden von Textnachrichten über eine iOS-App war bislang problematisch. Unsere Freunde auf Android haben das Problem bereits gelöst, nun sind wir an der Reihe. In unserem Fall lösen wir das Problem mit Swift.

Warum sollten wir keine SMS über die REST-API in Swift senden?

Twilio ist zwar eine REST-API, an die wir direkt eine HTTP-Anfrage senden könnten, aber das hieße auch, dass wir unsere Twilio-Anmeldeinformationen in der App speichern müssten, was ein erhebliches Sicherheitsrisiko darstellt. Ein Angreifer könnte die Anwendung dekompilieren, die Anmeldeinformationen extrahieren und unser Twilio-Konto für jeden beliebigen Zweck missbrauchen.

Ich wette, @SwiftOnSecurity hätte einiges dazu zu sagen.

Um dieses Risiko zu vermeiden, erstellen wir eine Back-End-Anwendung, die die Twilio-REST-API implementiert, unsere Anmeldeinformationen umschließt und SMS-Nachrichten für uns sendet. Dann können wir unsere Back-End-Anwendung über die Swift-Anwendung aufrufen und SMS-Nachrichten senden, ohne unsere Anmeldeinformationen preiszugeben.
Neben der Twilio-REST-API benötigen wir zum Senden einer Nachricht noch folgende Tools:

Einrichten des Python-Servers

Da wir Python auf dem Back-End verwenden und eine kleine Flask-Anwendung ausführen, öffnen wir unseren bevorzugten Texteditor und erstellen eine app.py-Datei.
Wir testen die Funktion mit einem kurzen „Hello World“-Programm:

from flask import Flask

app = Flask(__name__)

@app.route('/hello', methods=['GET'])
def say_hello():
    res = 'Hello World'
    return str(res)

if __name__ == '__main__':
        app.run()

Im Terminal führen wir die Anwendung über das Projektverzeichnis aus, in dem sich die app.py-Datei befindet:

python app.py

Wenn wir jetzt http://127.0.0.1:5000/hello oder einen anderen Port aufrufen, auf dem unsere Anwendung im Browser ausgeführt wird, sollten wir diese kurze „Hello World“-Nachricht sehen.
Dann müssen wir dafür sorgen, dass wir die Anwendung auch außerhalb des Localhosts erreichen können. Dazu führen wir sie über ngrok aus. Im Terminal führen wir Folgendes aus:

ngrok http 5000

Mit der erzeugten URL können wir unserer mobilen Anwendung Zugriff auf das Back-End gewähren. Wir sollten in etwa Folgendes sehen:

ngrok

Senden von SMS mit Snakes

Da die Grundlagen wie erwartet funktionieren, können wir unseren „Hello World“-Code durch einen neuen Endpunkt zu unserer Flask-Anwendung ersetzen, der das Senden von SMS-Nachrichten verarbeitet. Die iOS-Anwendung kann dann Anfragen an diesen Endpunkt senden, und damit haben wir unser Ziel erreicht.

from flask import Flask, request

from twilio.rest import Client

app = Flask(__name__)
 
# put your own credentials here 
ACCOUNT_SID = 'YOUR_ACCOUNT_SID' 
AUTH_TOKEN = 'YOUR_AUTH_TOKEN' 
 
client = Client(ACCOUNT_SID, AUTH_TOKEN)
 
@app.route('/sms', methods=['POST'])
def send_sms():
    message = client.messages.create(
        to=request.form['To'], 
        from_='YOUR_TWILIO_PHONE_NUMBER', 
        body=request.form['Body'],
    )

    return message.sid

if __name__ == '__main__':
        app.run()

Wir müssen darauf achten, dass wir die Konto-SID, das Authentifizierungstoken und die Twilio-Telefonnummer durch unsere tatsächlichen Werte aus der Twilio-Konsole ersetzen. Dann können wir die App mit dem folgenden Befehl neu starten: python run app.py.

Wenn wir uns vergewissern möchten, dass auch alles richtig funktioniert, senden wir eine kurze curl-Anfrage mit unserer Telefonnummer und der ngrok-URL.

curl -XPOST --data "To= YOUR_PHONE_NUMBER&Body=Test message" http://YOUR_NGROK_URL/sms

Alternatives Senden von SMS mit Twilio Functions

Beim Erstellen von Grund auf möchten wir wahrscheinlich schneller in die Produktion wechseln können, als es unsere kleine Python-Anwendung zulässt.

Wir müssen darauf achten, dass Functions in der Konsole aktiviert ist. Dann verwenden wir den folgenden Code, um das gleiche wie in Python durchzuführen.

exports.handler = function(context, event, callback) {
    const client = context.getTwilioClient();
    const to = event.To;
    const body = event.Body;
    client.messages.create({
      from: 'YOUR_TWILIO_PHONE_NUMBER',
      to: to,
      body: body
    }).then(msg => {
      callback(null);
    });
};

Wir speichern den Code. Dabei dürfen wir nicht vergessen, oben unsere Twilio-Telefonnummer zu konfigurieren.

Schließlich verwenden wir statt der ngrok-URL den Pfad, den wir oberhalb der Funktion finden. Der sieht ungefähr so aus:

https://limit-used-8951.twil.io/sms

Dafür gibt es eine App

Nun, da unsere Python-Anwendung ausgeführt wird, können wir uns an das Erstellen der iOS-App machen.

Wir klonen dieses Repository, das eine Storyboard-Einrichtung mit automatischem Layout und den entsprechenden UILabels, UITextFields und UIAction für diese Anwendung enthält. Ich verwende Xcode 8 und Swift Version 3.

Öffne das Terminal und navigiere zum gewünschten Speicherort dieses Projekts. Gib den folgenden Befehl ein und klone ihn. Du kannst auch eine ZIP-Datei des Projekts herunterladen:

git clone https://github.com/meganspeir/TwilioSms.git

Die Abhängigkeit, die wir für dieses Projekt benötigen, installieren wir mit CocoaPods. Falls noch nicht vorhanden, musst du zuerst CocoaPods installieren:

sudo gem install cocoapods

In dem Repository, das wir soeben geklont haben, befindet sich eine Podfile-Datei, in der die Abhängigkeiten aufgeführt sind, die installiert werden müssen. Wir verwenden lediglich Alamofire zum Senden von HTTP-Anfragen, deshalb finden wir nur diese Abhängigkeit in der Liste. Zur Installation verwenden wir den folgenden Befehl:

pod install

Möglicherweise sagt uns eine Fehlermeldung, dass wir pod repo update ausführen müssen, da es nicht mehr auf pod install in CocoaPods 1.0 ausgeführt wird. Nachdem wir das erledigt haben, sollten wir pod install erneut ohne Fehler ausführen können.
CocoaPods kümmert sich um die Verknüpfung aller Frameworks, indem es einen neuen Xcode-Arbeitsbereich erstellt. Wenn wir das Projekt von nun an in Xcode öffnen, müssen wir TwilioSms.xcworkspace statt unser normales Xcode-Projekt verwenden:

open TwilioSms.xcworkspace

Wir navigieren zu ViewController.swift. Dort ist der folgende Code bereits vorhanden:

class ViewController: UIViewController {
    
    @IBOutlet var phoneNumberField: UITextField!
    @IBOutlet var messageField: UITextField!
    
    @IBAction func sendData(sender: AnyObject) {
        
    }
    
    //

}

Dieser Ausschnitt legt folgende Variablen fest: eine Telefonnummer, phoneNumberField und eine Nachricht, messageField mit UITextField-Ausgängen zum Erfassen der Benutzereingaben. Außerdem haben wir ein @IBAction-Ziel mit dem ViewController verbunden und die Aktion als sendData(_:)-Methode festgelegt, die aufgerufen wird, wenn auf die Schaltfläche „Send“ getippt wird.

Wir können die korrekte Installation von Alamofire prüfen, indem wir die folgende Zeile zu ViewController.swift unterhalb des standardmäßigen import UIKit hinzufügen:

import Alamofire

Wir drücken Befehl+B, um zu bestätigen, dass das Projekt mit unserer Abhängigkeit erstellt wird.

xcode

Beim Erstellen und Ausführen des Projekts können wir ausprobieren, in die UITextFields etwas einzugeben, aber im Moment sind diese noch ohne Funktion. Das werden wir aber gleich ändern.

Senden von POST-Anfragen mit HTTP in Swift über Alamofire

Wir öffnen ViewController.swift und fügen den folgenden Code der ViewController-Klasse innerhalb der sendData(_:)-Methode hinzu:

    @IBAction func sendData(sender: AnyObject) { 
        let headers = [
            "Content-Type": "application/x-www-form-urlencoded"
        ]
        
        let parameters: Parameters = [
            "To": phoneNumberField.text ?? "",
            "Body": messageField.text ?? ""
        ]
        
        Alamofire.request("YOUR_NGROK_URL/sms", method: .post, parameters: parameters, headers: headers).response { response in
                print(response)
            
        }
    }

Wir haben die Parameter für eine POST-Anfrage an unseren Flask-Server festgelegt. Dazu haben wir Werte aus unseren UITextField-Ausgängen für die Parameter To und Body verwendet. Anschließend geben wir den Anfrage-Header als URL-codierten Formular-Header an, damit Twilio die Daten wie zuvor bei der Anfrage mit curl akzeptieren kann.

Voilà! Wir haben gerade eine SMS von T. Swift empfangen. Genau …Twilio Swift!

 

Sichere Verwendung mit Swift

Wenn wir ein potenzielles Sicherheitsrisiko in unserer Anwendung ausmerzen können, ist das immer ein Grund zum Feiern.

Congratulations!

Außerdem haben wir Python-Code erstellt, den wir auf anderen Plattformen wiederverwenden und an den wir weiterhin direkt HTTP-Anfragen senden können.

Auf ähnliche Weise könnten wir eine Telefonnummernsuche hinzufügen oder Telefonanrufe direkt in der App erzeugen. Wenn wir IP-MessagingVideo oder Client verwenden möchten, benötigen wir außerdem einen Server zum Erzeugen von Zugriffstoken für diese Dienste. Egal welche Herausforderungen der Kommunikation uns erwarten, wir verfügen jetzt über das erforderliche Handwerkszeug.

Ich würde gern erfahren, an welchen Entwicklungen du gerade arbeitest. Du findest mich auf Twitter @meganspeir, oder sende eine E-Mail an mspeir@twilio.com.