iOS / Objective-C:外设模式下的BLE抛出`libsystem_kernel.dylib`__abort_with_payload`

时间:2021-08-18 22:11:13

I'm trying to launch BLE in both Central and Peripheral modes. With hardcoded variables for now for sake of simplicity.
I think i've implemented everything according to the docs. I'm unable to check if Central mode works, but when the code contained only Central-mode-related code, the app was asking to enable BT, and wasn't crashing so i assume it was scanning properly :) I'll check this later.

我正试图在*和外围模式下启动BLE。现在为了简单起见,使用硬编码变量。我想我已根据文档实现了所有内容。我无法检查*模式是否有效,但当代码只包含与*模式相关的代码时,应用程序要求启用BT,并且没有崩溃所以我认为它正在扫描正确:)我会检查这个以后。

After i've added Peripheral mode in there, app started freezing once i've initiating start method.

在我添加外围模式后,应用程序在启动启动方法后开始冻结。

Xcode shows very informative log:

Xcode显示了非常丰富的日志:

libsystem_kernel.dylib`__abort_with_payload:
    0x18acc5d6c <+0>:  movz   x16, #0x209
    0x18acc5d70 <+4>:  svc    #0x80
->  0x18acc5d74 <+8>:  b.lo   0x18acc5d8c               ; <+32>
    0x18acc5d78 <+12>: stp    x29, x30, [sp, #-16]!
    0x18acc5d7c <+16>: mov    x29, sp
    0x18acc5d80 <+20>: bl     0x18acaa7d0               ; cerror_nocancel
    0x18acc5d84 <+24>: mov    sp, x29
    0x18acc5d88 <+28>: ldp    x29, x30, [sp], #16
    0x18acc5d8c <+32>: ret    

Nothing else, no errors, no warnings etc. This is not related to Central mode, because if i'm removing it, nothing changes.
So, what does it mean? I've googled a bit and found misc assumptions about permission descriptions, iOS 7 etc.

没有别的,没有错误,没有警告等。这与*模式无关,因为如果我删除它,没有任何改变。那么,这意味着什么?我已经google了一下,发现了关于权限描述,iOS 7等的错误假设。

I'm barely familiar with objective-c, so sorry, if i'm asking very simple question :)

我对objective-c几乎不熟悉,很抱歉,如果我问的是非常简单的问题:)

sendEventWithName in the code below works like logs atm. The only log i'm receiving is started (at the end of start method`)

下面代码中的sendEventWithName就像log atm一样。我收到的唯一日志已启动(在start方法结束时)

Here is .h:

这是.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

And .m:

而.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"]] }];

  [self sendEventWithName:@"BTManagerStatus" body:@"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

1 个解决方案

#1


1  

A few thoughts:

一些想法:

  1. The code declares CBCentralManager *centralManager and CBPeripheralManager *peripheralManager as local variables inside the start method. These variables will go out of scope when the method ends and cease to exist, preventing bluetooth operations from continuing. You need to declare these as class-level variables, then initialize them in the the start method. On a related subject, make sure that whatever code creates and executes your BTManager allows the object to live for long enough for the bluetooth actions to be performed. If it goes out of scope or gets garbage collected, you'll have the same problem.

    代码在start方法中声明CBCentralManager * centralManager和CBPeripheralManager * peripheralManager作为局部变量。当方法结束并且不再存在时,这些变量将超出范围,从而阻止蓝牙操作继续进行。您需要将它们声明为类级变量,然后在start方法中初始化它们。在相关主题上,确保无论代码创建和执行任何代码都允许对象存活足够长的时间以执行蓝牙操作。如果它超出范围或被垃圾收集,你将遇到同样的问题。

  2. Code should not perform actions on either the central or the peripheral until after receiving a powered on callback to: peripheralManagerDidUpdateState or centralManagerDidUpdateState, respectively. I would move the code that scans or sets up advertising to new initialization methods for peripheral/central, and call them when you get a callback to those methods with a value of CBPeripheralManagerStatePoweredOn or CBCentalManagerStatePoweredOn, respectively. Even if the interface is powered on when you code starts, CoreBluetooth won't let you do anything successfully until it has fully initialized and sent the powered on callback, so you must always wait for this.

    代码不应在*或外围设备上执行操作,直到分别接收到:peripheralManagerDidUpdateState或centralManagerDidUpdateState的上电回调。我会将扫描或设置广告的代码移动到外围/中心的新初始化方法,并在分别获得值为CBPeripheralManagerStatePoweredOn或CBCentalManagerStatePoweredOn的那些方法的回调时调用它们。即使代码启动时接口已打开电源,CoreBluetooth也不会让您成功完成任何操作,直到它完全初始化并发送了开机回调,因此您必须始终等待这一点。

  3. Make sure you trust your custom logging implementation. When in doubt, NSLog(@"XXXX") is a handy tool for a sanity check.

    确保您信任自定义日志记录实现。如有疑问,NSLog(@“XXXX”)是进行健全性检查的便利工具。

#1


1  

A few thoughts:

一些想法:

  1. The code declares CBCentralManager *centralManager and CBPeripheralManager *peripheralManager as local variables inside the start method. These variables will go out of scope when the method ends and cease to exist, preventing bluetooth operations from continuing. You need to declare these as class-level variables, then initialize them in the the start method. On a related subject, make sure that whatever code creates and executes your BTManager allows the object to live for long enough for the bluetooth actions to be performed. If it goes out of scope or gets garbage collected, you'll have the same problem.

    代码在start方法中声明CBCentralManager * centralManager和CBPeripheralManager * peripheralManager作为局部变量。当方法结束并且不再存在时,这些变量将超出范围,从而阻止蓝牙操作继续进行。您需要将它们声明为类级变量,然后在start方法中初始化它们。在相关主题上,确保无论代码创建和执行任何代码都允许对象存活足够长的时间以执行蓝牙操作。如果它超出范围或被垃圾收集,你将遇到同样的问题。

  2. Code should not perform actions on either the central or the peripheral until after receiving a powered on callback to: peripheralManagerDidUpdateState or centralManagerDidUpdateState, respectively. I would move the code that scans or sets up advertising to new initialization methods for peripheral/central, and call them when you get a callback to those methods with a value of CBPeripheralManagerStatePoweredOn or CBCentalManagerStatePoweredOn, respectively. Even if the interface is powered on when you code starts, CoreBluetooth won't let you do anything successfully until it has fully initialized and sent the powered on callback, so you must always wait for this.

    代码不应在*或外围设备上执行操作,直到分别接收到:peripheralManagerDidUpdateState或centralManagerDidUpdateState的上电回调。我会将扫描或设置广告的代码移动到外围/中心的新初始化方法,并在分别获得值为CBPeripheralManagerStatePoweredOn或CBCentalManagerStatePoweredOn的那些方法的回调时调用它们。即使代码启动时接口已打开电源,CoreBluetooth也不会让您成功完成任何操作,直到它完全初始化并发送了开机回调,因此您必须始终等待这一点。

  3. Make sure you trust your custom logging implementation. When in doubt, NSLog(@"XXXX") is a handy tool for a sanity check.

    确保您信任自定义日志记录实现。如有疑问,NSLog(@“XXXX”)是进行健全性检查的便利工具。