iOS MultipeerConnectivity框架使用

简易描述

MultipeerConnectivity框架可用来进行近场通讯,它兼容了WiFi和蓝牙的功能,只要两台手机同时开启了WiFi或者同时开启了蓝牙,就能进行通讯及数据传输。MultipeerConnectivity(以下简称MC)的使用也很简单,苹果已经封装的很好了。

MC框架的使用可以用创建房间和加入房间作比喻,A端打开房间,允许外部设备扫描,B端打开扫描器,扫描开放的房间,扫描到后B端发送指令申请加入,A端接收到指令同意加入请求,两端通过监测连接状态判断是否成功连接。

使用方法

导入MC框架

 #import 

MC对象

@property(nonatomic,strong) MCPeerID *peerID;  //用作房间的创建,peerID.displayName为房间名
@property(nonatomic,strong) MCSession *session; //管理对象
@property(nonatomic,strong) MCNearbyServiceAdvertiser *serviceAdvertiser;  //创建房间相关业务
@property(nonatomic,strong) MCNearbyServiceBrowser *serviceBrowser;   //扫描房间相关业务

懒加载

#pragma mark - 懒加载
- (MCPeerID *)peerID {
    if (!_peerID) {
        _peerID = [[MCPeerID alloc] initWithDisplayName:[UIDevice currentDevice].name];
    }
    return _peerID;
}

- (MCSession *)session {
    if (!_session) {
        _session = [[MCSession alloc] initWithPeer:self.peerID];
        _session.delegate = self;
    }
    return _session;
}

- (MCNearbyServiceAdvertiser *)serviceAdvertiser {
    if (!_serviceAdvertiser) {
        _serviceAdvertiser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:self.peerID discoveryInfo:nil serviceType:serviceTypeString];
        _serviceAdvertiser.delegate = self;
    }
    return _serviceAdvertiser;
}

- (MCNearbyServiceBrowser *)serviceBrowser {
    if (!_serviceBrowser) {
        _serviceBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:self.peerID serviceType:serviceTypeString];
        _serviceBrowser.delegate = self;
    }
    return _serviceBrowser;
}
别忘了遵循代理

//打开房间
[self.serviceAdvertiser startAdvertisingPeer];

//扫描房间
[self.serviceBrowser startBrowsingForPeers];

//关闭房间
[_serviceAdvertiser stopAdvertisingPeer];

//停止扫描
[_serviceBrowser stopBrowsingForPeers];

代理回调方法

#pragma mark - MCSessionDelegate
//监测连接状态
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state {
    switch (state) {
        case MCSessionStateConnecting:
            CCLog(@"正在连接...");
            break;
        case MCSessionStateConnected:
            CCLog(@"连接成功!");
            [self stop];
            break;
        case MCSessionStateNotConnected:
        default:
            CCLog(@"连接失败~");
            break;
    }
}

//小数据的接收
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID {
    CCLog(@"小数据接收");
}

//对流stream的接收
- (void)session:(MCSession *)session
didReceiveStream:(NSInputStream *)stream
       withName:(NSString *)streamName
       fromPeer:(MCPeerID *)peerID {
    CCLog(@"stream 接收");
}

//开始从远程端口接收文件
- (void)session:(MCSession *)session
didStartReceivingResourceWithName:(NSString *)resourceName
       fromPeer:(MCPeerID *)peerID
   withProgress:(NSProgress *)progress {
    CCLog(@"文件 接收...");
    
//_progress为 NSProgress,用来监听文件传输进度,具体KVO方法在下面有
    if (_progress) {
        [_progress removeObserver:self forKeyPath:@"completedUnitCount"];
        _progress = nil;
    }
    _progress = progress;
    //KVO观察
    [_progress addObserver:self forKeyPath:@"completedUnitCount" options:NSKeyValueObservingOptionNew context:nil];
}

//接收文件完成
- (void)session:(MCSession *)session
didFinishReceivingResourceWithName:(NSString *)resourceName
       fromPeer:(MCPeerID *)peerID
          atURL:(NSURL *)localURL
      withError:(nullable NSError *)error {
    CCLog(@"文件接收完成!");
}

#pragma mark - KVO
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if (object == _progress) {
        int64_t numberCom = _progress.completedUnitCount;
        int64_t numberTotal = _progress.totalUnitCount;
        CGFloat progress = (float)numberCom / (float)numberTotal;
    }

}
#pragma mark - MCNearbyServiceAdvertiserDelegate
//收到加入请求
- (void)            advertiser:(MCNearbyServiceAdvertiser *)advertiser
  didReceiveInvitationFromPeer:(MCPeerID *)peerID
                   withContext:(nullable NSData *)context
             invitationHandler:(void (^)(BOOL accept, MCSession * __nullable session))invitationHandler {
    CCLog(@"收到加入请求");
    invitationHandler(YES,self.session);   //NO为不同意加入请求
}

//连接错误时
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error {
    CCLog(@"didNotStartAdvertisingPeer error = %@",error);
}
#pragma mark - MCNearbyServiceBrowserDelegate
//搜索到房间
- (void)browser:(MCNearbyServiceBrowser *)browser
      foundPeer:(MCPeerID *)peerID
withDiscoveryInfo:(nullable NSDictionary *)info {
    CCLog(@"搜索到的设备名 %@",peerID.displayName);
    if (![_peerIDs containsObject:peerID]) {
        [_peerIDs addObject:peerID];
    }
}

//丢失房间信息
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID {
    CCLog(@"丢失房间信息 %@",peerID);
}

//连接错误
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error {
    CCLog(@"连接错误");
}
- (void)retset {
    //重置
    if (_session) {
        [_session disconnect];
        _session = nil;
    }
    if (_serviceAdvertiser) {
        [_serviceAdvertiser stopAdvertisingPeer];
        _serviceAdvertiser = nil;
    }
    if (_serviceBrowser) {
        [_serviceBrowser stopBrowsingForPeers];
        _serviceBrowser = nil;
    }
    _peerIDs = @[].mutableCopy;
}

具体的使用可以下载demo进行参考,由上面的代码可以看出使用还是比较简单的,在用途上可以做设备间的信息传输,可以实现一个短距离的即时通讯(好像没什么卵用),当然具体的方向就看需求了。

备注:文中的CCLog不用在意,替换成NSLog就行;文中还有stream流传输没有写,这里贴部分代码参考一下吧。

//发送stream数据
- (void)sendStreamWith:(NSString *)path {
    
    self.byteIndex = 0; //NSInteger
    _filePath = path;    
    self.streamData = [NSMutableData dataWithContentsOfFile:_filePath];
    NSLog(@"self.streamData.length = %ld",self.streamData.length);
    NSError *error;
    self.outputStream = [self.session startStreamWithName:@"super stream" toPeer:[self.session.connectedPeers firstObject] error:&error];
    self.outputStream.delegate = self;
    [self.outputStream scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    if(error || !self.outputStream) {
        NSLog(@"%@", error);
    }
    else{
        [self.outputStream open]; 
    }
}
#pragma mark - NSStreamDelegate
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
    switch (eventCode) {
        case NSStreamEventOpenCompleted:{
            NSLog(@"数据流开始,初始化数据");
            self.byteIndex = 0;
            self.streamData = [[NSMutableData alloc]init];
        }
            break;
        case NSStreamEventHasBytesAvailable:{
            //有数据可用
            NSInputStream *input = (NSInputStream *)aStream;
            uint8_t buffer[1024];
            NSInteger length = [input read:buffer maxLength:1024];
            NSLog(@"有数据可用: %ld", length);
            [self.streamData appendBytes:(const void *)buffer length:(NSUInteger)length];   //一点一点的进行传输
        }
            break;
        case NSStreamEventHasSpaceAvailable:{ 
            //有空间可以存放
            CCLog(@"有空间可以存放");
            self.streamData = [NSMutableData dataWithContentsOfFile:_filePath];
            NSOutputStream *output = (NSOutputStream *)aStream;
            NSUInteger len = ((self.streamData.length - self.byteIndex >= 1024) ? 1024 : (self.streamData.length-self.byteIndex));
            NSData *data1 = [self.streamData subdataWithRange:NSMakeRange(self.byteIndex, len)];
            
            [output write:data1.bytes maxLength:len];
            self.byteIndex += len;
            
            dispatch_async(dispatch_get_main_queue(), ^{
                //进度: (float)self.byteIndex / (float)self.streamData.length;
            });
        }
            break;
        case NSStreamEventEndEncountered:{
            //结束
            CCLog(@"结束");
            [aStream close];
            [aStream removeFromRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
            if([aStream isKindOfClass:[NSInputStream class]]){
                //将self.streamData存入本地即可保存
            }
            self.byteIndex = 0;
        }
            break;
        case NSStreamEventErrorOccurred:{
            //发生错误
            NSLog(@"error");
        }
            break;
        default:
            break;
    }
}

github链接:
https://github.com/602530268/MC_Demo2

你可能感兴趣的:(iOS MultipeerConnectivity框架使用)