目录
1. 蓝牙
1.1 中央设备(接收数据)常用
1.2 外围设备(发送数据)很少使用(测试协议时使用)
1.3 相关类
2. WiFi
1. 蓝牙
概念
CoreBluetooth蓝牙
蓝牙开发分为2种:
1.手机作为中央设备(常用99.99%)连接蓝牙设备;
2.手机作为外围设备(不常用)连接中央设备。
蓝牙4.0(现在多数设备已支持)以低功耗著称,又称BLE(Bluetoothlow energy)。
蓝牙只能支持16进制,且每次传输最多20字节。
蓝牙的数据交互类似于接口,硬件的service的UUID(相当于主地址)加上characteristic的UUID(相当于后边路径)
所有可用的iOS设备既可以作为周边(Peripheral)也可以作为中央(Central),但不可以同时既是周边也是中央。
蓝牙开发最核心的不是代码(代码是固定的),最核心的是协议(一般蓝牙的数据协议都会加密,不加密任何人都可以连接硬件)
蓝牙设备向 中心设备 发送广播,必定有一个或多个服务,服务包含一个或多个特征(是和外界交互的最小单位)。
历史框架
只能用于iOS设备之间的连接(ios7前)
只能用于iOS设备之间的连接(ios7后)
可用于第三方蓝牙设备交互,但是蓝牙设备必须经过苹果MFi认证
目前世界上最流行的蓝牙框架(99%)
相关名词
Central(中心设备)接收并处理周边设备发送的数据
Peripheral(周边设备)不断发送数据
advertising(广播)
Services(服务)
Characteristic(特征)
使用步骤
1.创建Central Manager中心设备管理者
2.搜索外围设备
3.连接外围设备
4.寻找外围设备的某服务中的某特征
5.从外围设备读取数据/向外围设备发送数据
6.断开连接
注意:
info.plist + 权限
Privacy - Bluetooth Peripheral Usage Description App需要访问蓝牙
1.1 中央设备(接收数据)常用
import "YTCentralViewController.h"
#import
#define ServiceUUID [CBUUID UUIDWithString:@"0000fee7-0000-1000-8000-00805f9b34fb"]
#define WirteCharactUUID [CBUUID UUIDWithString:@"000036f5-0000-1000-8000-00805f9b34fb"]
#define ReadCharactUUID [CBUUID UUIDWithString:@"000036f6-0000-1000-8000-00805f9b34fb"]
@interface YTCentralViewController ()
@property (nonatomic,strong) CBCentralManager *centralManager; // 创建中心设备管理者(数据接收方)
@property (nonatomic,strong) NSMutableArray *peripheralArr; // 存放外围设备
@end
@implementation YTCentralViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1.创建中心设备管理者
self.centralManager=[[CBCentralManager alloc]initWithDelegate:self queue:nil];
}
-(void)dealloc{
self.centralManager=nil;
}
#pragma mark dele CBCentralManagerDelegate
// 2.蓝牙状态发生改变时调用(必须实现),创建中心设备管理者调用一次
-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
if (@available(iOS 10.0, *)) {
switch (central.state) {
case CBManagerStatePoweredOn:{ // 蓝牙已打开
NSLog(@"蓝牙开启");
// 2.1 扫描外围设备(nil:扫描所有service)
[self.centralManager scanForPeripheralsWithServices:nil options:nil];
}
break;
case CBManagerStatePoweredOff:{ // 蓝牙未打开
NSLog(@"蓝牙关闭");
}
break;
case CBManagerStateUnauthorized:{
NSLog(@"未授权使用蓝牙");
}
break;
case CBManagerStateUnsupported:{
NSLog(@"不支持蓝牙");
}
break;
case CBManagerStateResetting:{
NSLog(@"");
}
break;
case CBManagerStateUnknown:{
NSLog(@"");
}
break;
default:{
NSLog(@"");
}
break;
}
}
}
// 3.扫描到外围设备后调用
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
// 3.1 找的唯一对应的设备后停止扫描
if([peripheral.name isEqualToString:@"device01"]||[peripheral.name isEqualToString:@"iPhone"]){
// 停止扫描
[self.centralManager stopScan];
}else{
return;
}
// 添加扫描设备到数组,并联入外围设备
if(peripheral){
//
if(![self.peripheralArr containsObject:peripheral]){
[self.peripheralArr addObject:peripheral];
}
// 3.2 联入外围设备(联接成功后调用didConnectPeripheral)
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
// 4.联入外围设备后调用
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
// 设置外围设备的dele CBPeripheralDelegate
[peripheral setDelegate:self];
// 外围设备寻找服务
[peripheral discoverServices:@[ServiceUUID]];
}
// 4.1联入外围设备失败后调用
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
//
NSLog(@"error connect");
}
/*
// 取消联接后调用
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{}
// 进入后台前调用保存信息?
-(void)centralManager:(CBCentralManager *)central willRestoreState:(NSDictionary *)dict{}
*/
#pragma mark dele CBPeripheralDelegate
// 5.外围设备寻找到服务后调用
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
if(error){ // 寻找服务失败
NSLog(@"寻找服务失败");
}
// 从外围设备的服务中找到对应service和对应charact
for(CBService *service in peripheral.services){
if([service.UUID isEqual:ServiceUUID]){
// 寻找对应特征
[peripheral discoverCharacteristics:nil forService:service];
}
}
}
// 6.寻找到特征时调用
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
if(error){ // 寻找特征出错
NSLog(@"寻找特征时出错");
}
// 找到对应service服务对应的charact特征,
if([service.UUID isEqual:ServiceUUID]){
for(CBCharacteristic *charact in service.characteristics){
if([charact.UUID isEqual:WirteCharactUUID]){ // 写
//
Byte reg[16];
reg[0]=0x05;
reg[1]=0x01;
reg[2]=0x06;
for(int i=0;i<13;i++){
reg[i+3]=0x01;
}
NSData *data=[NSData dataWithBytes:reg length:16];
[peripheral writeValue:data forCharacteristic:charact type:CBCharacteristicWriteWithResponse];
/*
// 更新通知状态:(调用didUpdateNoti,外围设备会收到订阅通知并添加到数据源中--需要发送数据时发送)
[peripheral setNotifyValue:true forCharacteristic:charact];
// 或
// 读取特征值
[peripheral readValueForCharacteristic:charact];
if(charact.value){
NSLog(@"特征值:%@",[[NSString alloc]initWithData:charact.value encoding:NSUTF8StringEncoding]);
}
*/
}else if([charact.UUID isEqual:ReadCharactUUID]){ // 读
// 1:监听通知(收到通知时调用didUpdateNoti,在其中调用2)(用于持续读取)
[peripheral setNotifyValue:true forCharacteristic:charact];
// 或
// 2:调用didUpdateValueForC从外围设备中读取数据(用于一次读取)
[peripheral readValueForCharacteristic:charact];
}
}
}
}
// 7.通知状态更新时调用
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if(error){ // 通知状态更新时出错
NSLog(@"通知状态更新时出错");
return;
}
//
if([characteristic.UUID isEqual:WirteCharactUUID]){
}else if([characteristic.UUID isEqual:ReadCharactUUID]){
if(characteristic.isNotifying){ // 正在监听(通知状态为true)
if(characteristic.properties==CBCharacteristicPropertyNotify){ // 调用setNotifyValue后进入
NSLog(@"已订阅特征通知。 ");
return;
}else if(characteristic.properties==CBCharacteristicPropertyRead){ // 外围设备发送数据后进入
// 调用didUpdateValueForC从外围设备中读取数据
[peripheral readValueForCharacteristic:characteristic];
}
}else{ // 停止监听(通知状态为false)
NSLog(@"stop 监听通知");
// 取消连接
[_centralManager cancelPeripheralConnection:peripheral];
}
}
}
// 8. 从外围设备读取数据(readValueForCharacteristic时会调用)
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
if(error){
NSLog(@"读取数据出错");
return;
}
if(characteristic.value){
NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding];
NSLog(@"读取到数据:%@",value);
}else{ // 无数据
NSLog(@"未发现特征值");
}
}
-(NSMutableArray *)peripheralArr{
if(!_peripheralArr){
_peripheralArr=[NSMutableArray arrayWithCapacity:10];
}
return _peripheralArr;
}
@end
1.2 外围设备(发送数据)
很少使用
可用来在设备未做好之前测试协议。
#import "YTPeripheralViewController.h"
#import
#define ServiceUUID [CBUUID UUIDWithString:@"0000fee7-0000-1000-8000-00805f9b34fb"]
#define WriteCharactUUID [CBUUID UUIDWithString:@"000036f5-0000-1000-8000-00805f9b34fb"]
#define ReadCharactUUID [CBUUID UUIDWithString:@"000036f6-0000-1000-8000-00805f9b34fb"]
@interface YTPeripheralViewController ()
@property (nonatomic,strong) CBPeripheralManager *peripheralManager; // 发射数据管理者(外围设备)
@property (nonatomic,strong) NSMutableArray *centralArr; // 联入的设备
@end
@implementation YTPeripheralViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 1.创建 外围设备管理者(发射数据)
self.peripheralManager=[[CBPeripheralManager alloc]initWithDelegate:self queue:nil];
}
-(void)dealloc{
self.peripheralManager=nil;
}
#pragma mark dele
// 2.蓝牙状态发生改变时调用(必须实现)
-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
//
switch (peripheral.state) {
case CBManagerStatePoweredOn:{ // 蓝牙已打开
NSLog(@"BLE open");
// 2.1 添加服务
CBMutableService *serviceM=[[CBMutableService alloc]initWithType:ServiceUUID primary:true];
// 给服务添加特征
CBMutableCharacteristic *writeCharaM=[[CBMutableCharacteristic alloc]initWithType:WriteCharactUUID properties:CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteable|CBCharacteristicPropertyNotify];
CBMutableCharacteristic *readCharaM=[[CBMutableCharacteristic alloc]initWithType:ReadCharactUUID properties:CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable|CBCharacteristicPropertyNotify];
/*
CBCharacteristicPropertyBroadcast = 0x01,
CBCharacteristicPropertyRead = 0x02,
CBCharacteristicPropertyWriteWithoutResponse = 0x04,
CBCharacteristicPropertyWrite = 0x08,
CBCharacteristicPropertyNotify = 0x10,
CBCharacteristicPropertyIndicate = 0x20,
CBCharacteristicPropertyAuthenticatedSignedWrites = 0x40,
CBCharacteristicPropertyExtendedProperties = 0x80,
CBCharacteristicPropertyNotifyEncryptionRequired NS_ENUM_AVAILABLE(10_9, 6_0) = 0x100,
CBCharacteristicPropertyIndicateEncryptionRequired NS_ENUM_AVAILABLE(10_9, 6_0) = 0x200
*/
/*
CBAttributePermissionsReadable = 0x01,
CBAttributePermissionsWriteable = 0x02,
CBAttributePermissionsReadEncryptionRequired = 0x04,
CBAttributePermissionsWriteEncryptionRequired = 0x08
*/
[serviceM setCharacteristics:@[writeCharaM,readCharaM]];
// 会调用didAddService方法
[self.peripheralManager addService:serviceM];
}
break;
case CBManagerStatePoweredOff:{ // 蓝牙未打开
//
NSLog(@"未打开蓝牙BLE");
}
break;
default:{
}
break;
}
}
// 3.外围设备添加servie后调用
-(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{
if(error){ // 添加servie出错
NSLog(@"错误:%@",error.localizedDescription);
return;
}
// 启动广播
// 调用DidStartAdvertising
[self.peripheralManager startAdvertising:@{CBAdvertisementDataLocalNameKey:@"外围设备名"}];
}
// 3.1启动广播
-(void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error{
if(error){ // 启动广播出错
NSLog(@"start error");
return;
}
NSLog(@"开始 广播");
}
// 4.有设备联入后调用
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic{
// 添加中心设备到数组
if(![self.centralArr containsObject:central]){
[self.centralArr addObject:central];
}
}
// 4.1有设备取消联入后调用
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic{
NSLog(@"cancel");
}
// 5.收到写数据请求后调用
-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests{
CBATTRequest *request = requests.lastObject;
NSString *content = [[NSString alloc] initWithData:request.value encoding:NSUTF8StringEncoding];
}
// 5.1 收到读数据请求后调用
-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveReadRequest:(CBATTRequest *)request{
//
Byte reg[16];
reg[0]=0x05;
reg[1]=0x02;
reg[2]=0x01;
reg[3]=0x00;
for(int i=0;i<12;i++){
reg[i+4]=0x00;
}
NSData *data=[NSData dataWithBytes:reg length:16];
request.value = data;
// [@"hello" dataUsingEncoding:NSUTF8StringEncoding];
[peripheral respondToRequest:request withResult:CBATTErrorSuccess];
}
// 6.进入后台存储数据?
-(void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary *)dict{
//
NSLog(@"will restore state");
}
// 7.updateValue:forCharacteristic:onSubscribedCentrals失败后再次准备好更新特征值时调用
-(void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral{}
// 懒加载(已联入的中心设备)
-(NSMutableArray *)centralArr{
if(!_centralArr){
_centralArr=[NSMutableArray arrayWithCapacity:10];
}
return _centralArr;
}
@end
1.3 相关类
// CBCentralManager 中心设备管理者(用来管理中心设备:扫描/连接 外围设备)
// 创建 CBCentralManagerDelegate
// CBCentralManager *centralManager=[[CBCentralManager alloc]initWithDelegate:self queue:nil];
CBCentralManager *centralManager=[[CBCentralManager alloc]initWithDelegate:self queue:nil options:@{}];
/*
CBCentralManagerOptionShowPowerAlertKey @(BOOL) 若蓝牙未打开,是否弹出alert
CBCentralManagerOptionRestoreIdentifierKey @"" 用于蓝牙恢复链接
*/
// CBCentralManager *centralManager=[CBCentralManager new];
// [centralManager setDelegate:self];
// 获取已连接的外围蓝牙设备(根据serviceID)
NSArray *perArr=[centralManager retrieveConnectedPeripheralsWithServices:@[[CBUUID UUIDWithString:@"NSUUID"]]];
// 获取已连接的外围蓝牙设备(根据Identifier)
NSArray *perArr=[centralManager retrievePeripheralsWithIdentifiers:@[[CBUUID UUIDWithString:@"SERVICE ID"]]];
// 扫描外围设备(services写nil 表示扫描所有)
[centralManager scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:@"SERVICE ID"]] options:@{}];
/*
CBCentralManagerScanOptionAllowDuplicatesKey @(BOOL) 是否重复扫描已发现的设备
CBCentralManagerScanOptionSolicitedServiceUUIDsKey @[CBUDID] 扫描的指定服务UUID数组
*/
// 停止扫描外围设备
[centralManager stopScan];
// 连接外围设备
[centralManager connectPeripheral:peripheral options:@{}];
/*
CBConnectPeripheralOptionNotifyOnConnectionKey @(BOOL) 是否弹出提示框(在后台连接上设备)
CBConnectPeripheralOptionNotifyOnDisconnectionKey @(BOOL) 是否弹出提示框(在后台断开连接设备)
CBConnectPeripheralOptionNotifyOnNotificationKey @(BOOL) 是否弹出提示框(在后台接受到数据时)
*/
// 断开连接外围设备
[centralManager cancelPeripheralConnection:peripheral];\
/*
CBCentralManagerRestoredStatePeripheralsKey
CBCentralManagerRestoredStateScanServicesKey
CBCentralManagerRestoredStateScanOptionsKey
*/
// CBPeripheral:周边设备
CBPeripheral *per=[CBPeripheral new];
// dele
[per setDelegate:nil];
// name(readOnly)
NSString *perName=per.name;
// state(readOnly)
CBPeripheralState perState=per.state;
/*
CBPeripheralStateDisconnected 未连接
CBPeripheralStateConnecting 连接中
CBPeripheralStateConnected 已连接
CBPeripheralStateDisconnecting 断开连接中
*/
// services(readOnly)
NSArray *perServiceArr=per.services;
// RSSI
[per readRSSI];
// 发现服务(根据ServiceID)
[per discoverServices:@[[CBUUID UUIDWithString:@"SERVICE ID"]]];
// 寻找特征(根据charactID service)
[per discoverIncludedServices:@[charactUUID] forService:service];
// ?
[per discoverCharacteristics:@[charactUUID] forService:service];
// 从外围设备读取数据(从相应特征值),调用didUpdateValue
[per readValueForCharacteristic:charact];
// 向特征写入值
[per writeValue:[NSData data] forCharacteristic:charact type:CBCharacteristicWriteWithResponse];
// CBCharacteristicWriteWithoutResponse/CBCharacteristicWriteWithResponse
// 从外围设备读取数据,并订阅特征(打开通知,一有数据就获取,false则关闭),调用didUpdateNoti
[per setNotifyValue:true forCharacteristic:charact];
// 发现描述
[per discoverDescriptorsForCharacteristic:charact];
// 读取值从描述
[per readValueForDescriptor:descriptor];
// 向描述写入值
[per writeValue:[NSData data] forDescriptor:descriptor];
// CBService:服务
CBService *service=[CBService new];
// 发送此服务的周边设备(readOnly)
CBPeripheral *servicePeripheral=service.peripheral;
// primary/secondary(readOnly)
BOOL serviceIsPrimary=service.isPrimary;
// 已经发现的服务列表?(readOnly)
NSArray *serviceIncludedServiceArr=service.includedServices;
// 已经发现的特征列表?(readOnly)
NSArray *serviceCharacteristicArr=service.characteristics;
// 特征
CBCharacteristic *charact=[CBCharacteristic new];
// 此特征属于哪个service(readOnly)
CBService *charactService=charact.service;
// 特征类型(readOnly)
CBCharacteristicProperties charactProperties=charact.properties;
/*
CBCharacteristicPropertyBroadcast 广播
CBCharacteristicPropertyRead 读数据
CBCharacteristicPropertyWriteWithoutResponse 写数据不要响应
CBCharacteristicPropertyWrite 写数据
CBCharacteristicPropertyNotify 通知
CBCharacteristicPropertyIndicate
CBCharacteristicPropertyAuthenticatedSignedWrites
CBCharacteristicPropertyExtendedProperties
*/
// 数据(readOnly)
NSData *charactData=charact.value;
// 改特征已经被发现的描述(readOnly)
NSArray *charactDescriptorArr=charact.descriptors;
// 该特征是否正在通知(readOnly)
BOOL charactIsNotifying=charact.isNotifying;
// CBDescriptor:描述
CBDescriptor *descriptor=[CBDescriptor new];
// 该描述属于哪个特征(readOnly)
CBCharacteristic *descriptorCharacteristic=descriptor.characteristic;
// value(readOnly)
id descriptorValue=descriptor.value;
2. WiFi
WiFi通讯
利用WiFi信号让手机和智能硬件设备进行数据传输处理的一种方式。
通讯原理
使用Socket(套接字,Scoket = IP地址(找到哪台电脑即服务器)+端口号(找到服务器上的哪个应用))进行UDP(一对多)通讯
构成
(1)路由器(提供WiFi信号,作为中间者负责转发传递数据)
(2)硬件(手机/硬件设备,数据发送与接收方)
3种使用类型
(1)手机(连上外部设备的WiFi)直接与外部设备(装有WiFi芯片)建立连接
(2)手机和外部设备都连接上同一路由器
(3)云端WiFi通讯(大趋势) ,手机<->服务器<->硬件,解决了前两种方法必须连上同一WiFi的局限。