NFC : Comment faire communiquer vos applications Windows Phone 8 et Windows 8

 

clip_image002Les API Proximity et NFC permettent à deux Windows ou Windows Phone d’échanger des données lorsqu’ils sont à proximité.

Comment ça marche ? Un message NFC est utilisé pour configurer une connexion qui va ensuite permettre aux 2 périphériques de communiquer via un socket en Bluetooth ou TCP/IP (Wifi).

Pourquoi c’est bien ? Cela vous évite de perdre du temps sur la configuration de la connexion (et c’est quoi ton mot de passe, etc.). Un seul « tap » vers l’autre téléphone ou PC, et hop la connexion est configurée. En effet, comme on considère que le tap a été volontaire, on se passe des protocoles usuels d’authentification.

Si vous voulez tester, c’est ce que fait votre Windows Phone 8 lorsque vous voulez partager une photo avec un autre téléphone en utilisant la fonction « Tap + Share » (ou « Toucher + Envoyer » en français).

Quand vous souhaitez utiliser ce scénario, le mieux est donc d’avoir le Bluetooth activé :) Si vous préférez passer par le Wifi en TCP/IP, il faudra que les téléphones soient sur le même réseau ou routeur (pas de conflits d’IP, etc.).

Remarque importante : Wi-Fi Direct est supporté sur Windows 8, mais pas sur Windows Phone 8.

N’oubliez pas que vous pouvez appeler le Launcher connectionSettingsTaskpour que votre utilisateur puisse aller activer le Bluetooth depuis votre application Windows Phone.

 ConnectionSettingsTask connectionSettingsTask = new ConnectionSettingsTask();
connectionSettingsTask.ConnectionSettingsType = ConnectionSettingsType.Bluetooth;
connectionSettingsTask.Show();

 

Voyons comment créer une petite application qui communique avec d’autres instances, au travers de 3 étapes :

  • Rechercher les autres instances de l’application et établir la communication
  • Envoyer un message
  • Recevoir un message

Le sample est téléchargeable ici : PeerCommunications.zip 

 

Etape 1 – Rechercher des Peers

Comme dans l’article précédent, vous initialisez le ProximityDevice au lancement de l’application (ou au moment opportun), et en plus, vous allez rechercher d’autres instances de votre application avec le PeerFinder :

 

         private void InitializeProximityDevice()
        {
            if (this.device == null)
            {
                this.device = ProximityDevice.GetDefault();
            }

            if (this.device != null)
            {
                this.device.DeviceArrived += ProximityDeviceArrived;
                this.device.DeviceDeparted += ProximityDeviceDeparted;
                lblStatus.Text = MSG_NFC_ACTIVE;

                PeerFinder.TriggeredConnectionStateChanged += OnTriggeredConnectionStateChanged;

                // Start finding peer apps, while making this app discoverable by peers
                PeerFinder.Start();
            }
            else
            {
                lblStatus.Text = MSG_NFC_NOT_FOUND;
            }
        }
  

Le PeerFinder va rechercher pour vous les autres instances de votre application, et rendre la vôtre trouvable par les autres. Automatiquement quand un autre Windows Phone va s’approcher de votre téléphone, ce dernier va lui proposer de lancer une instance de l’application :

 

clip_image004

 

Cela fonctionne aussi de Windows Phone vers Windows 8 et inversement. Pour vous connecter à Windows 8 depuis Windows Phone par exemple, vous allez juste spécifier l’identité de l’application à rechercher avec AlternateIdentities :

 if (device != null)
{
PeerFinder.AlternateIdentities.Add("Windows", "my Win8 appID");
PeerFinder.TriggeredConnectionStateChanged += OnTriggeredConnectionStateChanged;
PeerFinder.Start();
}

Ensuite, vous allez pouvoir récupérer les infos concernant la connexion ad-hoc créée par le PeerFinder en vous abonnant à l’événement TriggeredConnectionStateChanged :

 
        private void OnTriggeredConnectionStateChanged(object sender, TriggeredConnectionStateChangedEventArgs args)
        {
            switch (args.State)
            {
                case TriggeredConnectState.Listening:
                    lblStatus.Text = "Listening";
                    break;
                // Connecting as hostbreak;
                case TriggeredConnectState.PeerFound:
                    lblStatus.Text = "Peer Found";
                    break;
                // Proximity gesture is complete and user can pull their devices away. Remaining work is to // establish the connection using a different transport, like TCP/IP or Bluetoothbreak;
                case TriggeredConnectState.Connecting:
                    lblStatus.Text = "Connecting";
                    break;
                // Connecting as a clientbreak;
                case TriggeredConnectState.Completed:
                    // Connection completed, retrieve the socket over which to communicate
                    streamSocket = args.Socket;
                    lblStatus.Text = "Connection completed";
                    break;
                case TriggeredConnectState.Canceled:
                    lblStatus.Text = "Connection canceled";
                    break;
                case TriggeredConnectState.Failed:
                    lblStatus.Text = "Connection canceled";
                    break;
            }
        }

 

Cette fonction vous renvoie notamment dans ses arguments le socket initialisé pour la connexion entre les deux périphériques. C’est ensuite ce socket que vous allez utiliser pour échanger les données.

Vous êtes complètement libres d’utiliser le protocole de votre choix pour la communication une fois le socket initialisé. Dans la suite de l’article, je vais juste échanger une chaine de caractères entre les deux pour vous donner un exemple.

 

Etape 2 : Envoyer un message

J’ajoute un bouton à mon interface pour déclencher l’envoi du message :

         private void SendMessageButton_Click(object sender, RoutedEventArgs e)
        {
            SendMessage("YATTTA!");
        }

 

Pour envoyer un message, il suffit de créer un DataWriter à partir du socket que vous avez récupéré et d’y ajouter les données à transmettre :

         private async void SendMessage(string message)
        {
            if (streamSocket != null)
            {
                if (dataWriter == null)
                    dataWriter = new DataWriter(streamSocket.OutputStream);

                dataWriter.WriteInt32(message.Length);
                await dataWriter.StoreAsync();

                dataWriter.WriteString(message);
                await dataWriter.StoreAsync();
            }
        }

 

 

Etape 3 : Recevoir un message

De la même façon, j’attends la réception d’un message avec ma fonction asynchrone GetMessage. Celle-ci sera complétée quand elle aura un message à lire.

     private async void GetMessageButton_Click(object sender, RoutedEventArgs e)
    {
            string s = await GetMessage();
            lblMsg.Text = s;
    }

 

Pour recevoir un message, il suffit de créer un DataReader à partir du socket que vous avez récupéré:

         private async Task<string> GetMessage()
        {
            if (streamSocket != null)
            {
                if (dataReader == null) dataReader = new DataReader(streamSocket.InputStream);
                await dataReader.LoadAsync(4);
                uint messageLen = (uint)dataReader.ReadInt32();
                await dataReader.LoadAsync(messageLen);
                return dataReader.ReadString(messageLen);
            }
            else return null;
        }

 

N’oubliez pas de faire le ménage derrière vous en partant :

 

         protected override void OnNavigatingFrom(NavigatingCancelEventArgs e)
        {
            PeerFinder.Stop();
            CloseSocket();
        }

        private void CloseSocket()
        {
            if (streamSocket != null)
            {
                streamSocket.Dispose();
            }

            if (dataWriter != null)
            {
                dataWriter.Dispose();
            }

            if (dataReader != null)
            {
                dataReader.Dispose();
            }
        }

 

Vous pouvez télécharger le code source correspondant à cet exemple ici : PeerCommunications.zip

Je vous conseille aussi de jeter un coup d’œil aux samples Windows 8 sur ce sujet, notamment pour ceux qui voudraient voir comment cela fonctionne en JavaScript. Petit indice, ce sont les mêmes API, juste pas le même langage, donc pas de surprises Sourire

Quid de l’interop avec un device Android ou autre ? Pour l’instant, il n’y a pas de standard pour la communication NFC en Peer-to-Peer. Du coup, Android, Windows/Windows Phone et Meego ont tous leurs propres implémentations, et ne peuvent communiquer entre eux.