今天給大家介紹下 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