iOS 蓝牙4.0开发基础教程

一:简介

目前蓝牙开发越来越火,很多外部设备都使用的是蓝牙技术(如:智能手环,智能家居,可穿戴设备等)网上的资料也很多。随着蓝牙低功耗技术BLE(Bluetooth Low Energy)的发展,蓝牙技术正在一步步成熟,如今的大部分移动设备都配备有蓝牙4.0,相比之前的蓝牙技术耗电量大大降低。本文基于蓝牙4.0使用Apple自家的蓝牙框架Core Bluetooth讲解。如有不当之处,望各位朋友多多提醒!

二:基本概念
  • 中心模式和外设模式
    顾名思义,比如以App作为中心,连接其他外设的场景称为中心模式,而使用手机作为外设被其他中心设备操作的场景则被称为外设模式。

    如图在Core Bluetooth框架API中,左列为中心模式,右列为外设模式

  • Central和Peripheral是什么?
    Core Bluetooth框架核心的两个东西:中心Central和外围设备Peripheral

    如图是以APP作为中心Central,连接其他的外设Peripheral的中心模式。在中心模式中本地Central表示为CBCentralManager,用来发现和连接外设Peripheral表示为CBPeripheral。

  • 服务Service和特征Characteristic是什么?
    服务Service:外设对外广播必须要有服务,服务可以是多个,服务里面又包含了特征Characteristic
    特征Characteristic:存在于服务里面,服务里面也可以存在多个特征,特征就是具体的键值对,提供数据的地方。

三:开始使用

这里以APP为中心模式举个例

import UIKit
import CoreBluetooth //导入蓝牙框架
//添加蓝牙代理
class ViewController: UIViewController, CBCentralManagerDelegate, CBPeripheralDelegate {

@IBOutlet weak var tableView: UITableView!
var manager: CBCentralManager?//中心角色
var per: CBPeripheral?//服务
var readCharac: CBCharacteristic? // 读取特征
var writeCharac: CBCharacteristic? // 写入特征

var deviceArray: [CBPeripheral] = [] //外设数据源

override func viewDidLoad() {
    super.viewDidLoad()
    //建立中心角色
    manager = CBCentralManager(delegate: self, queue: nil)
}

//判断蓝牙是否开启,并开始扫描
func centralManagerDidUpdateState(_ central: CBCentralManager) {
    if let central = manager {
        switch central.state {
        case .poweredOn:
            print("蓝牙已打开,请扫描外设")
            manager?.scanForPeripherals(withServices: nil, options: nil)
        case .poweredOff:
            print("蓝牙没有打开,请先打开蓝牙")
        default:
            break
        }
    }
}

//查找外设的代理
func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
    //查找到外设后添加到数据源里面,并刷新tableView数据
    if !deviceArray.contains(peripheral) {
        deviceArray.append(peripheral)
    }
    tableView.reloadData()
}

//连接外设成功,启动发现服务
func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
    print("连接成功:\(peripheral.name)")//打印外设name
    peripheral.delegate = self
    peripheral.discoverServices(nil)//开始发现服务
    per = peripheral
}

//连接外设失败
func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
    print("连接失败:\(peripheral.name)")
}

//发现服务
func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
    //遍历服务,发现服务下的特征
    for server in peripheral.services! {
        //也可以通过服务UUID来过滤服务
        //server.uuid
        peripheral.discoverCharacteristics(nil, for: server)
    }
}

//信号检测
func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
    let rssi = abs(RSSI .intValue)
    let str = "发现BLT4.0热点:\(peripheral),强度:\(rssi)"
    print(str)
}

//搜索到特征Characteristics
func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
    print("服务UUID:\(service.uuid)")
    //遍历每个服务下的特征
    for c in service.characteristics! {
        print("特征UUID:\(c.uuid)")
        //根据外设所定制的特征,分别处理
        //比如特征"1111"为读取,"2222"为写入
        if (c.uuid.uuidString.range(of: "1111") != nil) {
            readCharac = c
            peripheral.readRSSI()//检测外设信号
            peripheral.readValue(for: c)//读取一次特征值
            peripheral.setNotifyValue(true, for: c)//当特征值改变时通知
        }else if (c.uuid.uuidString.range(of: "2222") != nil) {
            //写入的特征
            writeCharac = c
        }
    }
}

//获取外设发来的数据(无论是读取还是通知,都在这个方法接收)
func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
    if characteristic.uuid == CBUUID(string: "1111") {
        let data = characteristic.value
        //data则是读取过来的数据
    }
}

//检测中心向外设写数据是否成功
func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
    if (error != nil) {
        print("发送失败")
    }else {
        print("发送成功")
    }
}

//模拟写入数据
//func testWriteData() {
//    per?.writeValue(writeData, for: writeCharac!, type: CBCharacteristicWriteType.withResponse)
//}
}

extension ViewController: UITableViewDataSource, UITableViewDelegate {

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return deviceArray.count
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let identified = "cell"
    var cell = tableView.dequeueReusableCell(withIdentifier: identified)
    if cell == nil {
        cell = UITableViewCell(style: .default, reuseIdentifier: identified)
    }
    let per = deviceArray[indexPath.row]

    if let name = per.name {
        cell?.textLabel?.text = name
    }else {
        cell?.textLabel?.text = per.identifier.uuidString
    }

    return cell!
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    per = deviceArray[indexPath.row]
    manager?.connect(per!, options: nil)
}
}

总得来说蓝牙连接分为以下几个步骤
1.建立一个Central Manager实例进行蓝牙管理
2.搜索外围设备
3.连接外围设备
4.获得外围设备的服务
5.获得服务的特征
6.从外围设备读数据
7.给外围设备发送数据

Demo地址:https://github.com/yueyeqi/CoreBluetooth_Demo