蓝牙框架之MultipeerConnectivity框架

前面已经说了GameKit相关的蓝牙操作类从iOS7已经全部过期,苹果官方推荐使用MultipeerConnectivity代替。但是应该了解,MultipeerConnectivity.framework并不仅仅支持蓝牙连接,准确的说它是一种支持Wi-Fi网络、P2P Wi-Fi已经蓝牙个人局域网的通信框架,它屏蔽了具体的连接技术,让开发人员有统一的接口编程方法。通过MultipeerConnectivity连接的节点之间可以安全的传递信息、流或者其他文件资源而不必通过网络服务。此外使用MultipeerConnectivity进行近场通信也不再局限于同一个应用之间传输,而是可以在不同的应用之间进行数据传输(当然如果有必要的话你仍然可以选择在一个应用程序之间传输)。

要了解MultipeerConnectivity的使用必须要清楚一个概念:广播(Advertisting)和发现(Disconvering),这很类似于一种Client-Server模式。假设有两台设备A、B,B作为广播去发送自身服务,A作为发现的客户端。一旦A发现了B就试图建立连接,经过B同意二者建立连接就可以相互发送数据。在使用GameKit框架时,A和B既作为广播又作为发现,当然这种情况在MultipeerConnectivity中也很常见。

A.广播

无论是作为服务器端去广播还是作为客户端去发现广播服务,那么两个(或更多)不同的设备之间必须要有区分,通常情况下使用MCPeerID对象来区分一台设备,在这个设备中可以指定显示给对方查看的名称(display name)。另外不管是哪一方,还必须建立一个会话MCSession用于发送和接受数据。通常情况下会在会话的-(void)session:(MCSession )session peer:(MCPeerID )peerID didChangeState:(MCSessionState)state代理方法中跟踪会话状态(已连接、正在连接、未连接);在会话的-(void)session:(MCSession )session didReceiveData:(NSData )data fromPeer:(MCPeerID *)peerID代理方法中接收数据;同时还会调用会话的-(void)sendData: toPeers:withMode: error:方法去发送数据。

广播作为一个服务器去发布自身服务,供周边设备发现连接。在MultipeerConnectivity中使用MCAdvertiserAssistant来表示一个广播,通常创建广播时指定一个会话MCSession对象将广播服务和会话关联起来。一旦调用广播的start方法周边的设备就可以发现该广播并可以连接到此服务。在MCSession的代理方法中可以随时更新连接状态,一旦建立了连接之后就可以通过MCSession的connectedPeers获得已经连接的设备。

B.发现

前面已经说过作为发现的客户端同样需要一个MCPeerID来标志一个客户端,同时会拥有一个MCSession来监听连接状态并发送、接受数据。除此之外,要发现广播服务,客户端就必须要随时查找服务来连接,在MultipeerConnectivity中提供了一个控制器MCBrowserViewController来展示可连接和已连接的设备(这类似于GameKit中的GKPeerPickerController),当然如果想要自己定制一个界面来展示设备连接的情况你可以选择自己开发一套UI界面。一旦通过MCBroserViewController选择一个节点去连接,那么作为广播的节点就会收到通知,询问用户是否允许连接。由于初始化MCBrowserViewController的过程已经指定了会话MCSession,所以连接过程中会随时更新会话状态,一旦建立了连接,就可以通过会话的connected属性获得已连接设备并且可以使用会话发送、接受数据。

import UIKit

import MultipeerConnectivity

// import GameKit

// GameKit不需要手动开启广播,它会在搜索控制器出现的时候自动互相广播搜索

let xmgSerType = "XMGsssss"

class ViewController: UIViewController {

let peerID : MCPeerID = MCPeerID(displayName: UIDevice.currentDevice().name)

lazy var session: MCSession = {

let session = MCSession(peer: self.peerID)

session.delegate = self

return session

}()

lazy var bvc: MCBrowserViewController = {

let bvc = MCBrowserViewController(serviceType: xmgSerType, session: self.session)

bvc.delegate = self

return bvc

}()

lazy var adv: MCAdvertiserAssistant = {

let info: [String: String] = ["title": "xmg117", "des": "summer is comming"]

let adv = MCAdvertiserAssistant(serviceType: xmgSerType, discoveryInfo: info, session: self.session)

return adv

}()

override func viewDidLoad() {

super.viewDidLoad()

// Do any additional setup after loading the view, typically from a nib.

// GKPeerPickerController()

//        session = MCSession(peer: self.peerID)

//        session?.delegate = self

}

@IBOutlet weak var searchBluetoothPeripheral: UIButton!

@IBAction func searchBP(sender: AnyObject) {

self.presentViewController(self.bvc, animated: true) {

//

print("modal MCB")

}

}

@IBAction func switchAdv(sender: UISwitch) {

if sender.on == true {

adv.start()

print("adv start")

}else

{

adv.stop()

print("adv stop")

}

}

}

// 当协议的扩展中存在没有实现的非optional协议方法的时候,它就会报错,此时你只需要实现他们即可

extension ViewController: MCBrowserViewControllerDelegate

{

func browserViewControllerDidFinish(browserViewController: MCBrowserViewController)

{

print("browserViewControllerDidFinish")

}

// Notifies delegate that the user taps the cancel button.

func browserViewControllerWasCancelled(browserViewController: MCBrowserViewController)

{

print("browserViewControllerWasCancelled")

browserViewController.dismissViewControllerAnimated(true) {

print("dismissS")

}

}

func browserViewController(browserViewController: MCBrowserViewController, shouldPresentNearbyPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) -> Bool {

//

print("browserViewController")

if peerID == self.peerID {

print("It's the peer which I wanted!\(info)")

return true

}

return true

}

}

extension ViewController: MCSessionDelegate

{

func session(session: MCSession, peer peerID: MCPeerID, didChangeState state: MCSessionState)

{

print("\(state)")

print(state)

switch state {

case MCSessionState.Connected: break

//

case .Connecting: break

//

case .NotConnected: break

//

default: break

//

}

}

// Received data from remote peer.

func session(session: MCSession, didReceiveData data: NSData, fromPeer peerID: MCPeerID)

{

}

// Received a byte stream from remote peer.

func session(session: MCSession, didReceiveStream stream: NSInputStream, withName streamName: String, fromPeer peerID: MCPeerID)

{

}

// Start receiving a resource from remote peer.

func session(session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, withProgress progress: NSProgress)

{

}

// Finished receiving a resource from remote peer and saved the content

// in a temporary location - the app is responsible for moving the file

// to a permanent location within its sandbox.

func session(session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, atURL localURL: NSURL, withError error: NSError?)

{

}

}

  • 在iOS7中,引入了一个全新的框架——Multipeer Connectivity(多点连接)。

  • 利用Multipeer Connectivity框架,即使在没有连接到WiFi(WLAN)或移动网络(xG)的情况下,距离较近的Apple设备(iMac/iPad/iPhone)之间可基于蓝牙和WiFi(P2P WiFi)技术进行发现和连接实现近场通信。

  • Multipeer Connectivity扩充的功能与利用AirDrop传输文件非常类似,可以将其看作AirDrop不能直接使用的补偿,代价是需要自己实现。

  • 手机不联网也能跟附近的人聊得火热的FireChatSee You Around等近场聊天App、近距离无网遥控交互拍照神器拍咯App就是基于Multipeer Connectivity框架实现。

  • 相比AirDrop,Multipeer Connectivity在进行发现和会话时并不要求同时打开WiFi和蓝牙,也不像AirDrop那样强制打开这两个开关,而是根据条件适时选择使用蓝牙或(和)WiFi。

  • 粗略测试情况如下:

    • 双方WiFi和蓝牙都未打开:无法发现。
    • 双方都开启蓝牙:通过蓝牙发现和传输。
    • 双方都开启WiFi:通过WiFi Direct发现和传输,速度接近AirDrop(Reliable速率稍低),不知道同一WLAN下是否优先走局域网?

    • 双方都同时开启了WiFi和蓝牙:应该是模拟AirDrop,通过低功耗蓝牙技术扫描发现握手,然后通过WiFi Direct传输。

常用类

  • MCPeerID

类似sockaddr,用于标识连接的两端endpoint,通常是昵称或设备名称

该对象只开放了displayName属性,私有MCPeerIDInternal对象持有的设备相关的_idString/_pid64字段并未公开。 在许多情况下,客户端同时广播并发现同一个服务,这将导致一些混乱,尤其是在client/server模式中。所以,每一个服务都应有一个类型标示符——serviceType,它是由ASCII字母、数字和“-”组成的短文本串,最多15个字符

  • MCNearbyServiceAdvertiser

类似broadcaster,可以接收,并处理用户请求连接的响应。但是,这个类会有回调,告知有用户要与您的设备连接,然后可以自定义提示框,以及自定义连接处理

主线程(com.apple.main-thread(serial))创建MCNearbyServiceAdvertiser并启动startAdvertisingPeer。 MCNearbyServiceAdvertiserDelegate异步回调(didReceiveInvitationFromPeer)切换回主线程。 在主线程didReceiveInvitationFromPeer中创建MCSession并invitationHandler(YES, session)接受会话连接请求(accept参数为YES)。

  • MCNearbyServiceBrowser

类似servo listen+client connect,用于搜索附近的用户,并可以对搜索到的用户发出邀请加入某个会话中。 主线程(com.apple.main-thread(serial))创建MCNearbyServiceBrowser并启动startBrowsingForPeers。 MCNearbyServiceBrowserDelegate异步回调(foundPeer/lostPeer)切换回主线程。 主线程创建MCSession并启动invitePeer。

  • MCSession

启用和管理Multipeer连接会话中的所有人之间的沟通。 通过Sesion,给别人发送数据 注意,peerID并不具备设备识别属性。 类似TCP链接中的socket。创建MCSession时,需指定自身MCPeerID,类似bind。 为避免频繁的会话数据通知阻塞主线程,MCSessionDelegate异步回调(didChangeState/didReceiveCertificate/didReceiveData/didReceiveStream)有一个专门的回调线程——com.apple.MCSession.callbackQueue(serial)。为避免阻塞MCSeesion回调线程,最好新建数据读(写)线程!

  • MCAdvertiserAssistant/MCBrowserViewController

MCAdvertiserAssistant //可以接收,并处理用户请求连接的响应。没有回调,会弹出默认的提示框,并处理连接。MCBrowserViewController 弹出搜索框,需要手动modal

MCAdvertiserAssistant为针对Advertiser封装的管理助手;MCBrowserViewController继承自UIViewController,提供了基本的UI应用框架。 MCBrowser/MCAdvertiser的回调线程一般是delegate所在线程Queue:com.apple.main-thread(serial)。

蓝牙框架之MultipeerConnectivity框架相关推荐

  1. [python] 3 、基于串口通信的嵌入式设备上位机自动测试程序框架(简陋框架)...

    星期一, 20. 八月 2018 01:53上午 - beautifulzzzz 1.前言 做类似zigbee.ble mesh...无线网络节点性能测试的时候,手动操作然后看表象往往很难找出真正的原 ...

  2. java集合框架容器 java框架层级 继承图结构 集合框架的抽象类 集合框架主要实现类...

    本文关键词: java集合框架  框架设计理念  容器 继承层级结构 继承图 集合框架中的抽象类  主要的实现类 实现类特性   集合框架分类 集合框架并发包 并发实现类 什么是容器? 由一个或多个确 ...

  3. Django之MVC框架与MTV框架详解

    Django框架简介 MVC框架和MTV框架(了解即可) MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图 ...

  4. 【Android 逆向】Frida 框架 ( Frida 框架使用环境 | Frida 框架作用 | Frida 框架模块 )

    文章目录 一.Frida 框架使用环境 二.Frida 框架作用 三.Frida 框架模块 一.Frida 框架使用环境 Frida 官网 : https://frida.re/ Frida 源码 : ...

  5. TF之AutoML之AdaNet框架:AdaNet框架的简介、特点、使用方法详细攻略

    TF之AutoML之AdaNet框架:AdaNet框架的简介.特点.使用方法详细攻略 目录 AdaNet框架的简介 AdaNet框架的特点 AdaNet框架的使用方法 AdaNet框架的简介 谷歌开源 ...

  6. TF之AutoML框架:AutoML框架的简介、特点、使用方法详细攻略

    TF之AutoML框架:AutoML框架的简介.特点.使用方法详细攻略 目录 AutoML框架的简介 AutoML框架的特点 AutoML框架的使用方法 AutoML VS AutoKeras 框架 ...

  7. DL框架之AutoKeras框架:深度学习框架AutoKeras框架的简介、特点、安装、使用方法详细攻略

    DL框架之AutoKeras框架:深度学习框架AutoKeras框架的简介.特点.安装.使用方法详细攻略 Paper:<Efficient Neural Architecture Search ...

  8. python的django框架与springboot_Django框架简介

    一.MVC框架和MTV框架 MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model).视图(View)和控制器(Cont ...

  9. html框架集把那根框架隐藏,HTML 框架集 frameset 和内嵌框架 iframe

    HTML 框架集 frameset 和内嵌框架 iframe 今天总结 和 < ifrme> 两个标签. frameset 标签用于定义一组框架集, 将多个窗口组合在一个框架集中, 各个子 ...

最新文章

  1. Iframe 用法浅析
  2. Java经典面试题(N人循环报M个数出列)实现
  3. HTML之iframe内联框架
  4. 逗号操作符以及(0,function)()
  5. WTM 构建DotNetCore开源生态,坐而论道不如起而行之
  6. C#EXCEL 操作类--C#DataToExcel帮助类
  7. ipv4转换ipv6工具_IPv4与IPv6的区别,不仅仅是地址变长而已
  8. 图神经网络(GNN)教程 – 用 PyTorch 和 PyTorch Geometric 实现 Graph Neural Networks
  9. python去重排序_python读取TXT到数组及列表去重后按原来顺序排序的方法
  10. Flash 3D引擎比较
  11. 动手深度学习 李沐 pytorch版本 基于Win10环境配置
  12. 验证码图片不显示解决问题
  13. 【sql】SQL3 查找当前薪水详情以及部门编号dept_no
  14. 内核相关资源 开源/文档/社区/信息资源 1 http://www.kernel.org Linux...
  15. python中path函数_示例1-path函数
  16. Auto property synthesis will not synthesizeproterty;it will be implemented by its superclass, use@dy
  17. 持NPDP证书在深圳可享受子女入学、医疗保健、安居保障等福利
  18. 遇到Process finished with exit code -1073740791 (0xC0000409)实在不能解决的时候要注意
  19. 参数化扫描——Comsol中的灵敏度分析功能
  20. Oracle AWR报告生成步骤

热门文章

  1. 人体姿态估计综述写的比较好的
  2. thinkpad R61e 加装 atheros 5424 无线网卡经验谈
  3. 2台window电脑如何传输文件
  4. flutter构建的漫画app
  5. ReactNative 屏幕锁定横屏
  6. Games104现代游戏引擎入门-lecture6游戏中的大气和云的渲染(下)
  7. JavaScript 对象初探--创建对象
  8. hdoj4857逃生
  9. [Cocos Creator] 定时器
  10. 1028-可乐(中南大学18年研究生复试机试题)