Background Fetch, Remote Notifications und Background Transfer Service

Systemressourcen bei der App-Entwicklung für iOS schonen

02.04.2015 von Mark Zimmermann
Die größten Stromfresser bei der Nutzung von mobilen Endgeräten stellen das Übermitteln von Daten sowie die Verwendung des Multitasking dar. Entwickler sollten daher dafür Sorge tragen, Systemressourcen zu schonen.

Bei der Entwicklung von iOS 8 hat Apple großen Wert auf Erhöhung der Performance sowie der Betriebszeit der Endgeräte gelegt. Abgesehen von einigen wenigen Ausnahmen laufen die in der Multitasking-Übersicht ersichtlichen Anwendungen nicht wirklich im Hintergrund. Wenn der Home-Button des iOS-Gerätes gedrückt wird oder die Multitasking-Geste ausgeführt wird, fordert iOS die laufende Anwendung auf, sich zu schließen. Fast immer kommen die Apps dieser Aufforderung nach, beenden sich komplett und beanspruchen keine Ressourcen mehr. Über die Multitasking API besteht die Möglichkeit, weitere Aktivitäten voran zu treiben.

Multitasking wurde von Apple initial mit iOS 4 - also zeitgleich mit dem iPhone 3GS - zur Nutzung als API bereitgestellt. Diese API ermöglicht es dem Entwickler, Apps für rudimentäre Ereignisse zu registrieren, um diese vom System zu empfangen. Somit ist es etwa möglich, GPS-Anwendungen auch im Hintergrund zu betreiben. In diesem bis einschließlich iOS 6 zur Verfügung gestellten Multitasking standen dem Entwickler jedoch keine Möglichkeiten zur Verfügung, effizient mit den Ressourcen des Endgerätes umzugehen.

So hat das iOS System vor iOS 7 nach der Gerätesperre über einen festen Zeitraum hinweg (ca. bis zu 10 Minuten) noch Rechenzeit bereitgestellt, diese dann aber zu einem fix definierten Zeitpunkt abgeschaltet. Ziel dieser Übung war es, Apps die Möglichkeit zu bieten, etwa mit ihren Downloads fertig zu werden - dies wurde ihnen aber nicht garantiert und gegebenenfalls durch iOS 6 hart unterbrochen. Auch ein mehr als zehnminütiger Download von Daten im Hintergrund war nicht möglich, erschwerend kam hinzu, dass alle Downloads (auch unterschiedlicher Apps) gleichzeitig abliefen.

Zwischenzeitlich stellt iOS Entwicklern die folgenden Möglichkeiten für Hintergrunddienste zur Verfügung:

Die möglichen Hintergrunddienste

Audio und Airplay

Die App gibt Audiomaterial auch im Hintergrund wieder oder zeichnet Audiosignale weiter auf. Dies betrifft auch das Streamen von Audio oder Videomaterial per Airplay.

Location Updates

Aktualisierung der User Location - auch im Hintergrundbetrieb der App.

Voice over IP

Bereitstellung von Telefonie über VoIP - auch wenn sich die App im Hintergrund befindet.

Newsstand downloads

Download von Inhalten aus dem Apple-Newsstand.

External accessory communication

Kommunikation mit entsprechend zertifizierter Hardware um deren Status zu abzufragen oder Status zu setzen.

Uses Bluetooth LE accessoires

Kommunikation mit Bluetooth Zubehör.

Acts as a Bluetooth LE accessory

Kommunikation über Bluetooth.

Background fetch

Die App kann Daten laden, auch wenn sie sich im Hintergrund befindet.

Remote notifications

Events, die z.B. durch angeschlossene Hardware (Kopfhörer Fernbedienungen) ausgelöst werden.

Multitasking im Überblick

Seit iOS 7 gibt Apple den Entwicklern drei neue Arten des Multitaskings per API an die Hand, hierzu gehören: Background Fetch, Remote Notifications und die Background Transfer Services. Diese drei neuen APIs geben dem Entwickler die Möglichkeit, Anwendungen die Möglichkeiten des Gerätes (iPad, iPhone) auch mit Hinblick auf die Akkulaufzeit optimal zu nutzen - siehe Abbildung 1.

iOS: Multitasking im Vergleich
Foto: Mark Zimmermann

App Status

Die Multitasking-Dienste können zu unterschiedlichen Applikationsstatus verwendet werden. Dabei stehen die folgenden Stati zur Laufzeit einer Applikation innerhalb von iOS zur Verfügung:

Status von Apps unter iOS 8

Not running

Die App wurde nicht gestartet oder wurde durch das System beendet. Die Anwendung wird weder durch das System regelmäßig geweckt noch kann sie Code ausführen.

Inactive

Ist nur ein temporärer Status, der im Übergang zwischen den anderen Stati angenommen wird.

Active

Die Anwendung ist im Vordergrund aktiv, empfängt Benachrichtigungen und führt Code aus. Dies ist der normale Status einer App.

Background

Die Anwendung befindet sich im Hintergrund und führt noch Programmcode aus. In einer App kann zusätzliche Verarbeitungszeit angefordert werden, um länger in diesem Modus zu verharren, um Prozesse abschließen zu können.

Suspended

Eine App ist gestartet, befindet sich im Hintergrund - führt aber keinen Code aus. Pausierte Apps werden regelmäßig durch iOS 8 geweckt und erhalten so die Möglichkeit, innerhalb kleiner Zeitfenster Code auszuführen.

Background fetch

Vor iOS 7 konnten Entwickler in Apps lediglich auf Inhalte aus dem Internet zugreifen, wenn sich diese im Vordergrund befanden. Dies führte dazu, dass viele Apps beim Start erst einmal eine Initialisierung durchführen mussten, um ihre Inhalte zu aktualisieren - bedingt durch diese Verzögerung beim Datenabruf spürten Anwender eine Latenz bei der Bedienung bis aktuelle Informationen angezeigt werden.

Die Verbindungsgeschwindigkeit des Endgerätes sowie die Qualität der Datenverbindung stellen hierbei einen maßgeblichen Faktor für die Dauer dar, bis die Daten in dieser Anwendung verfügbar sind und aktualisiert dargestellt werden. Weiterhin beeinflusste die Länge der Inaktivität einer App die Menge der nachzuladenden Daten.

Mit der Background Fetch API stellt iOS ein Mittel zur Verfügung um diesem Problem zu begegnen. Dank der API kann eine App Content laden - auch wenn sie im Hintergrund ist.

iOS stellt solchen Apps Ausführungszeit des Systems zur Verfügung, bis die Daten-Updates abgeschlossen sind. Nach Abschluss der Datentransaktionen versetzt iOS 8 die Apps wieder in den pausierten Zustand bis der Anwender die App - dann mit aktualisierten Daten - öffnet. Der Update-Zeitpunkt kann zu einem vom Entwickler vordefinierten Zeitpunkt oder zu einem vom System bestimmten Intervall erfolgen.

Aus Energieeffizienzgründen empfiehlt der Autor, soweit möglich die Systemintervalle zu nutzen. Wenn aus App-spezifischen Gründen eigene Intervalle definiert werden müssen, so sollten diese mit Bedacht gewählt werden, damit kein unnötiger Ressourcenverbrauch erzeugt wird.

Überlässt der Entwickler dem Systemintervall den Vorzug, erstellt iOS 8 Prognosen über die Nutzungszeitpunkte des Anwenders für die jeweilige App. Dies wird durch eine systeminterne Protokollierung der Nutzungshäufigkeit und Zeiten bewerkstelligt. Mit diesen Informationen wird systemintern bestimmt, wann die Daten geladen werden müssen, um sie dem Anwender rechtzeitig "vorgeladen" vorzuhalten.

Xcode Background Funktionen aktivieren (Tab: Capabilities)

Um diese Multitasking-API zu nutzen sind drei Schritte für den Entwickler notwendig. Der erste Schritt in diesem Prozess ist es, die Option des Background Fetching innerhalb des Xcode Projektes (siehe Abbildung) zu aktivieren.

Neben der Aktivierung im eigentlichen Projekt sollte innerhalb der App zunächst der Status der Hintergrunddienste abgefragt werden. So hat der Anwender über die Systemeinstellungen dennoch die Möglichkeit diese zu deaktivieren oder ggf. zu überschreiben.

Mit der in Listing 1 angegebenen Prüfung kann der Entwickler prüfen, ob die Dienste genutzt werden können um auf die gegebenen Möglichkeiten innerhalb seiner App zu reagieren.

Listing 1 - Prüfung der Hintergrunddienste

// Kontrolle, ob auf dem Gerät die Hintergrunddienste genutzt werden können.

if ([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusAvailable) {

NSLog(@"Hintergrunddienste können in der App genutzt werden.");

}

else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusRestricted)

{

NSLog(@"Hintergrunddienste stehen nicht zur Verfügung. Z.B. durch Einschränkung in Konfigurationsprofilen oder anderen Einschränkungen.");

}

else if([[UIApplication sharedApplication] backgroundRefreshStatus] == UIBackgroundRefreshStatusDenied)

{

NSLog(@"Der Benutzer hat die Hintergrunddienste explizit deaktiviert.");

}

Standardmäßig ist der Ausführungsintervall mit dem "UIApplicationBackgroundFetchIntervalNever mode" belegt, dies bedeutet, dass keinerlei Hintergrundaktivitäten vorgesehen sind. Dies kann durch eine Anpassung des Entwicklers innerhalb der Standardmethode eines Projektes application:didFinishLaunchingWithOptions angepasst werden.

Listing 2 - Minimales Intervall zur Hintergrundaktualisierung definieren

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{

[application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum]; return YES;}

Als Wert kann entweder "UIApplicationBackgroundFetchIntervalMinimum" (Listing 2) übergeben werden, um das "kürzest mögliche" Intervall anzufordern oder aber ein per NSTimeInterval individueller Zeitwert.

iOS 8 wird versuchen die Zeitintervalle entsprechend einzuhalten, jedoch das Ganze an der Verfügbarkeit der Systemressourcen optimieren. Ferner versucht iOS 8 die Zeitintervalle unterschiedlichere Apps aufeinander abzustimmen.

Als letzter Integrationsschritt muss der neue EventHandler "application:performFetchWithCompletionHandler" verwendet werden.

Dieser Event wird bei Hintergrundaktivität aufgerufen und startet den Code zum Laden und Verarbeiten der geladenen Daten. Zur (Fehler-)Fallverarbeitung muss der Entwickler innerhalb dieses Events dem Betriebssystem mitteilen, dass entweder

Stehen neue Daten zur Verfügung, muss der Entwickler ferner das Interface für den Anwender updaten. Hierbei erzeugt iOS 8 automatisch einen neuen App-Screenshot (für den Taskmanager) wodurch eine "Art" echtes Multitasking für den Anwender simuliert wird. Die aktuellen Daten stehen dem Anwender nun sofort nach Aufruf der App zur Verfügung.

Der Autor empfiehlt für den Einsatz im Firmenumfeld, die Erstellung der Screenshots zu unterdrücken, zu löschen oder durch ein Standardhintergrundbild zu ersetzen. Anderenfalls könnten Unbefugte beim Durchwischen des Taskmanagers vertrauliche Informationen einsehen.

Es gibt jedoch eine wichtige Tatsache zu beachten. Die Ausführung innerhalb des Events inkl. des abschließenden Aufrufs des "completionHandler" ist auf maximal 30 Sekunden beschränkt. Braucht die Anwendung länger als 30 Sekunden, wird diese bis zum nächsten Intervall wieder "schlafen" gelegt. Werden größere Downloads benötigt, muss der Entwickler die Background Transfer Service API in der App verwenden.

Mögliche Risiken und Nebenwirkungen...

Background Fetch, also die beschriebene Möglichkeit, im Hintergrund regelmäßig auf Updates zu prüfen, kommt bei falscher Konfiguration einem zerstörerischen Bot-Netz gleich. Jede verteilte Kopie der eigenen Anwendung stellt periodisch Anfragen über deren Internet-Verbindung. Lediglich die Steuerung von iOS selbst (pro Gerät) sorgt für eine theoretische Begrenzung der Anfragen. Wenn die Anwendung nun an Beliebtheit und Popularität gewinnt, steigt der Traffic auf ein nicht absehbares Ausmaß. Neben dem Risiko einer dadurch entstehenden DoS Attacke gegen einen WebServer sind Abfragen an Bezahldienste ein nicht zu unterschätzendes Finanzrisiko. Auch die Nutzung kostenpflichtiger Dienste unter Verwendung von API-Keys kann so zur Kostenfalle werden.

Remote notifications

Remote Notifications sind eine Art "silent push notification". Der Unterschied zu den einher bekannten Push Notifications ist, dass die App selbst diese Benachrichtigungen empfängt und unmittelbar darauf reagieren kann. Eine User-Interaktion ist nur dann notwendig, wenn die App diese explizit anfordert.

Eine Remote Notification kann über die bestehende Push Infrastruktur abgesetzt werden - lediglich in der Payload der Notification muss der Wert "content-available" mit dem Wert 1 versehen werden. iOS interpretiert diese notifications dann entsprechend und reicht sie direkt an die App und deren Delegates weiter um individuell darauf reagieren zu können.

Mit der Remote Notifications API ist es hierdurch möglich auf individuelle Ereignisse zu reagieren und entsprechenden Programcode im Bedarfsfall auszuführen.

Hierdurch können regelmäßige Poll-Versuche von Apps reduziert werden - ein sinnvoller Einsatz dieser Technik kann somit merklich zu einer Reduzierung des Energieverbrauchs führen.

Eine App kann somit durch einen Server informiert werden, wenn neue Daten zur Verarbeitung vorliegen, diese dann abrufen und verarbeiten. Gerade bei unregelmäßigen Updates stellt dies eine energieeffiziente und ressourcenschonende Lösung dar.

Um diese Art des Multitasking nutzen zu können, muss dies ebenfalls in dem "Capabilities" Tap des Projektes aktiviert werden (Background Mode: Remote Notifications).

Ergänzend zur Aktivierung des Modus in den Projekteinstellungen muss im Anschluss auch der entsprechende Eventhandler "application:didReceiveRemoteNotification:fetchCompletionHandler" implementiert werden. Diese Protokollmethode wird in der App vom System aufgerufen, sobald der jeweilige Event eintritt. Auch diese API unterliegt der 30 Sekunden Verarbeitungszeit. Zusätzlich ist auch eine Besonderheit bei den hier verwendeten Notifications zu beachten: Alle Notifications laufen über das Backend von Apple. Silent Push Notifications werden von Apple gesammelt und mit "normalen" Notifications zum Endgerät mitgeschickt. Bleiben normale Notifications aus, überträgt Apple diese zu einem festen intern definierten Zeitpunkt.

Background Transfer Service

Wenn eine App größere Datenmengen über das Internet beziehen muss, empfiehlt es sich für Entwickler den Background Transfer Service zu nutzen. Dieser ermöglicht es Entwicklern das 30-Sekunden-Zeitfenster zu umgehen und umfangreiche Datenmengen im Hintergrund zu beziehen. Diese API stellt eine Systemwarteschlange (Queue) für Dateidownloads zur Verfügung. Diese Warteschlange wird von iOS 8 sehr robust verwaltet und bleibt auch nach Neustarts des Systems erhalten und ggf. weiter abgearbeitet.

Die Nutzung erfolgt über die Klasse NSURLSession. Diese Klasse ermöglicht den Dateitransfer über die Protokolle HTTP/HTTPS. Die NSURLSession stellt einen stark konfigurierbaren Container mit fein granularer Konfigurierbarkeit (z.B Unterstützung von "Privat Browsing) dar.

Die kleinste Einheit der NSURLSession stellt das Task Objekt (NSURLSessionTask) dar. Dabei handelt es sich um die Ausprägungen NSURLSessionDataTask, NSURLSessionUploadTask-, NSURLSessionDownloadTask. Die hierüber verwalteten Aktionen unterliegen keiner Zeitlimitierung.

Die NSURLSessionDataTask Klasse wird verwendet, um Daten von einem Server zu beziehen. Der grundsätzliche Unterschied zu Upload- und Download-Tasks liegt hierbei in der direkten "in Memory" Bereitstellung der Daten für die auftraggebende App - dies erfolgt ohne Umweg über das Dateisystem.

Die Klassen NSURLSessionUploadTask und NSURLSessionDownloadTask stellen eine Unterklasse der NSURLSessionDataTask dar. Im Gegensatz zum NSURLSessionDataTask lassen sich Upload- und Download-Vorgänge pausieren.

Nach der erfolgreichen Abarbeitung der Task Objekte in der Warteschlange wird dies der jeweiligen App, über den EventHandler ("application:handleEventsForBackgroundURLSession:completionHandler:") mitgeteilt. Innerhalb dieser Methode muss der Entwickler für die permanente Speicherung der empfangenen Daten sorgen, diese je nach Anwendungsfall verarbeiten und ggf. das Benutzerinterface aktualisieren (Listing 3).

Listing 3 - Daten permanent speichern

/**

* Unsere NSURLSession hat einen Download abgeschlossen und die Protokollmethode wird aufgerufen.

* Quelle: SimpleBackgroundTransfer Example von Apple.

*/

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask

*)downloadTask didFinishDownloadingToURL:(NSURL *)downloadURL

{

// Download wurde fertiggestellt - wir erzeugen einen NSFileManager zum Speichern

NSFileManager *fileManager = [NSFileManager defaultManager];

// Wir ermitteln den Ort für die Ablage der heruntergeladenen Daten

NSArray *URLs = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];

NSURL *documentsDirectory = [URLs objectAtIndex:0];

NSURL *originalURL = [[downloadTask originalRequest] URL];

NSURL *destinationURL = [documentsDirectory URLByAppendingPathComponent:[originalURL lastPathComponent]];

NSError *errorCopy;

// Wir entfernen ggf. schon vorhandene Daten

[fileManager removeItemAtURL:destinationURL error:NULL];

BOOL success = [fileManager copyItemAtURL:downloadURL toURL:destinationURL error:&errorCopy];

if (success)

{

// Das Speichern ist erfolgt, nun können wir z.B. darauf reagieren und die Anzeige aktualisieren oder die Daten verarbeiten.

});

}

else

{

// Es ist ein Fehler aufgetreten, den wir nun individuell auswerten können.

}

}

Für eine pragmatische Nutzung der APIs empfiehlt der Autor eine sinnvolle Kombination dieser.

Die zeitlimitierten Dienste eigenen sich vornehmlich für kurze und einfache Statusaktualisierungen sowie Initialisierungen von Apps - ggf. um einen Datentransfer und z.B. die Background Transfer Services anzustoßen.

Bei Apps im Unternehmensumfeld müssen Entwickler zudem bedenken, dass diese bei der Nutzung von NSURLSession dafür Sorge tragen müssen, dass die Möglichkeiten zur separierten und privaten Speicherung der Downloaddaten, die NSURLSession bereitstellt, zum Einsatz kommen. Das soll ein Kompromittieren der Nutzdaten während des Herunterladens unterbinden.

Geo-Ortung

Neben Download- und Kommunikationsverhalten im Hintergrund bei Multitasking Apps hat auch die Nutzung der Ortungsdienste maßgebliche Auswirkungen auf das Laufzeitverhalten sowie Nutzererlebnis der Apps. Die Nutzung der Ortungsdienste erfolgt über das Core Location Framework (PDF). Entwickler könne mit diesem Framework den Standort des Gerätes abfragen und in ihrer App nutzen.

Die Lokalisierung erfolgt auf Basis der Funkzellendaten, des GPS-Standortes sowie WLAN-Datenbanken. Hierbei lassen sich zwei Varianten der Ortung unterscheiden:

  1. Ein Entwickler legt mit dem --Standard Location Service -- fest, auf welche Ortungshardware des iOS-Gerätes zurückgegriffen werden soll (GPS, Funkzellen, verortete Wi-Fi Hotspots) und in welchen Zyklen der Standort überprüft werden soll. Die Genauigkeit der Ortung wirkt sich hierbei unmittelbar auf den Energieverbrauch aus - je mehr Interaktion zwischen einer App und der Hardware stattfindet, so stärker steigt auch der Energieverbrauch an. Dieser Service kommt z.B. bei Navi-Apps zum Einsatz und steht allen iOS Versionen zur Verfügung. Aktiviert ein Entwickler die Background Location Services, so kann er die Ortungsdienste auch dann in seiner App nutzen, wenn sich diese nicht im Vordergrund befindet.

  2. Seit iOS 4.0 steht außerdem der -- Significant Location-Change Service -- zur Verfügung. Dieser ist akkuschonender, da er die genauen Standortdaten nur dann aktualisiert, wenn sich das Gerät innerhalb einer Funkzelle bewegt bzw. diese wechselt. Dabei kümmert sich iOS selbstständig um die Abfragezyklen. Wird eine Veränderung erkannt, wird der Standort mit Hilfe der WLAN-Datenbanken und des GPS-Moduls so genau wie möglich bestimmt und an die nachfragenden Apps weitergeleitet.

Darüber hinaus kann dieser Dienst auch bestimmte Apps aufwecken, wenn ein z.B. ein vorher definierter Ort erreicht wird (Geofencing). Hierzu baut iOS einen virtuellen Zaun um die GPS Zielkoordinate auf und informiert wartende Apps beim Überqueren des Zauns. Solche Zäune sind über maximal 20 Orte definierbar. Die ortsbezogene Auswertung erfolgt dabei mithilfe des CLLocationManagers. Dieser wird zuerst mit verschiedenen Rahmenparametern initialisiert um z.B. die Auflösungsdistanz der Auswertung festzulegen (Listing 4). Es ist zu beachten, dass sich die Einstellung für den Distanzfilter direkt auf den Energieverbrauch des Gerätes auswirkt.

Listing 4 - Initialisierung CLLocationManager

locationManager=[[CLLocationManager alloc] init];

locationManager.delegate=self;

locationManager.distanceFilter=kCLLocationAccuracyHundredMeters;

locationManager.desiredAccuracy=kCLLocationAccuracyBest;

[locationmanager startUpdatingLocation];

Entwickler können über die Callback-Methoden didEnterRegion und didExitRegion des CLLocationManager feststellen, ob ein Anwender eine Region betritt oder verlässt.

Fazit

Background Fetch, Remote Notifications und Background Transfer Service APIs sind Features um die Erlebnisqualität der Anwender drastisch zu verbessern. Dies geschieht unter bei gleichzeitiger Optimierung der Ressourcen des Endgerätes und ermöglicht es Apps zu erstellen, die zumindest virtuell immer "up-to-date" sind. (mb/cvi)