»Hello World« am Apple TV 4

Mit der vierten Generation des Apple TVs hat Apple das Gerät (endlich) auch für Entwickler interessant gemacht. In Xcode können Sie nun tvOS-Apps programmieren und in der Apple-TV-Sparte des App Stores zum Download bzw. Verkauf anbieten. Dabei gibt es grundsätzlich zwei Arten von Apps: Native Apps, die in Objective C oder Swift entwickelt werden, sowie JavaScript-Apps, die auf einen externen Server zugreifen (Konzept in der Apple-Dokumentation). Ich gehe hier nur auf die Native-Swift-Variante ein.

Gerät registrieren

Eine neue tvOS-App starten Sie in Xcode wie üblich mit File / New / Project. Dabei wählen Sie als Vorlage tvOS Application / Single View Application aus. Das aus der Vorlage produzierte Projekt ist sofort ausführbar (auch wenn es natürlich nichts tut und lediglich einen grau melierten Hintergrund zeigt). Allerdings beklagt sich Xcode nun darüber, dass es die App nicht signieren könne, weil die erforderlichen Provisioning Profiles fehlen würden. Das Problem lässt sich mit Fix Issue unkompliziert lösen — vorausgesetzt, Sie haben Ihr Apple-TV-Gerät mit einem USB-C-Kabel mit Ihrem Mac verbunden.

Der erste Versuch, ein tvOS-App zu starten, führt zu einer Fehlermeldung
Der erste Versuch, ein tvOS-App zu starten, führt zu einer Fehlermeldung

Kabel-Chaos: Apple-TV-Geräten liegt eine Fernbedienung und ein Lightning-Kabel bei. Dessen einziger Zweck besteht darin, dass Sie damit den eingebauten Akku der Fernbedienung aufladen können. Ich hätte gedacht, dass ich mit diesem Kabel auch das Apple-TV-Gerät mit meinem Mac verbinden könnte — aber falsch gedacht. Dazu brauchen Sie ein USB-C-Kabel! Warum in alles in der Welt baut Apple in die Fernbedienung eine Lightning-Buchse ein, in das Gerät aber einen USB-C-Buchse? Dass Apple seinen selbst entwickelten Lightning-Adapter zugunsten USB-C aufgibt, diese Hoffnung habe ich schon längst begraben. Aber wenn schon Lightning, dann doch zumindest konsequent …

Ein USB-Verbindung zwischen Ihrem Mac und dem Apple-TV-Gerät vorausgesetzt, bewirkt Fix Issue, dass das tvOS-Gerät zur Liste der Geräte Ihres Apple-Developer-Account hinzugefügt wird. (Davon können Sie sich mit einem Blick auf https://developer.apple.com/account/ios/device/tvOS vergewissern.) Gleichzeitig lädt Xcode die erforderlichen Signing Identities und Provisioning Profiles herunter (siehe Xcode / Einstellungen / Accounts / Details).

App-Entwicklung in Xcode

Die Entwicklung einer tvOS-App in Xcode folgt nach den gleichen Konzepten wie bei iOS- oder OS-X-Apps: Sie gestalten im Storyboard-Editor die Benutzeroberfläche und verbinden diese dann mit eigenem Code. Als extrem irritierend hat sich dabei die riesige Darstellung des Storyboards herausgestellt: Selbst auf einem 27-Zoll-Monitor kann eine Ansicht des Storyboard nur dann vollständig angezeigt werden, wenn nahezu alle anderen Xcode-Elemente ausgeblendet werden. Eine verkleinerte Darstellung ist zwar möglich (Editor / Canvas / Zoom), dann ist aber keine Interaktion mehr möglich. Absurd! Auf einem Notebook ist es nahezu unmöglich, eine tvOS-Oberfläche zu gestalten. (Das Problem wurde auch in den Apple-Entwickler-Foren diskutiert, Lösung gibt es aktuell aber keine.)

Selbst auf einem 27-Zoll-iMac füllt das Storyboard nahezu den gesamten Bildschirm. Auf kleineren Displays wird die Arbeit zur Qual.
Selbst auf einem 27-Zoll-iMac füllt das Storyboard nahezu den gesamten Bildschirm. Auf kleineren Displays wird die Arbeit zur Qual.

Test im Simulator

tvOS-Programme können in einem Simulator getestet werden. Dieser zeigt die App anfänglich genau so riesig an wie im Storyboard-Editor von Xcode. Im Simulator lässt sich das glücklicherweise mit Window / Scale ändern. Auch in der verkleinerten Darstellung bleibt die App bedienbar.

Die Steuerung der App im Simlulator ist allerdings mühsam: Die App reagiert nicht auf Maus- oder Touchpad-Bewegungen bzw. -Clicks. Stattdessen müssen Sie die Fernbedienung einblenden und bei deren Steuerung dann gleichzeitig die Alt-Taste drücken. Alles in allem ist selbst in einfachen Fällen ein Test an einem echten Apple-TV-Gerät unumgänglich.

tvOS-App im Simulator ausprobieren
tvOS-App im Simulator ausprobieren

Screenshots

Um Screenshots der App im Live-Test (also ohne Simulator) zu erstellen, öffnen Sie in Xcode Window/Devices und wählen dort das Apple-TV-Gerät aus. Im Hauptfenster erscheint dann der Button Take Screenshot. Die Screenshots werden auf dem OS-X-Schreibtisch (Desktop) gespeichert.

tv-screenshot

Hello World!

Als Hello-World-App habe ich eine minimalistische Oberfläche mit vier Buttons gestaltet. Wenn der Benutzer einen Button auswählt und anklickt, werden im Textfeld darunter diverse Informationen angezeigt.

Screenshot der Hello-World-App
Screenshot der Hello-World-App

Der dazugehörende Code in der ViewController-Klasse sieht so aus:

import UIKit

class ViewController: UIViewController {

  @IBOutlet weak var outputText: UITextView!

  override func viewDidLoad() {
    super.viewDidLoad()
  }


  @IBAction func showDateTime(sender: UIButton) {
    let now = NSDate()
    outputText.text = now.descriptionWithLocale(NSLocale.currentLocale())
  }

  @IBAction func showMemory(sender: UIButton) {
    let gbyte = Double(1024*1024*1024)
    let ram = NSProcessInfo.processInfo().physicalMemory
    let flashtotal = deviceTotalInBytes()
    let flashfree = deviceRemainingFreeSpaceInBytes()

    // formatieren
    let fmt = NSNumberFormatter()
    fmt.minimumFractionDigits = 2
    fmt.maximumFractionDigits = 2
    let ramfmt   =
      fmt.stringFromNumber(Double(ram) / gbyte)!
    let flashfreefmt =
      fmt.stringFromNumber(Double(flashfree) / gbyte)!
    let flashtotalfmt =
      fmt.stringFromNumber(Double(flashtotal) / gbyte)!

    // ausgeben
    outputText.text =
      "Arbeitsspeicher (RAM, insgesamt):  \(ram) Byte = \(ramfmt) GByte\n" +
      "Gerätespeicher (Flash, insgesamt): \(flashtotalfmt) GByte\n" +
      "Gerätespeicher (Flash, noch frei): \(flashfreefmt) GByte"
  }

  @IBAction func showVersion(sender: UIButton) {
    let v = UIDevice.currentDevice().systemVersion
    outputText.text = "tvOS-Version \(v)"
  }

  @IBAction func showIpAddress(sender: UIButton) {
    var out = ""
    for s in getIPAddresses() {
      out += s + "\n"
    }
    outputText.text = "IP-Adresse(n): " + out
  }
}

Nicht im Listing enthalten sind die Funktionen deviceRemainingFreeSpaceInBytes, deviceTotalInBytes und getIPAddresses. Sie sind auf den unter Quellen angegebenen Stackoverflow-Seiten im Detail dokumentiert. Bemerkenswert ist, dass getIPAddresses selbst dann nur eine IP-Adresse liefert, wenn das Apple-TV-Gerät über WLAN-Zugang und eine Ethernet-Verbindung verfügt. In diesem Fall hat Ethernet Vorrang, die WLAN-Verbindung bleibt ungenutzt.

Quellen

Download

Hier können Sie den Quellcode des Hello-World-App herunterladen (erfordert Xcode 7.3, getestet mit Swift 2.2 unter tvOS 9.2):

tv-first-test.zip