我正在尝试以Central和Peripheral模式启动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
.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
除NSLog(@"Started");
我有这个建议:
在相关主题上,确保无论代码创建和执行任何代码,都可以让对象存活足够长的时间以执行蓝牙操作。如果它超出范围或被垃圾收集,你将遇到同样的问题。
我不知道如何判断这是否属实。
此外,this tutorial正在使用此方法:
- (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];
}
}
...但docs不包含任何与此CBPeripheralManagerStatePoweredOn
左右相关的内容。这篇文章已有4年历史了,所以现在可能甚至都不相关。
哦,是的,而且我对Objective-c几乎不熟悉,所以那里的错误可能非常简单。
感谢您阅读,直到这里:)
显然,viewDidLoad
永远不会被启动。因此,我已将代码从start
方法移至代码,并将start
中的代码移至...DidUpdateState
方法,如@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
现在一切顺利,直到状态更新。 central.state
和peripheral.state
都返回4
,而CB...ManagerStatePoweredOn
等于5
。如何使其等于5
?应用程序请求访问bt,但iphone没有启用它。当它手动启用时,一切似乎都运行良好。
答案 0 :(得分:3)
您可能过早地将服务transferService
添加到外围设备管理器中,您也可能过早地开始播放广告。
您需要等待,直到peripheralManagerDidUpdateState
报告外围经理的状态已达到CBPeripheralManagerStatePoweredOn
。
这就是说,您可以将代码从RCT_EXPORT_METHOD(start:(NSDictionary *)options)
移到空peripheralManagerDidUpdateState
实现中。
或者,如果您只想向peripheralManager
添加服务,然后在有人调用您的start
方法(看起来您正在创建React Native绑定?)时开始做广告,请确保self.peripheralManager.state
方法中CBPeripheralManagerStatePoweredOn
为start
。但是,这需要start
(您的React Native JS代码)的调用者不要过早调用此方法。
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");
}
同样,如果外围设备具有“开机”状态,则只能使用centralManager
开始扫描。
答案 1 :(得分:0)
显然,无法以编程方式在iOS上打开蓝牙,也无法以编程方式立即进行配对。
但是,我们可以通过RCT_EXPORT_METHOD(开始:(NSDictionary *)选项)方法,通过警报启用用户来打开蓝牙。
if(peripheralManager.state < CBPeripheralManagerStatePoweredOn){
{
//Show alert to user to turn on the Bluetooth and it will go to
peripheralManagerDidUpdateState when user turn it on.
}
else
{
//You can continue setting up the data.
}