当前位置:首页>优优资讯 > 软件教程 > 电脑软件教程 > IOS开发:Multipeer Connectivity的使用

IOS开发:Multipeer Connectivity的使用

作者:本站整理 时间:2015-10-30


  Multipeer connectivity是一个使附近设备通过Wi-Fi网络、P2P Wi-Fi以及蓝牙个人局域网进行通信的框架。互相链接的节点可以安全地传递信息、流或是其他文件资源,而不用通过网络服务。
 
  Advertising & Discovering
 
  通信的第一步是让大家互相知道彼此,我们通过广播(Advertising)和发现(discovering)服务来实现。
 
  广播作为服务器搜索附近的节点,而节点同时也去搜索附近的广播。在许多情况下,客户端同时广播并发现同一个服务,这将导致一些混乱,尤其是在client-server模式中。
 
  所以,每一个服务都应有一个类型(标示符),它是由ASCII字母、数字和“-”组成的短文本串,最多15个字符。通常,一个服务的名字应该由应用程序的名字开始,后边跟“-”和一个独特的描述符号。(作者认为这和 com.apple.*标示符很像),就像下边:
 
  static NSString * const XXServiceType = @"xx-service";
 
  一个节点有一个唯一标示MCPeerID对象,使用展示名称进行初始化,它可能是用户指定的昵称,或是单纯的设备名称。
 
  MCPeerID *localPeerID = [[MCPeerID alloc] initWithDisplayName:[[UIDevice currentDevice] name]];
 
  节点使用NSNetService或者Bonjour C API进行手动广播和发现,但这是一个特别深入的问题,关于手动节点管理可具体参见MCSession文档。
 
  Advertising
 
  服务的广播通过MCNearbyServiceAdvertiser来操作,初始化时带着本地节点、服务类型以及任何可与发现该服务的节点进行通信的可选信息。
 
  发现信息使用Bonjour TXT records encoded(according to RFC 6763)发送。
 
  MCNearbyServiceAdvertiser *advertiser =
 
  [[MCNearbyServiceAdvertiser alloc] initWithPeer:localPeerID
 
  discoveryInfo:nil
 
  serviceType:XXServiceType];
 
  advertiser.delegate = self;
 
  [advertiser startAdvertisingPeer];
 
  相关事件由advertiser的代理来处理,需遵从MCNearbyServiceAdvertiserDelegate协议。
 
  在下例中,考虑到用户可以选择是否接受或拒绝传入连接请求,并有权以拒绝或屏蔽任何来自该节点的后续请求选项。
 
  #pragma mark - MCNearbyServiceAdvertiserDelegate
 
  - (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
 
  didReceiveInvitationFromPeer:(MCPeerID *)peerID
 
  withContext:(NSData *)context
 
  invitationHandler:(void(^)(BOOL accept, MCSession *session))invitationHandler
 
  {
 
  if ([self.mutableBlockedPeers containsObject:peerID]) {
 
  invitationHandler(NO, nil);
 
  return;
 
  }
 
  [[UIActionSheet actionSheetWithTitle:[NSString stringWithFormat:NSLocalizedString(@"Received Invitation from %@", @"Received Invitation from {Peer}"), peerID.displayName]
 
  cancelButtonTitle:NSLocalizedString(@"Reject", nil)
 
  destructiveButtonTitle:NSLocalizedString(@"Block", nil)
 
  otherButtonTitles:@[NSLocalizedString(@"Accept", nil)]
 
  block:^(UIActionSheet *actionSheet, NSInteger buttonIndex)
 
  {
 
  BOOL acceptedInvitation = (buttonIndex == [actionSheet firstOtherButtonIndex]);
 
  if (buttonIndex == [actionSheet destructiveButtonIndex]) {
 
  [self.mutableBlockedPeers addObject:peerID];
 
  }
 
  MCSession *session = [[MCSession alloc] initWithPeer:localPeerID
 
  securityIdentity:nil
 
  encryptionPreference:MCEncryptionNone];
 
  session.delegate = self;
 
  invitationHandler(acceptedInvitation, (acceptedInvitation ? session : nil));
 
  }] showInView:self.view];
 
  }
 
  为了简单起见,本例中使用了一个带有block的actionsheet来作为操作框,它可以直接给invitationHandler传递信 息,用以避免创建和管理delegate造成的过于凌乱的业务逻辑,以避免创建和管理自定义delegate object造成的过于凌乱的业务逻辑。这种方法可以用category来实现,或者改编任何一个CocoaPods里有效的实现。
 
  Creating a Session
 
  在上面的例子中,我们创建了session,并在接受邀请连接时传递到节点。一个MCSession对象跟本地节点标识符、securityIdentity以及encryptionPreference参数一起进行初始化。
 
  MCSession *session = [[MCSession alloc] initWithPeer:localPeerID
 
  securityIdentity:nil
 
  encryptionPreference:MCEncryptionNone];
 
  session.delegate = self;
 
  securityIdentity是一个可选参数。通过X.509证书,它允许节点安全识别并连接其他节点。当设置了该参数时,第一个对象应该 是识别客户端的SecIdentityRef,接着是一个或更多个用以核实本地节点身份的SecCertificateRef objects。
 
  encryptionPreference参数指定是否加密节点之间的通信。MCEncryptionPreference枚举提供的三种值是:
 
  MCEncryptionOptional:会话更喜欢使用加密,但会接受未加密的连接。
 
  MCEncryptionRequired:会话需要加密。
 
  MCEncryptionNone:会话不应该加密。
 
  启用加密会显著降低传输速率,所以除非你的应用程序很特别,需要对用户敏感信息的处理,否则建议使用MCEncryptionNone。
 
  MCSessionDelegate协议将会在发送和接受信息的部分被覆盖.
 
  Discovering
 
  客户端使用MCNearbyServiceBrowser来发现广播,它需要local peer标识符,以及非常类似MCNearbyServiceAdvertiser的服务类型来初始化:
 
  MCNearbyServiceBrowser *browser = [[MCNearbyServiceBrowser alloc] initWithPeer:localPeerID serviceType:XXServiceType];
 
  browser.delegate = self;
 
  可能会有很多节点广播一个特定的服务,所以为了方便用户(或开发者),MCBrowserViewController将提供一个内置的、标准的方式来呈现链接到广播节点:
 
  MCBrowserViewController *browserViewController =
 
  [[MCBrowserViewController alloc] initWithBrowser:browser
 
  session:session];
 
  browserViewController.delegate = self;
 
  [self presentViewController:browserViewController
 
  animated:YES
 
  completion:
 
  ^{
 
  [browser startBrowsingForPeers];
 
  }];
 
  当browser完成节点连接后,它将使用它的delegate调用browserViewControllerDidFinish:,以通知展示视图控制器--它应该更新UI以适应新连接的客户端。
 
  Sending & Receiving Information
 
  一旦节点彼此相连,它们将能互传信息。Multipeer Connectivity框架区分三种不同形式的数据传输:
 
  Messages是定义明确的信息,比如端文本或者小序列化对象。
 
  Streams 流是可连续传输数据(如音频,视频或实时传感器事件)的信息公开渠道。
 
  Resources是图片、电影以及文档的文件。
 
  Messages
 
  Messages使用-sendData:toPeers:withMode:error::方法发送。
 
  NSString *message = @"Hello, World!";
 
  NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
 
  NSError *error = nil;
 
  if (![self.session sendData:data
 
  toPeers:peers
 
  withMode:MCSessionSendDataReliable
 
  error:&error]) {
 
  NSLog(@"[Error] %@", error);
 
  }
 
  通过MCSessionDelegate方法 -sessionDidReceiveData:fromPeer:收取信息。以下是如何解码先前示例代码中发送的消息:
 
  #pragma mark - MCSessionDelegate
 
  - (void)session:(MCSession *)session
 
  didReceiveData:(NSData *)data
 
  fromPeer:(MCPeerID *)peerID
 
  {
 
  NSString *message =
 
  [[NSString alloc] initWithData:data
 
  encoding:NSUTF8StringEncoding];
 
  NSLog(@"%@", message);
 
  }
 
  另一种方法是发送NSKeyedArchiver编码的对象:
 
  id <NSSecureCoding> object = // ...;
 
  NSData *data = [NSKeyedArchiver archivedDataWithRootObject:object];
 
  NSError *error = nil;
 
  if (![self.session sendData:data
 
  toPeers:peers
 
  withMode:MCSessionSendDataReliable
 
  error:&error]) {
 
  NSLog(@"[Error] %@", error);
 
  }
 
  #pragma mark - MCSessionDelegate
 
  - (void)session:(MCSession *)session
 
  didReceiveData:(NSData *)data
 
  fromPeer:(MCPeerID *)peerID
 
  {
 
  NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
 
  unarchiver.requiresSecureCoding = YES;
 
  id object = [unarchiver decodeObject];
 
  [unarchiver finishDecoding];
 
  NSLog(@"%@", object);
 
  }
 
  为了防范对象替换攻击,设置requiresSecureCoding为YES是很重要的,这样如果根对象类没有遵从<NSSecureCoding>,就会抛出一个异常。欲了解更多信息,请参阅[NSHipster article on NSSecureCoding]。
 
  Streams
 
  Streams 使用 -startStreamWithName:toPeer:创建:
 
  NSOutputStream *outputStream =
 
  [session startStreamWithName:name
 
  toPeer:peer];
 
  stream.delegate = self;
 
  [stream scheduleInRunLoop:[NSRunLoop mainRunLoop]
 
  forMode:NSDefaultRunLoopMode];
 
  [stream open];
 
  // ...
 
  Streams通过MCSessionDelegate的方法session:didReceiveStream:withName:fromPeer:来接收:
 
  #pragma mark - MCSessionDelegate
 
  - (void)session:(MCSession *)session
 
  didReceiveStream:(NSInputStream *)stream
 
  withName:(NSString *)streamName
 
  fromPeer:(MCPeerID *)peerID
 
  {
 
  stream.delegate = self;
 
  [stream scheduleInRunLoop:[NSRunLoop mainRunLoop]
 
  forMode:NSDefaultRunLoopMode];
 
  [stream open];
 
  }
 
  输入和输出的streams必须安排好并打开,然后才能使用它们。一旦这样做,streams就可以被读出和写入。
 
  Resources
 
  Resources 发送使用 -sendResourceAtURL:withName:toPeer:withCompletionHandler::
 
  NSURL *fileURL = [NSURL fileURLWithPath:@"path/to/resource"];
 
  NSProgress *progress =
 
  [self.session sendResourceAtURL:fileURL
 
  withName:[fileURL lastPathComponent]
 
  toPeer:peer
 
  withCompletionHandler:^(NSError *error)
 
  {
 
  NSLog(@"[Error] %@", error);
 
  }];
 
  返回的NSProgress对象可以是通过KVO(Key-Value Observed)来监视文件传输的进度,并且它提供取消传输的方法:-cancel。
 
  接收资源实现MCSessionDelegate两种方 法:-session:didStartReceivingResourceWithName:fromPeer:withProgress: 和 -session:didFinishReceivingResourceWithName:fromPeer:atURL:withError:
 
  #pragma mark - MCSessionDelegate
 
  - (void)session:(MCSession *)session
 
  didStartReceivingResourceWithName:(NSString *)resourceName
 
  fromPeer:(MCPeerID *)peerID
 
  withProgress:(NSProgress *)progress
 
  {
 
  // ...
 
  }
 
  - (void)session:(MCSession *)session
 
  didFinishReceivingResourceWithName:(NSString *)resourceName
 
  fromPeer:(MCPeerID *)peerID
 
  atURL:(NSURL *)localURL
 
  withError:(NSError *)error
 
  {
 
  NSURL *destinationURL = [NSURL fileURLWithPath:@"/path/to/destination"];
 
  NSError *error = nil;
 
  if (![[NSFileManager defaultManager] moveItemAtURL:localURL
 
  toURL:destinationURL
 
  error:&error]) {
 
  NSLog(@"[Error] %@", error);
 
  }
 
  }
 
  再次说明,在传输期间NSProgress parameter in -session:didStartReceivingResourceWithName:fromPeer:withProgress:允许接收节点来 监控文件传输进度。在 -session:didFinishReceivingResourceWithName:fromPeer:atURL:withError: 中,delegate的责任是从临时localURL移动文件至永久位置。
 
  Multipeer是突破性的API,其价值才刚刚开始被理解。虽然完整的支持功能比如AirDrop目前仅限于最新的设备,你应该会看到它将成为让所有人盼望的功能。
 

相关文章

相关推荐

最新攻略

用户评论

(已有0条评论)
表情
注:您的评论需要经过审核才能显示哦,请文明发言!
还没有评论,快来抢沙发吧!