自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS7新技術(shù):如何使用Multipeer Connectivity

移動(dòng)開發(fā) iOS
Multipeer connectivity是一個(gè)使附近設(shè)備通過Wi-Fi網(wǎng)絡(luò)、P2P Wi-Fi以及藍(lán)牙個(gè)人局域網(wǎng)進(jìn)行通信的框架?;ハ噫溄拥墓?jié)點(diǎn)可以安全地傳遞信息、流或是其他文件資源,而不用通過網(wǎng)絡(luò)服務(wù)。

[[111258]]

Multipeer connectivity是一個(gè)使附近設(shè)備通過Wi-Fi網(wǎng)絡(luò)、P2P Wi-Fi以及藍(lán)牙個(gè)人局域網(wǎng)進(jìn)行通信的框架?;ハ噫溄拥墓?jié)點(diǎn)可以安全地傳遞信息、流或是其他文件資源,而不用通過網(wǎng)絡(luò)服務(wù)。

Advertising & Discovering

通信的第一步是讓大家互相知道彼此,我們通過廣播(Advertising)和發(fā)現(xiàn)(discovering)服務(wù)來實(shí)現(xiàn)。

廣播作為服務(wù)器搜索附近的節(jié)點(diǎn),而節(jié)點(diǎn)同時(shí)也去搜索附近的廣播。在許多情況下,客戶端同時(shí)廣播并發(fā)現(xiàn)同一個(gè)服務(wù),這將導(dǎo)致一些混亂,尤其是在client-server模式中。

所以,每一個(gè)服務(wù)都應(yīng)有一個(gè)類型(標(biāo)示符),它是由ASCII字母、數(shù)字和“-”組成的短文本串,最多15個(gè)字符。通常,一個(gè)服務(wù)的名字應(yīng)該由應(yīng)用程序的名字開始,后邊跟“-”和一個(gè)獨(dú)特的描述符號(hào)。(作者認(rèn)為這和 com.apple.*標(biāo)示符很像),就像下邊:

  1. static NSString * const XXServiceType = @"xx-service";

一個(gè)節(jié)點(diǎn)有一個(gè)唯一標(biāo)示MCPeerID對(duì)象,使用展示名稱進(jìn)行初始化,它可能是用戶指定的昵稱,或是單純的設(shè)備名稱。

  1. MCPeerID *localPeerID = [[MCPeerID alloc] initWithDisplayName:[[UIDevice currentDevice] name]];

節(jié)點(diǎn)使用NSNetService或者Bonjour C API進(jìn)行手動(dòng)廣播和發(fā)現(xiàn),但這是一個(gè)特別深入的問題,關(guān)于手動(dòng)節(jié)點(diǎn)管理可具體參見MCSession文檔。

Advertising

服務(wù)的廣播通過MCNearbyServiceAdvertiser來操作,初始化時(shí)帶著本地節(jié)點(diǎn)、服務(wù)類型以及任何可與發(fā)現(xiàn)該服務(wù)的節(jié)點(diǎn)進(jìn)行通信的可選信息。

發(fā)現(xiàn)信息使用Bonjour TXT records encoded(according to RFC 6763)發(fā)送。

  1. MCNearbyServiceAdvertiser *advertiser = 
  2.     [[MCNearbyServiceAdvertiser alloc] initWithPeer:localPeerID 
  3.                                       discoveryInfo:nil 
  4.                                         serviceType:XXServiceType]; 
  5. advertiser.delegate = self; 
  6. [advertiser startAdvertisingPeer]; 

相關(guān)事件由advertiser的代理來處理,需遵從MCNearbyServiceAdvertiserDelegate協(xié)議。

在下例中,考慮到用戶可以選擇是否接受或拒絕傳入連接請(qǐng)求,并有權(quán)以拒絕或屏蔽任何來自該節(jié)點(diǎn)的后續(xù)請(qǐng)求選項(xiàng)。

  1. #pragma mark - MCNearbyServiceAdvertiserDelegate 
  2.  
  3. - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser 
  4. didReceiveInvitationFromPeer:(MCPeerID *)peerID 
  5.        withContext:(NSData *)context 
  6.  invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler 
  7.     if ([self.mutableBlockedPeers containsObject:peerID]) { 
  8.         invitationHandler(NO, nil); 
  9.         return
  10.     } 
  11.  
  12.     [[UIActionSheet actionSheetWithTitle:[NSString stringWithFormat:NSLocalizedString(@"Received Invitation from %@", @"Received Invitation from {Peer}"), peerID.displayName] 
  13.                        cancelButtonTitle:NSLocalizedString(@"Reject", nil) 
  14.                   destructiveButtonTitle:NSLocalizedString(@"Block", nil) 
  15.                        otherButtonTitles:@[NSLocalizedString(@"Accept", nil)] 
  16.                                    block:^(UIActionSheet *actionSheet, NSInteger buttonIndex) 
  17.     { 
  18.         BOOL acceptedInvitation = (buttonIndex == [actionSheet firstOtherButtonIndex]); 
  19.  
  20.         if (buttonIndex == [actionSheet destructiveButtonIndex]) { 
  21.             [self.mutableBlockedPeers addObject:peerID]; 
  22.         } 
  23.  
  24.         MCSession *session = [[MCSession alloc] initWithPeer:localPeerID 
  25.                                             securityIdentity:nil 
  26.                                         encryptionPreference:MCEncryptionNone]; 
  27.         session.delegate = self; 
  28.  
  29.         invitationHandler(acceptedInvitation, (acceptedInvitation ? session : nil)); 
  30.     }] showInView:self.view]; 
  31. }

為了簡(jiǎn)單起見,本例中使用了一個(gè)帶有block的actionsheet來作為操作框,它可以直接給invitationHandler傳遞信 息,用以避免創(chuàng)建和管理delegate造成的過于凌亂的業(yè)務(wù)邏輯,以避免創(chuàng)建和管理自定義delegate object造成的過于凌亂的業(yè)務(wù)邏輯。這種方法可以用category來實(shí)現(xiàn),或者改編任何一個(gè)CocoaPods里有效的實(shí)現(xiàn)。

Creating a Session

在上面的例子中,我們創(chuàng)建了session,并在接受邀請(qǐng)連接時(shí)傳遞到節(jié)點(diǎn)。一個(gè)MCSession對(duì)象跟本地節(jié)點(diǎn)標(biāo)識(shí)符、securityIdentity以及encryptionPreference參數(shù)一起進(jìn)行初始化。

  1. MCSession *session = [[MCSession alloc] initWithPeer:localPeerID 
  2.                                     securityIdentity:nil 
  3.                                 encryptionPreference:MCEncryptionNone]; 
  4. session.delegate = self; 

securityIdentity是一個(gè)可選參數(shù)。通過X.509證書,它允許節(jié)點(diǎn)安全識(shí)別并連接其他節(jié)點(diǎn)。當(dāng)設(shè)置了該參數(shù)時(shí),第一個(gè)對(duì)象應(yīng)該 是識(shí)別客戶端的SecIdentityRef,接著是一個(gè)或更多個(gè)用以核實(shí)本地節(jié)點(diǎn)身份的SecCertificateRef objects。

encryptionPreference參數(shù)指定是否加密節(jié)點(diǎn)之間的通信。MCEncryptionPreference枚舉提供的三種值是:

MCEncryptionOptional:會(huì)話更喜歡使用加密,但會(huì)接受未加密的連接。

MCEncryptionRequired:會(huì)話需要加密。

MCEncryptionNone:會(huì)話不應(yīng)該加密。

啟用加密會(huì)顯著降低傳輸速率,所以除非你的應(yīng)用程序很特別,需要對(duì)用戶敏感信息的處理,否則建議使用MCEncryptionNone。

MCSessionDelegate協(xié)議將會(huì)在發(fā)送和接受信息的部分被覆蓋.

Discovering

客戶端使用MCNearbyServiceBrowser來發(fā)現(xiàn)廣播,它需要local peer標(biāo)識(shí)符,以及非常類似MCNearbyServiceAdvertiser的服務(wù)類型來初始化:

  1. MCNearbyServiceBrowser *browser = [[MCNearbyServiceBrowser alloc] initWithPeer:localPeerID serviceType:XXServiceType]; 
  2. browser.delegate = self;

可能會(huì)有很多節(jié)點(diǎn)廣播一個(gè)特定的服務(wù),所以為了方便用戶(或開發(fā)者),MCBrowserViewController將提供一個(gè)內(nèi)置的、標(biāo)準(zhǔn)的方式來呈現(xiàn)鏈接到廣播節(jié)點(diǎn):

  1. MCBrowserViewController *browserViewController = 
  2.     [[MCBrowserViewController alloc] initWithBrowser:browser 
  3.                                              session:session]; 
  4. browserViewController.delegate = self; 
  5. [self presentViewController:browserViewController 
  6.                    animated:YES 
  7.                  completion: 
  8. ^{ 
  9.     [browser startBrowsingForPeers]; 
  10. }]; 

當(dāng)browser完成節(jié)點(diǎn)連接后,它將使用它的delegate調(diào)用browserViewControllerDidFinish:,以通知展示視圖控制器--它應(yīng)該更新UI以適應(yīng)新連接的客戶端。

Sending & Receiving Information

一旦節(jié)點(diǎn)彼此相連,它們將能互傳信息。Multipeer Connectivity框架區(qū)分三種不同形式的數(shù)據(jù)傳輸:

Messages是定義明確的信息,比如端文本或者小序列化對(duì)象。

Streams 流是可連續(xù)傳輸數(shù)據(jù)(如音頻,視頻或?qū)崟r(shí)傳感器事件)的信息公開渠道。

Resources是圖片、電影以及文檔的文件。

Messages

Messages使用-sendData:toPeers:withMode:error::方法發(fā)送。

  1. NSString *message = @"Hello, World!"
  2. NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding]; 
  3. NSError *error = nil; 
  4. if (![self.session sendData:data 
  5.                     toPeers:peers 
  6.                    withMode:MCSessionSendDataReliable 
  7.                       error:&error]) { 
  8.     NSLog(@"[Error] %@", error); 
  9. }

通過MCSessionDelegate方法 -sessionDidReceiveData:fromPeer:收取信息。以下是如何解碼先前示例代碼中發(fā)送的消息:

  1. #pragma mark - MCSessionDelegate 
  2.   
  3. - (void)session:(MCSession *)session 
  4.  didReceiveData:(NSData *)data 
  5.        fromPeer:(MCPeerID *)peerID 
  6.     NSString *message = 
  7.         [[NSString alloc] initWithData:data 
  8.                               encoding:NSUTF8StringEncoding]; 
  9.     NSLog(@"%@", message); 
  10. }

另一種方法是發(fā)送NSKeyedArchiver編碼的對(duì)象:

  1. id <NSSecureCoding> object = // ...; 
  2. NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object]; 
  3. NSError *error = nil; 
  4. if (![self.session sendData:data 
  5.                     toPeers:peers 
  6.                    withMode:MCSessionSendDataReliable 
  7.                       error:&error]) { 
  8.     NSLog(@"[Error] %@", error); 
  9. #pragma mark - MCSessionDelegate 
  10.   
  11. - (void)session:(MCSession *)session 
  12.  didReceiveData:(NSData *)data 
  13.        fromPeer:(MCPeerID *)peerID 
  14.     NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data]; 
  15.     unarchiver.requiresSecureCoding = YES; 
  16.     id object = [unarchiver decodeObject]; 
  17.     [unarchiver finishDecoding]; 
  18.     NSLog(@"%@", object); 
  19. }

為了防范對(duì)象替換攻擊,設(shè)置requiresSecureCoding為YES是很重要的,這樣如果根對(duì)象類沒有遵從<NSSecureCoding>,就會(huì)拋出一個(gè)異常。欲了解更多信息,請(qǐng)參閱[NSHipster article on NSSecureCoding]。

Streams

Streams 使用 -startStreamWithName:toPeer:創(chuàng)建:

  1. NSOutputStream *outputStream = 
  2.     [session startStreamWithName:name 
  3.                           toPeer:peer]; 
  4.  
  5. stream.delegate = self; 
  6. [stream scheduleInRunLoop:[NSRunLoop mainRunLoop] 
  7.                 forMode:NSDefaultRunLoopMode]; 
  8. [stream open]; 
  9.  
  10. // ...

Streams通過MCSessionDelegate的方法session:didReceiveStream:withName:fromPeer:來接收:

  1. #pragma mark - MCSessionDelegate 
  2.  
  3. - (void)session:(MCSession *)session 
  4. didReceiveStream:(NSInputStream *)stream 
  5.        withName:(NSString *)streamName 
  6.        fromPeer:(MCPeerID *)peerID 
  7.     stream.delegate = self; 
  8.     [stream scheduleInRunLoop:[NSRunLoop mainRunLoop] 
  9.                       forMode:NSDefaultRunLoopMode]; 
  10.     [stream open]; 

輸入和輸出的streams必須安排好并打開,然后才能使用它們。一旦這樣做,streams就可以被讀出和寫入。

Resources

Resources 發(fā)送使用 -sendResourceAtURL:withName:toPeer:withCompletionHandler::

  1. NSURL *fileURL = [NSURL fileURLWithPath:@"path/to/resource"]; 
  2. NSProgress *progress = 
  3.     [self.session sendResourceAtURL:fileURL 
  4.                            withName:[fileURL lastPathComponent] 
  5.                              toPeer:peer 
  6.                   withCompletionHandler:^(NSError *error) 
  7.     NSLog(@"[Error] %@", error); 
  8. }]; 

返回的NSProgress對(duì)象可以是通過KVO(Key-Value Observed)來監(jiān)視文件傳輸?shù)倪M(jìn)度,并且它提供取消傳輸?shù)姆椒ǎ?cancel。

接收資源實(shí)現(xiàn)MCSessionDelegate兩種方 法:-session:didStartReceivingResourceWithName:fromPeer:withProgress: 和 -session:didFinishReceivingResourceWithName:fromPeer:atURL:withError:

  1. #pragma mark - MCSessionDelegate 
  2.  
  3. - (void)session:(MCSession *)session 
  4. didStartReceivingResourceWithName:(NSString *)resourceName 
  5.        fromPeer:(MCPeerID *)peerID 
  6.    withProgress:(NSProgress *)progress 
  7.     // ... 
  8.  
  9. - (void)session:(MCSession *)session 
  10. didFinishReceivingResourceWithName:(NSString *)resourceName 
  11.        fromPeer:(MCPeerID *)peerID 
  12.           atURL:(NSURL *)localURL 
  13.       withError:(NSError *)error 
  14.     NSURL *destinationURL = [NSURL fileURLWithPath:@"/path/to/destination"]; 
  15.     NSError *error = nil; 
  16.     if (![[NSFileManager defaultManager] moveItemAtURL:localURL 
  17.                                                  toURL:destinationURL 
  18.                                                  error:&error]) { 
  19.         NSLog(@"[Error] %@", error); 
  20.     } 

再次說明,在傳輸期間NSProgress parameter in -session:didStartReceivingResourceWithName:fromPeer:withProgress:允許接收節(jié)點(diǎn)來 監(jiān)控文件傳輸進(jìn)度。在 -session:didFinishReceivingResourceWithName:fromPeer:atURL:withError: 中,delegate的責(zé)任是從臨時(shí)localURL移動(dòng)文件至永久位置。

Multipeer是突破性的API,其價(jià)值才剛剛開始被理解。雖然完整的支持功能比如AirDrop目前僅限于最新的設(shè)備,你應(yīng)該會(huì)看到它將成為讓所有人盼望的功能。

本文由郭歷成[博客]翻譯自nshipster中的Multipeer Connectivity一節(jié)。

【移動(dòng)開發(fā)視頻課程推薦】

責(zé)任編輯:閆佳明 來源: cocoachina
相關(guān)推薦

2013-09-18 10:46:15

2013-09-26 14:42:28

2013-08-20 15:51:06

iOS7iOS7 Beta6蘋果

2013-09-25 09:50:27

iOS7蘋果

2013-09-26 16:02:13

2013-06-12 15:19:05

iOS7WWDC

2013-06-13 08:58:02

iOS7WWDCDesign By C

2013-07-24 17:45:15

iOS7圖標(biāo)UI

2013-09-16 10:14:35

iOS7App Store

2013-06-19 09:28:29

2013-12-17 10:02:30

越獄iOS7

2013-06-25 10:13:11

iOS7WWDC蘋果

2013-10-29 14:31:33

移動(dòng)技術(shù)半月刊

2013-07-01 13:41:09

iOS7WWDC姿勢(shì)控制

2013-06-21 13:04:59

iOS7WWDCUI設(shè)計(jì)

2013-12-20 11:26:01

2022-02-07 09:07:38

黑客供應(yīng)鏈攻擊SolarWinds

2013-11-25 17:32:04

微軟Windows 9Aero

2015-09-17 08:55:47

react學(xué)習(xí)技術(shù)

2015-09-17 10:23:04

新技術(shù)學(xué)習(xí)
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)