Windows Phone 8 藍牙編程


《深入淺出Windows Phone 8應用開發》之藍牙編程

    藍牙是手機的近距離無限傳輸的技術,在之前的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的消息發送接收機制,類似於應用程序到應用程序的通信。在Windows Phone 8中使用到應用程序到設備的藍牙通訊技術,需要在項目的WMAppManifest.xml文件中添加ID_CAP_PROXIMITY和ID_CAP_NETWORKING的功能選項,表示支持臨近的設備通信能力和網絡通信能力,否則程序會出現異常。

藍牙編程類

    在Windows Phone 8里面使用到藍牙編程主要會用到PeerFinder類,PeerInformation類,StreamSocket類和ConnectionRequestedEventArgs類,這些類的說明如表19.1所示。因為藍牙也是基於TCP協議進行消息傳遞了,所以需要用到Socket的相關的編程知識,以及StreamSocket類。PeerFinder類是藍牙查找類,它的主要成員如表19.2所示。

                         表19.1 藍牙編程類的說明

類名

說明

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");
                }
            }
        }

程序的運行效果如圖19.3所示


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM