ios - 扫描特定 CBUUID 时,Core Bluetooth 未找到外围设备

标签 ios objective-c macos cocoa core-bluetooth

看来这个问题已经“回答”了here ,但没有任何代码来显示他们做了什么不同我不得不问一个新问题。

我自己的代码具有相同的行为,其中在 OS X 上使用 Core Bluetooth 的 CBCentralManager 扫描特定 CBUUID 不会发现充当 CBPeripheralManager 外围设备的 iOS 设备(除非它及其服务之前已被发现)。为了查看我的代码是否有问题,我下载了 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 开发时我不得不使用以太网。

关于ios - 扫描特定 CBUUID 时,Core Bluetooth 未找到外围设备,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28280025/

相关文章:

ios - appDelegate 没有名为 'PlayerName' 的成员

ios - 从应用程序向 Whatsapp 上的用户发送消息,无需打开 Whatsapp

ios - 应用程序委托(delegate)之前 NSURL 上的 NSInvalidArgumentException

ios - SceneKit 在移动相机时遇到测试错误

iphone - 在 iPhone 中完全加载之前获取图像宽度和高度

objective-c - slider 上的值绑定(bind)无法正确更新

ios - 无法与 iCloud 同步简单文本文件(文件描述符错误)

c++ - 使用 MacPorts 安装 GCC 4.9 调试符号错误?

c++ - 如何更改 Amazon kinesis_video_gstreamer_sample_app.cpp 中的视频源?

ios - 直播应用 iOS