2013年8月15日木曜日

Windows8でNFCを使う

Windows8ではNFCがサポートされていると言いますが、実際どんな事ができるのでしょうか。NFC R/Wを搭載したWindows8のPC(VAIO Pro 11)で調べてみました。

このPCではタッチパッドの所にR/Wがあります。
まずはNFCタグ(NTAG)を置いてみます。



・・・何も反応ありません。
(でも実はこの時NFCタグが置かれた事をWindowsは分かっているようです。後述します)

次はNexusを、Webブラウザで適当なページを開いた状態で置いてみます。



Nexusで例のNFC音が鳴って、画面に変化が出ました!Androidビームを送信できるようです。タップしてみます。



Windows8の画面に通知が出ました。通知をクリックすると、IEが起動してNexusで表示していたページが開きます。Android端末同士でURLをビームしたときの動作と似ています。

逆はできるのでしょうか。
Windows8でIEで適当なページを表示した状態でチャーム(Windowsキー+Cで表示されるメニュー)を開いて「デバイス」を選択すると「タップして送信」というアイコンがありますのでクリックしてみます。



何となく予想していた通り、Nexusでブラウザが開いてIEと同じページが表示されました。
URLのAndroidビームを受信したときの動作です。

-----

Androidビームというのは別の記事にあるように、NDEFメッセージのやりとりらしいです。
これまでの動きを見ると、Windows8でNDEFメッセージを送受信できるらしいという事がわかりました。では、自分で作成するアプリケーションで送受信したい場合はどうしたらいいのでしょうか?

Windows8ではWinRTに含まれるAPIを使用します。Windows.winmdというDLLのラッパー(?良くわかりません)に含まれています。
このWindows.winmdはVisualStudio Express 2012でWindowsストアアプリを作成すると標準で参照されているのですが、デスクトップアプリを作成した場合は参照されていません。なのでストアアプリ用かなと思ったのですが、デスクトップアプリを作る場合でも手動で参照に追加してやれば普通に使えるようです。(サポート内なのかは良くわかりません)

とりあえず試すだけなので、作り慣れたデスクトップアプリを使うことにします。
Button1とButton2という2つのボタンだけがあるWindowsフォームアプリケーションを作成したと思ってください。機能はButton1をクリックするとURLのNDEFメッセージを送信し、Button2をクリックすると、URLのNDEFメッセージを受信したときにメッセージボックスが開くだけです。

NFC用のクラスは名前空間Windows.Networking.Proximityにまとまっているようです。
ProximityDeviceというのがメインとなるクラスのようで、最初にこのクラスを取得しておきます。

private ProximityDevice proximityDevice;
private void Form1_Load(object sender, EventArgs e)
{
    proximityDevice = ProximityDevice.GetDefault();
}

NDEFメッセージを送信する場合はPublish○○○Messageというメソッドのどれかを使用します。
URIを送る場合はPublishUriMessageを使うのが簡単そうです。

private long publishUriId = -1;
private void button1_Click(object sender, EventArgs e)
{
    //一度にPublishするメッセージは1つにするのが作法のようなので
    //既にPublishしてたらまずはStopしておく
    if (publishUriId != -1)
        proximityDevice.StopPublishingMessage(publishUriId);
   
    //http://www.yahoo.co.jp をPublishする
    publishUriId = proximityDevice.PublishUriMessage(new Uri("http://www.yahoo.co.jp"));
}
NexusをR/Wに置いた状態でButton1をクリックすると、Nexusでブラウザが起動してYahooが開きました。送信できました!
ちなみに試していませんがPublishBinaryMessageメソッドでタグに書き込みできるようです。

次にNDEFメッセージの受信です。この場合はSubscribeForMessageメソッドを使用します。
1番目の引数には受信するメッセージの型を、2番目の引数には受信したときに呼び出されるハンドラーを渡します。

private void button2_Click(object sender, EventArgs e)
{
    proximityDevice.SubscribeForMessage("WindowsUri", messageReceived);
}
private void messageReceived(ProximityDevice device, ProximityMessage message)
{
    //なぜかURLの間に\0が挟まってるのでトリムする
    MessageBox.Show(message.DataAsString.Replace("\0", ""));
}
Button2を押してから、先程と同じようにNexusで適当なWebページのURIをビームすると、Windows8でメッセージボックスが開いてURIが表示されます。受信もできました。

-----

冒頭でやったように、タグをポンと置いてもWindowsは(一見)無反応でしたが、APIを使えば検知できます。
ProximityDeviceにはDeviceArrived、DeviceDepartedというイベントが定義されています。
ほかのデバイスがR/Wの範囲に入ったとき、または範囲から離れたときに発生するイベントです。

private ProximityDevice proximityDevice;
private void Form1_Load(object sender, EventArgs e)
{
    proximityDevice = ProximityDevice.GetDefault();
    proximityDevice.DeviceArrived += proximityDevice_DeviceArrived;
}
void proximityDevice_DeviceArrived(ProximityDevice sender)
{
    MessageBox.Show(sender.DeviceId);
}
タグをR/Wに置くとメッセージボックスが表示されます。
ちなみにDeviceIdの値は \\?\acpi#nxp5442#xxxxxxxx#{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx} みたいな値で、どのタグでも同じ値になります。Windows側のデバイスIDという事でしょうか。
タグのUIDをとれるかと思ったのですが無理なようです。残念でした。

※補足
ここで使っているタグは何も書き込みされていないタグでした。NDEFメッセージを書き込んだタグをR/Wに置くと反応がありました。URLを書き込んでおけば、Nexusでビームしたときと同じくIEでそのページが開きました。


0 件のコメント:

コメントを投稿