• 2.OC蓝牙功能


    一.  最早的蓝牙框架是GameKit,iOS7之前用的比较多,它有只能支持iOS设备间的传输,但是使用步骤简单,我们只需要搞清楚两个类就可以了。

    GKPeerPickerController:熟称浏览器,调用此控制器的show方法来显示当前的蓝牙热点,一旦发现有另一页在查找蓝牙的用户,之间就能实链接。

    GKSession:连接会话,主要用于发送和接受传输数据。档两个程序进行连接时,GKPeerPickerController的代理方法会将两者建立的会话(GKSession)对象传递给制定的对象。就能实现数据传输。

        下面构建一个简单简单的蓝牙发送

        1.1首先构建一个能显示区域的蓝牙控制器。

    - (void) connectToOtherBluetoolth {
        //1.首先构建一个区域内能显示其它蓝牙的控制器,我们手机上选择蓝牙列表其实对应的操作就是这个控制器,它可以对我的操作进行监听。
        GKPeerPickerController* peerVC = [GKPeerPickerController new];
        peerVC.delegate = self;
        [peerVC show];
    }
    

        1.2 通过这个现实控制器的代理方法来监听链接是否成功,如果成功就讲链接的管道保存下来,并为它设计一个句bin

    - (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的方法,可以简单的把它理解为类似于一个协议方法

    //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 接着我们只需要在链接成功后发送图片及可  创建图片控制器->设定代理,是否支持选择方式,制定图片的选择方式-》实现选择完成的方法,从字典内获取选择的图片

    - (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];
    }
    

      二. MutipeerConnectivity:

           字面意思多热点链接。这个事苹果研究出来的真对于GameKit的替代品。它不仅仅支持蓝牙连接。它属于一个局域网的痛惜狂减,屏蔽了具体的链接技术。 通过MultipeerConnectivity链接节点之间可使文件资源传递不依赖于网络。它的实现方式主要是通过adveristing和disconvering,类似于客户端和服务器端之间的交互响应。通过一个对象发送广播发送消息,而另一个对象作为客户接受消息。经过两者之间的同意认可后就实现了对接。通GameKit它门之间的链接也需要一个专门的管道MCSession。用于接收和传递数据。而管道的两端分别对应的是MCPeerID,及两台设备之间的标示。

          我们只需要设置会话对象的代理,并监听会话的状态(是否联机诶),是否有接收数据 。 其实这个和socket的套字节的用法差不多。  

          搞清楚了基本原理name我们就只需要熟悉下几个方法和关键单词就能熟练运动了。 

          2.1 设置基本的属性和控件。 

    @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(广播对象创建并启动)

    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控制器。 

    // 显示控制器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:@"
    Me:%@
    ",message];
        }else{
            finalMessage = [NSString stringWithFormat:@"
    %@:%@
    ",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 定义设备标示和名字;

    //蓝牙服务的唯一标识
    //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之后需要对用户是否同意定位进行判定

    - (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的代理方法选择性的实现当进入区域或者退出热点区域

    - (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的代理方法获取当前位置的所有热点对象

    - (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 开始监视热点,停止件事热点,停止检测热点,开始检测周围热点,开始广播,停止广播,

    //检测
    - (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]];
        }
    }
    
  • 相关阅读:
    jquery堆栈与队列
    类数组转成数组对象
    python基础教程总结8——特殊方法,属性,迭代器,生成器,八皇后问题
    python基础教程总结7——异常
    python基础教程总结6——类
    python基础教程总结5——函数
    python基础教程总结4—基本语句
    python——动态类型
    python基础教程总结3—字典
    python基础教程总结2——字符串
  • 原文地址:https://www.cnblogs.com/wwoo/p/5232665.html
Copyright © 2020-2023  润新知