zoukankan      html  css  js  c++  java
  • iOS 蓝牙

    # 蓝牙
    ##GameKit
    ###简介:
    * 实现蓝牙设备之间的`通讯`
    * 只能使用在`iOS设备`之间`同一个应用`内连接
    * 从`iOS7`开始过期了
    * 但是GameKit是`最基本的`蓝牙通讯框架
    * 通过蓝牙可以实现文件的共享(仅限设备沙盒中的文件)
    * 此框架一般用于游戏开发(比如五子棋对战)
    
    ##开始案例
    ###简介:
    * 使用蓝牙将两个iOS设备连接起来
    * 搜索对方的设备
    * 实现将手机中的图片发送给对方
    
    ###界面的搭建:
    ###蓝牙互连:
    * 搜索蓝牙设备
    
    ```
        // 初始化链接蓝牙控制器
        GKPeerPickerController *peerCtr = [[GKPeerPickerController alloc]init];
        // 显示匹配到的蓝牙设备
        [peerCtr show];
    ```
    * `GKPeerPickerController`最重要的两个代理
    
    ```
    /**
     *  链接成功
     *
     *  @param picker  蓝牙控制器
     *  @param peerID  连接蓝牙的设备id
     *  @param session 连接蓝牙的会话(通讯)用来传数据
     */
    - (void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session
    {
        NSLog(@"%s %d",__func__,__LINE__);
        // 隐藏蓝牙控制器
        [picker dismiss];
    }
    
    // 退出连接
    - (void)peerPickerControllerDidCancel:(GKPeerPickerController *)picker
    {
        NSLog(@"%s %d",__func__,__LINE__);
    }
    ```
    
    ###选择图片:
    * 选择图片方法
    
    ```
    // 选择图片
    - (IBAction)chooseImage {
        // 1.初始化图片选择控制器
        UIImagePickerController *imgPicker = [[UIImagePickerController alloc]init];
        // 2.判断图库是否可用
        if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeSavedPhotosAlbum]) {
            // 3.设置图库打开的类型
            imgPicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
            // 4. 设置代理
            imgPicker.delegate = self;
            // 5. 打开图库
            [self presentViewController:imgPicker animated:YES completion:nil];
        }
    }
    ```
    
    * 选择图片控制器的代理方法
    
    ```
    /**
     *  图片选择完成调用
     *
     *  @param picker 图片选择控制器
     *  @param info   选择的信息
     */
    - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info
    {
        NSLog(@"info == %@",info);
        // 设置选择的图片为当前的显示图片
        self.showImageView.image = info[UIImagePickerControllerOriginalImage];
        // 隐藏当前选择图片控制器
        [picker dismissViewControllerAnimated:YES completion:nil];
    }
    ```
    
    ###图片相互发送:
    * 需要在连接成功代理方法中存储当前的会话
    
    ```
    // 保存当前回话
        self.m_Session = session;
    ```
    
    * 发送图片方法
    
    ```
    // 发送图片
    - (IBAction)sendImage {
        
        // 拿到需要发送出去的图片
        UIImage *image = self.showImageView.image;
        // 将图片转换成NSData类型
        NSData *imgData = UIImagePNGRepresentation(image);
        
        /**
         *  发送数据给所有匹配上的用户
         *
         *  @param GKSendDataMode 数据发送的模式:(安全/不安全模式)
         *                        GKSendDataUnreliable : 不安全模式:就像发10个传单,传单直接往人群中砸过去,能不能收到不管
         *                        GKSendDataReliable:安全模式:就像发10个传单,每一个传单都得发到路人的手上,才再发下一个传单
         *  @return
         */
        [self.m_Session sendDataToAllPeers:imgData withDataMode:GKSendDataUnreliable error:nil];
    }
    ```
    
    ###设置图片:
    * GameKit提供的接受数据是方法的回调
        * 需要监听接收传递过来的数据
            * 在连接成功代理方法中设置监听
            
        ```
        
            /** 监听传递过来的数据
             *  setDataReceiveHandler: 由哪个对象来监听数据的接受
             *  withContext : 监听需要传递的参数
             */
            [session setDataReceiveHandler:self withContext:nil];
        
        ```
            
        * 实现监听方法
            * 只设置由谁监听传递过来的数据还是不足的,因为我们还是不能拿到传递过来的数据,进入监听方法的头文件可以看到
                
            ```
                // SEL = -receiveData:fromPeer:inSession:context:
            ```
            * 所以我们必须实现这个方法才能拿到接收到的数据,这个回调方法方法在Xcode 7之前的版本的解释如图:
    ![](素材/回调方法.png)
    
    ```
    /**
     *  实现接收数据的回调方法
     *
     *  @param data    接收到的数据
     *  @param peer    传递数据的设备ID
     *  @param session 当前回话
     *  @param context 注册监听传递过来的数据
     */
    - (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context
    {
        // 因为传递过来的是图片,所以我们直接使用UIImage来接受
        UIImage *image = [UIImage imageWithData:data];
        // 设置图片
        self.showImageView.image = image;
    }
    
    ```
    ##CoreBlueTooth
    ###简介:
    * 可用于第三方蓝牙设备交互,设备必须支持蓝牙4.0
    * iPhone的设备必须是4S或者更新
    * iPad设备必须是iPad mini或者更新
    * iOS的系统必须是iOS 6或者更新
    * 蓝牙4.0以`低功耗`著称,所以一般被称为BLE(bluetooth low energy)
    * 使用模拟器调试
        - Xcode 4.6
        - iOS 6.1
    * 应用场景
        + 运动手环
        + 智能家居 
        + 拉卡拉蓝牙刷卡器
    
    ###核心概念
    * CBCentralManager:中心设备(用来连接到外部设备的管家)
    * CBPeripheralManager:外部设备(第三方的蓝牙4.0设备)
    
    ![](素材/BLE.jpeg)
    
    ###开发步骤
    * 建立中心管家
    
    ```
    // 1. 创建中心管家,并且设置代理
    self.cmgr = [[CBCentralManager alloc]initWithDelegate:self queue:nil];
    ```
    * 扫描外设(discover)
    
    ```
    // 2. 在代理方法中扫描外部设备
     /**
      *  scanForPeripheralsWithServices :如果传入指定的数组,那么就只会扫描数组中对应ID的设备
      *                                   如果传入nil,那么就是扫描所有可以发现的设备
      *  扫描完外部设备就会通知CBCentralManager的代理
      */
     - (void)centralManagerDidUpdateState:(CBCentralManager *)central
    {
        if ([central state] == CBCentralManagerStatePoweredOn) {
            [self.cmgr scanForPeripheralsWithServices:nil options:nil];
        }
    }
    ```
    
    ```
    /**
     *  发现外部设备,每发现一个就会调用这个方法
     *  所以可以使用一个数组来存储每次扫描完成的数组
     */
    - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI
    {
        // 有可能会导致重复添加扫描到的外设
        // 所以需要先判断数组中是否包含这个外设
        if(![self.peripherals containsObject:peripheral]){
            [self.peripherals addObject:peripheral];
        }
    }
    ```
    
    * 连接外设
    
    ```
    /**
     *  模拟开始连接方法
     */
    - (void)start
    {
        // 3. 连接外设
        for (CBPeripheral *ppl in self.peripherals) {
            // 扫描外设的服务
            // 这个操作应该交给外设的代理方法来做
            // 设置代理
            ppl.delegate = self;
            [self.cmgr connectPeripheral:ppl options:nil];
        }
    }
    ```
    
    * 扫描外设中的服务和特征
        - 服务和特征的关系
        
            `每个蓝牙4.0的设备都是通过服务和特征来展示自己的,一个设备必然包含一个或多个服务,每个服务下面又包含若干个特征。`
    
    ```
    /**
     *  连接外设成功调用
     */
    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
    {
        // 查找外设服务
        [peripheral discoverServices:nil];
    }
    ```
    
    ```
    /**
     *  发现服务就会调用代理方法
     *
     *  @param peripheral 外设
     */
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
    {
        // 扫描到设备的所有服务
        NSArray *services = peripheral.services;
        // 根据服务再次扫描每个服务对应的特征
        for (CBService *ses in services) {
            [peripheral discoverCharacteristics:nil forService:ses];
        }
    }
    ```
    
    
    * 与外设做数据交互
        - 在指定的特征下做相应的操作
    
    ```
    /**
     *  发现服务对应的特征
     */
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error
    {
        // 服务对应的特征
        NSArray *ctcs = service.characteristics;
        // 遍历所有的特征
        for (CBCharacteristic *character in ctcs) {
            // 根据特征的唯一标示过滤
            if ([character.UUID.UUIDString isEqualToString:@"XMG"]) {
                NSLog(@"可以吃饭了");
            }
        }
    }
    ```
    * 断开连接
    
    ```
    /**
     *  断开连接
     */
    - (void)stop
    {
        // 断开所有连接上的外设
        for (CBPeripheral *per in self.peripherals) {
            [self.cmgr cancelPeripheralConnection:per];
        }
    }
    ```
  • 相关阅读:
    JVM五大知识点
    VIM命令
    JVM之GC算法
    SpringMVC之搭建框
    Mybatis之延迟加载机制
    分页查询
    Mybatis之占位符与拼接符
    == 和 equal
    LAMBDA表达式常用 (全)
    Jquery 时间格式化
  • 原文地址:https://www.cnblogs.com/liujiaoxian/p/5008875.html
Copyright © 2011-2022 走看看