data蓝牙 swift_swift 图片转data data转图片 - CSDN
  • Swift蓝牙开发详解及示例

    千次阅读 2018-11-16 12:11:40
    Swift 蓝牙使用详解蓝牙使用iOS 蓝牙简介具体使用步骤代码拆解实现其他相关优化 蓝牙使用 距离上次博客更新已经过去了好几个月 这段时间一直在忙公司项目的重构和整体UI重做 一直抽不出时间来对做的东西做一个归纳和...

    蓝牙使用

    距离上次博客更新已经过去了好几个月 这段时间一直在忙公司项目的重构和整体UI重做 一直抽不出时间来对做的东西做一个归纳和整理 前几天项目成功上线了 现在对这段时间项目重构中遇到的问题和使用的技术做一些简单的整理 首先介绍项目中用的的占比较重的东西 蓝牙的使用及蓝牙交互逻辑的优化

    iOS 蓝牙简介

    1. 蓝牙模式简介
      蓝牙开发分为两种模式,中心模式(central),和外设模式(peripheral)。一般来讲,我们需要在软件内连接硬件,通过连接硬件给硬件发送指令以完成一些动作的蓝牙开发都是基于中心模式(central)模式的开发,也就是说我们开发的app是中心,我们要连接的硬件是外设。如果需要其他设备连接手机蓝牙,并对手机进行一些操作,那就是基于外设模式(peripheral)的开发。 本次我们主要介绍的就是中心模式的蓝牙开发
    2. 设备简介
      • 中心设备(CBCentralManager):iOS系统的手机等设备
      • 外围设备(CBPeripheral):手环等第三方设备
    3. 蓝牙数据传输简介
      将外围设备(车辆)的数据传送给中心设备(手机)时, 数据是经过两层包装的
      第一层是 Service(服务) , 可以是一个或多个, 比如车辆数据(服务)
      第二层是 Characteristic(特征) , 他提供了更多关于Service(服务)的数据, 例如车辆数据(服务)中包含了两个数据, 分别是里程数据和续航数据, 这两个就是车辆数据(服务)的具体数据(特征)
    4. 具体操作简介
      读(read) , 写(write) , 订阅(notify)
      我们的目的是读取设备中的数据(read) , 或者给设备写入一定的数据(write)。有时候我们还想设备的数据变化的时候不需要我们手动去读取这个值,需要设备自动通知我们它的值变化了,值是多少。把值告诉app,这个时候就需要订阅这个特征了(notify)

    具体使用步骤

    • 数据读写步骤
      • 创建中心设备(CBCentralManager)
      • 中心设备开始扫描(scanForPeripherals)
      • 扫描到外围设备之后, 自动调用中心设备的代理方法(didDiscoverPeripheral)
      • 如果设备过多, 可以将扫描到的外围设备添加到数组
      • 开始连接, 从数组中过滤出自己想要的设备, 进行连接(connectPeripheral)
      • 连接上之后, 自动调用中心设备的代理方法(didConnectPeripheral), 在代理中, 进行查找外围设备的服务(peripheral.discoverServices)
      • 查找到服务之后, 自动调用外围设备的代理(didDiscoverServices), 可通过UUID,查找具体的服务,查找服务(discoverCharacteristics)
      • 查找到特征之后, 自动调用外围设备的代理(didDiscoverCharacteristics), 通过UUID找到自己想要的特征, 读取特征(readValueForCharacteristic)
      • 读取到特征之后, 自动调用外设的代理方法(didUpdateValueForCharacteristic),在这里打印或者解析自己想要的特征值.

    代码拆解实现

    //创建中心设备(CBCentralManager)
    import Foundation
    import CoreBluetooth
    
    //用于看发送数据是否成功!
    class LLBlueTooth:NSObject {
        //单例对象
        internal static let instance = LLBlueTooth()
        //中心对象
        var central : CBCentralManager?
        //中心扫描到的设备都可以保存起来,
        //扫描到新设备后可以通过通知的方式发送出去,连接设备界面可以接收通知,实时刷新设备列表
        var deviceList: NSMutableArray?
        // 当前连接的设备
        var peripheral:CBPeripheral!
        //发送数据特征(连接到设备之后可以把需要用到的特征保存起来,方便使用)
        var sendCharacteristic:CBCharacteristic?
        override init() {
            super.init()
            self.central = CBCentralManager.init(delegate:self, queue:nil, options:[CBCentralManagerOptionShowPowerAlertKey:false])
            self.deviceList = NSMutableArray()
        }
    	// MARK: 扫描设备的方法
        func scanForPeripheralsWithServices(_ serviceUUIDS:[CBUUID]?, options:[String: AnyObject]?){
           self.central?.scanForPeripherals(withServices: serviceUUIDS, options: options)
        }
    	// MARK: 停止扫描
        func stopScan() {
            self.central?.stopScan()
        }
        // MARK: 写数据
        func writeToPeripheral(_ data: Data) {
            peripheral.writeValue(data , for: sendCharacteristic!, type: CBCharacteristicWriteType.withResponse)
        }   
        // MARK: 连接某个设备的方法
        /*
         *  设备有几个状态
         @available(iOS 7.0, *)
         public enum CBPeripheralState : Int {
             case disconnected
             case connecting
             case connected
             @available(iOS 9.0, *)
             case disconnecting
         }
         */
        func requestConnectPeripheral(_ model:CBPeripheral) {
            if (model.state != CBPeripheralState.connected) {
                central?.connect(model , options: nil)
            }
        }
    }
    //MARK: -- 中心管理器的代理
    extension LLBlueTooth : CBCentralManagerDelegate{
        // MARK: 检查运行这个App的设备是不是支持BLE。
        func centralManagerDidUpdateState(_ central: CBCentralManager){
            if #available(iOS 10.0, *) {
                switch central.state {
                case CBManagerState.poweredOn:
                    print("蓝牙打开")
                case CBManagerState.unauthorized:
                    print("没有蓝牙功能")
                case CBManagerState.poweredOff:
                    print("蓝牙关闭")
                default:
                    print("未知状态")
                }
            }
            // 手机蓝牙状态发生变化,可以发送通知出去。提示用户
        }
        // 开始扫描之后会扫描到蓝牙设备,扫描到之后走到这个代理方法
        // MARK: 中心管理器扫描到了设备
        func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
            //  因为iOS目前不提供蓝牙设备的UUID的获取,所以在这里通过蓝牙名称判断是否是本公司的设备
            guard peripheral.name != nil , peripheral.name!.contains("蓝牙名称") else {
                return
            }
        }
        // MARK: 连接外设成功,开始发现服务
        func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral){
            // 设置代理
            peripheral.delegate = self
            // 开始发现服务
            peripheral.discoverServices(nil)
            // 保存当前连接设备
            self.peripheral = peripheral
            // 这里可以发通知出去告诉设备连接界面连接成功
        }
        // MARK: 连接外设失败
        func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
            // 这里可以发通知出去告诉设备连接界面连接失败
               }
        // MARK: 连接丢失
        func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
            NotificationCenter.default.post(name: Notification.Name(rawValue: "DidDisConnectPeriphernalNotification"), object: nil, userInfo: ["deviceList": self.deviceList as AnyObject])
            // 这里可以发通知出去告诉设备连接界面连接丢失
        }
    }
    // 外设的代理
    extension LLBlueTooth : CBPeripheralDelegate {
        //MARK: - 匹配对应服务UUID
        func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?){
            if error != nil {
                return
            }
            for service in peripheral.services! {
    peripheral.discoverCharacteristics(nil, for: service )
            }
        }
        //MARK: - 服务下的特征
        func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?){
            if (error != nil){
                return
            }
            for  characteristic in service.characteristics! {
    
                switch characteristic.uuid.description {
    
                case "具体特征值":
                    // 订阅特征值,订阅成功后后续所有的值变化都会自动通知
                    peripheral.setNotifyValue(true, for: characteristic)
                case "******":
                    // 读区特征值,只能读到一次
    peripheral.readValue(for:characteristic)
                default:
                    print("扫描到其他特征")
                }
            }
        }
        //MARK: - 特征的订阅状体发生变化
        func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?){
            guard error == nil  else {
                return
            }
        }
        // MARK: - 获取外设发来的数据
        // 注意,所有的,不管是 read , notify 的特征的值都是在这里读取
        func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?)-> (){
            if(error != nil){
                return
            }
            switch characteristic.uuid.uuidString {
            case "***************":
                print("接收到了设备的温度特征的值的变化")
            default:
                print("收到了其他数据特征数据: \(characteristic.uuid.uuidString)")
            }
        }
        //MARK: - 检测中心向外设写数据是否成功
        func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
            if(error != nil){
                print("发送数据失败!error信息:\(String(describing: error))")
            }
        }
    }
    //MARK: - 以上就是蓝牙模块的具体代码  在这里可以使用一些已有封装的第三方蓝牙框架  只要按步骤做就可以
    

    其他相关优化

    • 安全相关
      因为蓝牙的操作可能会涉及到设备的安全性问题,所以在安全方面需要考量一下,在这里我提供一些我在安全方面所做的具体措施
      • 在连接到蓝牙设备以后,先与蓝牙设备及服务端做一次三方的安全验证,使用一些加密算法,保证当前是自己的APP对自己设备下发的蓝牙指令
      • 在所有的蓝牙操作指令中增加时间戳安全判断,可以跟硬件工程师商讨具体设置的安全超时时长,时间超过预留时间的,不做响应
      • 在一些涉及到设备和财产安全的蓝牙操作上,可以加一些与服务端的实时安全校验,保证当前蓝牙指令的安全性
    • 性能相关
      • 因为受蓝牙信号强度限制,蓝牙操作的灵敏度和响应时间会存在一定问题,所以要求硬件工程师对蓝牙设备的型号强度进行定制
      • 在进行蓝牙设备搜索连接时,iOS没有自带的超时设置,如果不手动停止的话,会不停地进行设备搜索,影响设备性能,所以建议设置一个超时时长,进行一段时间的搜索以后停止对设备的搜索,并提示用户进行重试
    展开全文
  • swift data 转byte

    千次阅读 2019-03-04 16:59:39
    var bytes = [UInt8](data2) let pointer: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer(&bytes)

    var bytes = [UInt8](data2)

    let pointer: UnsafeMutablePointer<UInt8> = UnsafeMutablePointer(&bytes)

     

    展开全文
  • iOS 蓝牙开发 1.蓝牙简介2. 蓝牙连接2.1 CoreBluetooth框架2.2 外设、服务、特征间的关系2.3 蓝牙连接过程2.4 蓝牙中心模式,外设模式2.5 蓝牙设备状态 1.蓝牙简介 蓝牙模式简介 蓝牙开发分为两种模式,中心模式...

    1.蓝牙简介

    • 蓝牙模式简介
      蓝牙开发分为两种模式,中心模式(central),和外设模式(peripheral)。一般来讲,我们需要在软件内连接硬件,通过连接硬件给硬件发送指令以完成一些动作的蓝牙开发都是基于中心模式(central)模式的开发,也就是说我们开发的app是中心,我们要连接的硬件是外设。如果需要其他设备连接手机蓝牙,并对手机进行一些操作,那就是基于外设模式(peripheral)的开发。 本次我们主要介绍的就是中心模式的蓝牙开发

    • 设备简介
      中心设备(CBCentralManager):iOS系统的手机等设备
      外围设备(CBPeripheral):手环等第三方设备

    • 蓝牙数据传输简介
      将外围设备(车辆)的数据传送给中心设备(手机)时, 数据是经过两层包装的
      第一层是 Service(服务) , 可以是一个或多个, 比如车辆数据(服务)
      第二层是 Characteristic(特征) , 他提供了更多关于Service(服务)的数据, 例如车辆数据(服务)中包含了两个数据, 分别是里程数据和续航数据, 这两个就是车辆数据(服务)的具体数据(特征)

    • 具体操作简介
      读(read) , 写(write) , 订阅(notify)
      我们的目的是读取设备中的数据(read) , 或者给设备写入一定的数据(write)。有时候我们还想设备的数据变化的时候不需要我们手动去读取这个值,需要设备自动通知我们它的值变化了,值是多少。把值告诉app,这个时候就需要订阅这个特征了(notify)

    • 其他相关概念

    1. 目前都使用的是低功耗蓝牙4.0,蓝牙外设必需为4.0及以上(2.0需要MFI认证),否则无法开发,蓝牙4.0设施由于低耗电,所以也叫做BLE。
    2. CoreBluetooth框架的核心其实是两个东西,peripheral和central, 能了解成外设和中心,就是你的苹果手机就是中心,外部蓝牙称为外设。
    3. 服务和特征(service characteristic):简而言之,外部蓝牙中它有若干个服务service(服务你能了解为蓝牙所拥有的可以力),而每个服务service下拥有若干个特征characteristic(特征你能了解为解释这个服务的属性)。
    4. Descriptor(形容)使用来形容characteristic变量的属性。例如,一个descriptor能规定一个可读的形容,或者者一个characteristic变量可接受的范围,或者者一个characteristic变量特定的单位。
    5. 我们用的蓝牙板块是在淘宝买的, 大概十多元一个, ios大概每次能接受90个字节, 安卓大概每次能接收20个字节, 具体数字可可以会浮动, 应该是与蓝牙板块有关。

    2. 蓝牙连接

    自己实践的两个蓝牙demo:

    1. OC 编写的:Bluetooth4_configWifi
    2. swifit编写的:KYLBluetoothDemo_swift

    2.1 CoreBluetooth框架

    CoreBluetooth框架的核心其实是两个东西,peripheral和central, 可以理解成外设和中心。对应他们分别有一组相关的API和类

    在这里插入图片描述

    • 这两组api分别对应不同的业务场景,左侧叫做中心模式,就是以你的app作为中心,连接其他的外设的场景,而右侧称为外设模式,使用手机作为外设别其他中心设备操作的场景。
    • 服务和特征,特征的属性(service and characteristic):
      每个设备都会有一些服务,每个服务里面都会有一些特征,特征就是具体键值对,提供数据的地方。每个特征属性分为这么几种:读,写,通知这么几种方式。
    //objcetive c特征的定义枚举
    typedef NS_OPTIONS(NSUInteger, CBCharacteristicProperties) {
        CBCharacteristicPropertyBroadcast                                               = 0x01,
        CBCharacteristicPropertyRead                                                    = 0x02,
        CBCharacteristicPropertyWriteWithoutResponse                                    = 0x04,
        CBCharacteristicPropertyWrite                                                   = 0x08,
        CBCharacteristicPropertyNotify                                                  = 0x10,
        CBCharacteristicPropertyIndicate                                                = 0x20,
        CBCharacteristicPropertyAuthenticatedSignedWrites                               = 0x40,
        CBCharacteristicPropertyExtendedProperties                                      = 0x80,
        CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)     = 0x100,
        CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(NA, 6_0)   = 0x200
    };
    

    2.2 外设、服务、特征间的关系

    在这里插入图片描述

    在这里插入图片描述

    2.3 蓝牙连接过程

    1. 创建中心设备(CBCentralManager)
    2. 中心设备开始扫描(scanForPeripherals)
    3. 扫描到外围设备之后, 自动调用中心设备的代理方法(didDiscoverPeripheral)
    4. 如果设备过多, 可以将扫描到的外围设备添加到数组
    5. 开始连接, 从数组中过滤出自己想要的设备, 进行连接(connectPeripheral)
    6. 连接上之后, 自动调用中心设备的代理方法(didConnectPeripheral), 在代理中, 进行查找外围设备的服务(peripheral.discoverServices)
    7. 查找到服务之后, 自动调用外围设备的代理(didDiscoverServices), 可通过UUID,查找具体的服务,查找服务(discoverCharacteristics)
    8. 查找到特征之后, 自动调用外围设备的代理(didDiscoverCharacteristics), 通过UUID找到自己想要的特征, 读取特征(readValueForCharacteristic)
    9. 读取到特征之后, 自动调用外设的代理方法(didUpdateValueForCharacteristic),在这里打印或者解析自己想要的特征值.

    2.4 蓝牙中心模式,外设模式

    2.4.1 蓝牙中心模式

    • 中心模式流程
    1. 建立中心角色

    2. 扫描外设(discover)

    3. 连接外设(connect)

    4. 扫描外设中的服务和特征(discover)
      4.1 获取外设的services
      4.2 获取外设的Characteristics,获取Characteristics的值,获取Characteristics的 Descriptor和Descriptor的值

    5. 与外设做数据交互(explore and interact)

    6. 订阅Characteristic的通知

    7. 断开连接(disconnect)

    2.4.2 蓝牙外设模式

    • 蓝牙外设模式流程
    1. 启动一个Peripheral管理对象

    2. 本地Peripheral设置服务,特性,描述,权限等等

    3. Peripheral发送广告

    4. 设置处理订阅、取消订阅、读characteristic、写characteristic的委托方法

    2.5 蓝牙设备状态

    • 蓝牙设备状态
      待机状态(standby):设备没有传输和发送数据,并且没有连接到任何设
      广播状态(Advertiser):周期性广播状态
      扫描状态(Scanner):主动寻找正在广播的设备
      发起链接状态(Initiator):主动向扫描设备发起连接。
      主设备(Master):作为主设备连接到其他设备。
      从设备(Slave):作为从设备连接到其他设备。

    • 蓝牙设备的五种工作状态
      准备(standby)
      广播(advertising)
      监听扫描(Scanning
      发起连接(Initiating)
      已连接(Connected)

    2.6 蓝牙连接代码实现

    1. 初始化
    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
    
    1. 搜索扫描外围设备
    /**
     *  --  初始化成功自动调用
     *  --  必须实现的代理,用来返回创建的centralManager的状态。
     *  --  注意:必须确认当前是CBCentralManagerStatePoweredOn状态才可以调用扫描外设的方法:
     scanForPeripheralsWithServices
     */
    - (void)centralManagerDidUpdateState:(CBCentralManager *)central{
        switch (central.state) {
            case CBCentralManagerStateUnknown:
                NSLog(@">>>CBCentralManagerStateUnknown");
                break;
            case CBCentralManagerStateResetting:
                NSLog(@">>>CBCentralManagerStateResetting");
                break;
            case CBCentralManagerStateUnsupported:
                NSLog(@">>>CBCentralManagerStateUnsupported");
                break;
            case CBCentralManagerStateUnauthorized:
                NSLog(@">>>CBCentralManagerStateUnauthorized");
                break;
            case CBCentralManagerStatePoweredOff:
                NSLog(@">>>CBCentralManagerStatePoweredOff");
                break;
            case CBCentralManagerStatePoweredOn:
            {
                NSLog(@">>>CBCentralManagerStatePoweredOn");
                // 开始扫描周围的外设。
                /*
                 -- 两个参数为Nil表示默认扫描所有可见蓝牙设备。
                 -- 注意:第一个参数是用来扫描有指定服务的外设。然后有些外设的服务是相同的,比如都有FFF5服务,那么都会发现;而有些外设的服务是不可见的,就会扫描不到设备。
                 -- 成功扫描到外设后调用didDiscoverPeripheral
                 */
                [self.centralManager scanForPeripheralsWithServices:nil options:nil];
            }
                break;
            default:
                break;
        }
    }
    
    #pragma mark 发现外设
    - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary*)advertisementData RSSI:(NSNumber *)RSSI{
        NSLog(@"Find device:%@", [peripheral name]);
        if (![_deviceDic objectForKey:[peripheral name]]) {
            NSLog(@"Find device:%@", [peripheral name]);
            if (peripheral!=nil) {
                if ([peripheral name]!=nil) {
                    if ([[peripheral name] hasPrefix:@"根据设备名过滤"]) {
                        [_deviceDic setObject:peripheral forKey:[peripheral name]];
                         // 停止扫描, 看需求决定要不要加
    //                    [_centralManager stopScan];
                        // 将设备信息传到外面的页面(VC), 构成扫描到的设备列表
                        if ([self.delegate respondsToSelector:@selector(dataWithBluetoothDic:)]) {
                            [self.delegate dataWithBluetoothDic:_deviceDic];
                        }
                    }
                }
            }
        }
    }
    
    
    1. 连接外围设备
    // 连接设备(.h中声明出去的接口, 一般在点击设备列表连接时调用)
    - (void)connectDeviceWithPeripheral:(CBPeripheral *)peripheral
    {
        [self.centralManager connectPeripheral:peripheral options:nil];
    }
    
    
    
    #pragma mark 连接外设--成功
    - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
        //连接成功后停止扫描,节省内存
        [central stopScan];
        peripheral.delegate = self;
        self.peripheral = peripheral;
        //4.扫描外设的服务
        /**
         --     外设的服务、特征、描述等方法是CBPeripheralDelegate的内容,所以要先设置代理peripheral.delegate = self
         --     参数表示你关心的服务的UUID,比如我关心的是"FFE0",参数就可以为@[[CBUUID UUIDWithString:@"FFE0"]].那么didDiscoverServices方法回调内容就只有这两个UUID的服务,不会有其他多余的内容,提高效率。nil表示扫描所有服务
         --     成功发现服务,回调didDiscoverServices
         */
        [peripheral discoverServices:@[[CBUUID UUIDWithString:@"你要用的服务UUID"]]];
        if ([self.delegate respondsToSelector:@selector(didConnectBle)]) {
           // 已经连接
            [self.delegate didConnectBle];
        }
    }
    
    
    
    #pragma mark 连接外设——失败
    - (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
        NSLog(@"%@", error);
    }
    
    
    #pragma mark 取消与外设的连接回调
    - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
        NSLog(@"%@", peripheral);
    }
    
    
    1. 获得外围设备的服务
    #pragma mark 发现服务回调
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
     
        //NSLog(@"didDiscoverServices,Error:%@",error);
        CBService * __nullable findService = nil;
        // 遍历服务
        for (CBService *service in peripheral.services)
        {
            //NSLog(@"UUID:%@",service.UUID);
            if ([[service UUID] isEqual:[CBUUID UUIDWithString:@"你要用的服务UUID"]])
            {
                findService = service;
            }
        }
        NSLog(@"Find Service:%@",findService);
        if (findService)
            [peripheral discoverCharacteristics:NULL forService:findService];
    }
    
    
    #pragma mark 发现特征回调
    /**
     --  发现特征后,可以根据特征的properties进行:读readValueForCharacteristic、写writeValue、订阅通知setNotifyValue、扫描特征的描述discoverDescriptorsForCharacteristic。
     **/
    - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
        for (CBCharacteristic *characteristic in service.characteristics) {
            if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:@"你要用的特征UUID"]]) {
     
                /**
                 -- 读取成功回调didUpdateValueForCharacteristic
                 */
                self.characteristic = characteristic;
                // 接收一次(是读一次信息还是数据经常变实时接收视情况而定, 再决定使用哪个)
    //            [peripheral readValueForCharacteristic:characteristic];
                // 订阅, 实时接收
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
     
                // 发送下行指令(发送一条)
                NSData *data = [@"硬件工程师给我的指令, 发送给蓝牙该指令, 蓝牙会给我返回一条数据" dataUsingEncoding:NSUTF8StringEncoding];
                // 将指令写入蓝牙
                    [self.peripheral writeValue:data forCharacteristic:characteristic type:CBCharacteristicWriteWithResponse];
            }
            /**
             -- 当发现characteristic有descriptor,回调didDiscoverDescriptorsForCharacteristic
             */
            [peripheral discoverDescriptorsForCharacteristic:characteristic];
        }
    }
    
    
    
    1. 从外围设备读取数据
    #pragma mark - 获取值
    - (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
        // characteristic.value就是蓝牙给我们的值(我这里是json格式字符串)
        NSData *jsonData = [characteristic.value dataUsingEncoding:NSUTF8StringEncoding];
            NSDictionary *dataDic = [NSJSONSerialization JSONObjectWithData:jsonData options:NSJSONReadingMutableContainers error:nil];
        // 将字典传出去就可以使用了
    }
    
    
    #pragma mark - 中心读取外设实时数据
    - (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
        if (characteristic.isNotifying) {
            [peripheral readValueForCharacteristic:characteristic];
        } else { 
            NSLog(@"Notification stopped on %@.  Disconnecting", characteristic);
            NSLog(@"%@", characteristic);
            [self.centralManager cancelPeripheralConnection:peripheral];
        }
    }
    
    
    1. 给外围设备发送(写入)数据
    
    // 上文中发现特征之后, 发送下行指令的时候其实就是向蓝牙中写入数据
    // 例:
    // 发送检查蓝牙命令
    - (void)writeCheckBleWithBle
    {
        _style = 1;
        // 发送下行指令(发送一条)
        NSData *data = [@"硬件工程师提供给你的指令, 类似于5E16010203...这种很长一串" dataUsingEncoding:NSUTF8StringEncoding];
        [self.peripheral writeValue:data forCharacteristic:self.characteristic type:CBCharacteristicWriteWithResponse];
    }
    
    
    
    #pragma mark 数据写入成功回调
    - (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
        NSLog(@"写入成功");
        if ([self.delegate respondsToSelector:@selector(didWriteSucessWithStyle:)]) {
            [self.delegate didWriteSucessWithStyle:_style];
        }
    }
    
    
    1. 停止扫描
    
    #pragma mark 停止扫描外设
    - (void)stopScanPeripheral{
        [self.centralManager stopScan];
    }
    
    
    #pragma mark 扫描外设
    - (void)scanDevice
    {
        if (_centralManager == nil) {
        self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
        [_deviceDic removeAllObjects];
         }
    }
    
    
    1. 断开连接
    #pragma mark 断开连接
    - (void)disConnectPeripheral{
        /**
         -- 断开连接后回调didDisconnectPeripheral
         -- 注意断开后如果要重新扫描这个外设,需要重新调用[self.centralManager scanForPeripheralsWithServices:nil options:nil];
         */
        [self.centralManager cancelPeripheralConnection:self.peripheral];
    }
    
    
    展开全文
  • 引言 蓝牙是设备近距离通信的一种方便手段,在App引入蓝牙4.0后,设备之间的通讯变得更加简单。通过蓝牙进行通讯交互...Swift项目中简单快速的集成iOS蓝牙模块,对蓝牙的操作封装了一个蓝牙管理类。(EasyBleMana...

    引言

    此篇为实践篇,理论篇请见App蓝牙通讯技术

    背景

    Swift项目中简单快速的集成iOS蓝牙模块,对蓝牙的操作封装了一个蓝牙管理类。(EasyBleManager)

    功能如下

    • 同步获取蓝牙状态,使用更加的灵活和便捷
    • 扫描设备和连接设备
    • 可配置指定的设备名称、设备可被发现的Service
    • 扫描和连接超时设置
    • 添加设备准备就绪状态,设备连接成功后,并不能直接读写操作,要等设备准备就绪后,就随时可以读写操作
    • 方便简单的读写操作
    • 开启和关闭调试日志

    具体用法

    配置需要操作的特性uuid

    let DeviceVersion = "XXXX"
    let DeviceMode = "XXXX"
    

    检查蓝牙是否可用

    if EasyBleManager.shareInstance.isBleEnable {
        print("蓝牙可用")
    } else {
        print("蓝牙不可用")
    }
    
    

    获取连接上的设备

    let connectedDevice = EasyBleManager.shareInstance.connectedDevice()
    

    系统蓝牙状态变化时回调

    EasyBleManager.shareInstance.bleStateChangeBlock = {(state) in
        print("蓝牙状态:\(state)")
    }
    

    开启调试日志信息

    EasyBleConfig.enableLog = true //默认未启动调试日志
    

    配置可扫描到的设备名称/设备可被发现的Service

     EasyBleConfig.acceptableDeviceNames = ["XXXX"] //默认接受所有设备
     EasyBleConfig.acceptableDeviceServiceUUIDs = ["XXXX"] //默认发现设备所有的Service
    

    扫描超时回调

    EasyBleManager.shareInstance.bleScanTimeoutBlock = {
        print("扫描超时")
    }
    

    连接超时回调

    EasyBleManager.shareInstance.bleConnectTimeoutBlock = {
        print("连接超时")
    }
    

    扫描成功回调

    EasyBleManager.shareInstance.bleScanSuccessBlock = {(_) in
        print("扫描设备成功")
    }
    

    设备连接成功回调,此时设备还不能直接去读写操作

    EasyBleManager.shareInstance.bleConnectSuccessBlock = {(_) in
        print("设备连接成功")
    }
    

    设备准备就绪回调,此时可以读写操作

    EasyBleManager.shareInstance.deviceReadyBlock = {(_) in
        print("设备已经准备就绪成功")
    }
    

    扫描设备/停止扫描

    EasyBleManager.shareInstance.scanForDevices()//扫描设备
    EasyBleManager.shareInstance.stopScan()//停止扫描
    

    连接设备

    EasyBleManager.shareInstance.connectDevice(device)
    

    读取数据

    device?.readDeviceInfo("设备版本号特性uuid", complete: { (value) in
        var versionString = ""
        if value != nil {
            versionString = String.init(data: value!, encoding: String.Encoding.utf8) ?? ""
        }
        print("设备版本号:\(versionString)")
    })
    

    写入数据

    let bytes: [UInt8] = [0x10]
    device?.writeDevice("设备特性uuid", bytes: bytes) { (success) in
        if success {
            print("写入成功")
        } else {
            print("写入失败")
        }
    }
    

    遇到的一些坑

    1 蓝牙初始化后,直接去扫描设备,无法扫描到设备
    方法:

    蓝牙初始化后,蓝牙状态此时是unknown状态,要等系统回调updateManagerState后,蓝牙才进行正常状态,所以扫描方法应放到

    func updateManagerState(_ central: CBCentralManager?) {
       switch central.state {
            case .poweredOn:
       }
    }
    

    2 因为第一个坑的原因,所以扫描设备方法要放到蓝牙状态回调方法中去,使用起来特别的不方便
    方法:

    把获取系统蓝牙状态方法设计成同步方法,这里使用了DispatchGroup类,具体的请见源码

    3 能扫描到设备,无法连接到设备,连接成功和失败的接口都没有回调
    方法:

    把扫描到的peripheral保存起来,因为peripheral没有被引用的时候,设备连接成功后,会自动断开,并且不会进入回调方法。

    array.append(peripheral)
    

    4 连接成功后,读写数据失败
    方法:

    设备连接成功后,此时设备里的服务和特性值并没有被发现,直接去读写操作是不会成功的,要等需要访问的服务和特性值被发现后,才能对这个特性值读写操作。
    这里我设计了一个设备准备就绪回调方法,当设备准备就绪时,就可以随时读写任意的服务和特性了。

    BleManager.shareInstance.deviceReadyBlock = {(_) in
        print("设备已经准备就绪,随时可以读写操作")
    }
    

    具体的请见源码

    最后

    在使用过程中如果有任何问题和建议都可以随时联系我
    我的邮箱 344185723@qq.com
    源码地址 EasyBleManager
    愿大家都可以开开心心的写代码!

    展开全文
  • swift蓝牙的应用

    千次阅读 2019-01-15 15:05:42
    蓝牙的简易使用 */ import UIKit import CoreBluetooth @available(iOS 10.0, *) class LYBBlueToothVC: UIViewController ,CBCentralManagerDelegate, CBPeripheralDelegate { ////中央管理器的状...
  • 通过之前文章我们掌握SwiftUI构建蓝牙App的方法,那么macOS 平台该如何开发呢? 解决方案 SwiftUI 当初的设计理念就是 Write Once Run Anywhere,让我们来体验一下吧 下面iOS代码 import SwiftUI import ...
  • Swift 操作手机蓝牙

    2016-05-27 11:57:05
    关于Swift操作蓝牙,网上资料不少。但由于开发环境更新后,原来的代码出现了不少错误,因此无法直接使用。下面是我根据网上的有关资料整理的代码,在Xcode7.3.2及IOS9.3.2上验证通过,供大家参考。 1、引用...
  • IOS--swift BLE蓝牙通信管理(多设备)

    千次阅读 2018-08-28 17:56:04
    之前一直做的是Android,公司IOS端突然要同时进行多个项目,IOS同学表示压力山大,所以临危...总共有4个swift文件。 如图: BLEManager用于管理中心蓝牙提供扫描,延时停止扫描等功能 BLEModel是用于按照嵌入式...
  • iOS 蓝牙开发(ble4.0) -swift

    千次阅读 2017-06-23 17:20:26
    CmdBluetooth是一个针对于iOS的轻量级可扩展框架,Core内部将蓝牙周边抽象化,用户无需关注蓝牙内的操作细节与流程,仅需要你们自己的蓝牙协议,创造出自己的命令对象。 以往的蓝牙协议都是集中式处理,出现逻辑复杂...
  • // MARK: - 接收到数据,开始处理 //代理方法 func getData(_ data: Data!) { let nsdata:NSData = NSData.init(data: data); // MyPrint("收:\(nsdata)"); // MyPrint(flag); ...
  • 前面总结了几篇关于Swift的使用,今天要讲的是关于使用Swift开发IOS中蓝牙4.0的开发流程,我以前只是会搞android的蓝牙开发,最近开始了Swift的学习,作为一个swift爱好者,想把蓝牙4.0的这个装逼神器在swift中使用...
  • iOS开发 -GameKit蓝牙开发

    千次阅读 2015-10-26 09:47:27
    蓝牙4.0蓝牙4.0是2012年最新蓝牙版本,是3.0的升级版本;较3.0版本更省电、成本低、3毫秒低延迟、超长有效连接距离、AES-128加密等;通常用在蓝牙耳机、蓝牙音箱等设备上。蓝牙技术联盟(Bluetooth SIG)2010年7月7日...
  • swift -> 蓝牙

    2018-08-12 23:00:51
    来源 : ...   ** 扫描 外设 或 连接 , 具体 DEMO 看 附件 。   ...// ViewController.swift ...// 蓝牙中心设备Swift // // Created by 吴浩 on 2018/1/12. // Copyright © 2018年 wuhao. All ...
  • 看过一些蓝牙App的事例,大体上对蓝牙的连接过程进行了了解。但是开始真正自己写一个小的BLE程序的时候就举步维艰了。那些模棱两可的概念在头脑中瞬间就蒸发了,所以还是决定从最基本的蓝牙连接过程进行。这里所说的...
  • 11 import UIKit import CoreBluetooth import PlaygroundBluetooth import PlaygroundSupport class MyViewController2 : UIViewController,PlaygroundBluetoothConnectionViewDelegate,...
  • swift 字符串String转Int 16进制字符串String转Int var hexi:UInt = UInt(hexS, radix: 16) let n = 14 var st = String(format:"%02X", n) st += " is the hexadecimal representation of \(n)" print(st...
  • 我现在程序里可以接收蓝牙通知,但是如果接收的数据大于20个字节 ,就只能接收到20后面的数据 , 有什么办法可以全部接收吗
  • iOS开发- 蓝牙后台接收数据(BLE4.0)

    万次阅读 多人点赞 2014-06-05 19:35:21
    最近在做一个蓝牙相关的项目, 需要在应用进入后台, 或者手机属于锁屏状态的情况下, 仍然保持蓝牙连接, 并且能正常接收数据。本来以后会很麻烦, 但是学习了下..发现就2步而已。简单的不能再简单了。好了。下面是具体...
  • iOS 蓝牙(GameKit)

    2017-09-11 10:23:55
    iOS中提供了4个框架用于实现蓝牙连接 GameKit.framework(用法简单) 只能用于iOS设备之间的连接,多用于游戏(比如五子棋对战),从iOS7开始过期 MultipeerConnectivity.framework 只能用于iOS设备之间的连接,从...
  • swift3.0蓝牙开发(2)

    千次阅读 2017-05-08 22:10:19
    承接上篇swift3.0蓝牙开发(1)三.代码展示1.设置代理 CBCentralManagerDelegate 中心者的代理 CBPeripheralDelegate 外设的代理class ViewController: UIViewController,CBCentralManagerDelegate,...
1 2 3 4 5 ... 20
收藏数 838
精华内容 335
关键字:

data蓝牙 swift