Multipeer connectivity是一个使附近设备通过Wi-Fi网络、P2P Wi-Fi以及蓝牙个人局域网进行通信的框架。互相链接的节点可以安全地传递信息、流或是其他文件资源。
个人认为其功能与iOS\MacOS中的AirDrop很相似,其飞一样的效率确实很酸爽。
废话少说,我们来集成MultipeerConnectivity的功能。
首先引入系统框架
#import
依次声明如下属性,这里都给予了详细的备注,就不赘述了。
/**
* 表示为一个用户,亦可认为是当前设备
*/
@property (nonatomic,strong)MCPeerID * peerID;
/**
* 数据流,启用和管理Multipeer连接会话中的所有人之间的沟通。 通过Sesion,给别人发送数据。类似于Scoket
*/
@property (nonatomic,strong)MCSession * session;
/**
* 可以接收,并处理用户请求连接的响应。没有回调,会弹出默认的提示框,并处理连接。
*/
@property (nonatomic,strong)MCAdvertiserAssistant * advertiser;
/**
* 用于搜索附近的用户,并可以对搜索到的用户发出邀请加入某个会话中。
*/
@property (nonatomic,strong)MCNearbyServiceBrowser * brower;
/**
* 附近用户列表
*/
@property (nonatomic,strong)MCBrowserViewController * browserViewController;
/**
* 存储连接
*/
@property (nonatomic,strong)NSMutableArray * sessionArray;
接下来我们将当前设备初始化,并开启附近用户搜索等功能。
/**
* 连接设置
*/
- (void)createMC{
//获取设备名称
NSString * name = [UIDevice currentDevice].name;
//用户
_peerID = [[MCPeerID alloc]initWithDisplayName:name];
//为用户建立连接
_session = [[MCSession alloc]initWithPeer:_peerID];
//设置代理
_session.delegate = self;
//设置广播服务(发送方)
_advertiser = [[MCAdvertiserAssistant alloc]initWithServiceType:@"type" discoveryInfo:nil session:_session];
//开始广播
[_advertiser start];
//设置发现服务(接收方)
_brower = [[MCNearbyServiceBrowser alloc]initWithPeer:_peerID serviceType:@"type"];
//设置代理
_brower.delegate = self;
[_brower startBrowsingForPeers];
}
这里不要忘记添加其协议,如下
MCSessionDelegate,MCBrowserViewControllerDelegate,MCNearbyServiceBrowserDelegate。
最后实现其对应的代理方法即可
#pragma MC相关代理方法
/**
* 发现附近用户
*
* @param browser 搜索附近用户
* @param peerID 附近用户
* @param info 详情
*/
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID withDiscoveryInfo:(NSDictionary *)info{
NSLog(@"发现附近用户%@",peerID.displayName);
if (_browserViewController == nil) {
_browserViewController = [[MCBrowserViewController alloc]initWithServiceType:@"type" session:_session];
_browserViewController.delegate = self;
/**
* 跳转发现界面
*/
[self presentViewController:_browserViewController animated:YES completion:nil];
}
}
/**
* 附近某个用户消失了
*
* @param browser 搜索附近用户
* @param peerID 用户
*/
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID{
NSLog(@"附近用户%@离开了",peerID.displayName);
}
#pragma mark BrowserViewController附近用户列表视图相关代理方法
/**
* 选取相应用户
*
* @param browserViewController 用户列表
*/
- (void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController{
[self dismissViewControllerAnimated:YES completion:nil];
_browserViewController = nil;
//关闭广播服务,停止其他人发现
[_advertiser stop];
}
/**
* 用户列表关闭
*
* @param browserViewController 用户列表
*/
- (void)browserViewControllerWasCancelled:(MCBrowserViewController *)browserViewController{
[self dismissViewControllerAnimated:YES completion:nil];
_browserViewController = nil;
[_advertiser stop];
}
#pragma mark MCSession代理方法
/**
* 当检测到连接状态发生改变后进行存储
*
* @param session MC流
* @param peerID 用户
* @param state 连接状态
*/
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{
//判断如果连接
if (state == MCSessionStateConnected) {
//保存这个连接
if (![_sessionArray containsObject:session]) {
//如果不存在 保存
[_sessionArray addObject:session];
}
}
}
/**
* 接收到消息
*
* @param session MC流
* @param data 传入的二进制数据
* @param peerID 用户
*/
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
NSString * message = [NSString stringWithFormat:@"%@:%@",peerID.displayName,[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]];
dispatch_async(dispatch_get_main_queue(), ^{
[_dataArray addObject:message];
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:_dataArray.count - 1 inSection:0];
[_tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
[_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
});
}
/**
* 接收数据流
*
* @param session MC流
* @param stream 数据流
* @param streamName 数据流名称(标示)
* @param peerID 用户
*/
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID{
}
/**
* 开始接收资源
*/
- (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{
}
效果图如下
选定后点击Done即可完成连接。
代理方法中具有监听附近设备,连接,接收流程等流程。
对于发送数据,可以简单搭建一个页面来进行。比如在textField点击Return时触发。对于发送的数据类型具有两种形式,对应的即为socket中的UDP与TCP。
- (BOOL)textFieldShouldReturn:(UITextField *)textField{
if (textField.text.length > 0) {
/**
* 两种类型
MCSessionSendDataUnreliable 类似于UDP连接方式
MCSessionSendDataReliable 类似于TCP连接方式
*/
[_session sendData:[textField.text dataUsingEncoding:NSUTF8StringEncoding] toPeers:_session.connectedPeers withMode:MCSessionSendDataUnreliable error:nil];
//UI操作
[_dataArray addObject:textField.text];
NSIndexPath * indexPath = [NSIndexPath indexPathForRow:_dataArray.count - 1 inSection:0];
[_tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationTop];
[_tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
}
return YES;
}
效果图
这里测试的话可以使用两台设备,模拟器、真机均可。当其中一个设备检测到附近设备后会弹起附近设备列表,点击选取后即可进行通讯操作。用例里模拟的是发送字符串操作,也可以替换为文件,因为都传递的为二进制嘛。相信你会察觉到其飞一样的速度的,就写到这里。
demo下载链接
iOS被遗忘的近距离通讯利器demo