美文网首页
iOS MultipeerConnectivity框架使用

iOS MultipeerConnectivity框架使用

作者: Double_Chen | 来源:发表于2017-05-15 18:16 被阅读109次

    简易描述

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

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

    使用方法

    导入MC框架

     #import <MultipeerConnectivity/MultipeerConnectivity.h>
    

    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;
    }
    
    别忘了遵循代理
    <MCSessionDelegate,MCNearbyServiceAdvertiserDelegate,MCNearbyServiceBrowserDelegate>
    
    //打开房间
    [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<NSString *, NSString *> *)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框架使用

          本文链接:https://www.haomeiwen.com/subject/qpihxxtx.html