Bluetooth in Windows 8.1 Apps nutzen

Eine spannende Neuerung von Windows 8.1 im Unterschied zu Windows 8 ist die native Unterstützung von Bluetooth RFCOMM mithilfe des Windows.Devices.Bluetooth namespaces. RFCOMM ist ein Bluetooth Protokoll das dazu genutzt werden kann, um Daten zwischen zwei Computern zu übertragen.

Prinzipiell läuft dieser Vorgang auf Seiten des Servers wie folgt ab:

  1. Erstellen einer RFCOMM-ServiceID (128-Bit) über die das angebotene Bluetooth-Service eindeutig identifizierbar ist (UUID genannt, Microsoft nennt es GUID)
  2. Erstellen eines listeners, der eine Funktion aufruft, sobald eine Verbindung zu einem anderen Gerät hergestellt wurde
  3. Binden der RFCOMM-ServiceID auf den listener
  4. Nutzung des erhaltenen Socket-Objekts um darauf Daten zu schreiben oder zu empfangen

Am Client passiert folgendes:

  1. Durchsuchen aller auf diesem Gerät bekannten Bluetooth-Services mittels der Methode FindAllAsync()
  2. Verbindung zu diesem Service mittels der Methode FromIdAsync()
  3. Nutzung des erhaltenen Socket-Objekts um darauf Daten zu schreiben oder zu empfangen

Es existiert hier ein Code-Beispiel, bei dem die Nutzung von Bluetooth anhand eines Chats erklärt wird (Der Server wurde in C# geschrieben, die Clients jeweils in C++ und JavaScript). Dieses Beispiel zum Laufen zu bringen bzw. nachzubauen kann sich allerdings als tückisch erweisen, weil einige Fallstricke vorhanden sind, vor denen nicht gewarnt wird. Aber glücklicherweise gibt es diesen Blog und viel Kaffee, sodass ich in einigen Nachtschichten die Geheimnisse von Bluetooth auf Windows 8.1 näher ergründen konnte.

Bluetooth Services hinzufügen

Wer das code-sample kompiliert und auf einem Gerät einen Server und auf dem anderen einen Client installiert, wird vom Client zu hören bekommen, dass kein Chat-Service vorhanden ist (“No chat service were found. Please pair Windows with a device that is advertising the chat service”).

Zunächst sollte sichergestellt werden, dass bei beiden Geräten Bluetooth korrekt installiert ist und beide Geräte gekoppelt sind. In Windows 8.1 öffnet man die Einstellungen über die Charms-Bar > “Einstellungen” > “PC-Einstellungen ändern” > “PC und Geräte” > “Bluetooth”. Das Gerät, mit dem man die Verbindung herstellen möchte, sollte hier aufscheinen und falls es noch nicht mit dem eigenen Gerät gekoppelt wurde, kann man das mit einem Klick ändern (die Kennzeichnung “Nicht verbunden” ist nicht weiter tragisch, wichtig ist, dass das andere Gerät dem eigenen bekannt und gekoppelt ist).
Mein Zweitgerät heißt ASTORIA und auf diesem läuft der Bluetooth-Chat-Server.
Wenn das Gerät hier nicht aufscheint, mit einem Klick auf das Bluetooth-Symbol in der Taskleiste (falls vorhanden, wenn nicht, in die Systemsteuerung navigieren) das Bluetooth-Menü öffnen und sicherstellen, dass auf beiden Geräten ein Häkchen neben “Bluetooth Geräte können diesen PC ermitteln” gesetzt ist.
Damit ist es noch nicht getan, denn das von ASTORIA gebroadcastete Chat-Service wurde noch nicht am Client aktiviert. Um das zu tun, wechseln wir in die Systemsteuerung > “Hardware und Sound” > “Geräte und Drucker”, klicken mit der rechten Maustaste auf unseren Bluetooth-Server und dann im Kontext-Menü auf “Eigenschaften”

Im sich öffnenden Fenster wählen wir den Reiter “Dienste” aus und aktivieren jenes Service, das wir nutzen wollen (in diesem Beispiel heißt das Service “Bluetooth Rfcomm Chat” und wird über den seriellen Anschluss angeboten).

ACHTUNG: Dieser Eintrag erscheint nur, wenn das andere Gerät (auf dem der Bluetooth-Chat-Server läuft) gerade broadcastet, also mittels der Methode .StartAdvertising() nach Clients lauscht.
Warum man diesen Dienst unbedingt manuell hinzufügen muss und warum Windows das nicht automatisch übernimmt (gekoppelt sind die Geräte ja schon) erschließt sich mir nicht. Noch dazu sind diese Einstellungen etwas versteckt. Aber sei es drum, nenne wir es einfach “Sicherheitsfeature”.

Die Tücken im App-Manifest

Hat man die obigen Einstellungen getätigt, sollte das Chat-Code-Beispiel nun laufen. Erstellt man eine eigene App, könnten sich aber erneut Probleme ergeben. Und zwar dann, wenn man am Server den listener auf den Namen binden möchte. Man erhält dann eventuell die Fehlermeldung:

0x80070005 - Runtime error: Access is denied (bzw: 0x80070005 - Laufzeitfehler: Zugriff verweigert)

Der Grund dafür ist, dass der Zugriff auf das Bluetooth-Gerät (noch) nicht erlaubt wurde. Wer jetzt in das App-Manifest blickt und dem Bluetooth-Gerät Berechtigungen geben möchte, der wird nicht fündig werden, denn im GUI existiert kein Eintrag dafür. Um ein Bluetooth-Gerät hinzuzufügen, müssen wir die Code-Ansicht öffnen (rechte Maustaste auf das Package.appxmanifest > “Code anzeigen”). Das Manifest ist eigentlich nichts anderes als eine gewöhnliche XML-Datei in der sich Dinge wie der App-Name, der Developer-Name und eben auch eine “Capabilites”-Liste befinden. In dieser Liste scheinen alle Geräte auf, auf die die App zugreifen darf. Wir fügen nach dem Applications-Endtag folgenden Eintrag hinzu:

   <Capabilities>
    <m2:DeviceCapability Name="bluetooth.rfcomm">
      <m2:Device Id="any">
        <m2:Function Type="serviceId:00001101-0000-1000-8000-00805F9B34FB" />
      </m2:Device>
    </m2:DeviceCapability>
  </Capabilities>

Hierbei tauschen wir die serviceID mit jener ID aus, die wir verwenden möchten. Der letzte Teil des App-Manifests sollte damit so aussehen:

Warum man Bluetooth-Geräte nicht in der GUI-Ansicht hinzufügen kann, erschließt sich mir abermals nicht… Egal, jedenfalls ist die Freude umso größer, wenn zwei Geräte dann tatsächlich über Bluetooth kommunizieren können. Und da Bluetooth bekanntlich ein offenes Protokoll ist, können auch viele coole Geräte von Drittanbietern gesteuert werden. Ein nettes Beispiel dafür ist der intelligente Ball “Sphero”, der über Bluetooth angesprochen und gesteuert werden kann.

Ein Kollege hat den Code um “Sphero” von einem Windows 8.1-Gerät (oder Windows Phone 8) aus zu steuern hier zum Download angeboten.