似乎这个问题被“回答”了
here,但没有任何代码来表明他们做了不同的事情,我不得不问一个新问题.
我有自己的代码具有相同的行为,在OS X上使用Core Bluetooth的CBCentralManager扫描特定的CBUUID并没有发现一个iOS设备充当CBPeripheralManager的外围设备(除非它及其服务先前已被发现).为了查看我的代码是否有问题,我下载了Apple’s sample code.在两台iOS设备上运行示例代码按预期工作,但是当将CBCentralManager代码复制到OS X应用程序时,它无法找到iOS设备.
我已经为OS X应用程序上传了一个Xcode项目,它是hosted on WikiUpload,因为它似乎是最不狡猾的.如果人们愿意,还有a copy on my hosting.
这是OS X项目中的AppDelegate.m代码(CoreBluetooth框架在项目中链接):
#import <CoreBluetooth/CoreBluetooth.h>
@interface AppDelegate () <CBCentralManagerDelegate,CBPeripheralDelegate>
@property (strong,nonatomic) CBCentralManager *centralManager;
@property (strong,nonatomic) CBPeripheral *discoveredPeripheral;
@property (strong,nonatomic) NSMutableData *data;
@property (weak) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
@synthesize centralManager = _centralManager,discoveredPeripheral = _discoveredPeripheral,data = _data;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
// Start up the CBCentralManager
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
// And somewhere to store the incoming data
_data = [[NSMutableData alloc] init];
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
#pragma mark - Central Methods
/** centralManagerDidUpdateState is a required protocol method.
* Usually,you'd check for other states to make sure the current device supports LE,is powered on,etc.
* In this instance,we're just using it to wait for CBCentralManagerStatePoweredOn,which indicates
* the Central is ready to be used.
*/
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if (central.state != CBCentralManagerStatePoweredOn) {
// In a real app,you'd deal with all the states correctly
return;
}
// The state must be CBCentralManagerStatePoweredOn...
// ... so start scanning
[self scan];
}
/** Scan for peripherals - specifically for our service's 128bit CBUUID
*/
- (void)scan
{
// This brings up nothing,unlike on iOS where it finds the device straight away
[self.centralManager scanForperipheralsWithServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]
options:@{ CBCentralManagerScanoptionAllowDuplicatesKey : @YES }];
// [self.centralManager scanForperipheralsWithServices:nil
// options:@{ CBCentralManagerScanoptionAllowDuplicatesKey : @YES }];
NSLog(@"Scanning started");
}
/** This callback comes whenever a peripheral that is advertising the TRANSFER_SERVICE_UUID is discovered.
* We check the RSSI,to make sure it's close enough that we're interested in it,and if it is,* we start the connection process
*/
- (void)centralManager:(CBCentralManager *)central diddiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
NSLog(@"discovered %@ at %@",peripheral.name,RSSI);
//Took out RSSI check
if (self.discoveredPeripheral != peripheral) {
// Save a local copy of the peripheral,so CoreBluetooth doesn't get rid of it
self.discoveredPeripheral = peripheral;
// And connect
NSLog(@"Connecting to peripheral %@",peripheral);
[self.centralManager connectPeripheral:peripheral options:nil];
}
}
/** If the connection fails for whatever reason,we need to deal with it.
*/
- (void)centralManager:(CBCentralManager *)central didFailToConnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"Failed to connect to %@. (%@)",peripheral,[error localizedDescription]);
[self cleanup];
}
/** We've connected to the peripheral,Now we need to discover the services and characteristics to find the 'transfer' characteristic.
*/
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral
{
NSLog(@"Peripheral Connected");
// Stop scanning
[self.centralManager stopScan];
NSLog(@"Scanning stopped");
// Clear the data that we may already have
[self.data setLength:0];
// Make sure we get the discovery callbacks
peripheral.delegate = self;
// Search only for services that match our UUID
[peripheral discoverServices:@[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]]];
}
/** The Transfer Service was discovered
*/
- (void)peripheral:(CBPeripheral *)peripheral diddiscoverServices:(NSError *)error
{
if (error) {
NSLog(@"Error discovering services: %@",[error localizedDescription]);
[self cleanup];
return;
}
// discover the characteristic we want...
// Loop through the newly filled peripheral.services array,just in case there's more than one.
for (CBService *service in peripheral.services) {
[peripheral discovercharacteristics:@[[CBUUID UUIDWithString:TRANSFER_CHaraCTERISTIC_UUID]] forService:service];
}
}
/** The Transfer characteristic was discovered.
* Once this has been found,we want to subscribe to it,which lets the peripheral kNow we want the data it contains
*/
- (void)peripheral:(CBPeripheral *)peripheral diddiscovercharacteristicsForService:(CBService *)service error:(NSError *)error
{
// Deal with errors (if any)
if (error) {
NSLog(@"Error discovering characteristics: %@",[error localizedDescription]);
[self cleanup];
return;
}
// Again,we loop through the array,just in case.
for (CBCharacteristic *characteristic in service.characteristics) {
// And check if it's the right one
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHaraCTERISTIC_UUID]]) {
// If it is,subscribe to it
[peripheral setNotifyValue:YES forCharacteristic:characteristic];
}
}
// Once this is complete,we just need to wait for the data to come in.
}
/** This callback lets us kNow more data has arrived via notification on the characteristic
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(@"Error discovering characteristics: %@",[error localizedDescription]);
return;
}
Nsstring *stringFromData = [[Nsstring alloc] initWithData:characteristic.value encoding:NSUTF8StringEncoding];
// Have we got everything we need?
if ([stringFromData isEqualToString:@"EOM"]) {
// We have,so show the data,//[self.textview setText:[[Nsstring alloc] initWithData:self.data encoding:NSUTF8StringEncoding]];
NSLog(@"Text: %@",[[Nsstring alloc] initWithData:self.data encoding:NSUTF8StringEncoding]);
// Cancel our subscription to the characteristic
[peripheral setNotifyValue:NO forCharacteristic:characteristic];
// and disconnect from the peripehral
[self.centralManager cancelPeripheralConnection:peripheral];
}
// Otherwise,just add the data on to what we already have
[self.data appendData:characteristic.value];
// Log it
NSLog(@"Received: %@",stringFromData);
}
/** The peripheral letting us kNow whether our subscribe/unsubscribe happened or not
*/
- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error
{
if (error) {
NSLog(@"Error changing notification state: %@",error.localizedDescription);
}
// Exit if it's not the transfer characteristic
if (![characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHaraCTERISTIC_UUID]]) {
return;
}
// Notification has started
if (characteristic.isnotifying) {
NSLog(@"Notification began on %@",characteristic);
}
// Notification has stopped
else {
// so disconnect from the peripheral
NSLog(@"Notification stopped on %@. disconnecting",characteristic);
[self.centralManager cancelPeripheralConnection:peripheral];
}
}
/** Once the disconnection happens,we need to clean up our local copy of the peripheral
*/
- (void)centralManager:(CBCentralManager *)central diddisconnectPeripheral:(CBPeripheral *)peripheral error:(NSError *)error
{
NSLog(@"Peripheral disconnected");
self.discoveredPeripheral = nil;
// We're disconnected,so start scanning again
[self scan];
}
/** Call this when things either go wrong,or you're done with the connection.
* This cancels any subscriptions if there are any,or straight disconnects if not.
* (didUpdateNotificationStateForCharacteristic will cancel the connection if a subscription is involved)
*/
- (void)cleanup
{
// Don't do anything if we're not connected
if (!self.discoveredPeripheral.isConnected) {
return;
}
// See if we are subscribed to a characteristic on the peripheral
if (self.discoveredPeripheral.services != nil) {
for (CBService *service in self.discoveredPeripheral.services) {
if (service.characteristics != nil) {
for (CBCharacteristic *characteristic in service.characteristics) {
if ([characteristic.UUID isEqual:[CBUUID UUIDWithString:TRANSFER_CHaraCTERISTIC_UUID]]) {
if (characteristic.isnotifying) {
// It is notifying,so unsubscribe
[self.discoveredPeripheral setNotifyValue:NO forCharacteristic:characteristic];
// And we're done.
return;
}
}
}
}
}
}
// If we've got this far,we're connected,but we're not subscribed,so we just disconnect
[self.centralManager cancelPeripheralConnection:self.discoveredPeripheral];
}
在AppDelegate.h中有UUID定义:
#ifndef LE_Transfer_TransferService_h #define LE_Transfer_TransferService_h #define TRANSFER_SERVICE_UUID @"E20A39F4-73F5-4BC4-A12F-17D1AD07A961" #define TRANSFER_CHaraCTERISTIC_UUID @"08590F7E-DB05-467E-8757-72F6FAEB13D4" #endif
这有什么问题?根据上面的链接问题,服务必须是广告包的一部分,但据我所知,这正是iOS外设正在做的事情
[self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }];
解决方法
CoreBluetooth可能非常令人沮丧.这里有几件事要尝试:
#1:已连接的外围设备停止广告.如果您成功连接到外围设备,则需要重新开始广告.
#2:iOS缓存已发现状态和提供的服务.没有编程方式来刷新/清除缓存.尝试在iOS设备和Mac上禁用BT并重新启用它.然后尝试另一个连接.
#3:您的UUID存在问题.尝试扫描UUID参数设置为nil的外围设备.然后,您应该发现范围内的所有外围设备.
#4:如果Wifi打开,Mac上的BT连接可能很挑剔.尝试在Mac上禁用Wifi,然后重试.我发现BTLE在启用Wifi时完全无法使用,因此我在MacBook上执行任何BTLE开发时都必须使用以太网.