藍牙是手機的近距離無限傳輸的技術,在以前的Windows Phone 7系統手機裏面僅支持藍牙耳機功能,並不支持藍牙文件信息傳輸,那麼在Windows Phone 8手機裏面將全面支持藍牙技術,而且提供了相關的API來給開發者使用。開發者能夠利用藍牙的相關API來建立應用程序,在應用程序裏面使用手機的藍牙技術來進行近距離的文件傳輸和發送接收消息,創造出更加有趣和方便的應用軟件。編程
在Windows Phone 8裏面能夠在應用程序裏面利用藍牙進行通訊,使用藍牙相關的API,可讓應用程序鏈接到另外的一個應用程序,也可讓應用程序鏈接到一個設備上。Windows Phone 8的藍牙技術支持兩個藍牙方案:一個是應用程序到應用程序的通訊,另一個是應用程序到設備的通訊。網絡
1.應用程序到應用程序的通訊併發
應用程序到應用程序的通訊的過程是,應用程序使用藍牙去查找正在廣播藍牙服務的對等的應用程序,若是在應用程序提供服務的範圍內發現一個應用程序,那麼該應用程序能夠發起鏈接請求。當這兩個應用程序接受鏈接,它們之間就能夠進行通訊了,通訊的過程是使用socket的消息發送接收機制。在Windows Phone 8中使用到應用程序到應用程序的藍牙通信技術,須要在項目的WMAppManifest.xml文件中添加ID_CAP_PROXIMITY的功能選項,表示支持臨近的設備通訊能力,不然程序會出現異常。異步
2.應用程序到設備的通訊socket
在應用程序到設備的通訊過程時,應用程序使用藍牙去查找提供服務的設備,若是提供的服務範圍以內發現一個能夠鏈接的藍牙設備,那麼該應用程序能夠發起鏈接請求。當應用程序和設備同時接受該鏈接,它們之間就能夠進行通訊了,通訊的過程也是使用socket的消息發送接收機制,相似於應用程序到應用程序的通訊。在Windows Phone 8中使用到應用程序到設備的藍牙通信技術,須要在項目的WMAppManifest.xml文件中添加ID_CAP_PROXIMITY和ID_CAP_NETWORKING的功能選項,表示支持臨近的設備通訊能力和網絡通訊能力,不然程序會出現異常。async
藍牙編程類測試
在Windows Phone 8裏面使用到藍牙編程主要會用到PeerFinder類,PeerInformation類,StreamSocket類和ConnectionRequestedEventArgs類,這些類的說明如表19.1所示。由於藍牙也是基於TCP協議進行消息傳遞了,因此須要用到Socket的相關的編程知識,以及StreamSocket類。PeerFinder類是藍牙查找類,它的主要成員如表19.2所示。ui
表19.1 藍牙編程類的說明spa
類名orm |
說明 |
PeerFinder |
用於去查找附近的設備是否有運行和當前應用程序相同的應用程序,而且能夠在兩個應用程序之間創建起socket鏈接,從而能夠進行通訊。對等應用程序是在其餘設備上運行的應用程序的另外一個實例。 |
PeerInformation |
包含對等應用程序或設備的識別信息。 |
StreamSocket |
支持使用一個TCP的Socket流的網絡通訊。 |
ConnectionRequestedEventArgs |
表示傳遞到一個應用程序的ConnectionRequested事件的屬性 |
表 19.2 PeerFinder類的成員
成員 |
說明 |
bool AllowBluetooth |
指定 PeerFinder 類的此實例是否能夠經過使用 Bluetooth 來鏈接 ProximityStreamSocket 對象。若是PeerFinder 的此實例能夠經過使用 Bluetooth 來鏈接 ProximityStreamSocket 對象,則爲 true;不然爲false。默認爲 true。 |
bool AllowInfrastructure |
是否使用TCP/IP協議鏈接到StreamSocket |
bool AllowWiFiDirect |
指定 PeerFinder 類的此實例是否能夠經過使用 Wi-Fi Direct 來鏈接 ProximityStreamSocket 對象。若是 PeerFinder 的此實例能夠經過使用 Wi-Fi Direct 來鏈接 ProximityStreamSocket 對象,則爲 true;不然爲false。默認爲 true。 |
IDictionary<string, string> AlternateIdentities |
獲取要與其餘平臺上的對等應用程序匹配的備用 AppId 值列表。返回要與其餘平臺的對等類應用程序匹配的備用 AppId 值列表。 |
string DisplayName |
獲取或設置標識計算機到遠程對等類的名稱。 |
PeerDiscoveryTypes SupportedDiscoveryTypes |
獲取一個值,該值指示哪些發現選項可與 PeerFinder 類一同使用 |
event TypedEventHandler<object, ConnectionRequestedEventArgs> ConnectionRequested |
遠程對等類使用 ConnectAsync 方法請求鏈接時發生。 |
event TypedEventHandler<object, TriggeredConnectionStateChangedEventArgs> TriggeredConnectionStateChanged |
在遠程對等類的輕擊筆勢期間發生。 |
IAsyncOperation< StreamSocket> ConnectAsync(PeerInformation peerInformation) |
鏈接已發現了對 FindAllPeersAsync 方法的調用的對等類。peerInformation:表示鏈接到的對等類的對等類信息對象。返回經過使用所提供的臨近StreamSocket 對象鏈接遠程對等類的異步操做。 |
IAsyncOperation<IReadOnlyList<PeerInformation>> FindAllPeersAsync() |
適用於無線範圍內運行相同應用程序的對等計算機的異步瀏覽。返回經過使用 Wi-Fi直連技術瀏覽對等類的異步操做。 |
void Start(string peerMessage) |
向臨近設備上的對等類應用程序傳遞消息。 |
void Stop() |
中止查找對等類應用程序或廣播對等類鏈接的過程 |
查找藍牙設備和對等項
查找在服務範圍內的藍牙設備和對等項是藍牙編程的第一步,查找藍牙設備和對等項中會使用到PeerFinder類的FindAllPeersAsync方法去進行查找,而後以異步的方式返回查找到的對等項列表的信息IReadOnlyList<PeerInformation>,注意要使查找對等的應用程序時,在調用FindAllPeersAsync方法前必須先調用PeerFinder類的Start方法,主要的目的是啓動廣播服務,讓對方的應用程序也能查找到本身。PeerInformation包含三個屬性:一個是DisplayName表示對等項的名字,這個名字通常都是由對方的設備的名稱或者查找到的應用程序自身設置的現實名字,一個是HostName表示主機名字或者IP地址,還有一個屬性是ServiceName表示服務名稱或者TCP協議的端口號。而後能夠利用查找到的PeerInformation信息進行鏈接和通訊。
查找對等的應用程序的代碼示例:
async void AppToApp(){ // 啓動查找服務 PeerFinder.Start(); //開始查找 ObservableCollection<PeerInformation> peers = await PeerFinder.FindAllPeersAsync(); if (peers.Count == 0) { //未找到任何的對等項 } else { //處理查找到的對等項,可使用PeerFinder類的ConnectAsync方法來鏈接選擇的要進行通訊的對等項 }}
查找藍牙設備的代碼示例:
private async void AppToDevice(){ // 設置查找所匹配的藍牙設備 PeerFinder.AlternateIdentities["Bluetooth:Paired"] = ""; // 開始查找 ObservableCollection<PeerInformation> pairedDevices = await PeerFinder.FindAllPeersAsync(); if (pairedDevices.Count == 0) { // 沒有找到可用的藍牙設備 } else { //處理查找到的藍牙設備,能夠新建一個StreamSocket對象,而後使用StreamSocket類的ConnectAsync方法經過HostName和ServiceName來鏈接藍牙設備 }}
藍牙發送消息
藍牙編程的發送消息機制使用的是TCP的StreamSocket的方式,原理與Socket的一致。在藍牙鏈接成功後,能夠獲取到一個StreamSocket類的對象,而後咱們使用該對象的OutputStream屬性來初始化一個DataWriter對象,經過DataWriter對象來進行發送消息。OutputStream屬性表示的是Socket的輸出流,用於發送消息給對方。下面來看一下發送消息的示例:
async void SendMessage(string message){ // 鏈接選中的對等項,selectedPeer爲查找到的PeerInformation對象 StreamSocket _socket= = await PeerFinder.ConnectAsync(selectedPeer); // 建立DataWriter DataWriter _dataWriter = new DataWriter(_socket.OutputStream); // 先寫入發送消息的長度 _dataWriter.WriteInt32(message.Length); await _dataWriter.StoreAsync(); // 最後寫入發送消息的內容 _dataWriter.WriteString(message); await _dataWriter.StoreAsync();}
藍牙接收消息
藍牙編程的接收消息機制一樣也是使用的是TCP的StreamSocket的方式,原理與Socket的一致。在藍牙鏈接成功後,能夠獲取到一個StreamSocket類的對象,而後咱們使用該對象的InputStream屬性來初始化一個DataReader對象,經過DataReader對象來進行接收消息。InputStream屬性表示的是Socket的輸入流,用於接收對方的消息。下面來看一下接收消息的示例:
async Task<string> GetMessage(){ // 鏈接選中的對等項,selectedPeer爲查找到的PeerInformation對象 StreamSocket _socket= = await PeerFinder.ConnectAsync(selectedPeer); // 建立DataReader DataReader _dataReader = new DataReader(_socket.InputStream); // 先讀取消息的長度 await _dataReader.LoadAsync(4); uint messageLen = (uint)_dataReader.ReadInt32(); // 最後讀取消息的內容 await _dataReader.LoadAsync(messageLen); return _dataReader.ReadString(messageLen); }
實例:實現藍牙程序對程序的傳輸
下面給出藍牙程序對程序傳輸的示例:經過使用藍牙功能查找周邊也要使用改應用的手機,互相創建起鏈接和發送測試消息。
代碼清單19-1:藍牙程序對程序傳輸(源代碼:第19章/Examples_19_1)
MainPage.xaml文件主要代碼
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel> <Button x:Name="btFindBluetooth" Content="經過藍牙查找該應用設備" Click="btFindBluetooth_Click"/> <ListBox x:Name="lbBluetoothApp" ItemsSource="{Binding}" > <ListBox.ItemTemplate > <DataTemplate> <StackPanel> <TextBlock Text="{Binding DisplayName}" /> <TextBlock Text="{Binding ServiceName}" /> <Button Content="鏈接" HorizontalAlignment="Left" Width="308" Height="91" Click="btConnect_Click"/> </StackPanel> </DataTemplate> </ListBox.ItemTemplate> </ListBox> </StackPanel> </Grid>
MainPage.xaml.cs文件主要代碼
using System;using System.Windows;using System.Windows.Controls;using Microsoft.Phone.Controls;using Windows.Networking.Proximity;using Windows.Networking.Sockets;using Windows.Storage.Streams;namespace BluetoothDemo{ public partial class MainPage : PhoneApplicationPage { private StreamSocket _socket = null; // Socket數據流對象 private DataWriter _dataWriter; // 數據寫入對象 private DataReader _dataReader; // 數據讀取對象 public MainPage() { InitializeComponent(); Loaded += MainPage_Loaded;//頁面加載事件 } // 查找藍牙對等項按鈕事件處理 private async void btFindBluetooth_Click(object sender, RoutedEventArgs e) { try { //開始查找對等項 PeerFinder.Start(); // 等待找到的對等項 var peers = await PeerFinder.FindAllPeersAsync(); if (peers.Count == 0) { MessageBox.Show("沒有發現對等的藍牙應用"); } else { // 把對等項目綁定到列表中 lbBluetoothApp.ItemsSource = peers; } } catch(Exception ex) { if ((uint)ex.HResult == 0x8007048F) { MessageBox.Show("Bluetooth已關閉請打開手機的藍牙開關"); } else { MessageBox.Show(ex.Message); } } } // 鏈接藍牙對等項的按鈕事件處理 private async void btConnect_Click(object sender, RoutedEventArgs e) { Button deleteButton = sender as Button; PeerInformation selectedPeer = deleteButton.DataContext as PeerInformation; // 鏈接到選擇的對等項 _socket = await PeerFinder.ConnectAsync(selectedPeer); // 使用輸出輸入流創建數據讀寫對象 _dataReader = new DataReader(_socket.InputStream); _dataWriter = new DataWriter(_socket.OutputStream); // 開始讀取消息 PeerFinder_StartReader(); } // 讀取消息 async void PeerFinder_StartReader() { try { uint bytesRead = await _dataReader.LoadAsync(sizeof(uint)); if (bytesRead > 0) { // 獲取消息內容的大小 uint strLength = (uint)_dataReader.ReadUInt32(); bytesRead = await _dataReader.LoadAsync(strLength); if (bytesRead > 0) { String message = _dataReader.ReadString(strLength); MessageBox.Show("獲取到消息:" + message); // 開始下一條消息讀取 PeerFinder_StartReader(); } else { MessageBox.Show("對方已關閉鏈接"); } } else { MessageBox.Show("對方已關閉鏈接"); } } catch (Exception e) { MessageBox.Show("讀取失敗: " + e.Message); } } // 頁面加載事件處理 void MainPage_Loaded(object sender, RoutedEventArgs e) { // 訂閱鏈接請求事件 PeerFinder.ConnectionRequested += PeerFinder_ConnectionRequested; } // 鏈接請求事件處理 void PeerFinder_ConnectionRequested(object sender, ConnectionRequestedEventArgs args) { // 鏈接而且發送消息 ConnectToPeer(args.PeerInformation); } // 鏈接併發送消息給對方 async void ConnectToPeer(PeerInformation peer) { _socket = await PeerFinder.ConnectAsync(peer); _dataReader = new DataReader(_socket.InputStream); _dataWriter = new DataWriter(_socket.OutputStream); string message = "測試消息"; uint strLength = _dataWriter.MeasureString(message); _dataWriter.WriteUInt32(strLength);//寫入消息的長度 _dataWriter.WriteString(message);//寫入消息的內容 uint numBytesWritten = await _dataWriter.StoreAsync(); } }}
程序的運行效果如圖19.2所示。
實例:實現藍牙程序對設備的鏈接
下面給出藍牙程序對設備鏈接的示例:查找藍牙設備,並對找到的第一個藍牙設備進行鏈接。
代碼清單19-2:藍牙程序對設備鏈接(源代碼:第19章/Examples_19_2)
MainPage.xaml文件主要代碼
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <StackPanel> <Button x:Name="btFindBluetooth" Content="鏈接周圍的藍牙設備" Click="btFindBluetooth_Click"/> </StackPanel> </Grid>
MainPage.xaml.cs文件主要代碼
// 查找藍牙設備事件處理 private async void btFindBluetooth_Click(object sender, RoutedEventArgs e) { try { // 配置PeerFinder藍牙服務的GUID去搜索設備 PeerFinder.AlternateIdentities["Bluetooth:SDP"] = "5bec6b8f-7eba-4452-bf59-1a510745e99d"; var peers = await PeerFinder.FindAllPeersAsync(); if (peers.Count == 0) { Debug.WriteLine("沒發現藍牙設備"); } else { // 鏈接找到的第一個藍牙設備 PeerInformation selectedPeer = peers[0]; StreamSocket socket = new StreamSocket(); await socket.ConnectAsync(selectedPeer.HostName, selectedPeer.ServiceName); MessageBox.Show("鏈接上了HostName:" + selectedPeer.HostName + "ServiceName:" + selectedPeer.ServiceName); } } catch (Exception ex) { if ((uint)ex.HResult == 0x8007048F) { MessageBox.Show("Bluetooth is turned off"); } } }