用CoreBluetooth原生蓝牙功能操作蓝牙防丢器

注:本代码只能真机测试,还需要一个蓝牙防丢器,没有做连接判断,若未连接成功或者不是连接的蓝牙防丢器,就不能点击报警或取消报警,主界面是直接通过StoryBoard搭建的:NavigationController-> UItableViewController
另外防丢功能一般都需要后台可以执行,所以要设置程序可以后台执行,设置方法如图所示:

用CoreBluetooth原生蓝牙功能操作蓝牙防丢器_第1张图片
开启后台执行.png

GET
这里只需要勾选Uses Bluetooth LE accessories选项,如果有其他需求再勾选其他选项,但是不能随意勾选,否则在app上架时会被拒

Demo:
蓝牙防丢器和手机之间可以互相通信,当防丢器给手机发送消息时,需要用到本地消息,就需要在appdelegate中做相应的操作

  • AppDelegate相关方法
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.
    
    //开启通知权限
    if ([UIApplication instancesRespondToSelector:@selector(registerUserNotificationSettings:)]) {
        UIUserNotificationSettings *settings = [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeBadge | UIUserNotificationTypeSound | UIUserNotificationTypeAlert categories:nil];
        [[UIApplication sharedApplication]registerUserNotificationSettings:settings];
    }
    return YES;
}

//收到通知后的回调
-(void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification{
    UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:notification.alertTitle message:notification.alertBody delegate:nil cancelButtonTitle:@"确定" otherButtonTitles:nil];
    [alertView show];
    
}
  • 核心代码
#import "SearchTableViewController.h"

//蓝牙开发框架
#import 

//将当前iOS设备作为中心设备用来连接外设

//报警服务
NSString *const kImmediateAlertService = @"1802";
NSString *const kAlertLevel = @"2A06";

//按键服务
NSString *const kHeyStartService = @"FFE0";
NSString *const kKeyPressState = @"FFE1";

@interface SearchTableViewController () 

//中心角色管理对象
@property (nonatomic , strong) CBCentralManager *centralManager;
//存储所有外设
@property (nonatomic , strong) NSMutableArray *peripheralalArray;
//信号强度数组
@property (nonatomic , strong) NSMutableArray *rssiArray;
//保存连接成功的设备
@property (nonatomic , strong) CBPeripheral *connectedPeripheral;
//报警特征
@property (nonatomic , strong) CBCharacteristic *alertCharacteristic;
//按键特征
@property (nonatomic , strong) CBCharacteristic *keyPressCharacteristic;

@end

@implementation SearchTableViewController

//懒加载, 在OC中重写属性的getter,只能通过.语法进行访问
- (NSMutableArray *)peripheralalArray{
    if (!_peripheralalArray){
        _peripheralalArray = [NSMutableArray array];
    }
    return _peripheralalArray;
}

- (NSMutableArray *)rssiArray{
    if (!_rssiArray) {
        _rssiArray = [NSMutableArray array];
    }
    return _rssiArray;
}

- (IBAction)alertAction:(UIBarButtonItem *)sender {
    //0x02:开启报警
    int alertNum = 0x02;
    NSData *alertData = [NSData dataWithBytes:&alertNum length:1];
    [self.connectedPeripheral writeValue:alertData forCharacteristic :self.alertCharacteristic type:CBCharacteristicWriteWithoutResponse];
}


- (IBAction)cancelAlertAction:(UIBarButtonItem *)sender {
    //0x00:取消报警
    int alertNum = 0x00;
    NSData *alertData = [NSData dataWithBytes:&alertNum length:1];
    [self.connectedPeripheral writeValue:alertData forCharacteristic :self.alertCharacteristic type:CBCharacteristicWriteWithoutResponse];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    
    [self setupCentralManager];
}

- (void) setupCentralManager{
    self.centralManager = [[CBCentralManager alloc]initWithDelegate:self queue:dispatch_get_main_queue() options:@{CBCentralManagerOptionShowPowerAlertKey: @YES}];
}

/**
 *  扫描蓝牙设备
 */
- (void)startScan{
    //参数1:限定要扫描的服务
    //参数2:选项(字典)
    [self.centralManager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
}

-(void)stopScan{
    [self.centralManager stopScan];
}

-(void)connectPeripheral:(CBPeripheral *)peripheral{
    //停止扫描
    [self stopScan];
    //连接
    [self.centralManager connectPeripheral:peripheral options:@{CBConnectPeripheralOptionNotifyOnConnectionKey:@YES}];
}

#pragma mark - CBCentralManagerDelegate
/**
 *  当蓝牙设备状态改变时的回调
 *
 *  @param central 蓝牙状态
 */
- (void)centralManagerDidUpdateState:(CBCentralManager *)central{
    switch (central.state) {
        case CBCentralManagerStateUnknown:{
            NSLog(@"未知情况");
            break;
        }
            
        case CBCentralManagerStatePoweredOn:{
            NSLog(@"蓝牙开启");
            [self startScan];
            break;
        }
        
        case CBCentralManagerStateResetting:{
            NSLog(@"蓝牙重置中");
            break;
        }
            
        case CBCentralManagerStatePoweredOff:{
            NSLog(@"蓝牙关闭");
            [self stopScan];
            break;
        }
            
        case CBCentralManagerStateUnsupported:{
            NSLog(@"蓝牙不支持");
            break;
        }
            
        case CBCentralManagerStateUnauthorized:{
            NSLog(@"蓝牙未授权");
            break;
        }
        default:
            break;
    }
}

/**
 *  当扫描到外设时的回调
 *
 *  @param central           中心
 *  @param peripheral        外设
 *  @param advertisementData 广告包数据
 *  @param RSSI              信号强度
 */
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
    NSLog(@"======================");
    NSLog(@"advertisementData=%@",advertisementData);
    NSLog(@"RSSI=%@",RSSI);
    
    __block BOOL isFind = NO;
    __weak typeof (self) weakSelf = self;
    
    [self.peripheralalArray enumerateObjectsUsingBlock:^(CBPeripheral *tempPeripheral, NSUInteger idx, BOOL * _Nonnull stop) {
        
        //判断UUID是否一样
        if ([tempPeripheral.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]){
            //替换
            [weakSelf.peripheralalArray replaceObjectAtIndex:idx withObject:peripheral];
            [weakSelf.rssiArray replaceObjectAtIndex:idx withObject:RSSI];
            isFind = YES;
            //停止循环
            *stop = YES;
        }
    }];
    //未找到
    if (!isFind){
        [self.peripheralalArray addObject:peripheral];
        [self.rssiArray addObject:RSSI];
    }
    
    //刷新视图
    dispatch_async(dispatch_get_main_queue(), ^{
        [weakSelf.tableView reloadData];
    });
}

//连接成功的回调
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    
    self.connectedPeripheral = peripheral;
    self.connectedPeripheral.delegate = self;
    
    //扫描外部设备的服务和特征
    [self.connectedPeripheral discoverServices:nil];
}
//连接失败的回调
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    
}
//断开连接的回调
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    
}

#pragma mark - tableViewDataSouce

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    NSLog(@"%lu",(unsigned long)self.peripheralalArray.count);
    return self.peripheralalArray.count;
}

-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    CBPeripheral *peripheral = self.peripheralalArray[indexPath.row];
    NSNumber *RSSI = self.rssiArray[indexPath.row];
    cell.textLabel.text = peripheral.name;
    cell.detailTextLabel.text = RSSI.stringValue;
    return cell;
}

#pragma mark - tableViewDelegate
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
    CBPeripheral *peripheral = self.peripheralalArray[indexPath.row];
    UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"连接外设" message: [NSString stringWithFormat:@"是否连接外设名为%@的设备",peripheral.name] preferredStyle:UIAlertControllerStyleAlert];
    UIAlertAction *connectAction = [UIAlertAction actionWithTitle:@"连接" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        [self connectPeripheral:peripheral];
    }];
    UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:@"取消" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        
    }];
    
    [alert addAction:connectAction];
    [alert addAction:cancelAction];
    
    [self presentViewController:alert animated:YES completion:nil];
}

#pragma mark - CBPripheralDelegate
//发现外设中可用服务
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    if (error) {
        NSLog(@"%s %@",__func__,error.localizedDescription);
        return;
    }
    //扫描外设的服务,找到的服务放在CBPeripheral.services中
    for (CBService *service in peripheral.services) {
        NSLog(@"services=%@",service);
        //扫描服务中的特征
        [peripheral discoverCharacteristics:nil forService:service];
    }
}

//发现外设中某个服务的所有特征
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    if (error) {
        NSLog(@"%s %@",__func__,error.localizedDescription);
        return;
    }
    
    //发现的特征放在服务的characteristics数组
    for (CBCharacteristic *characteristic in service.characteristics) {
        
        //找到匹配的特征
        if ([service.UUID.UUIDString isEqualToString:kImmediateAlertService] && [characteristic.UUID.UUIDString isEqualToString:kAlertLevel]) {
            self.alertCharacteristic = characteristic;
        }
        
        if ([service.UUID.UUIDString isEqualToString:kHeyStartService] && [characteristic.UUID.UUIDString isEqualToString:kKeyPressState]) {
            self.keyPressCharacteristic = characteristic;
            
            //开启通知
            [peripheral setNotifyValue:YES forCharacteristic:self.keyPressCharacteristic];
        }
        
        NSLog(@"characteristic=%@",characteristic);
        //发现特征中描述
        [peripheral discoverDescriptorsForCharacteristic:characteristic];
    }
}

//发现特征中的描述信息
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) {
        NSLog(@"%s %@",__func__,error.localizedDescription);
        return;
    }
    
    for (CBDescriptor *descriptor in characteristic.descriptors) {
        NSLog(@"descriptor=%@",descriptor);
    }
}

//特征值改变时的回调
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) {
        NSLog(@"%s %@",__func__,error.localizedDescription);
        return;
    }
    
    if ([characteristic.UUID.UUIDString isEqualToString:self.keyPressCharacteristic.UUID.UUIDString]) {
        //当按键按下时,收到特征数据的改变
        //创建本地通知
        UILocalNotification *notification = [[UILocalNotification alloc] init];
        notification.alertTitle = @"防丢器查找";
        notification.alertBody = @"防丢器正在查找中";
        notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:1];
        [[UIApplication sharedApplication] scheduleLocalNotification:notification];
    }
}

@end

你可能感兴趣的:(用CoreBluetooth原生蓝牙功能操作蓝牙防丢器)