一:简介
目前蓝牙开发越来越火,很多外部设备都使用的是蓝牙技术(如:智能手环,智能家居,可穿戴设备等)网上的资料也很多。随着蓝牙低功耗技术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.给外围设备发送数据