CoreBluetooth For Central (4)
Connect BLE Device
承前面Discover BLE Device所介绍内容,我们修改这个专案更名为BluetoothLE-Connect,这节要完成的项目是从发现装置之后,符合自已设定的周边名称后就自动连线至周边,不过,Xcode的操作细节就不像先前一样做介绍。
取得连线周边的名称
依照之前完成的程式码,当按下Scan
时就可以取得周边讯息,范例如下:
2014-03-31 16:33:48.935 BluetoothLE-Connect[3454:60b] Scan And Connect 2014-03-31 16:33:49.032 BluetoothLE-Connect[3454:60b] peripheral <CBPeripheral: 0x1753d3d0 identifier = 419D6B15-1F6C-EE7B-7751-2748ACA0D7C3, Name = "DannySerialApp", state = disconnected> 2014-03-31 16:33:49.034 BluetoothLE-Connect[3454:60b] advertisementData { kCBAdvDataChannel = 39; kCBAdvDataIsConnectable = 1; kCBAdvDataLocalName = DannySimpleBLE; kCBAdvDataServiceUUIDs = ( FFF0 ); kCBAdvDataTxPowerLevel = 0; } 2014-03-31 16:33:49.036 BluetoothLE-Connect[3454:60b] RSSI -61 2014-03-31 16:33:49.037 BluetoothLE-Connect[3454:60b] localName:DannySimpleBLE
请将这息讯纪录下来,后面要利用这讯息判断周边是否有存在,当存在时就自动进行连线。
Scan And Connect 按键
将ButtonScan
改成Scan And Connect
,这是为了要提示使用者,但实际上按下后只有Scan的动作,Connect是在Delegate才会进行,程式码还是不变,只在最前面加上Stop的动作,避免使用者连续按下时会无法重复的Scan。
//-----------start----------- - (IBAction)buttonScanAndConnect:(id)sender { [CM stopScan]; [CM scanForPeripheralsWithServices:nil options:nil]; NSLog(@"Scan And Connect"); } //------------end------------
外观UI变更为:
Scan执行之后就会引发didDiscoverPeripheral
,其中的连线是在这处理的,我们继续看下去。
Stop And Disconnect 按键
Button改成Stop and Disconnect
,按下之后会停止 Scan动作以及将已连线动作断线,原先的程式:
//-----------start----------- - (IBAction)buttonStop:(id)sender { [CM stopScan]; NSLog(@"stopScan"); } //------------end------------
我们连线后会将连线的CBPeripheral
物件传至connectPeripheral
,所以在按下时能够使用物件的方法去执行断线的动作,当未指定时connectPeripheral = NULL
,不需要执行断线命令,将这段判断加入:
//-----------start----------- if (connectPeripheral == NULL){ NSLog(@"connectPeripheral == NULL"); return; } //------------end------------
接下来再加入断线的动作,在动作之前先判断是否已经连线,但判断是否已连线的状态在iOS7之后有作变更:
- iOS7
//-----------start----------- if (connectPeripheral.state == CBPeripheralStateConnected) { [CM cancelPeripheralConnection:connectPeripheral]; NSLog(@"disconnect-1"); } //------------end------------
使用state
方法取得状态,状态分为:
CBPeripheralStateDisconnected CBPeripheralStateConnecting CBPeripheralStateConnected
- iOS6
//-----------start----------- if ([connectPeripheral isConnected]) { [CM cancelPeripheralConnection:connectPeripheral]; NSLog(@"disconnect-1"); } //------------end------------
外观UI变更为:
UI外观都已经完成,后面就会开始加入连线需要的程式码。
连线指定的周边
Scan蓝牙的周边时就会引发didDiscoverPeripheral
的Delegate,发现多少周边就会不断的重复执行 didDiscoverPeripheral
,我们要在这个情况下,对每个周边进行比对,如果比对是指定要连线的周边就会进行连线,否则程式就不理会。看一下原先的didDiscoverPeripheral
程式码:
//-----------start----------- - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { NSLog(@"peripheral\n%@\n",peripheral); NSLog(@"advertisementData\n%@\n",advertisementData); NSLog(@"RSSI\n%@\n",RSSI); } //------------end------------
我们利用advertisementData
资料中的CBAdvertisementDataLocalNameKey
取得的周边连线名称来判断周边是否存在,从刚的资料得到:
2014-03-31 16:33:49.034 BluetoothLE-Connect[3454:60b] advertisementData { kCBAdvDataChannel = 39; kCBAdvDataIsConnectable = 1; kCBAdvDataLocalName = DannySimpleBLE; kCBAdvDataServiceUUIDs = ( FFF0 ); kCBAdvDataTxPowerLevel = 0; }
CBAdvertisementDataLocalNameKey
取得的就是列表中的kCBAdvDataLocalName
内容,结果就是DannySimpleBLE
kCBAdvDataLocalName = DannySimpleBLE;
使用NSString的rangeOfString
来比对字串内容是否相同,判断的程式为:
//-----------start----------- if ([localName length] && [localName rangeOfString:@"DannySimpleBLE"].location != NSNotFound) { : : } //------------end------------
最后,我们加入一些判断需不需要连线至周边的程式码就会是下面的内容:
//-----------start----------- NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; NSLog(@"localName:%@",localName); if ([localName length] && [localName rangeOfString:@"DannySimpleBLE"].location != NSNotFound) { //抓到周边后就立即停子Scan [CM stopScan]; NSLog(@"stopScan"); connectPeripheral = peripheral; [CM connectPeripheral:peripheral options:nil]; NSLog(@"connect to %@",peripheral.name); } //------------end------------
其实确定连线时,会将目前连线的CBPeripheral
指定至connectPeripheral
,配合按下Stop and Disconnect
,整个程式码修改成:
//-----------start----------- - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI { NSLog(@"peripheral\n%@\n",peripheral); NSLog(@"advertisementData\n%@\n",advertisementData); NSLog(@"RSSI\n%@\n",RSSI); NSString *localName = [advertisementData objectForKey:CBAdvertisementDataLocalNameKey]; NSLog(@"localName:%@",localName); if ([localName length] && [localName rangeOfString:@"DannySimpleBLE"].location != NSNotFound) { //抓到周边后就立即停止Scan [CM stopScan]; NSLog(@"stopScan"); connectPeripheral = peripheral; [CM connectPeripheral:peripheral options:nil]; NSLog(@"connect to %@",peripheral.name); } } //------------end------------
是否已连线至周边
已连线、已断线一旦发生时就会引发2个Delegate,直接看程式内容。
已连线
//-----------start----------- -(void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral { NSLog(@"%@",@"connected"); } //------------end------------
已断线
//-----------start----------- -(void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error { NSLog(@"%@",@"disconnect-2"); } //------------end------------
所以程式增加了已连线 与 已断线 状态显示于Debug中,在这部分也都完成这次范例程式的解说。
执行范例程式
我们将范例程式执行之后,按下选单的Scan and Connect
,接下来看一下Debug视窗会看到讯息。
下面为输出的讯息结果:
图片字太小的话,下面是文字讯息:
2014-03-31 17:25:59.000 BluetoothLE-Connect[3465:60b] UpdateState:PoweredOn 2014-03-31 17:26:02.021 BluetoothLE-Connect[3465:60b] Scan And Connect 2014-03-31 17:26:02.115 BluetoothLE-Connect[3465:60b] peripheral <CBPeripheral: 0x15559e00 identifier = 419D6B15-1F6C-EE7B-7751-2748ACA0D7C3, Name = "DannySerialApp", state = disconnected> 2014-03-31 17:26:02.118 BluetoothLE-Connect[3465:60b] advertisementData { kCBAdvDataChannel = 39; kCBAdvDataIsConnectable = 1; kCBAdvDataLocalName = DannySimpleBLE; kCBAdvDataServiceUUIDs = ( FFF0 ); kCBAdvDataTxPowerLevel = 0; } 2014-03-31 17:26:02.120 BluetoothLE-Connect[3465:60b] RSSI -61 2014-03-31 17:26:02.121 BluetoothLE-Connect[3465:60b] localName:DannySimpleBLE 2014-03-31 17:26:02.123 BluetoothLE-Connect[3465:60b] stopScan 2014-03-31 17:26:02.125 BluetoothLE-Connect[3465:60b] connect to DannySerialApp 2014-03-31 17:26:02.224 BluetoothLE-Connect[3465:60b] connected
结果中能看到在程式中的connected
的Debug讯息,当我们按下按键上的Stop And Disconnect
,就会立即断线
Debug讯息看到在Button中提示disconnect-1
及在didDisconnectPeripheral
中的disconnect-2
提示出现,也就是当我们执行断线cancelPeripheralConnection
时就会引发Delegate让开发者可以在断线时做一些程式的处理逻辑。
额外说明
程式执行时,如果您需要再利用Deubg讯息观看Scan所有周边的结果,我们Scan and Connect
程式内容修改一下:
//-----------start----------- if ([localName length] && [localName rangeOfString:@"DannySimpleBLE"].location != NSNotFound) { //------------end------------
修改成
//-----------start----------- if ([localName length] && [localName rangeOfString:@""].location != NSNotFound) { //------------end------------
将比对的名称改成空白,使比对条件不符合就能列出所有已Scan到的BLE周边。