程序员

iOS端近场围栏检测(二) ——MultipeerConnect

2018-06-04  本文已影响35人  尛破孩波波
image

前言

P2P已经成为时下很流行的一种交互方式,穿戴设备连手机、智能硬件连手机等等,那么在智能手机领域是否存在这样一种协议,能在没有WIFI,没有中间服务器的情况下,能直接2个手机传输信息呢?没错,之前的蓝牙是一种方式,苹果的AirDrop也是一种方式。今天我们就来聊一下MultipeerConnectivity这个在ios7系统上公开但是又极少有人使用的P2P方案。本章与其说是近场围栏检测,还不如说是近场通信更贴切,因为只是利用了其通信的能力才能发现周边设备并作出下一步动作。

如何使用

使用条件

流程分析

P2P时序图

简单实现

1.准备阶段
//创建session
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:[[UIDevice currentDevice] name]];
self.session = [[MCSession alloc] initWithPeer:peerID securityIdentity:nil encryptionPreference:MCEncryptionRequired];
self.session.delegate = self;
    
//创建接收者信号监听
self.nearbyServiceBrowser = [[MCNearbyServiceBrowser alloc] initWithPeer:peerID serviceType:@"p2p-test"];
self.nearbyServiceBrowser.delegate = self;
[self.nearbyServiceBrowser startBrowsingForPeers];
//创建session
MCPeerID *peerID = [[MCPeerID alloc] initWithDisplayName:[UIDevice currentDevice].name];
self.session = [[MCSession alloc] initWithPeer:peerID securityIdentity:nil encryptionPreference:MCEncryptionRequired];
self.session.delegate = self;
    
//发送接收者信号
self.nearbyServiceAdveriser = [[MCNearbyServiceAdvertiser alloc] initWithPeer:peerID discoveryInfo:nil serviceType:@"p2p-test"];
self.nearbyServiceAdveriser.delegate = self;
[self.nearbyServiceAdveriser startAdvertisingPeer];

这里一定要注意的是:
1.session的加密方式必须一致。
2.serviceType在1-15个字符之间,由ASCII字母、数字和“-”组成,不能以“-”为开头或结尾。如果出现MCErrorInvalidParameter错误,请自己检查是否满足要求。
3.广播者和监听广播者的serviceType必须一致才能匹配。

2.session连接
// 发现接收者
- (void)browser:(MCNearbyServiceBrowser *)browser foundPeer:(MCPeerID *)peerID
withDiscoveryInfo:(nullable NSDictionary<NSString *, NSString *> *)info
{
    self.peerID = peerID;
    //发起会话邀请
    [self.nearbyServiceBrowser invitePeer:self.peerID toSession:self.session withContext:nil timeout:10];
}

// 接收者消失,清空peerID
- (void)browser:(MCNearbyServiceBrowser *)browser lostPeer:(MCPeerID *)peerID
{
    self.peerID = nil;
}

// 监听失败
- (void)browser:(MCNearbyServiceBrowser *)browser didNotStartBrowsingForPeers:(NSError *)error
{
    [browser stopBrowsingForPeers];
}
// 收到会话邀请
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser
didReceiveInvitationFromPeer:(MCPeerID *)peerID withContext:(nullable NSData *)context invitationHandler:(void (^)(BOOL accept, MCSession * __nullable session))invitationHandler
{ 
    //弹窗提示接收者是否连接session
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:nil message:[NSString stringWithFormat:@"接收到%@的邀请", peerID.displayName] preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *accept = [UIAlertAction actionWithTitle:@"接受" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        invitationHandler(YES, self.session);
    }];
    [alert addAction:accept];
    UIAlertAction *reject = [UIAlertAction actionWithTitle:@"拒绝" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
        invitationHandler(NO, self.session);
    }];
    [alert addAction:reject];
    [self presentViewController:alert animated:YES completion:nil];
}

// 广播失败回调
- (void)advertiser:(MCNearbyServiceAdvertiser *)advertiser didNotStartAdvertisingPeer:(NSError *)error
{
   [advertiser stopAdvertisingPeer];
}

当接收者答应了发送者的会话邀请后,一切就开始发生了。反之一切回到原点。

3.传输内容
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state
{
    //session连接情况
    switch (state) {
        case MCSessionStateNotConnected:
            //未连接
            break;
        case MCSessionStateConnecting:
            //连接中
            break;
        case MCSessionStateConnected:
        {
            //已连接
            /* 此处可以选择以下几个方法发送
            
            发送Data
            - (BOOL)sendData:(NSData *)data
                     toPeers:(NSArray<MCPeerID *> *)peerIDs
                    withMode:(MCSessionSendDataMode)mode
                       error:(NSError * __nullable * __nullable)error;
           
            发送resource
            - (nullable NSProgress *)sendResourceAtURL:(NSURL *)resourceURL
                                  withName:(NSString *)resourceName
                                    toPeer:(MCPeerID *)peerID
                     withCompletionHandler:(nullable void (^)(NSError * __nullable error))completionHandler;

            发送stream
            - (nullable NSOutputStream *)startStreamWithName:(NSString *)streamName
                                          toPeer:(MCPeerID *)peerID
                                           error:(NSError * __nullable * __nullable)error;
            
            */
            
        }
            break;
    }
}
// 传输进度
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progress
{
    //通过progress字段可以获取到指定内容的传输进度。
}

// 数据传输完成回调
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(nullable NSError *)error
{
    if (error) 
    {
        //传输出错
    }
    else 
    {
        //通过localURL获取到一个传输完成的临时文件,此时在此方法中应将其存入到业务指定的沙盒文件中固化。
    }
}

场景联想

下面YY了一些场景,可以作为MultipeerConnectivity的业务落脚点。

结论

上一篇 下一篇

猜你喜欢

热点阅读