iOS/Objective-C:外围模式下的BLE不起作用

stk*_*flw 10 bluetooth objective-c ios bluetooth-lowenergy react-native

我正试图在中央外围模式下启动BLE .现在为了简单起见,使用硬编码变量.
我想我已根据文档实现了所有内容.

我可以使用Android智能手机检查外设模式是否正常工作(api-19,不支持外设模式).例如,当我使用MyBeacon应用程序时,iPhone会正确显示.

但是,当我在我的应用程序中运行此代码时,它不会显示:

这是.h:

#import <RCTBridgeModule.h>
#import <RCTEventEmitter.h>
@import CoreBluetooth;
@import QuartzCore;

@interface BTManager : RCTEventEmitter <RCTBridgeModule, CBCentralManagerDelegate, CBPeripheralManagerDelegate, CBPeripheralDelegate>

@property (nonatomic, strong) CBCentralManager *centralManager;
@property (nonatomic, strong) CBPeripheralManager *peripheralManager;
@property (nonatomic, strong) CBMutableCharacteristic *transferCharacteristic;

@end
Run Code Online (Sandbox Code Playgroud)

而且.m:

#import "BTManager.h"

@implementation BTManager

RCT_EXPORT_MODULE();

- (NSArray<NSString *> *)supportedEvents
{
  return @[@"BTManagerDeviceFound", @"BTManagerStatus"];
}

- (void)viewDidLoad
{
  CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
  self.centralManager = centralManager;
  CBPeripheralManager *peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
  self.peripheralManager = peripheralManager;
}

RCT_EXPORT_METHOD(start:(NSDictionary *)options)
{

  [self.centralManager scanForPeripheralsWithServices:nil options:nil];

  self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:@"EB6727C4-F184-497A-A656-76B0CDAC633A"] properties:CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable];

  CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"EB6727C4-F184-497A-A656-76B0CDAC633A"] primary:YES];

  transferService.characteristics = @[self.transferCharacteristic];

  [self.peripheralManager addService:transferService];

  [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:@"FB694B90-F49E-4597-8306-171BBA78F846"]] }];

  NSLog(@"Started");
}

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
  // log peripheralManager state
  NSLog(@"peripheralManagerDidUpdateState peripheral %@", peripheral);
}

- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
{
  // log centralManager state
  NSLog(@"peripheralManager didAddService peripheral %@", peripheral);
  NSLog(@"peripheralManager didAddService service %@", service);
  NSLog(@"peripheralManager didAddService error %@", error);
}

- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
{
  NSLog(@"peripheralManagerDidStartAdvertising peripheral %@", peripheral);
  NSLog(@"peripheralManagerDidStartAdvertising error %@", error);
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
  [self sendEventWithName:@"BTManagerDeviceFound" body:advertisementData];
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
  NSLog(@"centralManagerDidUpdateState central %@", central);
}

RCT_EXPORT_METHOD(stop:(NSDictionary *)options)
{
  // remove all related processes, send event to js
  [self sendEventWithName:@"BTManagerStatus" body:@"details here"];
  //  [self.myCentralManager stopScan];
}

@end
Run Code Online (Sandbox Code Playgroud)

上面没有任何事件监听器正在触发,除了 NSLog(@"Started");

我有这个建议:

在相关主题上,确保无论代码创建和执行什么代码都允许对象生存足够长的时间以执行蓝牙操作.如果它超出范围或被垃圾收集,你将遇到同样的问题.

我不知道如何检查这是否属实.

此外,本教程使用此方法:

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
    if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
        return;
    }

    if (peripheral.state == CBPeripheralManagerStatePoweredOn) {
        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];
    }
}
Run Code Online (Sandbox Code Playgroud)

......但是文档中没有任何与此相关的内容CBPeripheralManagerStatePoweredOn.这篇文章已有4年历史了,所以现在可能还不相关.

哦,是的,而且我对Objective-c几乎不熟悉,所以那里的错误可能很简单.

谢谢你在这里阅读:)

更新1

显然,viewDidLoad永远不会被发起.因此,我已经将代码从它转移到start方法,并将代码start转换为...DidUpdateStates方法,正如@LarsBlumberg建议的那样.

#import "BTManager.h"
#import <React/RCTLog.h>

@implementation BTManager

RCT_EXPORT_MODULE();

- (NSArray<NSString *> *)supportedEvents
{
  return @[@"BTManagerDeviceFound", @"BTManagerStatus"];
}

RCT_EXPORT_METHOD(start:(NSDictionary *)options)
{
  RCTLogInfo(@"Start?");
  CBCentralManager *centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:@{CBCentralManagerOptionShowPowerAlertKey: @(YES)}];
  self.centralManager = centralManager;
  CBPeripheralManager *peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:nil];
  self.peripheralManager = peripheralManager;
  RCTLogInfo(@"Started");
}

- (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
  // log peripheralManager state
  RCTLogInfo(@"peripheralManagerDidUpdateState peripheral %ld", (long)peripheral.state);
  if (peripheral.state != CBPeripheralManagerStatePoweredOn) {
    RCTLogInfo(@"Peripheral is not powered on");
    return;
  }
  self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:@"EB6727C4-F184-497A-A656-76B0CDAC633A"] properties:CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable];

  CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"EB6727C4-F184-497A-A656-76B0CDAC633A"] primary:YES];

  transferService.characteristics = @[self.transferCharacteristic];

  [peripheral addService:transferService];

  NSDictionary *advertisingData = @{CBAdvertisementDataLocalNameKey : @"yphone", CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:@"EBA38950-0D9B-4DBA-B0DF-BC7196DD44FC"]]};
  [peripheral startAdvertising:advertisingData];
}

- (void)peripheralManager:(CBPeripheralManager *)peripheral didAddService:(CBService *)service error:(NSError *)error
{
  // log centralManager state
  RCTLogInfo(@"peripheralManager didAddService peripheral %@", peripheral);
  RCTLogInfo(@"peripheralManager didAddService service %@", service);
  RCTLogInfo(@"peripheralManager didAddService error %@", error);
}

- (void)peripheralManagerDidStartAdvertising:(CBPeripheralManager *)peripheral error:(NSError *)error
{
  RCTLogInfo(@"peripheralManagerDidStartAdvertising peripheral %@", peripheral);
  RCTLogInfo(@"peripheralManagerDidStartAdvertising error %@", error);
}

- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI
{
  [self sendEventWithName:@"BTManagerDeviceFound" body:advertisementData];
}

- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
  RCTLogInfo(@"centralManagerDidUpdateState central %ld", (long)central.state);
  // if (central.state == CBCentralManagerStatePoweredOff) {
  //   UIAlertView *alert = [[UIAlertView alloc] initWithTitle: @"Error" message: @"Please turn on Bluetooth in Settings" delegate: nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
  //   [alert show]; 
  // }
  if (central.state != CBCentralManagerStatePoweredOn) {
    RCTLogInfo(@"Central is not powered on");
    return;
  }
  [central scanForPeripheralsWithServices:nil options:nil];
}

RCT_EXPORT_METHOD(stop:(NSDictionary *)options)
{
  // remove all related processes, send event to js
  [self sendEventWithName:@"BTManagerStatus" body:@"details here"];
  //  [self.myCentralManager stopScan];
}

@end
Run Code Online (Sandbox Code Playgroud)

现在一切顺利,直到状态更新.无论central.stateperipheral.state回报4,而CB...ManagerStatePoweredOn等于5.我如何使它等于5?应用程序请求访问bt,但iphone没有启用它.当手动启用时,一切似乎都运行良好.

Lar*_*erg 3

您可能太早地将服务添加transferService到外围设备管理器中,并且您也可能太早开始广告。

您必须等到报告peripheralManagerDidUpdateState您的外设管理器的状态已达到CBPeripheralManagerStatePoweredOn

也就是说,您可以将代码从RCT_EXPORT_METHOD(start:(NSDictionary *)options)peripheralManagerDidUpdateState实现中移出。

或者,如果您只想向您的方法添加服务peripheralManager,然后在有人调用您的start方法时开始广告(看起来您正在创建 React Native 绑定?),请确保它self.peripheralManager.stateCBPeripheralManagerStatePoweredOn您的start方法中。然而,这要求(您的 React Native JS 代码)的调用者start不要过早调用此方法。

RCT_EXPORT_METHOD(start:(NSDictionary *)options)
{
  NSLog(@"Start?");
  if (self.peripheralManager.state != CBPeripheralManagerStatePoweredOn) {
      NSLog(@"Peripheral is not powered on");
      return;
  }
  if (self.centralManager.state != CBCentralManagerStatePoweredOn) {
      NSLog(@"Central is not powered on");
      return;
  }
  NSLog(@"OK, peripheral and central are both powered on");
  [self.centralManager scanForPeripheralsWithServices:nil options:nil];

  self.transferCharacteristic = [[CBMutableCharacteristic alloc] initWithType:[CBUUID UUIDWithString:@"EB6727C4-F184-497A-A656-76B0CDAC633A"] properties:CBCharacteristicPropertyRead value:nil permissions:CBAttributePermissionsReadable];

  CBMutableService *transferService = [[CBMutableService alloc] initWithType:[CBUUID UUIDWithString:@"EB6727C4-F184-497A-A656-76B0CDAC633A"] primary:YES];

  transferService.characteristics = @[self.transferCharacteristic];

  [self.peripheralManager addService:transferService];

  [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[[CBUUID UUIDWithString:@"FB694B90-F49E-4597-8306-171BBA78F846"]] }];

  NSLog(@"Started");
}
Run Code Online (Sandbox Code Playgroud)

centralManager同样,只有当外围设备处于“开机”状态时,您才能开始扫描外围设备。