IOS 鏈接多個藍牙設備,收發數據

這段時間一直在做關于藍牙的項目,有點心得,拿出來和大家分享下。希望對大家有幫助,廢話不多說。直接上代碼

屏幕快照 2016-08-05 下午8.11.17.png

首先,我在ViewController這個類中主要做的是藍牙的搜索,鏈接,及斷開。在LinkViewController這個類中,設置藍牙外設的代理人,打開訂閱的通道,給外設發數據。(我這個藍牙是一問一答模式)leftView和rightView分別是作為兩個藍牙的代理人,來設置寫入特征和訂閱特征并且接收藍牙數據

下面代碼中的全局實例對象cell僅是為了在tableView中展示的時候區別鏈接與未鏈接。
#import "ViewController.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import "LinkViewController.h"

@interface ViewController ()<CBCentralManagerDelegate,UITableViewDelegate,UITableViewDataSource>
{
UITableViewCell *cell;
}

@property (nonatomic,strong ) CBCentralManager *manager;// 中心設備
@property (nonatomic,strong ) NSMutableArray   *devices;// 掃描到的外圍設備
@property (nonatomic, strong) NSMutableArray   *connectSuccess;//鏈接成功的的外設
@property (weak, nonatomic  ) IBOutlet UITableView      *tableView;

@end

在ViewDidLoad中對中心設備及可變數據進行初始化。
- (void)viewDidLoad {
cell = [[UITableViewCell alloc] init];
[super viewDidLoad];
self.manager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
self.devices = [NSMutableArray array];
self.connectSuccess = [NSMutableArray array];
self.tableView.delegate = self;
self.tableView.dataSource = self;
}
下面代碼是掃描外設以及停止掃描
- (IBAction)startScan:(id)sender {
//掃描外設
[self.manager scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey:@YES}];
//3秒后停止。(開啟掃描后會不停的掃描)
[self performSelector:@selector(stopScan) withObject:nil afterDelay:3];
}
/**
* 停止掃描
*/
-(void)stopScan{
[self.manager stopScan];
}
藍牙的代理(藍牙的狀態改變的代理,掃描外設的代理,連接成功,失敗,以及斷開藍牙的代理)
#pragma mark - 藍牙的代理事件
//中心設備狀態改變的代理必須實現
- (void)centralManagerDidUpdateState: (CBCentralManager *)central
{
switch (central.state)
{
case CBCentralManagerStatePoweredOn:
// [self showInfo:@"藍牙已打開"];
break;
case CBCentralManagerStateUnknown:
// [self showInfo:@"藍牙 狀態位置"];
break;
case CBCentralManagerStatePoweredOff:
// [self showInfo:@"藍牙未打開"];
break;
case CBCentralManagerStateResetting:
// [self showInfo:@"藍牙初始化中"];
break;
case CBCentralManagerStateUnsupported:
// [self showInfo:@"藍牙不支持狀態"];
break;
case CBCentralManagerStateUnauthorized:
// [self showInfo:@"藍牙設備未授權"];
break;
default:
break;
}
}

/**
 *  掃描藍牙的代理
 *
 *  @param central           中心設備
 *  @param peripheral        掃描到的藍牙
 *  @param advertisementData 在ios中藍牙廣播信息中通常會包含以下4種類型的信息。ios的藍牙通信協議中不接受其他類型的廣播信息。
                         因此需要注意的是,如果需要在掃描設備時,通過藍牙設備的Mac地址來唯一辨別設備,那么需要與藍牙設備的硬件工程師溝通好:將所需要的Mac地址放到一下幾種類型的廣播信息中。
                         通常放到kCBAdvDataManufacturerData這個字段中。
        kCBAdvDataIsConnectable = 1;
        kCBAdvDataLocalName = XXXXXX;
        kCBAdvDataManufacturerData = <XXXXXXXX>;
        kCBAdvDataTxPowerLevel = 0;
 *  @param RSSI              信號強度
 */
//掃描到的藍牙設備添加到devices數組中,刷新列表
-(void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary<NSString *,id> *)advertisementData
             RSSI:(NSNumber *)RSSI{

if (![self.devices containsObject:peripheral]) {
    [self.devices addObject:peripheral];
    [self.tableView reloadData];
    NSLog(@"發現外圍設備:%@---RSSI:%@---advertisementData:%@",peripheral,RSSI,advertisementData);
}
}

在表格的點擊代理中去連接外設

-(void)tableView:(UITableView *)tableView       didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
[self.manager connectPeripheral:self.devices[indexPath.row] options:nil];
cell = [tableView cellForRowAtIndexPath:indexPath];
}

藍牙連接的代理

/**
 *  藍牙連接成功時候的代理
 *
 *  @param central    中心設備
 *  @param peripheral 當前連接的設備
 */
-(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral{
NSLog(@"%@名字的藍牙連接成功",peripheral.name);
cell.detailTextLabel.text = @"已連接";
[self.connectSuccess addObject:peripheral];
}
/**
 *  藍牙鏈接失敗的代理
 *
 *  @param central    中心設備
 *  @param peripheral 當前連接的外設
 *  @param error      錯誤信息
 */
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error;{
   NSLog(@"%@名字的藍牙連接失敗",peripheral.name); 
}

cell左劃斷開藍牙連接,這里的cell.detailTextLabel.text在連接成功,和斷開成功的時候進行設置,區分。

-(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell2 = [tableView cellForRowAtIndexPath:indexPath];
if ([cell2.detailTextLabel.text isEqualToString:@"已連接"]) {
    return YES;
}
return NO;
}

- (NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath{
cell = [tableView cellForRowAtIndexPath:indexPath];

UITableViewRowAction *disconnect = [UITableViewRowAction rowActionWithStyle:1 title:@"斷開連接" handler:^(UITableViewRowAction * _Nonnull action, NSIndexPath * _Nonnull indexPath) {
    //斷開藍牙連接
    CBPeripheral *peripheral = self.devices[indexPath.row];
    [self.manager cancelPeripheralConnection:peripheral];
    [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
}];
return @[disconnect];
}

藍牙斷開連接的代理

/**
 *  藍牙斷開連接的代理
 *
 *  @param central    中心設備
 *  @param peripheral 當前需要斷開連接的外設
 *  @param error      錯誤信息
 */
-(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error{
NSLog(@"%@名字的藍牙斷開鏈接",peripheral.name);
cell.detailTextLabel.text = @"";
for (CBPeripheral *p in self.connectSuccess) {
    if ([p.identifier.UUIDString isEqualToString:peripheral.identifier.UUIDString]) {
        [self.connectSuccess removeObject:p];
    }
}
}

以上就是藍牙的掃描,連接,斷開

最后跳轉到LinkViewController頁面,并且把連接成功的外設傳遞過去,這里我就不把外設一一對應了。
#pragma mark - 跳轉
- (IBAction)gotoLink:(id)sender {
LinkViewController *link = [[LinkViewController alloc] init];
if (self.connectSuccess.count > 0) {
for (int i = 0; i < self.connectSuccess.count; i++) {
CBPeripheral *p = self.connectSuccess[i];
if (i == 0) {
link.leftperipheral = p;
}
if (i == 1) {
link.rightperipheral = p;
}
}
[self.navigationController pushViewController:link animated:YES];
}
}

這里我們將進行的是藍牙的收發數據

leftView和rightView分別對應一個藍牙的代理人。這里我就展示一個。另外一個也是同樣的操作

leftView.h文件中。textView只是用來展示接收到的藍牙數據,mutStr存放接收到藍牙數據
#import <UIKit/UIKit.h>
#import <CoreBluetooth/CoreBluetooth.h>
@interface leftView : UIView<CBPeripheralDelegate>
@property (nonatomic, strong) UITextView *textView;
@property (nonatomic, strong) CBCharacteristic *leftNotiC, *leftWriteC;
@property (nonatomic, strong) NSMutableString *mutStr;
@end
leftView.m文件

#import "leftView.h"
//這里是和硬件工程師溝通好訂閱與寫入的服務通道
#define leftNotiService @"FFE0"
#define leftWriteService @"FFE5"

@implementation leftView
//重寫init方法
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
    self.mutStr = [NSMutableString string];
    [self addTextView];
}
return self;
}
//添加textView
-(void)addTextView{
self.textView = [[UITextView alloc] initWithFrame:self.bounds];
self.textView.backgroundColor = [UIColor lightGrayColor];
[self addSubview:self.textView];
}


#pragma mark - 外圍設備服務的代理
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(NSError *)error
{

for (CBService *s in peripheral.services) {
    NSLog(@"%@",[s.UUID UUIDString]);
    if ([[s.UUID UUIDString] isEqualToString:@"FFE0"]) {
        [peripheral discoverCharacteristics:nil forService:s];
    }
    if ([[s.UUID UUIDString] isEqualToString:@"FFE5"]) {
        [peripheral discoverCharacteristics:nil forService:s];
    }
}
}
#pragma mark 2. 外圍設備 掃描到服務下有哪些特征
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(nonnull CBService *)service error:(nullable NSError *)error
{
if ([[service.UUID UUIDString] isEqualToString:@"FFE0"]) {
    //這里也需要個硬件工程師溝通好。
    self.leftNotiC = service.characteristics[0];
}
if ([[service.UUID UUIDString] isEqualToString:@"FFE5"]) {
    self.leftWriteC = service.characteristics[0];
}
}

#pragma mark 3.接收外圍設備的數據(這里就能接到藍牙發送過來的數據,具體協議就要看你們是怎么定義的)
-(void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error{
NSData *testData           = characteristic.value;
Byte *testByte             = (Byte *)[testData bytes];
NSMutableArray *midArray   = [NSMutableArray array];
for(int i                  = 0;i<[testData length];i++){
    [midArray addObject:[NSString stringWithFormat:@"%d",testByte[i]]];
    }

for (NSString *str in midArray) {
    [_mutStr appendString:str];
    [_mutStr appendString:@","];
}
self.textView.text = self.mutStr;

}
LinkViewController.m文件中

- (void)viewDidLoad {
[super viewDidLoad];
[self setUI];
//發現左邊外設的服務 (運行到這個方法會進入leftView.m文件中的外圍設備服務的代理)
[self.leftperipheral discoverServices:nil];
//發現右邊外設的服務
[self.rightperipheral discoverServices:nil];
}
-(void)setUI{
self.l = [[leftView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, 200)];
[self.view addSubview:_l];
//設置代理人。這個很重要
self.leftperipheral.delegate = _l;

self.r = [[rightView alloc] initWithFrame:CGRectMake(0, 284, [UIScreen mainScreen].bounds.size.width, 200)];
[self.view addSubview:_r];
//設置代理人。這個很重要
self.rightperipheral.delegate = _r;
}
- (IBAction)writeData:(id)sender {
//打開通道
[self.leftperipheral setNotifyValue:YES forCharacteristic:_l.leftNotiC];
[self.leftperipheral writeValue:[self hexToBytes:@"a55a03010003"] forCharacteristic:_l.leftWriteC type:1];
//打開通道
[self.rightperipheral setNotifyValue:YES forCharacteristic:_r.rightNotiC];
[self.rightperipheral writeValue:[self hexToBytes:@"a55a03010003"] forCharacteristic:_r.rightWriteC type:1];
//這里我們的工程師定義為 給外設發送@"a55a03010003"的字節數組。藍牙就會給我發送對應的數據。
_l.mutStr = [NSMutableString string];
_r.mutStr = [NSMutableString string];
}

//字符串改為字節數組,需要轉換的字符串也是與硬件工程師溝通好的
- (NSData *)hexToBytes:(NSString *)str{
NSMutableData* data = [NSMutableData data];
int idx;
for (idx = 0; idx+2 <= str.length; idx+=2) {
    NSRange range = NSMakeRange(idx, 2);
    NSString* hexStr = [str substringWithRange:range];
    NSScanner* scanner = [NSScanner scannerWithString:hexStr];
    unsigned int intValue;
    [scanner scanHexInt:&intValue];
    [data appendBytes:&intValue length:1];
}
return data;
}

以上就是IOS 鏈接兩個設備的操作。希望可以幫助到剛接觸到藍牙的IOS攻城獅。如果喜歡請不吝點擊下喜歡。
這是本人第一次寫文章,如有哪里不對請給我寶貴的意見。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 原文:http://www.myexception.cn/operating-system/2052286.htm...
    KYM1988閱讀 1,983評論 2 2
  • 備注:下面說到的內容都基于藍牙4.0標準以上,主要以實踐為主。 ~ CoreBluetooth.framework...
    未_漆小七閱讀 1,649評論 1 8
  • 藍牙 藍牙的波段為2400-2483.5MHz(包括防護頻帶)。這是全球范圍內無需取得執照(但定不是無管制的)的工...
    蘇永茂閱讀 6,280評論 0 11
  • 本文主要以藍牙4.0做介紹,因為現在iOS能用的藍牙也就是只僅僅4.0的設備 用的庫就是core bluetoot...
    暮雨飛煙閱讀 857評論 0 2
  • 每天打給妻子的電話,基本上是努爾接聽。昨晚突發奇想,十點估計她睡著了,再打,妻子順利接聽。 今晨,想到白天給努爾打...
    兩個女兒的爸爸閱讀 701評論 7 2