У меня есть нативный модуль, который расширяет rcteventemitter, а также реализует турбомодуль Спецификация:
shrong>rctnativeLocalStorage.h:>
#import
#import
NS_ASSUME_NONNULL_BEGIN
@interface RCTNativeLocalStorage : RCTEventEmitter
@end
NS_ASSUME_NONNULL_END
rctnativelocalstorage.m (частично):
Код: Выделить всё
#import "RCTNativeLocalStorage.h"
#import
#import
using namespace facebook;
@interface RCTNativeLocalStorage ()
@property (strong, nonatomic) NSUserDefaults *localStorage;
@property (strong, nonatomic) CBCentralManager *centralManager;
@property (strong, nonatomic) NSMutableArray *discoveredDevices;
@property (nonatomic, assign) BOOL hasListeners;
@end
@implementation RCTNativeLocalStorage
// Register the module
RCT_EXPORT_MODULE(NativeLocalStorage)
// These methods are required for NativeEventEmitter to work properly
RCT_EXPORT_METHOD(addListener:(NSString *)eventName)
{
NSLog(@"🎧 addListener called for: %@", eventName);
}
RCT_EXPORT_METHOD(removeListeners:(double)count)
{
NSLog(@"🔕 removeListeners called: %f", count);
}
// Define supported events
- (NSArray *)supportedEvents {
return @[
@"BluetoothDeviceFound",
];
}
// Event listener tracking
- (void)startObserving {
NSLog(@"✅ startObserving called - events will be emitted");
self.hasListeners = YES;
}
- (void)stopObserving {
NSLog(@"⚠️ stopObserving called - events will not be emitted");
self.hasListeners = NO;
}
- (instancetype)init {
if (self = [super init]) {
_localStorage = [[NSUserDefaults alloc] initWithSuiteName:@"local-storage"];
_centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:nil];
_discoveredDevices = [NSMutableArray new];
_hasListeners = NO;
}
return self;
}
+ (BOOL)requiresMainQueueSetup {
return NO;
}
// TurboModule implementation
- (std::shared_ptr)getTurboModule:(const facebook::react::ObjCTurboModule::InitParams &)params {
return std::make_shared(params);
}
// MARK: - TurboModule Methods
- (NSString * _Nullable)getItem:(NSString *)key {
return [self.localStorage stringForKey:key];
}
- (void)setItem:(NSString *)value key:(NSString *)key {
[self.localStorage setObject:value forKey:key];
}
- (void)removeItem:(NSString *)key {
[self.localStorage removeObjectForKey:key];
}
- (void)clear {
NSDictionary *allItems = [self.localStorage dictionaryRepresentation];
for (NSString *key in allItems.allKeys) {
[self.localStorage removeObjectForKey:key];
}
}
// Export the startScan method to make it available to JavaScript
RCT_EXPORT_METHOD(startScan) {
NSLog(@"✅ startScan triggered from JavaScript");
if (_centralManager.state != CBManagerStatePoweredOn) {
NSLog(@"❌ Bluetooth not powered on");
return;
}
// Show an alert to verify the method was called
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Scan"
message:@"startScan called!"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *ok = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil];
[alert addAction:ok];
UIViewController *root = UIApplication.sharedApplication.keyWindow.rootViewController;
[root presentViewController:alert animated:YES completion:nil];
});
[_discoveredDevices removeAllObjects];
[_centralManager scanForPeripheralsWithServices:nil options:nil];
}
// Central Manager Delegates
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
switch (central.state) {
case CBManagerStatePoweredOn:
NSLog(@"✅ Bluetooth is powered on.");
break;
case CBManagerStatePoweredOff:
NSLog(@"❌ Bluetooth is powered off.");
break;
default:
NSLog(@"⚠️ Bluetooth state changed: %ld", (long)central.state);
break;
}
}
- (void)centralManager:(CBCentralManager *)central
didDiscoverPeripheral:(CBPeripheral *)peripheral
advertisementData:(NSDictionary *)advertisementData
RSSI:(NSNumber *)RSSI {
NSString *deviceName = peripheral.name ?: @"Unknown";
NSString *deviceId = peripheral.identifier.UUIDString;
NSDictionary *deviceInfo = @{
@"name": deviceName,
@"id": deviceId
};
BOOL alreadyExists = NO;
for (NSDictionary *existingDevice in _discoveredDevices) {
if ([existingDevice[@"id"] isEqualToString:deviceId]) {
alreadyExists = YES;
break;
}
}
if (!alreadyExists) {
[_discoveredDevices addObject:deviceInfo];
NSLog(@"✅ Device discovered: %@", deviceInfo);
// Send event directly on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
// The hasListeners check is important to avoid the warning
if (self.hasListeners) {
NSLog(@"🚀 Sending BluetoothDeviceFound event");
[self sendEventWithName:@"BluetoothDeviceFound" body:deviceInfo];
} else {
NSLog(@"⚠️ No listeners registered for BluetoothDeviceFound event");
}
});
}
}
@end
const { NativeLocalStorage } = NativeModules;
const eventEmitter = new NativeEventEmitter(NativeLocalStorage);
useEffect(() => {
console.log('Setting up event listener...');
const subscription = eventEmitter.addListener(
'BluetoothDeviceFound',
(deviceInfo) => {
console.log('Device found:', deviceInfo);
// Update state...
}
);
console.log('Starting scan...');
NativeLocalStorage.startScan();
return () => subscription.remove();
}, []);
< /code>
Консоль
'`new NativeEventEmitter()` was called with a non-null argument without the required `addListener` method.', { [Component Stack] name: 'Component Stack' }
'`new NativeEventEmitter()` was called with a non-null argument without the required `removeListeners` method.', { [Component Stack] name: 'Component Stack' }
id = "E2DEF552-4C7E-FA6F-1CC3-3F6B0DE3CC31";
name = Unknown;
}
< /code>
Проблема < /strong> < /p>
Невозможно отправить события из нативного кода iOS.
Тот же код работает с Android, и я могу отправлять данные слушателям событий. https://reactnative.dev/docs/0.77/legac ... javascript
Подробнее здесь: https://stackoverflow.com/questions/795 ... s-with-ios
Мобильная версия