iOS網絡編程實踐--藍牙對等網絡通信實例講解

基於藍牙對等網絡通信就是使用Game Kit中的GKSession、GKSessionDelegate、GKPeerPickerController和GKPeerPickerControllerDelegate來實現。開發過程分爲3個步驟:連接、發送數據和接收數據。

下面我們通過一個實例介紹一下基於藍牙對等網絡通信過程。用戶點擊“連接”按鈕,建立連接過程中會出現連接對話框,根據具體情況也會彈出其它的對話框。這些都是針對藍牙對等網絡標準對話框,而Wifi對等網絡沒有標準對話框可以使用,需要開發者自己實現。當兩個設備連接好之後,兩個玩家就可以連續輕點“點擊”按鈕,點擊的次數會傳遞給對方,倒計時時間是30秒。

4

1、連接

由於對等網絡連接過程有點複雜,貫穿了這些協議和類,我們繪製了連接過程的流程圖。

5

下面我們通過代碼直接介紹連接流程,其中ViewController.h代碼如下:

[java] view plaincopy
  1. #import <UIKit/UIKit.h>  
  2.   
  3. #import <GameKit/GameKit.h>  
  4.   
  5.    
  6.   
  7. #define  GAMING 0          //遊戲進行中  
  8.   
  9. #define  GAMED  1          //遊戲結束  
  10.   
  11.    
  12.   
  13. @interface ViewController : UIViewController <GKSessionDelegate, GKPeerPickerControllerDelegate>  
  14.   
  15. {  
  16.   
  17. NSTimer *timer;  
  18.   
  19. }  
  20.   
  21. @property (weak, nonatomic) IBOutlet UILabel *lblTimer;  
  22.   
  23.    
  24.   
  25. @property (weak, nonatomic) IBOutlet UILabel *lblPlayer2;  
  26.   
  27. @property (weak, nonatomic) IBOutlet UILabel *lblPlayer1;  
  28.   
  29. @property (weak, nonatomic) IBOutlet UIButton *btnConnect;  
  30.   
  31. @property (weak, nonatomic) IBOutlet UIButton *btnClick;  
  32.   
  33.    
  34.   
  35. @property (nonatomic, strong) GKPeerPickerController *picker;  
  36.   
  37. @property (nonatomic, strong) GKSession *session;  
  38.   
  39.    
  40.   
  41. - (IBAction)onClick:(id)sender;  
  42.   
  43. - (IBAction)connect:(id)sender;  
  44.   
  45.    
  46.   
  47. //清除UI畫面上的數據  
  48.   
  49. -(void) clearUI;  
  50.   
  51.    
  52.   
  53. //更新計時器  
  54.   
  55. -(void) updateTimer;  
  56.   
  57.    
  58.   
  59. @end  


使用Game Kit需要引入頭文件<GameKit/GameKit.h>,之前需要把GameKit.framework框架添加到工程中。而且定義類的時候需要實現協議GKSessionDelegate和GKPeerPickerControllerDelegate,並且定義GKPeerPickerController類型的屬性picker,定義GKSession類型的屬性session。

ViewController.m中創建GKPeerPickerController對象的代碼如下:

[java] view plaincopy
  1. - (IBAction)connect:(id)sender {  
  2.   
  3. _picker = [[GKPeerPickerController alloc] init];  
  4.   
  5. _picker.delegate = self; ①  
  6.   
  7. _picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby;  ②  
  8.   
  9. [_picker show];  
  10.   
  11. }  


用戶點擊的連接按鈕時,觸發connect:方法。在該方法中創建GKPeerPickerController對象。創建完成不要忘記設置GKPeerPickerController委託爲self,第②行代碼所示。在第③行代碼中connectionTypesMask屬性是設置對等網絡連接類型,其中有兩種類型選擇:GKPeerPickerConnectionTypeNearby和GKPeerPickerConnectionTypeOnline,GKPeerPickerConnectionTypeNearby用於藍牙通訊也是默認的通訊方法,GKPeerPickerConnectionTypeOnline用於Wifi通訊的局域網通訊,這種方式麻煩,需要開發人員自己設計UI畫面,自己使用Bonjour服務發現管理連接,以及自己編寫輸入輸出流實現通訊。如果給用戶一個選擇對話框,代碼可以如下編寫:

_picker.connectionTypesMask = GKPeerPickerConnectionTypeNearby | GKPeerPickerConnectionTypeOnline;

6

其中“在線”就是GKPeerPickerConnectionTypeOnline類型,“附近”就是GKPeerPickerConnectionTypeNearby類型。

連接成功之後回調ViewController.m中的回調委託方法peerPickerController:didConnectPeer:toSession:代碼:

[java] view plaincopy
  1. - (void)peerPickerController:(GKPeerPickerController *)pk didConnectPeer:(NSString *)peerID  
  2.   
  3. toSession:(GKSession *) session  
  4.   
  5. {  
  6.   
  7. NSLog(@”建立連接”);  
  8.   
  9. _session = session; ①  
  10.   
  11. _session.delegate = self;  ②  
  12.   
  13. [_session setDataReceiveHandler:self withContext:nil];  ③  
  14.   
  15. _picker.delegate = nil;  
  16.   
  17. [_picker dismiss]; ④  
  18.   
  19. [_btnClick setEnabled:YES];  
  20.   
  21. [_btnConnect setTitle:@"斷開連接" forState:UIControlStateNormal];  
  22.   
  23. //開始計時  
  24.   
  25. timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self  
  26.   
  27. selector:@selector(updateTimer)  
  28.   
  29. userInfo:nil repeats:YES]; ⑤  
  30.   
  31. }  


上述代碼第①行_session = session將委託方法中返回的會話參數賦值給成員變量,這樣我們就獲得了一個會話對象。這種方式中,會話ID是應用程序的包ID,如果想自己分配會話ID,可以實現下面委託方法,在方法中使用GKSession的構造方法initWithSessionID:displayName: sessionMode:,自己創建會話對象。

[java] view plaincopy
  1. - (GKSession *)peerPickerController:(GKPeerPickerController *)picker  
  2.   
  3. sessionForConnectionType:(GKPeerPickerConnectionType)type {  
  4.   
  5. GKSession *session = [[GKSession alloc] initWithSessionID: <自定義SessionID>  
  6.   
  7. displayName:<顯示的名字> sessionMode:GKSessionModePeer];  
  8.   
  9. return session;  
  10.   
  11. }  


有的時候會話的狀態會發生變化,我們要根據狀態的變化做一些UI的清理和資源的釋放。監測狀態變化在委託方法session:peer:didChangeState:中實現,方法代碼如下:

[java] view plaincopy
  1. - (void)session:(GKSession *)session peer:(NSString *)peerID  
  2.   
  3. didChangeState:(GKPeerConnectionState)state  
  4.   
  5. {  
  6.   
  7. if (state == GKPeerStateConnected)  
  8.   
  9. {  
  10.   
  11. NSLog(@”connected”);  
  12.   
  13. [_btnConnect setTitle:@"斷開連接" forState:UIControlStateNormal];  
  14.   
  15. [_btnClick setEnabled:YES];  
  16.   
  17. else if (state == GKPeerStateDisconnected)  
  18.   
  19. {  
  20.   
  21. NSLog(@”disconnected”);  
  22.   
  23. [self clearUI];  
  24.   
  25. }  
  26.   
  27. }  


其中GKPeerStateConnected常量是已經連接狀態,GKPeerStateDisconnected常量是斷開連接狀態。

2、發送數據

發送數據的代碼如下:

[java] view plaincopy
  1. - (IBAction)onClick:(id)sender {  
  2.   
  3. int count = [_lblPlayer1.text intValue];  
  4.   
  5. _lblPlayer1.text = [NSString stringWithFormat:@"%i",++count];  
  6.   
  7. NSString *sendStr = [NSString  
  8.   
  9. stringWithFormat:@"{\"code\":%i,\"count\":%i}",GAMING,count]; ①  
  10.   
  11. NSData* data = [sendStr dataUsingEncoding: NSUTF8StringEncoding];  
  12.   
  13. if (_session) {  
  14.   
  15. [_session sendDataToAllPeers:data  
  16.   
  17. withDataMode:GKSendDataReliable  error:nil]; ②  
  18.   
  19. }  
  20.   
  21. }  


3、接收數據

爲了接收數據首先需要在設置會話時候通過[_session setDataReceiveHandler:self withContext:nil]語句設置接收數據的處理程序是self。這樣當數據到達時候就會觸發下面的方法特定:

[java] view plaincopy
  1. - (void) receiveData:(NSData *)data  fromPeer:(NSString *)peer  
  2.   
  3. inSession:(GKSession *)session  context:(void *)context  
  4.   
  5. {  
  6.   
  7. id jsonObj = [NSJSONSerialization JSONObjectWithData:data  
  8.   
  9. options:NSJSONReadingMutableContainers error:nil];  
  10.   
  11. NSNumber *codeObj = [jsonObj objectForKey:@"code"];  
  12.   
  13. if ([codeObj intValue]== GAMING) {  
  14.   
  15. NSNumber * countObj= [jsonObj objectForKey:@"count"];  
  16.   
  17. _lblPlayer2.text = [NSString stringWithFormat:@"%@",countObj];  
  18.   
  19. else if ([codeObj intValue]== GAMED) {  
  20.   
  21. [self clearUI];  
  22.   
  23. }  
  24.   
  25. }  


上面的代碼是接收到數據之後,進行JSON解碼,取出遊戲狀態和點擊次數。

主要的程序代碼就是這些,根據具體的業務情況還可以能有所變化,讀者可以下載完整代碼在兩臺之間設備或是一個設備一個模擬器之間進行測試。

發佈了41 篇原創文章 · 獲贊 5 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章