Obj- c: ядро ​​Bluetooth - API MISUSE: может только принять эту команду, находясь во включенном состоянии? - PullRequest
0 голосов
/ 02 февраля 2020

Я настраиваю Периферийное устройство и его контроллеры просмотра для отправки данных Bluetooth - по какой-то причине при запуске приложения я получаю следующую ошибку:

[CoreBluetooth] API MISUSE: может принимать эту команду только во включенном состоянии

Не знаю, почему это происходит. Bluetooth включен, и мой код отображается в правильном порядке.

ViewController.m

 - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.


        _peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];

        [_peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }];



    }

    - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {

        if (peripheral.state == CBManagerStatePoweredOn) {


            self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];

            CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] primary:YES];

            transferService.characteristics = @[_transferCharacteristic];

            [_peripheralManager addService:transferService];
        }

       if (peripheral.state != CBManagerStatePoweredOn) {

            return;
        }


    }


- (void)peripheralManager:(CBPeripheralManager *)peripheral central:(CBCentral *)central didSubscribeToCharacteristic:(CBCharacteristic *)characteristic {

    _dataToSend = [_textView.text dataUsingEncoding:NSUTF8StringEncoding];

    _sendDataIndex = 0;

    [self sendData];
}

- (void)sendData {

    static BOOL sendingEOM = NO;

    // end of message?
    if (sendingEOM) {
        BOOL didSend = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];

        if (didSend) {
            // It did, so mark it as sent
            sendingEOM = NO;
        }
        // didn't send, so we'll exit and wait for peripheralManagerIsReadyToUpdateSubscribers to call sendData again
        return;
    }

    // We're sending data
    // Is there any left to send?
    if (self.sendDataIndex >= self.dataToSend.length) {
        // No data left.  Do nothing
        return;
    }

    // There's data left, so send until the callback fails, or we're done.
    BOOL didSend = YES;

    while (didSend) {
        // Work out how big it should be
        NSInteger amountToSend = self.dataToSend.length - self.sendDataIndex;

        // Can't be longer than 20 bytes
        if (amountToSend > NOTIFY_MTU) amountToSend = NOTIFY_MTU;

        // Copy out the data we want
        NSData *chunk = [NSData dataWithBytes:self.dataToSend.bytes+self.sendDataIndex length:amountToSend];

        didSend = [self.peripheralManager updateValue:chunk forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];

        // If it didn't work, drop out and wait for the callback
        if (!didSend) {
            return;
        }

        NSString *stringFromData = [[NSString alloc] initWithData:chunk encoding:NSUTF8StringEncoding];
        NSLog(@"Sent: %@", stringFromData);

        // It did send, so update our index
        self.sendDataIndex += amountToSend;

        // Was it the last one?
        if (self.sendDataIndex >= self.dataToSend.length) {

            // Set this so if the send fails, we'll send it next time
            sendingEOM = YES;

            BOOL eomSent = [self.peripheralManager updateValue:[@"EOM" dataUsingEncoding:NSUTF8StringEncoding] forCharacteristic:self.transferCharacteristic onSubscribedCentrals:nil];

            if (eomSent) {
                // It sent, we're all done
                sendingEOM = NO;
                NSLog(@"Sent: EOM");
            }

            return;
        }
    }
}


- (void)peripheralManagerIsReadyToUpdateSubscribers:(CBPeripheralManager *)peripheral {
    [self sendData];
}

1 Ответ

0 голосов
/ 02 февраля 2020

Вы получаете сообщение об ошибке, потому что вы вызываете startAdvertising сразу после создания экземпляра CBPeripheralManager. Как говорится в сообщении об ошибке, вы должны подождать, пока не получите обратный вызов с указанием состояния CBManagerStatePoweredOn, прежде чем выполнять какие-либо операции Bluetooth.

На самом деле начинать рекламу в этот момент бессмысленно, потому что вы еще не определили ваш сервис. Вам просто нужно переместить вызов startAdvertising в метод peripheralManagerDidUpdateState, в котором вы настраиваете свой сервис:

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {

    if (peripheral.state == CBManagerStatePoweredOn) {


        self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_CHARACTERISTIC_UUID] properties:CBCharacteristicPropertyNotify value:nil permissions:CBAttributePermissionsReadable];

        CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID] primary:YES];

        transferService.characteristics = @[_transferCharacteristic];

        [_peripheralManager addService:transferService];
        [_peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:TRANSFER_SERVICE_UUID]] }];
    }

   if (peripheral.state != CBManagerStatePoweredOn) {

        return;
    }


}

Кроме того, из соображений стиля я бы не получил доступ к _peripheralManager ivar напрямую, если у вас нет веских причин. Всегда лучше использовать сеттер / геттер. Потеря производительности является незначительной, и она позволяет избежать незначительных ошибок в случае, когда установщик / получатель был переопределен.

...