Donnerstag, 30. Mai 2013

Near Field Communication mit Windows Phone

Near Field Communication (NFC) ist ein internationaler Standard zum kontaktlosen Austausch von Daten per Funktechnologie über kurze Strecken von bis zu 10 cm mit einer Datenübertragungsrate von maximal 424 kBit/s. Obwohl die Entwicklung der Technologie bereits ihre Anfänge in 2002 hatte, steckt ihre Verbreitung bisher noch in den Startlöchern. Die immer größer werdende Anzahl von NFC-fähigen Geräten - insbesondere Smartphones -, die vielfältigen Einsatzmöglichkeiten und die einfache Handhabung machen diese Technologie jedoch zunehmend interessanter für kommerzielle Anwendungen.

Etwas Historie

Die NFC Technologie basiert auf die bereits im zweiten Weltkrieg eingesetzte RFID-Technologie (radio-frequency identification). Hier wurden Transponder und Lesegeräte an Panzern und Flugzeugen eingesetzt, um fremde von eigenen Fahrzeugen unterscheiden zu können. In den 70igern gab es dann die ersten Systeme zur Sicherung von Waren auf RFID-Chip Basis. Ab 1990 wurden große Fortschritte in der technologischen Entwicklung von Transpondern erzielt, sodass immer mehr Anwendungen entwickelt wurden. Darunter zählen Zugangskontrollen zu Gebäuden, die Wegfahrsperre in Autos, Mautsysteme oder die Zeiterfassungen in Betrieben und die Zeitmessung bei Sportveranstaltungen.

NFC wurde im Jahre 2002 durch die beiden Firmen NXP Semiconductors und Sony entwickelt, die führend im Bereich von kontaktlosen Chipkarten sind. Zwei Jahre später wurde durch diese beiden Firmen und Nokia das NFC Forum gegründet. Dieses hat es sich zur Aufgabe gemacht, die Entwicklung von NFC voranzutreiben und weiter zu standardisieren. Die ersten NFC-fähigen Handys gab es bereits 2005, mit denen ein Feldversuch in Frankreich durchgeführt wurde. Hier konnten Benutzer Waren im Einzelhandel bezahlen, Parktickets kaufen oder touristische Informationen abrufen. In Deutschland wurde ebenso 2005 ein Feldversuch für den Personennahverkehr vom Rhein-Main-Verkehrsverbund (RMV) gestartet, bei dem Fahrscheine über ein Handy gekauft werden konnten.

 

Wo wird NFC genutzt?

Bisher kommt diese Technik vor allem in Lösungen für das Micropayment - bargeldlose Zahlungen kleiner Beträge – zum Einsatz. In Deutschland wird die Technik beispielsweise von den Sparkassen, unter dem Namen girogo zur Zahlung von Summen bis zu 20 Euro angeboten. Des Weiteren bietet die Deutsche Bahn mit dem Touch & Travel-System ein sehr einfaches Verfahren zum Erwerben von Fahrtickets mit NFC-fähigen Smartphones, welches für alle Fernverkehrs-, einigen Auslandsverbindungen und in ausgewählten Städten und Regionen verfügbar ist.

Ein weiteres Anwendung Szenario sind intelligente Plakate, denen zusätzliche technische Informationen hinzugefügt wurden. Dies geschieht heute noch in der Regel mit QR-Codes, kann aber mittels NFC-Technologie um weitere Möglichkeiten, wie die Übertragung von Texten in mehreren Sprachen, Bilder und Aktionen erweitert werden. Darüber hinaus bieten NFC Tags hier einen besseren Schutz gegen „Edding Attacken“ die dann QR Codes unlesbar machen. Noch im Versuchsstadium befindet sich aktuell die Idee einiger Automobilhersteller (Hyundai, BMW), mit Hilfe des Smartphones und NFC-Funktionen die Autotür zu entriegeln und persönliche Einstellungen der Komfortoptionen im Automobil (Sitz- und Spiegelpositionen, Senderwahl) zu aktivieren.

Dies sind an dieser Stelle nur ein paar Anwendungsfälle. In Zukunft werden diese, durch die weitere Verbreitung der NFC Technologie, sicherlich noch zunehmen.

Aktuell unterstützen u.a. Geräte von Nokia, Samsung, Blackberry, Google, HTC, LG, Motorola und Sony die NFC Verfahren. Nachlegen wird hier sicher auch bald Apple, da das aktuelle iPhone 5 die NFC-Technologie noch nicht beinhaltet. Neben vielen aktuellen Smartphones sind auch einige Tablet-PCs mit eingebauter NFC-Technik verfügbar.

NFC Kommunikationswege

NFC setzt auf induktiv gekoppelte Systeme, bei denen passive Transponder die Energie aus einem Magnetfeld ziehen. Da jedoch bei NFC, im Gegensatz zu RFID, die strikte Trennung zwischen Lesegerät und Transponder entfällt, ergeben sich einige neue zusätzliche Kommunikationsmöglichkeiten. Für diese unterschiedlichen Kombinationen von Komponenten sind verschiedene Übertragungsmodi vom NFC Forum definiert worden.

So ermöglicht der Reader/Writer-Modus die Kommunikation zwischen einem NFC-Gerät und einem passiven Transponder. Im Peer-to-Peer-Modus können zwei NFC-Geräte Daten untereinander austauschen (z.B. bei Windows Phone Tap & Senden). Der Card-Emulation-Modus ermöglicht dem NFC-Gerät als Smartcard zu agieren und als passiver Teilnehmer mit einem normalen RFID basierenden Lesegerät zu kommunizieren.

 

Was braucht man alles um mit der NFC Entwicklung loszulegen?

Zur Entwicklung von NFC Anwendungen für Windows Phone benötigen wir Visual Studio 2012, das Windows Phone SDK und ein Windows Phone 8 (z.B. Nokia Lumia 920). Man braucht ein echtes Gerät, da vom aktuellen Windows Phone Emulator NFC leider noch nicht unterstützt wird. Als weitere Software-Komponente benötigt man die NDEF Library for Proximity APIS, da die native Windows Phone API keine NDEF Nachrichten schreiben kann. Es ist auch möglich, die NDEF Library via Nuget mit dem Kommando Install-Package NdefLibrary zu installieren.

Als weiteres benötigen wir natürlich noch brauchbare NFC Tags, welches sich bei mir als ein sehr schwieriges Unterfangen herausgestellt hat. Es waren zwei Bestellversuche notwendig, um geeignete NFC Tags zu erhalten. Wichtig ist nämlich hierbei, dass man keine leeren NFC Tags verwendet, sondern NFC Tags, welche mit dem NDEF (NFC Data Exchange Format) Format beschrieben bzw. formatiert wurden. Aktuell bietet uns die Windows Phone Proximity Api keine Möglichkeit NFC Tags zu formatieren. Ein NFC Tag kann in verschiedenen Ausprägungen – als Armband, Schlüsselanhänger oder Papier Sticker – bezogen werden. Einfach NFC Tags in eine Suchmaschine seiner Wahl eingeben und einen geeigneten Shop suchen.

Windows Phone NFC

Ein NFC Tag kann durch das Windows Phone mit unterschiedlichen Informationen im NDEF Format beschrieben werden. Die Größe der aktuellen Tags reicht von 168 Byte, über einem bis zu maximal vier Kilo Byte.

Unterstützt werden von Windows Phone folgende NFC Tags:

  • Type 1: Topaz family
  • Type 2: Mifare Ultralight family, my-d-move, NTag
  • Type 3: Felica family
  • Type 4: Desfire family
  • Non standardized: Mifare Standard

 

Einige Einschränkungen

Aktuell müssen wir beim Umgang mit NFC Tags mit einigen Einschränkungen leben, die die Arbeit mit NFC Tags eigentlich nicht beschneiden, sondern lediglich einige Anwendungsszenarien beschränken.

  • Es ist durch die fehlende Unterstützung des RAW Modus bei Windows Phone nicht möglich, den Schreibschutz eines NFC Tags zu aktivieren.
  • Mittels Windows Phone können keine NFC Tags formatiert werden – also nur vorformatierte oder beschriebene Tags im NDEF Format kaufen. Eine weitere Alternative ist die Verwendung eines NFC USB Reader/Writer oder – ich wage es kaum zu erwähnen – die Benutzung eines Android Geräts.
  • Der NFC Tag darf nur NDEF Nachrichten enthalten, damit er lesbar bleibt.
  • Es ist nicht möglich, den kompletten Speicherplatz eines NFC Tags zu benutzen. Beispielsweise können nur 716 Bytes bei einem 1KB Tag oder 454 Bytes bei einem Tag mit einer Größe von 512 Byte genutzt werden
  • Die Proximity API von Windows Phone bietet keine Möglichkeit direkt NDEF Nachrichten auf den Tag zu schreiben. Dies ist aber durch die Benutzung der Open Source NDEF Library möglich, die ich in meinem Beispiel auch verwendet habe
  • Es ist nicht möglich die Daten eines NFC Tags zu empfangen oder zu schreiben, wenn die Windows Phone App im Hintergrund läuft. Man kann aber über Schemata-Zuordnungen und die Auto-Launch Funktion – dazu später mehr - eine im Hintergrund oder noch nicht laufende Applikation starten

 

Der Schüssel zu allem: Windows.Networking.Proximity

Im Namensbereich Windows.Networking.Proximity befindet sich der Einstiegspunkt der Proximity API von Windows Phone. Die wichtigste Klasse ist hierbei ProximityDevice.

 

Der Use Case - Check-in mit NFC Tags

Innerhalb der SDX AG nutzen wir eine neue eigenentwickelte Zeiterfassungs-Software mit der Bezeichnung WorkTime. Dieses System basiert auf dem Microsoft CRM System und ist als Client für Windows 8 (Modern UI App), Windows Phone 8 sowie als Web-Anwendung verfügbar. Also warum sich nicht die NFC Tags zu Nutze machen und die lästige Zeiterfassung bei unterschiedlichen Projekten dadurch verkürzen, das ein NFC Tag die projektspezifischen Daten zu einem Zeiterfassungsvorgang bereits enthält und durch das „Tappen“ mit dem Windows Phone ein Zeiterfassungsvorgang automatisiert vorgenommen werden kann. Ich hätte dann für unterschiedliche Kunden und Projekte jeweils einen anderen farblich gekennzeichneten Tag und könnte diese sogar am entsprechenden Arbeitsplatz irgendwo hin kleben.

Also Idee in die Tat umsetzen…

Erster Schritt – Speichern der Daten auf dem NFC Tag

Das folgende Code Schnipsel verwende ich, um den serialisierten aktuellen Zeiteintrag auf einem NFC Tag zu speichern. Wichtige Einstiegspunkte sind hierbei die Events DeviceArrived und DeviceDeparted, welche entsprechend geworfen werden, sobald sich ein NFC Tag in der Nähe des Windows Phone befindet oder sich wieder entfernt hat. Im Konstruktor meiner NfcService Klasse ermittele ich mir dazu zunächst das aktuelle Proximity Device über die ProximityDevice.GetDefault() Methode.

Zum Zugriff auf den NFC Tag verwende ich in meinem Beispiel, wie gesagt, die NDEF Library welche es auf einfache Art und Weise ermöglicht NDEF Datensätze zu parsen sowie diese zu erstellen. Ein NFC Tag kann dabei immer einen oder mehrere NDEF Datensätze enthalten. Die NDEF Library unterstützt verschiedene Datensatz Typen, wie beispielsweise WpSettings (zum Starten von Windows Phone Einstellungsseiten), Mailto (Datensätze zum automatischen Versenden von E-Mails), DriveTo und WalkTo (Starten der Navigationsfunktionen von Windows Phone 8), Nokia Accessories (Datensatz zum Starten von Nokia Zusatzanwendungen auf Lumia Smartphones) und der wichtige Launch App Record zum automatischen Start einer Windows Phone App. Dieses NDEF Nachrichtenformat wird auch in folgenden Beispiel verwendet.

 

private const string ProductId = "{Your ProductId from WMAppManifest.xml}";
private readonly ProximityDevice _device;
private string _messageContent;
 
public NfcService()
{
    _device = ProximityDevice.GetDefault();
}
 
#region public events
 
public event EventHandler NfcNotAvailable;
 
protected virtual void OnNfcNotAvailable()
{
    EventHandler handler = NfcNotAvailable;
    if (handler != null) handler(this,EventArgs.Empty);
}
 
public event EventHandler<string> NfcArrived;
 
protected virtual void OnNfcArrived(string e)
{
    EventHandler<string> handler = NfcArrived;
    if (handler != null) handler(this, e);
}
 
 
public event EventHandler<string> NfcDeparted;
 
protected virtual void OnNfcDeparted(string e)
{
    EventHandler<string> handler = NfcDeparted;
    if (handler != null) handler(this, e);
}
 
public event EventHandler NfcMessageWritten;
 
protected virtual void OnNfcMessageWritten()
{
    EventHandler handler = NfcMessageWritten;
    if (handler != null) handler(this, EventArgs.Empty);
}
 
#endregion
 
public static string NfcLaunchParameterName
{
    get { return "ms_nfp_launchargs"; }
}
 
public void WriteLaunchRecordToNfc(string messageContent)
{
    // check if NFC is available on the Windows Phone device
    if (_device != null)
    {
        _device.DeviceArrived += DeviceArrived;
        _device.DeviceDeparted += DeviceDeparted;
        _messageContent = messageContent;
    }
    else
    {
        OnNfcNotAvailable();
    }
}
 
void DeviceDeparted(ProximityDevice sender)
{
    var deviceId = String.Empty;
    if (sender != null)
    {
        deviceId = sender.DeviceId;
    }
  
    OnNfcDeparted(deviceId);
}
 
void DeviceArrived(ProximityDevice sender)
{
    var deviceId = String.Empty;
    if (sender != null)
    {
        deviceId = sender.DeviceId;
    }
 
    OnNfcArrived(deviceId);
  
    // Create a LaunchApp record, specifying our recognized text as arguments
    var record = new NdefLaunchAppRecord { Arguments = _messageContent };
    // Add the app ID of your app!
    record.AddPlatformAppId("WindowsPhone", ProductId);
 
    // Wrap the record into a message, which can be written to a tag
    var msg = new NdefMessage { record };
 
    _device.PublishBinaryMessage("NDEF:WriteTag", msg.ToByteArray().AsBuffer(), MessageWrittenHandler);
 
}
 
private void MessageWrittenHandler(ProximityDevice sender, long messageId)
{
    // detach event handlers
    _device.DeviceArrived -= DeviceArrived;
    _device.DeviceDeparted -= DeviceDeparted;
 
    // stopping publishing the message
    _device.StopPublishingMessage(messageId);
 
    OnNfcMessageWritten();
}
    }

Beim Schreiben auf einen NFC Tag sind folgende Punkt besonders zu beachten:

  • Bei Verwendung eines NdefAppLauchRecord muss als Plattform WindowsPhone und die ProductId der App aus dem AppManifest angegeben werden
  • Ein Aufruf von _device.StopPublishingMessage nach erfolgtem Schreiben ist notwendig
  • Die Message Größe des NDEF Records darf nicht die Nettokapazität des NFC Tags überschreiten
  • Um NFC in der App nutzen zu können, muss ID_CAP_PROXIMITY in den Application Capabilities aktiviert werden

Der Umgang mit den anderen NDEF Nachrichtentypen ist analog zu diesem Beispiel, außer dass hier die Nachricht anders aufgebaut werden muss.

So weit so gut - jetzt können wir die Daten auf einen NFC Tag schreiben. Aber wie schaffe ich es, dass meine App nun automatisch beim „Tappen“ mit meinem Lumia gestartet wird?

 

Hinzufügen der Auto-Start Funktionalität

Um eine Windows Phone 8 automatisch starten zu können, ist es notwendig eine URI Zuordnung für die jeweilige App zu erstellen. Was diese URI auszeichnet, ist das diese mit einem festen Schemanamen beginnt, der für diese App registriert wurde. Nachdem diese Registrierung dem Betriebssystem bekannt gemacht wurde, wird durch das „Tappen“ mit einem NFC Tag, welcher einen LaunchApp NDEF Record enthält, über die ProductId im NDEF Record genau eine solche URI von Windows Phone OS aufgebaut und die App mit dieser URI gestartet.

Die Nutzung von Schema-Zuordnungen zu einer Windows Phone App ist übrigens ein allgemeines Feature und kann beispielsweise auch zum Aufruf einer Windows Phone App über eine URI aus einer anderen App genutzt werden.

Beispiel: worktime:ShowTimeSheetEntry?UniqueId=89819279-4fe0-4531-9f57-d633f0949a19

In diesem Beispiel ist worktime das registrierte App Schema und alles nach dem Doppelpunkt kann durch die App in der UriMapper Klasse – dazu später mehr – interpretiert werden.

Über den folgenden Code kann die WorkTime App aus einer anderen App aufgerufen werden:

Windows.System.Launcher.LaunchUriAsync(new System.Uri("worktime:ShowTimeSheetEntry?UniqueId=89819279-4fe0-4531-9f57-d633f0949a19"));

Um eine URI Verknüpfung für eine App zu erstellen, muss die WMAppManifest.xml Datei des Windows Phone Projekts mit dem XML(Text) Editor bearbeitet werden. Im Extensions-Element der Manifest-Datei wird eine URI-Verknüpfung durch das Hinzufügen eines Protocol-Elements definiert. Bitte beachten, dass das Extensions Element sofort nach dem Tokens-Element eingefügt werden muss. Man kann maximal 10 URI-Verknüpfungen in jeder App definieren. Die Schema-Namen einer App müssen dabei eindeutig bei den installierten Apps sein – also genau überlegen was man hier nimmt.

 
<Extensions>  
    <Protocol Name="worktime" NavUriFragment="encodedLaunchUri=%s" TaskID="_default" />
</Extensions>

Einige Schemata sind reserviert und würden bei Verwendung ignoriert werden. Für mehr Informationen, siehe Reservierte Datei und URI Verknüpfungen für Windows Phone 8.

Die generierte URI aus dem NFC Tag LaunchApp Record zum automatischen Starten der WorkTime App sieht dann folgendermaßen aus:

Protocol?encodedLaunchUri=worktime:<xml string of our TimesheetEntry object>

Hinter dem Doppelpunkt folgt die XML Repräsentanz der Zeiteintrags-Instanz.

 

Extrahieren der Aufrufparameter aus der URI

Um nun die aufrufende URI aufzulösen, ist die Klasse UriMapper zu implementieren, welche von UriMapperBase abgeleitet ist. Die Argumente der LaunchApp NDEF Nachricht auf unserem Tag müssen dann in dem Parameter ms_nfp_launchargs für den Aufruf der gewünschte Einstiegsseite der Windows Phone App übergeben werden, da dieser Mechanismus auch vom Betriebssystem beispielsweise über eine Sekundärkachel (deep linking) verwendet wird.
(Niemand weiß, ob ms_nfc_launchargs korrekt ist oder ms_nfp_launchargs weil in der MSDN Dokumentation werden beide erwähnt :-( - aber alle Beispiele funktionieren mit ms_nfp_launchargs)

Die folgende UriMapper Klasse dekodiert zunächst die aufrufende Uri und benutzt dann einen regulären Ausdruck um die Payload der NDEF Nachricht zu extrahieren:

class WorkTimeUriMapper: UriMapperBase
{
    public override Uri MapUri(Uri uri)
    {
        // Example: "Protocol?encodedLaunchUf64ri=worktime:testmessage"
        var tempUri = HttpUtility.UrlDecode(uri.ToString());
        var launchContents = Regex.Match(tempUri, @"worktime:(.*)$").Groups[1].Value;
        if (!String.IsNullOrEmpty(launchContents))
        {
            // Call MainPage.xaml with parameters
            return new Uri("/MainPage.xaml?ms_nfp_launchargs=" + launchContents, UriKind.Relative);
        }
 
        // Include the original URI with the mapping to the main page
        return uri;
    }
}

Um die neu definierte Klasse WorkTimeUriMapper nun als UriMapper zu verwenden, ist es notwendig, folgenden Anweisungen in die InitializePhoneApplication Methode der App.xaml.cs einzufügen.

RootFrame = new TransitionFrame();
RootFrame.UriMapper = new WorkTimeUriMapper();
RootFrame.Navigated += CompleteInitializePhoneApplication;

Jetzt wird die aufrufende Uri mit dem Schema der App in eine relative Adresse der gewünschten Aufrufseite (in meinem Fall MainPage.xaml) transformiert und die Payload der NDEF Nachricht wird im Parameter ms_nfp_launchargs übergeben.

 

Parsen der Argumente und Zeiteintrag anlegen

In meiner MainPage.xaml, oder der jeweiligen Zielseite, müssen nur noch die Übergabeargumente extrahiert und einer entsprechenden Funktion übergeben werden. Im OnNavigateTo Event kann hierzu mittels NavigationContext.QueryString["ms_nfp_launchargs"] der Aufrufparameter, also die Payload des NFC Tags, ausgelesen werden. In meinem Fall handelt es sich, wie bereits erwähnt, um die serialisierte Klasseninstanz eines Zeiteintrags. Durch eine Funktion wird nun auf Basis dieses Zeiteintrags ein neuer Eintrag für den aktuellen Tag angelegt, den ich aus Gründen der besseren Usability noch mal zur Betätigung anzeige.

 

Das Ergebnis

Schreiben eines NFC Tags über die Kontextfunktion aus einem bestehenden Zeiteintrag:

Windows Phone NFC

 

Ziel erreicht

Jetzt kann ich diese wunderbar farbigen NFC Tags für die automatisierte Zeiterfassung in meinen unterschiedlichen Projekten nutzen:

Windows Phone NFC

 

Weiter führende Links zum Thema