iOS技术点

iOS之蓝牙开发

2017-02-19  本文已影响104人  maybe_mylove

前言#

什么是蓝牙?####

蓝牙在开发中的框架有哪些?####

蓝牙在开发中的框架优缺点?####

前两个框架使用起来比较简单,但是缺点也比较明显:仅仅支持iOS设备,传输内容仅限于沙盒或者照片库中用户选择的文件,并且第一个框架只能在同一个应用之间进行传输(一个iOS设备安装应用A,另一个iOS设备上安装应用B是无法传输的)。当然CoreBluetooth就摆脱了这些束缚,它不再局限于iOS设备之间进行传输,你可以通过iOS设备向Android、Windows Phone以及其他安装有蓝牙4.0芯片的智能设备传输,因此也是目前智能家居、无线支付等热门智能设备所推崇的技术。

蓝牙框架之GameKit框架####

蓝牙查找、连接用的视图控制器,通常情况下应用程序A打开后会调用此控制器的show方法来展示一个蓝牙查找的视图,一旦发现了另一个同样在查找蓝牙连接的客户客户端B就会出现在视图列表中,此时如果用户点击连接B,B客户端就会询问用户是否允许A连接B,如果允许后A和B之间建立一个蓝牙连接。

连接会话,主要用于发送和接受传输数据。一旦A和B建立连接GKPeerPickerController的代理方法会将A、B两者建立的会话(GKSession)对象传递给开发人员,开发人员拿到此对象可以发送和接收数据。

-(void)peerPickerController:(GKPeerPickerController )picker didConnectPeer:(NSString )peerID toSession:(GKSession *)session

在此方法中可以获得连接的设备id(peerID)和连接会话(session);此时可以设置会话的数据接收句柄(相当于一个代理)并保存会话以便发送数据时使用;一旦一端(假设是A)调用会话的

sendDataToAllPeers: withDataMode: error:

方法发送数据,此时另一端(假设是B)就会调用句柄的

  - (void) receiveData:(NSData )data fromPeer:(NSString )peer   inSession: (GKSession )session context:(void )context

方法,在此方法可以获得发送数据并处理。下面是程序代码:

   #import "ViewController.h"
   #import <GameKit/GameKit.h>
   @interface ViewController ()

   @property (weak, nonatomic) IBOutlet UIImageView    *imageView;//照片显示视图
   @property (strong,nonatomic) GKSession *session;//蓝牙连接会话

   @end
@implementation ViewController
 #pragma mark - 控制器视图方法
 - (void)viewDidLoad {
    [super viewDidLoad];

    GKPeerPickerController *pearPickerController=[[GKPeerPickerController alloc]init];
    pearPickerController.delegate=self;

    [pearPickerController show];
}
    #pragma mark - UI事件
    - (IBAction)selectClick:(UIBarButtonItem *)sender {
      UIImagePickerController *imagePickerController=    [[UIImagePickerController alloc]init];
      imagePickerController.delegate=self;

      [self presentViewController:imagePickerController animated:YES completion:nil];
}

  - (IBAction)sendClick:(UIBarButtonItem *)sender {
      NSData *data=UIImagePNGRepresentation(self.imageView.image);
      NSError *error=nil;
      [self.session sendDataToAllPeers:data withDataMode:GKSendDataReliable error:&error];
      if (error) {
            NSLog(@"发送图片过程中发生错误,错误信    息:%@",error.localizedDescription);
        }
}
#pragma mark - GKPeerPickerController代理方法
/**
 *  连接到某个设备
 *
 *  @param picker  蓝牙点对点连接控制器
 *  @param peerID  连接设备蓝牙传输ID
 *  @param session 连接会话
 */
-(void)peerPickerController:(GKPeerPickerController *)picker didConnectPeer:(NSString *)peerID toSession:(GKSession *)session{
        self.session=session;
        NSLog(@"已连接客户端设备:%@.",peerID);
      //设置数据接收处理句柄,相当于代理,一旦数据接收完成调用它的-receiveData:fromPeer:inSession:context:方法处理数据
      [self.session setDataReceiveHandler:self withContext:nil];

      [picker dismiss];//一旦连接成功关闭窗口
}
  #pragma mark - 蓝牙数据接收方法
  - (void) receiveData:(NSData *)data fromPeer:(NSString *)peer inSession: (GKSession *)session context:(void *)context{
        UIImage *image=[UIImage imageWithData:data];
        self.imageView.image=image;
        UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
        NSLog(@"数据发送成功!");
}

  #pragma mark - UIImagePickerController代理方法
  -(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
        self.imageView.image=[info objectForKey:UIImagePickerControllerOriginalImage];
        [self dismissViewControllerAnimated:YES completion:nil];
}

  -(void)imagePickerControllerDidCancel:  (UIImagePickerController *)picker{
         [self dismissViewControllerAnimated:YES completion:nil];
}
@end

蓝牙框架之MultipeerConnectivity框架

A.广播
-(void)session:(MCSession )session peer:(MCPeerID )peerID didChangeState:(MCSessionState)state

代理方法中跟踪会话状态(已连接、正在连接、未连接);在会话的

-(void)session:(MCSession )session didReceiveData:(NSData )data fromPeer:(MCPeerID *)peerID

代理方法中接收数据;同时还会调用会话的

-(void)sendData: toPeers:withMode: error:

方法去发送数据。

B.发现
程序:
#import "ViewController.h"
#import 

@interface ViewController ()
@property (strong,nonatomic) MCSession *session;
@property (strong,nonatomic) MCAdvertiserAssistant *advertiserAssistant;
@property (strong,nonatomic) UIImagePickerController *imagePickerController;

@property (weak, nonatomic) IBOutlet UIImageView *photo;

@end
@implementation ViewController

#pragma mark - 控制器视图事件
- (void)viewDidLoad {
    [super viewDidLoad];
    //创建节点,displayName是用于提供给周边设备查看和区分此服务的
    MCPeerID *peerID=[[MCPeerID alloc]initWithDisplayName:@"KenshinCui_Advertiser"];
    _session=[[MCSession alloc]initWithPeer:peerID];
    _session.delegate=self;
    //创建广播
    _advertiserAssistant=[[MCAdvertiserAssistant alloc]initWithServiceType:@"cmj-stream" discoveryInfo:nil session:_session];
    _advertiserAssistant.delegate=self;

}

#pragma mark - UI事件
- (IBAction)advertiserClick:(UIBarButtonItem *)sender {
    //开始广播
    [self.advertiserAssistant start];
}
- (IBAction)selectClick:(UIBarButtonItem *)sender {
    _imagePickerController=[[UIImagePickerController alloc]init];
    _imagePickerController.delegate=self;
    [self presentViewController:_imagePickerController animated:YES completion:nil];
}

#pragma mark - MCSession代理方法
-(void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{
    NSLog(@"didChangeState");
    switch (state) {
        case MCSessionStateConnected:
            NSLog(@"连接成功.");
            break;
        case MCSessionStateConnecting:
            NSLog(@"正在连接...");
            break;
        default:
            NSLog(@"连接失败.");
            break;
    }
}
//接收数据
-(void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
    NSLog(@"开始接收数据...");
    UIImage *image=[UIImage imageWithData:data];
    [self.photo setImage:image];
    //保存到相册
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);

}
#pragma mark - MCAdvertiserAssistant代理方法


#pragma mark - UIImagePickerController代理方法
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
    UIImage *image=[info objectForKey:UIImagePickerControllerOriginalImage];
    [self.photo setImage:image];
    //发送数据给所有已连接设备
    NSError *error=nil;
    [self.session sendData:UIImagePNGRepresentation(image) toPeers:[self.session connectedPeers] withMode:MCSessionSendDataUnreliable error:&error];
    NSLog(@"开始发送数据...");
    if (error) {
        NSLog(@"发送数据过程中发生错误,错误信息:%@",error.localizedDescription);
    }
    [self.imagePickerController dismissViewControllerAnimated:YES completion:nil];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
    [self.imagePickerController dismissViewControllerAnimated:YES completion:nil];
}
@end
  #import "ViewController.h"
  #import 

  @interface ViewController ()
  @property (strong,nonatomic) MCSession *session;
  @property (strong,nonatomic) MCBrowserViewController *browserController;
  @property (strong,nonatomic) UIImagePickerController *imagePickerController;

  @property (weak, nonatomic) IBOutlet UIImageView *photo;
  @end
@implementation ViewController

#pragma mark - 控制器视图事件
- (void)viewDidLoad {
    [super viewDidLoad];
    //创建节点
    MCPeerID *peerID=[[MCPeerID alloc]initWithDisplayName:@"KenshinCui"];
    //创建会话
    _session=[[MCSession alloc]initWithPeer:peerID];
    _session.delegate=self;


}
#pragma mark- UI事件
- (IBAction)browserClick:(UIBarButtonItem *)sender {
    _browserController=[[MCBrowserViewController alloc]initWithServiceType:@"cmj-stream" session:self.session];
    _browserController.delegate=self;

    [self presentViewController:_browserController animated:YES completion:nil];
}
- (IBAction)selectClick:(UIBarButtonItem *)sender {
    _imagePickerController=[[UIImagePickerController alloc]init];
    _imagePickerController.delegate=self;
    [self presentViewController:_imagePickerController animated:YES completion:nil];
}


#pragma mark - MCBrowserViewController代理方法
-(void)browserViewControllerDidFinish:(MCBrowserViewController *)browserViewController{
    NSLog(@"已选择");
    [self.browserController dismissViewControllerAnimated:YES completion:nil];
}
-(void)browserViewControllerWasCancelled:(MCBrowserViewController *)browserViewController{
    NSLog(@"取消浏览.");
    [self.browserController dismissViewControllerAnimated:YES completion:nil];
}

#pragma mark - MCSession代理方法
-(void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{
    NSLog(@"didChangeState");
    switch (state) {
        case MCSessionStateConnected:
            NSLog(@"连接成功.");
            [self.browserController dismissViewControllerAnimated:YES completion:nil];
            break;
        case MCSessionStateConnecting:
            NSLog(@"正在连接...");
            break;
        default:
            NSLog(@"连接失败.");
            break;
    }
}
//接收数据
-(void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
    NSLog(@"开始接收数据...");
    UIImage *image=[UIImage imageWithData:data];
    [self.photo setImage:image];
    //保存到相册
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);

}
#pragma mark - UIImagePickerController代理方法
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info{
    UIImage *image=[info objectForKey:UIImagePickerControllerOriginalImage];
    [self.photo setImage:image];
    //发送数据给所有已连接设备
    NSError *error=nil;
    [self.session sendData:UIImagePNGRepresentation(image) toPeers:[self.session connectedPeers] withMode:MCSessionSendDataUnreliable error:&error];
    NSLog(@"开始发送数据...");
    if (error) {
        NSLog(@"发送数据过程中发生错误,错误信息:%@",error.localizedDescription);
    }
    [self.imagePickerController dismissViewControllerAnimated:YES completion:nil];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker{
    [self.imagePickerController dismissViewControllerAnimated:YES completion:nil];
}
@end

蓝牙框架之CoreBluetooth框架

A.外围设备
创建一个外围设备通常分为以下几个步骤:
  1. 创建外围设备CBPeripheralManager对象并指定代理。
  2. 创建特征CBCharacteristic、服务CBSerivce并添加到外围设备
  3. 外围设备开始广播服务(startAdvertisting:)。
  4. 和中央设备CBCentral进行交互。
#import "ViewController.h"
#import 
#define kPeripheralName @"Kenshin Cui's Device" //外围设备名称
#define kServiceUUID @"C4FB2349-72FE-4CA2-94D6-1F3CB16331EE" //服务的UUID
#define kCharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5E2004534FC" //特征的UUID

@interface ViewController ()

@property (strong,nonatomic) CBPeripheralManager *peripheralManager;//外围设备管理器

@property (strong,nonatomic) NSMutableArray *centralM;//订阅此外围设备特征的中心设备

@property (strong,nonatomic) CBMutableCharacteristic *characteristicM;//特征
@property (weak, nonatomic) IBOutlet UITextView *log; //日志记录

@end
@implementation ViewController
#pragma mark - 视图控制器方法
- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark - UI事件
//创建外围设备
- (IBAction)startClick:(UIBarButtonItem *)sender {
    _peripheralManager=[[CBPeripheralManager alloc]initWithDelegate:self queue:nil];
}
//更新数据
- (IBAction)transferClick:(UIBarButtonItem *)sender {
    [self updateCharacteristicValue];
}

#pragma mark - CBPeripheralManager代理方法
//外围设备状态发生变化后调用
-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral{
    switch (peripheral.state) {
        case CBPeripheralManagerStatePoweredOn:
            NSLog(@"BLE已打开.");
            [self writeToLog:@"BLE已打开."];
            //添加服务
            [self setupService];
            break;

        default:
            NSLog(@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备.");
            [self writeToLog:@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备."];
            break;
    }
}
//外围设备添加服务后调用
-(void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error{
    if (error) {
        NSLog(@"向外围设备添加服务失败,错误详情:%@",error.localizedDescription);
        [self writeToLog:[NSString stringWithFormat:@"向外围设备添加服务失败,错误详情:%@",error.localizedDescription]];
        return;
    }

    //添加服务后开始广播
    NSDictionary *dic=@{CBAdvertisementDataLocalNameKey:kPeripheralName};//广播设置
    [self.peripheralManager startAdvertising:dic];//开始广播
    NSLog(@"向外围设备添加了服务并开始广播...");
    [self writeToLog:@"向外围设备添加了服务并开始广播..."];
}
-(void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error{
    if (error) {
        NSLog(@"启动广播过程中发生错误,错误信息:%@",error.localizedDescription);
        [self writeToLog:[NSString stringWithFormat:@"启动广播过程中发生错误,错误信息:%@",error.localizedDescription]];
        return;
    }
    NSLog(@"启动广播...");
    [self writeToLog:@"启动广播..."];
}
//订阅特征
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic{
    NSLog(@"中心设备:%@ 已订阅特征:%@.",central,characteristic);
    [self writeToLog:[NSString stringWithFormat:@"中心设备:%@ 已订阅特征:%@.",central.identifier.UUIDString,characteristic.UUID]];
    //发现中心设备并存储
    if (![self.centralM containsObject:central]) {
        [self.centralM addObject:central];
    }
    /*中心设备订阅成功后外围设备可以更新特征值发送到中心设备,一旦更新特征值将会触发中心设备的代理方法:
     -(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
     */

//    [self updateCharacteristicValue];
}
//取消订阅特征
-(void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didUnsubscribeFromCharacteristic:(CBCharacteristic *)characteristic{
    NSLog(@"didUnsubscribeFromCharacteristic");
}
-(void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(CBATTRequest *)request{
    NSLog(@"didReceiveWriteRequests");
}
-(void)peripheralManager:(CBPeripheralManager *)peripheral willRestoreState:(NSDictionary *)dict{
    NSLog(@"willRestoreState");
}
#pragma mark -属性
-(NSMutableArray *)centralM{
    if (!_centralM) {
        _centralM=[NSMutableArray array];
    }
    return _centralM;
}

#pragma mark - 私有方法
//创建特征、服务并添加服务到外围设备
-(void)setupService{
    /*1.创建特征*/
    //创建特征的UUID对象
    CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID];
    //特征值
//    NSString *valueStr=kPeripheralName;
//    NSData *value=[valueStr dataUsingEncoding:NSUTF8StringEncoding];
    //创建特征
    /** 参数
     * uuid:特征标识
     * properties:特征的属性,例如:可通知、可写、可读等
     * value:特征值
     * permissions:特征的权限
     */
    CBMutableCharacteristic *characteristicM=[[CBMutableCharacteristic alloc]initWithType:characteristicUUID properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];
    self.characteristicM=characteristicM;
//    CBMutableCharacteristic *characteristicM=[[CBMutableCharacteristic alloc]initWithType:characteristicUUID properties:CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable];
//    characteristicM.value=value;

    /*创建服务并且设置特征*/
    //创建服务UUID对象
    CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID];
    //创建服务
    CBMutableService *serviceM=[[CBMutableService alloc]initWithType:serviceUUID primary:YES];
    //设置服务的特征
    [serviceM setCharacteristics:@[characteristicM]];


    /*将服务添加到外围设备*/
    [self.peripheralManager addService:serviceM];
}
//更新特征值
-(void)updateCharacteristicValue{
    //特征值
    NSString *valueStr=[NSString stringWithFormat:@"%@ --%@",kPeripheralName,[NSDate   date]];
    NSData *value=[valueStr dataUsingEncoding:NSUTF8StringEncoding];
    //更新特征值
    [self.peripheralManager updateValue:value forCharacteristic:self.characteristicM onSubscribedCentrals:nil];
    [self writeToLog:[NSString stringWithFormat:@"更新特征值:%@",valueStr]];
}
/**
 *  记录日志
 *
 *  @param info 日志信息
 */
-(void)writeToLog:(NSString *)info{
    self.log.text=[NSString stringWithFormat:@"%@\r\n%@",self.log.text,info];
}
@end
B.中央设备
#import "ViewController.h"
#import 
#define kServiceUUID @"C4FB2349-72FE-4CA2-94D6-1F3CB16331EE" //服务的UUID
#define kCharacteristicUUID @"6A3E4B28-522D-4B3B-82A9-D5E2004534FC" //特征的UUID

@interface ViewController ()

@property (strong,nonatomic) CBCentralManager *centralManager;//中心设备管理器
@property (strong,nonatomic) NSMutableArray *peripherals;//连接的外围设备
@property (weak, nonatomic) IBOutlet UITextView *log;//日志记录

@end
@implementation ViewController
#pragma mark - 控制器视图事件
- (void)viewDidLoad {
    [super viewDidLoad];
}

#pragma mark - UI事件
- (IBAction)startClick:(UIBarButtonItem *)sender {
    //创建中心设备管理器并设置当前控制器视图为代理
    _centralManager=[[CBCentralManager alloc]initWithDelegate:self queue:nil];
}

#pragma mark - CBCentralManager代理方法
//中心服务器状态更新后
-(void)centralManagerDidUpdateState:(CBCentralManager *)central{
    switch (central.state) {
        case CBPeripheralManagerStatePoweredOn:
            NSLog(@"BLE已打开.");
            [self writeToLog:@"BLE已打开."];
            //扫描外围设备
//            [central scanForPeripheralsWithServices:@[[CBUUID UUIDWithString:kServiceUUID]] options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
            [central scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
            break;

        default:
            NSLog(@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备.");
            [self writeToLog:@"此设备不支持BLE或未打开蓝牙功能,无法作为外围设备."];
            break;
    }
}
/**
 *  发现外围设备
 *
 *  @param central           中心设备
 *  @param peripheral        外围设备
 *  @param advertisementData 特征数据
 *  @param RSSI              信号质量(信号强度)
 */
-(void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI{
    NSLog(@"发现外围设备...");
    [self writeToLog:@"发现外围设备..."];
    //停止扫描
    [self.centralManager stopScan];
    //连接外围设备
    if (peripheral) {
        //添加保存外围设备,注意如果这里不保存外围设备(或者说peripheral没有一个强引用,无法到达连接成功(或失败)的代理方法,因为在此方法调用完就会被销毁
        if(![self.peripherals containsObject:peripheral]){
            [self.peripherals addObject:peripheral];
        }
        NSLog(@"开始连接外围设备...");
        [self writeToLog:@"开始连接外围设备..."];
        [self.centralManager connectPeripheral:peripheral options:nil];
    }

}
//连接到外围设备
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
    NSLog(@"连接外围设备成功!");
    [self writeToLog:@"连接外围设备成功!"];
    //设置外围设备的代理为当前视图控制器
    peripheral.delegate=self;
    //外围设备开始寻找服务
    [peripheral discoverServices:@[[CBUUID UUIDWithString:kServiceUUID]]];
}
//连接外围设备失败
-(void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
    NSLog(@"连接外围设备失败!");
    [self writeToLog:@"连接外围设备失败!"];
}

#pragma mark - CBPeripheral 代理方法
//外围设备寻找到服务后
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error{
    NSLog(@"已发现可用服务...");
    [self writeToLog:@"已发现可用服务..."];
    if(error){
        NSLog(@"外围设备寻找服务过程中发生错误,错误信息:%@",error.localizedDescription);
        [self writeToLog:[NSString stringWithFormat:@"外围设备寻找服务过程中发生错误,错误信息:%@",error.localizedDescription]];
    }
    //遍历查找到的服务
    CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID];
    CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID];
    for (CBService *service in peripheral.services) {
        if([service.UUID isEqual:serviceUUID]){
            //外围设备查找指定服务中的特征
            [peripheral discoverCharacteristics:@[characteristicUUID] forService:service];
        }
    }
}
//外围设备寻找到特征后
-(void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error{
    NSLog(@"已发现可用特征...");
    [self writeToLog:@"已发现可用特征..."];
    if (error) {
        NSLog(@"外围设备寻找特征过程中发生错误,错误信息:%@",error.localizedDescription);
        [self writeToLog:[NSString stringWithFormat:@"外围设备寻找特征过程中发生错误,错误信息:%@",error.localizedDescription]];
    }
    //遍历服务中的特征
    CBUUID *serviceUUID=[CBUUID UUIDWithString:kServiceUUID];
    CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID];
    if ([service.UUID isEqual:serviceUUID]) {
        for (CBCharacteristic *characteristic in service.characteristics) {
            if ([characteristic.UUID isEqual:characteristicUUID]) {
                //情景一:通知
                /*找到特征后设置外围设备为已通知状态(订阅特征):
                 *1.调用此方法会触发代理方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
                 *2.调用此方法会触发外围设备的订阅代理方法
                 */
                [peripheral setNotifyValue:YES forCharacteristic:characteristic];
                //情景二:读取
//                [peripheral readValueForCharacteristic:characteristic];
//                    if(characteristic.value){
//                    NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding];
//                    NSLog(@"读取到特征值:%@",value);
//                }
            }
        }
    }
}
//特征值被更新后
-(void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    NSLog(@"收到特征更新通知...");
    [self writeToLog:@"收到特征更新通知..."];
    if (error) {
        NSLog(@"更新通知状态时发生错误,错误信息:%@",error.localizedDescription);
    }
    //给特征值设置新的值
    CBUUID *characteristicUUID=[CBUUID UUIDWithString:kCharacteristicUUID];
    if ([characteristic.UUID isEqual:characteristicUUID]) {
        if (characteristic.isNotifying) {
            if (characteristic.properties==CBCharacteristicPropertyNotify) {
                NSLog(@"已订阅特征通知.");
                [self writeToLog:@"已订阅特征通知."];
                return;
            }else if (characteristic.properties ==CBCharacteristicPropertyRead) {
                //从外围设备读取新值,调用此方法会触发代理方法:-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
                [peripheral readValueForCharacteristic:characteristic];
            }

        }else{
            NSLog(@"停止已停止.");
            [self writeToLog:@"停止已停止."];
            //取消连接
            [self.centralManager cancelPeripheralConnection:peripheral];
        }
    }
}
//更新特征值后(调用readValueForCharacteristic:方法或者外围设备在订阅后更新特征值都会调用此代理方法)
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
    if (error) {
        NSLog(@"更新特征值时发生错误,错误信息:%@",error.localizedDescription);
        [self writeToLog:[NSString stringWithFormat:@"更新特征值时发生错误,错误信息:%@",error.localizedDescription]];
        return;
    }
    if (characteristic.value) {
        NSString *value=[[NSString alloc]initWithData:characteristic.value encoding:NSUTF8StringEncoding];
        NSLog(@"读取到特征值:%@",value);
        [self writeToLog:[NSString stringWithFormat:@"读取到特征值:%@",value]];
    }else{
        NSLog(@"未发现特征值.");
        [self writeToLog:@"未发现特征值."];
    }
}

#pragma mark - 属性
-(NSMutableArray *)peripherals{
   if(!_peripherals){
       _peripherals=[NSMutableArray array];
   }
   return _peripherals;
}

#pragma mark - 私有方法
/**
 *  记录日志
 *
 *  @param info 日志信息
 */
-(void)writeToLog:(NSString *)info{
    self.log.text=[NSString stringWithFormat:@"%@\r\n%@",self.log.text,info];
}

@end

上面程序运行的流程图如下:

外围设备.png
上一篇 下一篇

猜你喜欢

热点阅读