2.OC蓝牙功能
一. 最早的蓝牙框架是GameKit,iOS7之前用的比较多,它有只能支持iOS设备间的传输,但是使用步骤简单,我们只需要搞清楚两个类就可以了。
GKPeerPickerController:熟称浏览器,调用此控制器的show方法来显示当前的蓝牙热点,一旦发现有另一页在查找蓝牙的用户,之间就能实链接。
GKSession:连接会话,主要用于发送和接受传输数据。档两个程序进行连接时,GKPeerPickerController的代理方法会将两者建立的会话(GKSession)对象传递给制定的对象。就能实现数据传输。
下面构建一个简单简单的蓝牙发送
1.1首先构建一个能显示区域的蓝牙控制器。
1 2 3 4 5 6 | - ( void ) connectToOtherBluetoolth { //1.首先构建一个区域内能显示其它蓝牙的控制器,我们手机上选择蓝牙列表其实对应的操作就是这个控制器,它可以对我的操作进行监听。 GKPeerPickerController * peerVC = [ GKPeerPickerController new ]; peerVC . delegate = self ; [ peerVC show ]; } |
1.2 通过这个现实控制器的代理方法来监听链接是否成功,如果成功就讲链接的管道保存下来,并为它设计一个句bin
1 2 3 4 5 6 | - ( void ) peerPickerController :( GKPeerPickerController *) picker didConnectPeer :( NSString *) peerID toSession :( GKSession *) session { //2. 通过实现GKPeerPickerController 的代理方法对链接成功后的消息进行处理;这里首先我们需要吧会话对象session保存下来,应为它就相当于一个传输的管道,功能和二维码扫描的管道差不多。 self . session = session ; //3. 此时我们还需要制定一个用哪个方法来接收数据。这个功能可以简单的理解为类似代理的功能,此处表示给session管道对象设置一个hander(句bin),这个句bin必须实现一个接收到数据的方法。 [ session setDataReceiveHandler : self withContext : nil ]; } |
1.3 实现这个句bin的方法,可以简单的把它理解为类似于一个协议方法
1 2 3 4 5 | //4. 使用self对象 实现句bin规定的方法 - ( void ) recevieData :( NSData *) data fromPeer :( NSString *) peer inSession :( GKSession *) session context :( void *) context { UIImage * image = [ UIImage imageWithData : data ]; self . imageView . image = image ; } |
1.4 接着我们只需要在链接成功后发送图片及可 创建图片控制器->设定代理,是否支持选择方式,制定图片的选择方式-》实现选择完成的方法,从字典内获取选择的图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | - ( void ) chooserImage { /*从相册选择图片的方法 创建一个图片选择控制器-》判断是否可以用-》设置打开图片库的类型-》处理完这个动作需要执行相关方法,所以此处需要设置图片控制器的代理 */ UIImagePickerController * imagePiker = [ UIImagePickerController new ]; if ([ UIImagePickerController isSourceTypeAvailable : UIImagePickerControllerSourceTypeSavedPhotosAlbum ]) { imagePiker . sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum ; imagePiker . delegate = self ; } } # pragma mark - UIImagePikerControllerDelegate - ( void ) imagePickerController :( UIImagePickerController *) picker didFinishPickingMediaWithInfo :( NSDictionary < NSString *, id > *) info { //此处为选择择完某一张图片后的方法,选中的图片可以从一个key中取出来。 self . imageView . image = info [ UIImagePickerControllerOriginalImage ]; //将弹出的控制器关闭。 [ picker dismissViewControllerAnimated : YES completion : nil ]; } // 3. 发送图片数据 -( void ) sendimage { //利用链接成功的session会话对象发送 UIImage * image = self . imageView . image ; NSData * data = UIImagePNGRepresentation ( image ); [ self . session sendData : data toPeers : nil withDataMode : GKSendDataReliable error : nil ]; } |
字面意思多热点链接。这个事苹果研究出来的真对于GameKit的替代品。它不仅仅支持蓝牙连接。它属于一个局域网的痛惜狂减,屏蔽了具体的链接技术。 通过MultipeerConnectivity链接节点之间可使文件资源传递不依赖于网络。它的实现方式主要是通过adveristing和disconvering,类似于客户端和服务器端之间的交互响应。通过一个对象发送广播发送消息,而另一个对象作为客户接受消息。经过两者之间的同意认可后就实现了对接。通GameKit它门之间的链接也需要一个专门的管道MCSession。用于接收和传递数据。而管道的两端分别对应的是MCPeerID,及两台设备之间的标示。
我们只需要设置会话对象的代理,并监听会话的状态(是否联机诶),是否有接收数据 。 其实这个和socket的套字节的用法差不多。
搞清楚了基本原理name我们就只需要熟悉下几个方法和关键单词就能熟练运动了。
2.1 设置基本的属性和控件。
1 2 3 4 5 6 7 8 9 10 11 12 13 | @ interface ViewController () < MCSessionDelegate , MCAdvertiserAssistantDelegate , MCBrowserViewControllerDelegate , UITextFieldDelegate > @ property ( weak , nonatomic ) IBOutlet UIButton * browserButton ; @ property ( weak , nonatomic ) IBOutlet UITextField * chatBox ; @ property ( weak , nonatomic ) IBOutlet UITextView * textBox ; // 设备id,用来表示发送广播和接受广播消息的设备标示信息 @ property ( strong , nonatomic ) MCPeerID * myPerrID ; // 连接会话,用于维持当前会话持续链接 @ property ( strong , nonatomic ) MCSession * mySession ; // 广播对象,创建后需要开启才会发送广播,它有两个协议方法,将要发送广播和已经发送广播 @ property ( strong , nonatomic ) MCAdvertiserAssistant * advertiserAssistant ; // 选择会话控制器,时机上就是选择蓝牙热点的列表,它可以监听我们选择的哪个热点 @ property ( strong , nonatomic ) MCBrowserViewController * browserViewController ; @ end |
2.2 设置MCPeerID,MCAdvertiserAssistant(广播对象创建并启动)
1 2 3 4 5 6 7 8 9 10 | static NSString * ServiceType = @ "chat" ; - ( void ) setupMutipeer { self . myPerrID = [[ MCPeerID alloc ] initWithDisplayName :[ UIDevice currentDevice ]. name ]; self . mySession = [[ MCSession alloc ] initWithPeer : self . myPerrID ]; self . advertiserAssistant = [[ MCAdvertiserAssistant alloc ] initWithServiceType : ServiceType discoveryInfo : nil session : self . mySession ]; self . browserViewController = [[ MCBrowserViewController alloc ] initWithServiceType : ServiceType session : self . mySession ]; self . browserViewController . delegate = self ; self . mySession . delegate = self ; [ self . advertiserAssistant start ]; } |
2.3 设置sessionde代理方法通道是否链接Ok,是否有接收到数据;设置MCBrowserViewController是否选择了蓝牙热点,并dissmiss控制器。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | // 显示控制器view - ( void ) showBroserVc { [ self presentViewController : self . browserViewController animated : YES completion : nil ]; } //取消控制器 - ( void ) dismissBrowserVc { [ self . browserViewController dismissViewControllerAnimated : YES completion : nil ]; } // 点击browser按钮 - ( IBAction ) browserBtnClick :( id ) sender { [ self showBroserVc ]; } // 发送文本 - ( void ) sendText { NSString * message = self . chatBox . text ; self . chatBox . text = @ "" ; NSData * data = [ message dataUsingEncoding : NSUTF8StringEncoding ]; // 通过会话发送 [ self . mySession sendData : data toPeers :[ self . mySession connectedPeers ] withMode : MCSessionSendDataReliable error : nil ]; // 收取数据 [ self reciveMessage : message fromPeer : self . myPerrID ]; } // 收取数据 - ( void ) reciveMessage :( NSString *) message fromPeer :( MCPeerID *) perrid { NSString * finalMessage = nil ; if ( perrid == self . myPerrID ) { finalMessage = [ NSString stringWithFormat :@ "\nMe:%@\n" , message ]; } else { finalMessage = [ NSString stringWithFormat :@ "\n%@:%@\n" , perrid . displayName , message ]; } self . textBox . text = [ self . textBox . text stringByAppendingString : finalMessage ]; } # pragma mark MCBroserControllerDelegate - ( void ) browserViewControllerDidFinish :( MCBrowserViewController *) browserViewController { [ self dismissBrowserVc ]; } - ( void ) browserViewControllerWasCancelled :( MCBrowserViewController *) browserViewController { [ self dismissBrowserVc ]; } # pragma mark 文本框的代理 - ( BOOL ) textFieldShouldReturn :( UITextField *) textField { [ textField resignFirstResponder ]; [ self sendText ]; return YES ; } // session 的代理方法监听是否接收到数据 - ( void ) session :( MCSession *) session didReceiveData :( NSData *) data fromPeer :( MCPeerID *) peerID { NSString * message = [[ NSString alloc ] initWithData : data encoding : NSUTF8StringEncoding ]; dispatch_async ( dispatch_get_main_queue (), ^{ [ self reciveMessage : message fromPeer : peerID ]; }); } //session 监听是否连接成功 - ( void ) session :( MCSession *) session peer :( MCPeerID *) peerID didChangeState :( MCSessionState ) state { |
三 . 目前最常用的一种CoreBluetoolth 核新蓝牙技术,也称为低功耗
无论是GameKit还是MultipeerConnectivity 都局限于苹果的手机上运行,非常的不方便。 CoreBluetooth.framework 基于BLE4.0标准,同时也能满足其它手机,目前使用非常广泛。运用在市场定义,室内定位,微支付,家具等领域。它的设计方式同样是机遇服务器和客户端的设计模式。 服务器端为外围设备Peripheral,客户端为Central.
下面以本地LocationManage定位为中央设备,外围热点为其它蓝牙设备来做相关说明
3.1 定义设备标示和名字;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | //蓝牙服务的唯一标识 //32位 8 - 4-4-4 - 12 # define kUUID @ "00000000-0000-0000-0000-000000000000" //当前蓝牙的标志 # define kIdentifier @ "SomeIdentifier" @ import CoreBluetooth ; @ import CoreLocation ; @ interface ViewController () < CLLocationManagerDelegate , CBPeripheralManagerDelegate > /** 向外广播的beacon */ @ property ( nonatomic , strong ) CBPeripheralManager * peripheralManager ; /** beacon的范围*/ @ property ( nonatomic , strong ) CLBeaconRegion * beaconRegion ; /** 定位管理 */ @ property ( nonatomic , strong ) CLLocationManager * locationManager ; @ end |
3.2 请求定位服务->需要注意iOS8.0之后需要对用户是否同意定位进行判定
1 2 3 4 5 6 7 8 9 10 11 12 13 | - ( CLLocationManager *) locationManager { if (! _locationManager ) { // iOS8之后,定位服务需要用户许可 _locationManager = [ CLLocationManager new ]; _locationManager . delegate = self ; //先判断是否有某个方法,如果有则执行.. if ([ _locationManager respondsToSelector :@ selector ( requestAlwaysAuthorization )]) { //请求授权操作,需要修改info.plist文件 [ _locationManager requestAlwaysAuthorization ]; } } return _locationManager ; } |
3.3 在LocationManage的代理方法选择性的实现当进入区域或者退出热点区域
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | - ( void ) locationManager :( CLLocationManager *) manager didExitRegion :( CLRegion *) region { NSLog (@ "didExitRegion 退出某个区域" ); } - ( void ) locationManager :( CLLocationManager *) manager didEnterRegion :( CLRegion *) region { NSLog (@ "didEnterRegion 进入某个区域" ); } - ( void ) locationManager :( CLLocationManager *) manager didDetermineState :( CLRegionState ) state forRegion :( CLRegion *) region { // 在里面,在外面,未知 NSLog (@ "状态的变更" ); } - ( void ) locationManager :( CLLocationManager *) manager didRangeBeacons :( NSArray < CLBeacon * > *) beacons inRegion :( CLBeaconRegion *) region { NSLog (@ "didRangeBeacons 获知beacon的距离 %@" , beacons ); for ( CLBeaconRegion * region in beacons ) { // 可以获取每个region 的 详细参数 // proximity这个枚举变量, 标志当前距离 // 远/近/特别近/找不到 // region.proximity } } |
3.4 使用LocaitonManager的代理方法获取当前位置的所有热点对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | - ( void ) locationManager :( CLLocationManager *) manager didRangeBeacons :( NSArray < CLBeacon * > *) beacons inRegion :( CLBeaconRegion *) region { NSLog (@ "didRangeBeacons 获知beacon的距离 %@" , beacons ); for ( CLBeaconRegion * region in beacons ) { // 可以获取每个region 的 详细参数 // proximity这个枚举变量, 标志当前距离 // 远/近/特别近/找不到 // region.proximity } } # pragma mark - beacon 类型 - ( CLBeaconRegion *) beaconRegion { if (! _beaconRegion ) { NSUUID * proximityUUID =[[ NSUUID alloc ] initWithUUIDString : kUUID ]; _beaconRegion = [[ CLBeaconRegion alloc ] initWithProximityUUID : proximityUUID identifier : kIdentifier ]; } return _beaconRegion ; } |
3.5 开始监视热点,停止件事热点,停止检测热点,开始检测周围热点,开始广播,停止广播,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | //检测 - ( IBAction ) monterning :( UISegmentedControl *) sender { if ( sender . selectedSegmentIndex == 0 ) { [ self . locationManager stopMonitoringForRegion : self . beaconRegion ]; } else { [ self . locationManager startMonitoringForRegion : self . beaconRegion ]; } } //定位, Ranging 范围 - ( IBAction ) location :( UISegmentedControl *) sender { if ( sender . selectedSegmentIndex == 0 ) { [ self . locationManager stopRangingBeaconsInRegion : self . beaconRegion ]; } else { [ self . locationManager startRangingBeaconsInRegion : self . beaconRegion ]; } } //广播 - ( IBAction ) advertise :( UISegmentedControl *) sender { if ( sender . selectedSegmentIndex == 0 ) { [ _peripheralManager stopAdvertising ]; } else { _peripheralManager =[[ CBPeripheralManager alloc ] initWithDelegate : self queue : nil options : nil ]; } } //当广播状态更新时触发 - ( void ) peripheralManagerDidUpdateState :( CBPeripheralManager *) peripheral { // 如果广播状态为 开启 if ( peripheral . state == CBPeripheralManagerStatePoweredOn ) { CLBeaconRegion * region =[[ CLBeaconRegion alloc ] initWithProximityUUID : self . beaconRegion . proximityUUID major : rand () minor : rand () identifier : kIdentifier ]; [ _peripheralManager startAdvertising :[ region peripheralDataWithMeasuredPower : nil ]]; } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 智能桌面机器人:用.NET IoT库控制舵机并多方法播放表情
· Linux glibc自带哈希表的用例及性能测试
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 手把手教你在本地部署DeepSeek R1,搭建web-ui ,建议收藏!
· 新年开篇:在本地部署DeepSeek大模型实现联网增强的AI应用
· Janus Pro:DeepSeek 开源革新,多模态 AI 的未来
· 互联网不景气了那就玩玩嵌入式吧,用纯.NET开发并制作一个智能桌面机器人(三):用.NET IoT库
· 【非技术】说说2024年我都干了些啥