Windows Phone 8 近场通信 NFC / Bluetooth Proximity
今天给大家介绍下 windows phone 8 的近场通信技术,常用近场通信技术有几种 NFC、蓝牙(Bluetooth)、Wifi 以上三种都是在WP8的API中所支持的,NFC我个人感觉是一个可以让人耳目一新的功能。而且NFC设备目前被很多手机厂商应用,目前NFC技术在手机上应用主要有以下五类。
- 接触通过(Touch and Go),如门禁管理、车票和门票等,用户将储存着票证或门控密码的设备靠近读卡器即可,也可用于物流管理。
- 接触支付(Touch and Pay),如非接触式移动支付,用户将设备靠近嵌有NFC模块的POS机可进行支付,并确认交易。
- 接触连接(Touch and Connect),如把两个NFC设备相连接(如图1中手机和笔记本电脑),进行点对点(Peer-to-Peer)数据传输,例如下载音乐、图片互传和交换通讯录等。
- 接触浏览(Touch and Explore),用户可将NFC手机接靠近街头有NFC功能的智能公用电话或海报,来浏览交通信息等。
- 下载接触(Load and Touch),用户可通过GPRS网络接收或下载信息,用于支付或门禁等功能,如前述,用户可发送特定格式的短信至家政服务员的手机来控制家政服务员进出住宅的权限。
可能有人会问到关于NFC的安全问题,以及传输速度问题,这里我也给大家列出NFC的特性来帮助大家了解NFC。
- 当设备之间的距离在 3-4 厘米(1-1.5 英寸)内时发生通信。
- 通信是非常具有选择性和意图性的,因为用户有意将各自的设备放在一起进行连接。
- 最大的理论数据传输速率是 424 kbits/s。典型的数据传输速率在 30 kbits/s 至 60 kbits/s 之间。
- 也可以在 NFC 设备和无动力 NFC 芯片或标记之间发生通信。
- 另外我们还可以使用 System.Security.Cryptography.AesManaged 对数据流进行加密。
如何在我们的应用中使用NFC呢?下来我逐一给大家介绍。
首先 还是设置我们的 WMAppManifest.xml 文件标记我们应用需要是有近场通信技术
这里我还选择了NetWoking 是因为后面我还会使用 Bluetooth 和 TCP/IP (Wi-Fi)连接。
建立NFC的连接我们要用到 Windows.Networking.Proximity.ProximityDevice 我们可以使用 Windows.Networking.Proximity.ProximityDevice.GetDefault(); 来判断手机硬件是否支持NFC。
private void InitializeProximityDevice() { if (mProximityDevice == null) { mProximityDevice = Windows.Networking.Proximity.ProximityDevice.GetDefault(); } if (mProximityDevice != null) { mProximityDevice.DeviceArrived += ProximityDeviceArrived; mProximityDevice.DeviceDeparted += ProximityDeviceDeparted; AddToSysMsgList(MSG_NFC_EXISTS); } else { AddToSysMsgList(MSG_NFC_NOT_EXISTS); } }
上面的代码还看到了连个事件 DeviceArrived 和 DeviceDeparted 分别用于判断一个NFC设备进入和离开我们设备的感应区域。
下面我列举一个发送消息的code
ProximityDevice device = ProximityDevice.GetDefault(); // Make sure NFC is supported if (device!= null) { long Id = device.PublishMessage("Windows.SampleMessageType", "Hello World!"); Debug.WriteLine("Published Message. ID is {0}", Id); // Store the unique message Id so that it // can be used to stop publishing this message }
注册接收消息的code
Windows.Networking.Proximity.ProximityDevice proximityDevice; private void InitializeProximityDevice() { proximityDevice = Windows.Networking.Proximity.ProximityDevice.GetDefault(); if (proximityDevice != null) { proximityDevice.DeviceArrived += ProximityDeviceArrived; proximityDevice.DeviceDeparted += ProximityDeviceDeparted; WriteMessageText("Proximity device initialized.\n"); } else { WriteMessageText("Failed to initialized proximity device.\n"); } } private void ProximityDeviceArrived(Windows.Networking.Proximity.ProximityDevice device) { WriteMessageText("Proximate device arrived. id = " + device.DeviceId + "\n"); } private void ProximityDeviceDeparted(Windows.Networking.Proximity.ProximityDevice device) { WriteMessageText("Proximate device departed. id = " + device.DeviceId + "\n"); } // Write a message to MessageBlock on the UI thread. private Windows.UI.Core.CoreDispatcher messageDispatcher = Window.Current.CoreWindow.Dispatcher; async private void WriteMessageText(string message, bool overwrite = false) { await messageDispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { if (overwrite) MessageBlock.Text = message; else MessageBlock.Text += message; }); }
这里WP8除了支持信息的传输还支持更多的文件类型
Windows.Networking.Proximity.ProximityDevice proximityDevice; private void PublishLaunchApp() { proximityDevice = Windows.Networking.Proximity.ProximityDevice.GetDefault(); if (proximityDevice != null) { // The format of the app launch string is: "<args>\tWindows\t<AppName>". // The string is tab or null delimited. // The <args> string can be an empty string (""). string launchArgs = "user=default"; // The format of the AppName is: PackageFamilyName!PRAID. string praid = "MyAppId"; // The Application Id value from your package.appxmanifest. string appName = Windows.ApplicationModel.Package.Current.Id.FamilyName + "!" + praid; string launchAppMessage = launchArgs + "\tWindows\t" + appName; var dataWriter = new Windows.Storage.Streams.DataWriter(); dataWriter.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf16LE; dataWriter.WriteString(launchAppMessage); var launchAppPubId = proximityDevice.PublishBinaryMessage( "LaunchApp:WriteTag", dataWriter.DetachBuffer()); } }
其中包含了 配对请求,Tag信息的写入,以及设备间交互。
其中交互功能可以使用连接deeplink的形式打开应用传入参数或者打开应用或者应用商店。参考我之前的帖子:windows phone 8 中的应用间通信
由于NFC技术仅限近距离通信,如果传输大文件或者长时间连接的一种场景,bluetooth和wifi无疑是更好的一种连接方式,下面我给大家继续介绍下windows phone 8 的蓝牙传输。
临近感应和 NFC 使您能够通过点击或将两个设备放在几毫米的距离内来连接它们。该方案适用于 Windows Phone 8 和 Windows 8 设备。点击成功时,您会获得一个套接字,通过它即可与另一个设备通信。在 Windows Phone 8 上,在 TCP/IP (Wi-Fi) 连接或蓝牙连接时建立该套接字。临近感应 API 根据PeerFinder.AllowBluetooth 和 PeerFinder.AllowInfrastructure 的属性值(默认为 true)确定建立何种连接。当希望进行连接的设备已启用蓝牙时,可获得最一致的用户体验(就能够随处点击和连接而言)。如果两个设备处于相同的基础结构网络(相同的网络或路由器、无 IP 冲突、无防火墙、设备之间可执行 ping 操作),则有可能建立 Wi-Fi 连接。因此,建议应用在进行点击尝试之前通知用户,以确保两个设备都已启用蓝牙。
以上这段话摘自MSDN 可能看上去说的比较蹩脚,简单来说在连建立连接的时候呢如果两台设备在同一个局域网中并且没有网络限制的情况下,连接会优先选择TCP/IP (Wi-Fi) 其次会进行蓝牙连接。
等待查找(连接)的代码
ProximityDevice device = ProximityDevice.GetDefault(); // Make sure NFC is supported if (device!= null) { PeerFinder.TriggeredConnectionStateChanged += OnTriggeredConnectionStateChanged; // Start finding peer apps, while making this app discoverable by peers PeerFinder.Start(); }
连接状态处理
StreamSocket _streamSocket; void OnTriggeredConnectionStateChanged(object sender, TriggeredConnectionStateChangedEventArgs args) { switch (args.State) { case TriggeredConnectState.Listening: // Connecting as host break; case TriggeredConnectState.PeerFound: // 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 Bluetooth break; case TriggeredConnectState.Connecting: // Connecting as a client break; case TriggeredConnectState.Completed: // Connection completed, retrieve the socket over which to communicate _streamSocket = args.Socket; break; case TriggeredConnectState.Canceled: break; case TriggeredConnectState.Failed: // Connection was unsuccessful break; } }
蓝牙主动连接设备/应用
TO APP
async void AppToApp() { // PeerFinder.Start() is used to advertise our presence so that peers can find us. // It must always be called before FindAllPeersAsync. PeerFinder.Start(); var peers = await PeerFinder.FindAllPeersAsync(); if (peers.Count == 0) { Debug.WriteLine("Peer not found."); } else { // Select a peer. In this example, let's just pick the first peer. PeerInformation selectedPeer = peers[0]; // Attempt a connection var streamSocket = await PeerFinder.ConnectAsync(selectedPeer); DoSomethingUseful(streamSocket); } }
To device
// Note: You can only browse and connect to paired devices! private async void AppToDevice() { // Configure PeerFinder to search for all paired devices. PeerFinder.AlternateIdentities["Bluetooth:Paired"] = ""; var pairedDevices = await PeerFinder.FindAllPeersAsync(); if (pairedDevices.Count == 0) { Debug.WriteLine("No paired devices were found."); } else { // Select a paired device. In this example, just pick the first one. PeerInformation selectedDevice = pairedDevices[0]; // Attempt a connection StreamSocket socket = new StreamSocket(); // Make sure ID_CAP_NETWORKING is enabled in your WMAppManifest.xml, or the next // line will throw an Access Denied exception. await socket.ConnectAsync(selectedDevice.HostName, selectedDevice.ServiceName); DoSomethingUseful(socket); } }
监听连接请求
// Page Constructor public MainPage() { InitializeComponent(); Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { PeerFinder.ConnectionRequested += PeerFinder_ConnectionRequested; } void PeerFinder_ConnectionRequested(object sender, ConnectionRequestedEventArgs args) { if (ShouldConnect()) { // Go ahead and connect ConnectToPeer(args.PeerInformation); } } async void ConnectToPeer(PeerInformation peer) { StreamSocket socket = await PeerFinder.ConnectAsync(peer); DoSomethingUseful(socket); } private bool ShouldConnect() { // Determine whether to accept this connection request and return return true; }
检查设备的蓝牙是否处于打开状态
private async void FindPaired() { // Search for all paired devices PeerFinder.AlternateIdentities["Bluetooth:Paired"] = ""; try { var peers = await PeerFinder.FindAllPeersAsync(); // Handle the result of the FindAllPeersAsync call } catch (Exception ex) { if ((uint)ex.HResult == 0x8007048F) { MessageBox.Show("Bluetooth is turned off"); } } }
这里看到连接后得到的都是一个StreamSocket 对象所以后面的工作就是将你的数据Stream在传输就好了,我就不做过多篇幅介绍Stream的使用了。
此文是 升级到WP8必需知道的13个特性 系列的一个更新 希望这个系列可以给 Windows Phone 8开发者带来一些开发上的便利。
同时欢迎大家在这里和我沟通交流或者在新浪微博上 @王博_Nick