CoreBluetooth框架
App shares data using CoreBluetooth 和 App communicates using CoreBluetooth
2.很多demo用控制器加载的蓝牙 ,在控制器dealloc的时候 蓝牙也消失了. 程序运行期间蓝牙应该一直存在的
所以我是把蓝牙写成了单例,在需要使用蓝牙的时候调用方法即可.
周边(Peripheral)是生成或者保存了数据的设备,中央(Central)是使用这些数据的设备。所有可用的iOS设备可以作为周边(Peripheral)也可以作为中央(Central),但不可以同时既是周边也是中央。
周边和中央这两个角色在CoreBluetooth框架中是用两个类来表示的,CBPeripheralManager这个类代表周边,CBCentralManager 这个类代表中央。
在中央这边,一个CBPeripheral 对象代表着相应的和中央连接着的周边;同样的,在周边这边,一个CBCentral 对象代表着相应的和周边连接着的中央。
你可以认为周边是一个广播数据的设备,他广播到外部世界说他这儿有数据,并且也说明了能提供的服务。另一边,中央开始扫描附近有没有服务,如果中央发现了想要的服务,然后中央就会请求连接周边,一旦连接建立成功,两个设备之间就开始交换传输数据了。
中央设备对应的类
CBCentralManager
CBPeripheral
/*
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)
*/
//设置一个数组的属性 存储发现的设备 @property (nonatomic, strong) NSMutableArray *peripherals; //设置一个中心管理者 @property (nonatomic, strong) CBCentralManager *manager; // 创建一个tableView 来展示数据 //@property (nonatomic, strong) UITableView *tableview; //搜到的外设 @property (nonatomic, strong) CBPeripheral *perpheral; //外设的特征 @property (nonatomic, strong) CBCharacteristic *charactertic; //信号强度 @property (nonatomic, strong) NSNumber *RSSIValue; //存储数据的路径 @property (nonatomic, strong) NSString *dataSourcePath; @property (nonatomic, strong) NSMutableArray *dataArr; @property (nonatomic, strong) NSFileHandle *fileHandle; + (BSBluetoothSingleton *)shareBlutooth; //搜寻蓝牙 - (void)findBluetooth; //链接对应的蓝牙 - (void)connectPerpheralWithIndexpath:(NSIndexPath *)index; // 对应的控制器 用于展示搜到的蓝牙对象 @property (nonatomic, strong) BSBluetoothViewController *bsblueVC;
单例的创建方法
+ (BSBluetoothSingleton *)shareBlutooth{ static BSBluetoothSingleton *bluetoothHandle = nil; // if (bluetoothHandle == nil) { // bluetoothHandle = [[BSBluetoothSingleton alloc]init]; // } static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ bluetoothHandle = [[BSBluetoothSingleton alloc]init]; }); return bluetoothHandle; } - (instancetype)init{ self = [super init]; if (self) { self.isConnected = NO; } return self; } // 懒加载 - (NSMutableArray *)peripherals{ if (!_peripherals) { _peripherals = [[NSMutableArray alloc]init]; } return _peripherals; }
第一步 >> 第三步 都是套路 一样的
#pragma mark 第一步 - (void)findBluetooth{ // 设置代理 self.manager = [[CBCentralManager alloc]initWithDelegate:self queue:nil]; self.manager.delegate = self; // 2.利用中心设备 扫描 // 如果给定数组代表只扫描指定设备 [self.manager scanForPeripheralsWithServices:nil options:nil]; //[self.tableview reloadData]; } #pragma mark 第二步 扫描外设 #pragma mark -- CBCentralmanagerDelegate - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *,id> *)advertisementData RSSI:(NSNumber *)RSSI{ // 保存扫描到得外部设备 // 但是要判断这个这个设备 是不是已经找到过 存储新发现的设备 peripheral.delegate = self; NSLog(@"信号强度 >> %@",RSSI); // self.perpheral.delegate = self; if (![self.peripherals containsObject:peripheral]) { [self.peripherals addObject:peripheral]; // NSLog(@"找的了几个蓝牙 %ld",self.peripherals.count); // NSLog(@"找到的对象%@",peripheral); } // self.bsblueVC.peripherals = self.peripherals; [self.bsblueVC.tableview reloadData]; } #pragma mark 第三步 连接外设 - (void)connectPerpheralWithIndexpath:(NSIndexPath *)index{ self.perpheral = self.peripherals[index.row]; NSLog(@"开始链接蓝牙> %@",self.perpheral.name); [self.manager connectPeripheral:self.perpheral options:nil]; } // 链接外设成功调用 - (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{ [self.manager stopScan]; // 扫描外设中得服务 [peripheral discoverServices:nil]; NSLog(@"链接成功"); _bluePointdrawArr = [[NSMutableArray alloc]init]; [self changeIsconect]; if (_isConnected == YES) { } } // 链接外设失败调用 - (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{ [self.bsblueVC.tableview reloadData]; self.isConnected = NO; NSLog(@"连接失败"); }
第四步
#pragma mark 第四步 //只要扫到服务就会调用 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{ NSLog(@"扫描服务"); // 获取外设中 所有扫描得到的服务 NSArray *services = peripheral.services; for (CBService *service in services) { // 找到需要的服务 NSLog(@"%@",service.UUID.UUIDString); NSLog(@"服务identifierUUID >> %@",service.UUID); // [self showTheAlertViewWithMessage:@"拿到对应的服务了"]; // 拿到服务里的所有特征 应该找特定的 [peripheral discoverCharacteristics:nil forService:service]; // if ([service.UUID.UUIDString isEqualToString:@"11"]) { // [self showTheAlertViewWithMessage:@"拿到对应的服务了"]; //// 从需要的服务中 查找需要的特征 //// 从外设 peripheral 的service中扫描特征 // // [peripheral discoverCharacteristics:nil forService:service]; // } } } //只要扫描到特征 就会调用 - (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{ NSLog(@"扫描特征"); // 拿到服务中所有的特征 // NSArray *characteristics = service.characteristics; // 遍历这个特征 拿到需要的特征 然后处理 if (error) { NSLog(@"error Discovered characteristics for %@ with error: %@", service.UUID, [error localizedDescription]); return; } for (CBCharacteristic *characteristic in service.characteristics) { // characteristic. NSLog(@"service:%@ 的 Characteristic: %@",service.UUID,characteristic.UUID); } //获取Characteristic的值,读到数据会进入方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error for (CBCharacteristic *characteristic in service.characteristics){ { [peripheral readValueForCharacteristic:characteristic]; } } //搜索Characteristic的Descriptors,读到数据会进入方法:-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error // 获取特征里面的描述值 并且订阅 这个特征 for (CBCharacteristic *characteristic in service.characteristics){ [peripheral discoverDescriptorsForCharacteristic:characteristic]; [peripheral setNotifyValue:YES forCharacteristic:characteristic]; } }
// 下班了
使用蓝牙的套路就是 将手机作为中心设备, 蓝牙设备作为外设. 蓝牙设备打开的情况下,会一直向外广播( 我可以被连接,快来连我 ). 打开中心设备(手机)的蓝牙功能>>开始扫描 就能扫描到周围的蓝牙.>>连接你想要连接的蓝牙 >> 连接之后 就会自动扫描这个蓝牙设备的所有服务和特征 在官方的蓝牙的API介绍中可以看到关于服务和特征的详细介绍. >> 找到你需要的服务 和 特征 >> 特征里面有一个属性value 这个就是我们需要的东西. 蓝牙向外部发送数据 就是通过特征的value. 而且只要这恶搞值变化 就会调用方法. 我们通过代理方法 就能一直收到蓝牙的数据了.