[ios] Add multiple listener support
This commit is contained in:
parent
312b7b37b1
commit
6d4b5bc406
11
.gitignore
vendored
11
.gitignore
vendored
@ -14,16 +14,16 @@ xcuserdata/
|
||||
# Android
|
||||
|
||||
# Built application files
|
||||
android/*/build/
|
||||
**/android/**/build/
|
||||
|
||||
# Crashlytics configuations
|
||||
android/com_crashlytics_export_strings.xml
|
||||
|
||||
# Local configuration file (sdk path, etc)
|
||||
android/local.properties
|
||||
**/android/local.properties
|
||||
|
||||
# Gradle generated files
|
||||
android/.gradle/
|
||||
**/android/.gradle/
|
||||
|
||||
# Signing files
|
||||
android/.signing/
|
||||
@ -41,7 +41,7 @@ android/.idea/misc.xml
|
||||
android/.idea/modules.xml
|
||||
android/.idea/scopes/scope_settings.xml
|
||||
android/.idea/vcs.xml
|
||||
android/*.iml
|
||||
**/android/**/*.iml
|
||||
ios/RnFirebase.xcodeproj/xcuserdata
|
||||
|
||||
# OS-specific files
|
||||
@ -60,3 +60,6 @@ android/gradle/
|
||||
.idea
|
||||
coverage
|
||||
yarn.lock
|
||||
|
||||
**/ios/Pods/**
|
||||
**/ios/ReactNativeFirebaseDemo.xcworkspace/
|
||||
|
@ -5,64 +5,61 @@
|
||||
@interface RNFirebaseDBReference : NSObject
|
||||
@property RCTEventEmitter *emitter;
|
||||
@property FIRDatabaseQuery *query;
|
||||
@property NSNumber *refId;
|
||||
@property NSString *path;
|
||||
@property NSString *modifiersString;
|
||||
@property NSMutableDictionary *listeners;
|
||||
@property FIRDatabaseHandle childAddedHandler;
|
||||
@property FIRDatabaseHandle childModifiedHandler;
|
||||
@property FIRDatabaseHandle childRemovedHandler;
|
||||
@property FIRDatabaseHandle childMovedHandler;
|
||||
@property FIRDatabaseHandle childValueHandler;
|
||||
+ (NSDictionary *) snapshotToDict:(FIRDataSnapshot *) snapshot;
|
||||
@end
|
||||
|
||||
@implementation RNFirebaseDBReference
|
||||
|
||||
|
||||
- (id) initWithPathAndModifiers:(RCTEventEmitter *) emitter
|
||||
database:(FIRDatabase *) database
|
||||
refId:(NSNumber *) refId
|
||||
path:(NSString *) path
|
||||
modifiers:(NSArray *) modifiers
|
||||
modifiersString:(NSString *) modifiersString
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
_emitter = emitter;
|
||||
_refId = refId;
|
||||
_path = path;
|
||||
_modifiersString = modifiersString;
|
||||
_query = [self buildQueryAtPathWithModifiers:database path:path modifiers:modifiers];
|
||||
_listeners = [[NSMutableDictionary alloc] init];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) addEventHandler:(NSString *) eventName
|
||||
- (void) addEventHandler:(NSNumber *) listenerId
|
||||
eventName:(NSString *) eventName
|
||||
{
|
||||
if (![self isListeningTo:eventName]) {
|
||||
if (![_listeners objectForKey:listenerId]) {
|
||||
id withBlock = ^(FIRDataSnapshot * _Nonnull snapshot) {
|
||||
NSDictionary *props = [RNFirebaseDBReference snapshotToDict:snapshot];
|
||||
[self sendJSEvent:DATABASE_DATA_EVENT
|
||||
title:eventName
|
||||
props: @{
|
||||
@"eventName": eventName,
|
||||
@"refId": _refId,
|
||||
@"listenerId": listenerId,
|
||||
@"path": _path,
|
||||
@"modifiersString": _modifiersString,
|
||||
@"snapshot": props
|
||||
}];
|
||||
};
|
||||
id errorBlock = ^(NSError * _Nonnull error) {
|
||||
NSLog(@"Error onDBEvent: %@", [error debugDescription]);
|
||||
[self unsetListeningOn:eventName];
|
||||
[self removeEventHandler:listenerId eventName:eventName];
|
||||
[self getAndSendDatabaseError:error
|
||||
path:_path
|
||||
modifiersString:_modifiersString];
|
||||
listenerId:listenerId];
|
||||
};
|
||||
int eventType = [self eventTypeFromName:eventName];
|
||||
FIRDatabaseHandle handle = [_query observeEventType:eventType
|
||||
withBlock:withBlock
|
||||
withCancelBlock:errorBlock];
|
||||
[self setEventHandler:handle forName:eventName];
|
||||
[_listeners setObject:@(handle) forKey:listenerId];
|
||||
} else {
|
||||
NSLog(@"Warning Trying to add duplicate listener for type: %@ with modifiers: %@ for path: %@", eventName, _modifiersString, _path);
|
||||
NSLog(@"Warning Trying to add duplicate listener for refId: %@ listenerId: %@", _refId, listenerId);
|
||||
}
|
||||
}
|
||||
|
||||
@ -74,7 +71,7 @@
|
||||
callback(@[[NSNull null], @{
|
||||
@"eventName": @"value",
|
||||
@"path": _path,
|
||||
@"modifiersString": _modifiersString,
|
||||
@"refId": _refId,
|
||||
@"snapshot": props
|
||||
}]);
|
||||
}
|
||||
@ -83,7 +80,7 @@
|
||||
callback(@[@{
|
||||
@"eventName": DATABASE_ERROR_EVENT,
|
||||
@"path": _path,
|
||||
@"modifiers": _modifiersString,
|
||||
@"refId": _refId,
|
||||
@"code": @([error code]),
|
||||
@"details": [error debugDescription],
|
||||
@"message": [error localizedDescription],
|
||||
@ -92,44 +89,14 @@
|
||||
}];
|
||||
}
|
||||
|
||||
- (void) removeEventHandler:(NSString *) name
|
||||
- (void) removeEventHandler:(NSNumber *) listenerId
|
||||
eventName:(NSString *) eventName
|
||||
{
|
||||
int eventType = [self eventTypeFromName:name];
|
||||
switch (eventType) {
|
||||
case FIRDataEventTypeValue:
|
||||
if (self.childValueHandler != nil) {
|
||||
[_query removeObserverWithHandle:self.childValueHandler];
|
||||
self.childValueHandler = nil;
|
||||
}
|
||||
break;
|
||||
case FIRDataEventTypeChildAdded:
|
||||
if (self.childAddedHandler != nil) {
|
||||
[_query removeObserverWithHandle:self.childAddedHandler];
|
||||
self.childAddedHandler = nil;
|
||||
}
|
||||
break;
|
||||
case FIRDataEventTypeChildChanged:
|
||||
if (self.childModifiedHandler != nil) {
|
||||
[_query removeObserverWithHandle:self.childModifiedHandler];
|
||||
self.childModifiedHandler = nil;
|
||||
}
|
||||
break;
|
||||
case FIRDataEventTypeChildRemoved:
|
||||
if (self.childRemovedHandler != nil) {
|
||||
[_query removeObserverWithHandle:self.childRemovedHandler];
|
||||
self.childRemovedHandler = nil;
|
||||
}
|
||||
break;
|
||||
case FIRDataEventTypeChildMoved:
|
||||
if (self.childMovedHandler != nil) {
|
||||
[_query removeObserverWithHandle:self.childMovedHandler];
|
||||
self.childMovedHandler = nil;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
FIRDatabaseHandle handle = [[_listeners objectForKey:listenerId] integerValue];
|
||||
if (handle) {
|
||||
[_listeners removeObjectForKey:listenerId];
|
||||
[_query removeObserverWithHandle:handle];
|
||||
}
|
||||
[self unsetListeningOn:name];
|
||||
}
|
||||
|
||||
+ (NSDictionary *) snapshotToDict:(FIRDataSnapshot *) snapshot
|
||||
@ -159,21 +126,19 @@
|
||||
}
|
||||
|
||||
- (NSDictionary *) getAndSendDatabaseError:(NSError *) error
|
||||
path:(NSString *) path
|
||||
modifiersString:(NSString *) modifiersString
|
||||
listenerId:(NSNumber *) listenerId
|
||||
{
|
||||
NSDictionary *event = @{
|
||||
@"eventName": DATABASE_ERROR_EVENT,
|
||||
@"path": path,
|
||||
@"modifiers": modifiersString,
|
||||
@"path": _path,
|
||||
@"refId": _refId,
|
||||
@"listenerId": listenerId,
|
||||
@"code": @([error code]),
|
||||
@"details": [error debugDescription],
|
||||
@"message": [error localizedDescription],
|
||||
@"description": [error description]
|
||||
};
|
||||
|
||||
// [self sendJSEvent:DATABASE_ERROR_EVENT title:DATABASE_ERROR_EVENT props: event];
|
||||
|
||||
|
||||
@try {
|
||||
[_emitter sendEventWithName:DATABASE_ERROR_EVENT body:event];
|
||||
}
|
||||
@ -181,7 +146,7 @@
|
||||
NSLog(@"An error occurred in getAndSendDatabaseError: %@", [err debugDescription]);
|
||||
NSLog(@"Tried to send: %@ with %@", DATABASE_ERROR_EVENT, event);
|
||||
}
|
||||
|
||||
|
||||
return event;
|
||||
}
|
||||
|
||||
@ -194,70 +159,59 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (FIRDatabaseQuery *) buildQueryAtPathWithModifiers:(FIRDatabase*) database
|
||||
path:(NSString*) path
|
||||
modifiers:(NSArray *) modifiers
|
||||
{
|
||||
FIRDatabaseQuery *query = [[database reference] child:path];
|
||||
|
||||
for (NSString *str in modifiers) {
|
||||
if ([str isEqualToString:@"orderByKey"]) {
|
||||
query = [query queryOrderedByKey];
|
||||
} else if ([str isEqualToString:@"orderByPriority"]) {
|
||||
query = [query queryOrderedByPriority];
|
||||
} else if ([str isEqualToString:@"orderByValue"]) {
|
||||
query = [query queryOrderedByValue];
|
||||
} else if ([str containsString:@"orderByChild"]) {
|
||||
NSArray *args = [str componentsSeparatedByString:@":"];
|
||||
NSString *key = args[1];
|
||||
query = [query queryOrderedByChild:key];
|
||||
} else if ([str containsString:@"limitToLast"]) {
|
||||
NSArray *args = [str componentsSeparatedByString:@":"];
|
||||
NSString *key = args[1];
|
||||
NSUInteger limit = key.integerValue;
|
||||
query = [query queryLimitedToLast:limit];
|
||||
} else if ([str containsString:@"limitToFirst"]) {
|
||||
NSArray *args = [str componentsSeparatedByString:@":"];
|
||||
NSString *key = args[1];
|
||||
NSUInteger limit = key.integerValue;
|
||||
query = [query queryLimitedToFirst:limit];
|
||||
} else if ([str containsString:@"equalTo"]) {
|
||||
NSArray *args = [str componentsSeparatedByString:@":"];
|
||||
int size = (int)[args count];;
|
||||
id value = [self getIdValue:args[1] type:args[2]];
|
||||
if (size > 3) {
|
||||
NSString *key = args[3];
|
||||
query = [query queryEqualToValue:value
|
||||
childKey:key];
|
||||
} else {
|
||||
query = [query queryEqualToValue:value];
|
||||
|
||||
for (NSDictionary *modifier in modifiers) {
|
||||
NSString *type = [modifier valueForKey:@"type"];
|
||||
NSString *name = [modifier valueForKey:@"name"];
|
||||
if ([type isEqualToString:@"orderBy"]) {
|
||||
if ([name isEqualToString:@"orderByKey"]) {
|
||||
query = [query queryOrderedByKey];
|
||||
} else if ([name isEqualToString:@"orderByPriority"]) {
|
||||
query = [query queryOrderedByPriority];
|
||||
} else if ([name isEqualToString:@"orderByValue"]) {
|
||||
query = [query queryOrderedByValue];
|
||||
} else if ([name isEqualToString:@"orderByChild"]) {
|
||||
NSString *key = [modifier valueForKey:@"key"];
|
||||
query = [query queryOrderedByChild:key];
|
||||
}
|
||||
} else if ([str containsString:@"endAt"]) {
|
||||
NSArray *args = [str componentsSeparatedByString:@":"];
|
||||
int size = (int)[args count];;
|
||||
id value = [self getIdValue:args[1] type:args[2]];
|
||||
if (size > 3) {
|
||||
NSString *key = args[3];
|
||||
query = [query queryEndingAtValue:value
|
||||
childKey:key];
|
||||
} else {
|
||||
query = [query queryEndingAtValue:value];
|
||||
} else if ([type isEqualToString:@"limit"]) {
|
||||
int limit = [[modifier valueForKey:@"limit"] integerValue];
|
||||
if ([name isEqualToString:@"limitToLast"]) {
|
||||
query = [query queryLimitedToLast:limit];
|
||||
} else if ([name isEqualToString:@"limitToFirst"]) {
|
||||
query = [query queryLimitedToFirst:limit];
|
||||
}
|
||||
} else if ([str containsString:@"startAt"]) {
|
||||
NSArray *args = [str componentsSeparatedByString:@":"];
|
||||
id value = [self getIdValue:args[1] type:args[2]];
|
||||
int size = (int)[args count];;
|
||||
if (size > 3) {
|
||||
NSString *key = args[3];
|
||||
query = [query queryStartingAtValue:value
|
||||
childKey:key];
|
||||
} else {
|
||||
query = [query queryStartingAtValue:value];
|
||||
} else if ([type isEqualToString:@"filter"]) {
|
||||
NSString* valueType = [modifier valueForKey:@"valueType"];
|
||||
NSString* key = [modifier valueForKey:@"key"];
|
||||
id value = [self getIdValue:[modifier valueForKey:@"value"] type:valueType];
|
||||
if ([name isEqualToString:@"equalTo"]) {
|
||||
if (key != nil) {
|
||||
query = [query queryEqualToValue:value childKey:key];
|
||||
} else {
|
||||
query = [query queryEqualToValue:value];
|
||||
}
|
||||
} else if ([name isEqualToString:@"endAt"]) {
|
||||
if (key != nil) {
|
||||
query = [query queryEndingAtValue:value childKey:key];
|
||||
} else {
|
||||
query = [query queryEndingAtValue:value];
|
||||
}
|
||||
} else if ([name isEqualToString:@"startAt"]) {
|
||||
if (key != nil) {
|
||||
query = [query queryStartingAtValue:value childKey:key];
|
||||
} else {
|
||||
query = [query queryStartingAtValue:value];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@ -273,62 +227,15 @@
|
||||
}
|
||||
}
|
||||
|
||||
- (void) setEventHandler:(FIRDatabaseHandle) handle
|
||||
forName:(NSString *) name
|
||||
{
|
||||
int eventType = [self eventTypeFromName:name];
|
||||
switch (eventType) {
|
||||
case FIRDataEventTypeValue:
|
||||
self.childValueHandler = handle;
|
||||
break;
|
||||
case FIRDataEventTypeChildAdded:
|
||||
self.childAddedHandler = handle;
|
||||
break;
|
||||
case FIRDataEventTypeChildChanged:
|
||||
self.childModifiedHandler = handle;
|
||||
break;
|
||||
case FIRDataEventTypeChildRemoved:
|
||||
self.childRemovedHandler = handle;
|
||||
break;
|
||||
case FIRDataEventTypeChildMoved:
|
||||
self.childMovedHandler = handle;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
[self setListeningOn:name withHandle:handle];
|
||||
}
|
||||
|
||||
- (void) setListeningOn:(NSString *) name
|
||||
withHandle:(FIRDatabaseHandle) handle
|
||||
{
|
||||
[_listeners setValue:@(handle) forKey:name];
|
||||
}
|
||||
|
||||
- (void) unsetListeningOn:(NSString *) name
|
||||
{
|
||||
[_listeners removeObjectForKey:name];
|
||||
}
|
||||
|
||||
- (BOOL) isListeningTo:(NSString *) name
|
||||
{
|
||||
return [_listeners valueForKey:name] != nil;
|
||||
}
|
||||
|
||||
- (BOOL) hasListeners
|
||||
{
|
||||
return [[_listeners allKeys] count] > 0;
|
||||
}
|
||||
|
||||
- (NSArray *) listenerKeys
|
||||
{
|
||||
return [_listeners allKeys];
|
||||
}
|
||||
|
||||
- (int) eventTypeFromName:(NSString *)name
|
||||
{
|
||||
int eventType = FIRDataEventTypeValue;
|
||||
|
||||
|
||||
if ([name isEqualToString:DATABASE_VALUE_EVENT]) {
|
||||
eventType = FIRDataEventTypeValue;
|
||||
} else if ([name isEqualToString:DATABASE_CHILD_ADDED_EVENT]) {
|
||||
@ -343,24 +250,6 @@
|
||||
return eventType;
|
||||
}
|
||||
|
||||
- (void) cleanup {
|
||||
if (self.childValueHandler > 0) {
|
||||
[self removeEventHandler:DATABASE_VALUE_EVENT];
|
||||
}
|
||||
if (self.childAddedHandler > 0) {
|
||||
[self removeEventHandler:DATABASE_CHILD_ADDED_EVENT];
|
||||
}
|
||||
if (self.childModifiedHandler > 0) {
|
||||
[self removeEventHandler:DATABASE_CHILD_MODIFIED_EVENT];
|
||||
}
|
||||
if (self.childRemovedHandler > 0) {
|
||||
[self removeEventHandler:DATABASE_CHILD_REMOVED_EVENT];
|
||||
}
|
||||
if (self.childMovedHandler > 0) {
|
||||
[self removeEventHandler:DATABASE_CHILD_MOVED_EVENT];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@ -393,27 +282,27 @@ RCT_EXPORT_METHOD(startTransaction:(NSString *) path identifier:(NSString *) ide
|
||||
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
||||
[transactionState setObject:sema forKey:@"semaphore"];
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
|
||||
|
||||
[ref runTransactionBlock:^FIRTransactionResult * _Nonnull(FIRMutableData * _Nonnull currentData) {
|
||||
dispatch_barrier_async(_transactionQueue, ^{
|
||||
[_transactions setValue:transactionState forKey:identifier];
|
||||
[self sendTransactionEvent:DATABASE_TRANSACTION_EVENT body:@{ @"id": identifier, @"type": @"update", @"value": currentData.value }];
|
||||
});
|
||||
|
||||
|
||||
// wait for the js event handler to call tryCommitTransaction
|
||||
// this wait occurs on the Firebase Worker Queue
|
||||
// so if the tryCommitTransaction fails to signal the semaphore
|
||||
// no further blocks will be executed by Firebase until the timeout expires
|
||||
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, 30 * NSEC_PER_SEC);
|
||||
BOOL timedout = dispatch_semaphore_wait(sema, delayTime) != 0;
|
||||
|
||||
|
||||
BOOL abort = [transactionState valueForKey:@"abort"] || timedout;
|
||||
id value = [transactionState valueForKey:@"value"];
|
||||
|
||||
|
||||
dispatch_barrier_async(_transactionQueue, ^{
|
||||
[_transactions removeObjectForKey:identifier];
|
||||
});
|
||||
|
||||
|
||||
if (abort) {
|
||||
return [FIRTransactionResult abort];
|
||||
} else {
|
||||
@ -442,34 +331,34 @@ RCT_EXPORT_METHOD(startTransaction:(NSString *) path identifier:(NSString *) ide
|
||||
|
||||
RCT_EXPORT_METHOD(tryCommitTransaction:(NSString *) identifier withData:(NSDictionary *) data) {
|
||||
__block NSMutableDictionary *transactionState;
|
||||
|
||||
|
||||
dispatch_sync(_transactionQueue, ^{
|
||||
transactionState = [_transactions objectForKey: identifier];
|
||||
});
|
||||
|
||||
|
||||
if (!transactionState) {
|
||||
NSLog(@"tryCommitTransaction for unknown ID %@", identifier);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
dispatch_semaphore_t sema = [transactionState valueForKey:@"semaphore"];
|
||||
|
||||
|
||||
BOOL abort = [[data valueForKey:@"abort"] boolValue];
|
||||
|
||||
|
||||
if (abort) {
|
||||
[transactionState setValue:@true forKey:@"abort"];
|
||||
} else {
|
||||
id newValue = [data valueForKey:@"value"];
|
||||
[transactionState setValue:newValue forKey:@"value"];
|
||||
}
|
||||
|
||||
|
||||
dispatch_semaphore_signal(sema);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(enablePersistence:(BOOL) enable
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
|
||||
|
||||
BOOL isEnabled = [FIRDatabase database].persistenceEnabled;
|
||||
if ( isEnabled != enable) {
|
||||
[FIRDatabase database].persistenceEnabled = enable;
|
||||
@ -526,10 +415,10 @@ RCT_EXPORT_METHOD(push:(NSString *) path
|
||||
{
|
||||
FIRDatabaseReference *ref = [self getPathRef:path];
|
||||
FIRDatabaseReference *newRef = [ref childByAutoId];
|
||||
|
||||
|
||||
NSURL *url = [NSURL URLWithString:newRef.URL];
|
||||
NSString *newPath = [url path];
|
||||
|
||||
|
||||
if ([data count] > 0) {
|
||||
[newRef setValue:[data valueForKey:@"value"] withCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
|
||||
if (error != nil) {
|
||||
@ -540,7 +429,7 @@ RCT_EXPORT_METHOD(push:(NSString *) path
|
||||
@"message": [error localizedDescription],
|
||||
@"description": [error description]
|
||||
};
|
||||
|
||||
|
||||
callback(@[evt]);
|
||||
} else {
|
||||
callback(@[[NSNull null], @{
|
||||
@ -558,58 +447,50 @@ RCT_EXPORT_METHOD(push:(NSString *) path
|
||||
}
|
||||
|
||||
|
||||
|
||||
RCT_EXPORT_METHOD(on:(NSString *) path
|
||||
modifiersString:(NSString *) modifiersString
|
||||
RCT_EXPORT_METHOD(on:(nonnull NSNumber *) refId
|
||||
path:(NSString *) path
|
||||
modifiers:(NSArray *) modifiers
|
||||
listenerId:(nonnull NSNumber *) listenerId
|
||||
name:(NSString *) eventName
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
RNFirebaseDBReference *ref = [self getDBHandle:path modifiers:modifiers modifiersString:modifiersString];
|
||||
[ref addEventHandler:eventName];
|
||||
RNFirebaseDBReference *ref = [self getDBHandle:refId path:path modifiers:modifiers];
|
||||
[ref addEventHandler:listenerId eventName:eventName];
|
||||
callback(@[[NSNull null], @{
|
||||
@"status": @"success",
|
||||
@"refId": refId,
|
||||
@"handle": path
|
||||
}]);
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(once:(NSString *) path
|
||||
modifiersString:(NSString *) modifiersString
|
||||
RCT_EXPORT_METHOD(once:(nonnull NSNumber *) refId
|
||||
path:(NSString *) path
|
||||
modifiers:(NSArray *) modifiers
|
||||
name:(NSString *) name
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
RNFirebaseDBReference *ref = [self getDBHandle:path modifiers:modifiers modifiersString:modifiersString];
|
||||
[ref addSingleEventHandler:callback];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(off:(NSString *)path
|
||||
modifiersString:(NSString *) modifiersString
|
||||
eventName:(NSString *) eventName
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
NSString *key = [self getDBListenerKey:path withModifiers:modifiersString];
|
||||
NSArray *listenerKeys;
|
||||
RNFirebaseDBReference *ref = [_dbReferences objectForKey:key];
|
||||
if (ref == nil) {
|
||||
listenerKeys = @[];
|
||||
} else {
|
||||
if (eventName == nil || [eventName isEqualToString:@""]) {
|
||||
[ref cleanup];
|
||||
[_dbReferences removeObjectForKey:key];
|
||||
} else {
|
||||
[ref removeEventHandler:eventName];
|
||||
RNFirebaseDBReference *ref = [self getDBHandle:refId path:path modifiers:modifiers];
|
||||
[ref addSingleEventHandler:callback];
|
||||
}
|
||||
|
||||
RCT_EXPORT_METHOD(off:(nonnull NSNumber *) refId
|
||||
listeners:(NSArray *) listeners
|
||||
callback:(RCTResponseSenderBlock) callback)
|
||||
{
|
||||
RNFirebaseDBReference *ref = [_dbReferences objectForKey:refId];
|
||||
if (ref != nil) {
|
||||
for (NSDictionary *listener in listeners) {
|
||||
NSNumber *listenerId = [listener valueForKey:@"listenerId"];
|
||||
NSString *eventName = [listener valueForKey:@"eventName"];
|
||||
[ref removeEventHandler:listenerId eventName:eventName];
|
||||
if (![ref hasListeners]) {
|
||||
[_dbReferences removeObjectForKey:key];
|
||||
[_dbReferences removeObjectForKey:refId];
|
||||
}
|
||||
}
|
||||
listenerKeys = [ref listenerKeys];
|
||||
}
|
||||
callback(@[[NSNull null], @{
|
||||
@"result": @"success",
|
||||
@"handle": path,
|
||||
@"modifiersString": modifiersString,
|
||||
@"remainingListeners": listenerKeys,
|
||||
@"status": @"success",
|
||||
@"refId": refId,
|
||||
}]);
|
||||
}
|
||||
|
||||
@ -680,30 +561,23 @@ RCT_EXPORT_METHOD(goOnline)
|
||||
}
|
||||
}
|
||||
|
||||
- (RNFirebaseDBReference *) getDBHandle:(NSString *) path
|
||||
modifiers:modifiers
|
||||
modifiersString:modifiersString
|
||||
- (RNFirebaseDBReference *) getDBHandle:(NSNumber *) refId
|
||||
path:(NSString *) path
|
||||
modifiers:(NSArray *) modifiers
|
||||
{
|
||||
NSString *key = [self getDBListenerKey:path withModifiers:modifiersString];
|
||||
RNFirebaseDBReference *ref = [_dbReferences objectForKey:key];
|
||||
|
||||
RNFirebaseDBReference *ref = [_dbReferences objectForKey:refId];
|
||||
|
||||
if (ref == nil) {
|
||||
ref = [[RNFirebaseDBReference alloc] initWithPathAndModifiers:self
|
||||
database:[FIRDatabase database]
|
||||
refId:refId
|
||||
path:path
|
||||
modifiers:modifiers
|
||||
modifiersString:modifiersString];
|
||||
[_dbReferences setObject:ref forKey:key];
|
||||
modifiers:modifiers];
|
||||
[_dbReferences setObject:ref forKey:refId];
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
- (NSString *) getDBListenerKey:(NSString *) path
|
||||
withModifiers:(NSString *) modifiersString
|
||||
{
|
||||
return [NSString stringWithFormat:@"%@ | %@", path, modifiersString, nil];
|
||||
}
|
||||
|
||||
// Not sure how to get away from this... yet
|
||||
- (NSArray<NSString *> *)supportedEvents {
|
||||
return @[DATABASE_DATA_EVENT, DATABASE_ERROR_EVENT, DATABASE_TRANSACTION_EVENT];
|
||||
|
61
tests/.gitignore
vendored
61
tests/.gitignore
vendored
@ -1,61 +0,0 @@
|
||||
# OSX
|
||||
#
|
||||
.DS_Store
|
||||
|
||||
# Xcode
|
||||
#
|
||||
build/
|
||||
*.pbxuser
|
||||
!default.pbxuser
|
||||
*.mode1v3
|
||||
!default.mode1v3
|
||||
*.mode2v3
|
||||
!default.mode2v3
|
||||
*.perspectivev3
|
||||
!default.perspectivev3
|
||||
xcuserdata
|
||||
*.xccheckout
|
||||
*.moved-aside
|
||||
DerivedData
|
||||
*.hmap
|
||||
*.ipa
|
||||
*.xcuserstate
|
||||
project.xcworkspace
|
||||
|
||||
# Android/IntelliJ
|
||||
#
|
||||
|
||||
android/gradle
|
||||
.idea
|
||||
.gradle
|
||||
local.properties
|
||||
*.iml
|
||||
|
||||
# node.js
|
||||
#
|
||||
node_modules/
|
||||
ios/Pods
|
||||
npm-debug.log
|
||||
yarn-error.log
|
||||
yarn.lock
|
||||
npm-debug*
|
||||
|
||||
# BUCK
|
||||
buck-out/
|
||||
\.buckd/
|
||||
*.keystore
|
||||
|
||||
# fastlane
|
||||
#
|
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
|
||||
# screenshots whenever they are needed.
|
||||
# For more information about the recommended setup visit:
|
||||
# https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
|
||||
|
||||
fastlane/report.xml
|
||||
fastlane/Preview.html
|
||||
fastlane/screenshots
|
||||
ios/Podfile
|
||||
ios/Podfile.lock
|
||||
ios/Pods/
|
||||
ios/ReactNativeFirebaseDemo.xcworkspace/
|
40
tests/ios/Podfile
Normal file
40
tests/ios/Podfile
Normal file
@ -0,0 +1,40 @@
|
||||
install! 'cocoapods', :deterministic_uuids => false
|
||||
# Uncomment this line to define a global platform for your project
|
||||
# platform :ios, '9.0'
|
||||
|
||||
target 'ReactNativeFirebaseDemo' do
|
||||
platform :ios, '8.0'
|
||||
# Uncomment this line if you're using Swift or would like to use dynamic frameworks
|
||||
# use_frameworks!
|
||||
|
||||
# Pods for ReactNativeFirebaseDemo
|
||||
pod 'React', :path => '../node_modules/react-native', :subspecs => [
|
||||
'Core',
|
||||
'RCTActionSheet',
|
||||
'RCTAnimation',
|
||||
'RCTCameraRoll',
|
||||
'RCTGeolocation',
|
||||
'RCTImage',
|
||||
'RCTLinkingIOS',
|
||||
'RCTNetwork',
|
||||
'RCTPushNotification',
|
||||
'RCTSettings',
|
||||
'RCTText',
|
||||
'RCTVibration',
|
||||
'RCTWebSocket'
|
||||
# Add any other subspecs you want to use in your project
|
||||
]
|
||||
|
||||
pod 'Firebase/Auth'
|
||||
pod 'Firebase/Analytics'
|
||||
pod 'Firebase/AppIndexing'
|
||||
pod 'Firebase/Core'
|
||||
pod 'Firebase/Crash'
|
||||
pod 'Firebase/Database'
|
||||
pod 'Firebase/DynamicLinks'
|
||||
pod 'Firebase/Messaging'
|
||||
pod 'Firebase/RemoteConfig'
|
||||
pod 'Firebase/Storage'
|
||||
|
||||
pod 'RNFirebase', :path => '../node_modules/react-native-firebase'
|
||||
end
|
177
tests/ios/Podfile.lock
Normal file
177
tests/ios/Podfile.lock
Normal file
@ -0,0 +1,177 @@
|
||||
PODS:
|
||||
- Firebase/Analytics (3.15.0):
|
||||
- Firebase/Core
|
||||
- Firebase/AppIndexing (3.15.0):
|
||||
- Firebase/Core
|
||||
- FirebaseAppIndexing (= 1.2.0)
|
||||
- Firebase/Auth (3.15.0):
|
||||
- Firebase/Core
|
||||
- FirebaseAuth (= 3.1.1)
|
||||
- Firebase/Core (3.15.0):
|
||||
- FirebaseAnalytics (= 3.7.0)
|
||||
- FirebaseCore (= 3.5.2)
|
||||
- Firebase/Crash (3.15.0):
|
||||
- Firebase/Core
|
||||
- FirebaseCrash (= 1.1.6)
|
||||
- Firebase/Database (3.15.0):
|
||||
- Firebase/Core
|
||||
- FirebaseDatabase (= 3.1.2)
|
||||
- Firebase/DynamicLinks (3.15.0):
|
||||
- Firebase/Core
|
||||
- FirebaseDynamicLinks (= 1.3.4)
|
||||
- Firebase/Messaging (3.15.0):
|
||||
- Firebase/Core
|
||||
- FirebaseMessaging (= 1.2.2)
|
||||
- Firebase/RemoteConfig (3.15.0):
|
||||
- Firebase/Core
|
||||
- FirebaseRemoteConfig (= 1.3.4)
|
||||
- Firebase/Storage (3.15.0):
|
||||
- Firebase/Core
|
||||
- FirebaseStorage (= 1.1.0)
|
||||
- FirebaseAnalytics (3.7.0):
|
||||
- FirebaseCore (~> 3.5)
|
||||
- FirebaseInstanceID (~> 1.0)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- FirebaseAppIndexing (1.2.0)
|
||||
- FirebaseAuth (3.1.1):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- GoogleToolboxForMac/NSDictionary+URLArguments (~> 2.1)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- FirebaseCore (3.5.2):
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- FirebaseCrash (1.1.6):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- FirebaseInstanceID (~> 1.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseDatabase (3.1.2):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- FirebaseDynamicLinks (1.3.4):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- FirebaseInstanceID (1.0.9)
|
||||
- FirebaseMessaging (1.2.2):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- FirebaseInstanceID (~> 1.0)
|
||||
- GoogleToolboxForMac/Logger (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseRemoteConfig (1.3.4):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- FirebaseInstanceID (~> 1.0)
|
||||
- GoogleToolboxForMac/NSData+zlib (~> 2.1)
|
||||
- Protobuf (~> 3.1)
|
||||
- FirebaseStorage (1.1.0):
|
||||
- FirebaseAnalytics (~> 3.7)
|
||||
- GTMSessionFetcher/Core (~> 1.1)
|
||||
- GoogleToolboxForMac/DebugUtils (2.1.1):
|
||||
- GoogleToolboxForMac/Defines (= 2.1.1)
|
||||
- GoogleToolboxForMac/Defines (2.1.1)
|
||||
- GoogleToolboxForMac/Logger (2.1.1):
|
||||
- GoogleToolboxForMac/Defines (= 2.1.1)
|
||||
- GoogleToolboxForMac/NSData+zlib (2.1.1):
|
||||
- GoogleToolboxForMac/Defines (= 2.1.1)
|
||||
- GoogleToolboxForMac/NSDictionary+URLArguments (2.1.1):
|
||||
- GoogleToolboxForMac/DebugUtils (= 2.1.1)
|
||||
- GoogleToolboxForMac/Defines (= 2.1.1)
|
||||
- GoogleToolboxForMac/NSString+URLArguments (= 2.1.1)
|
||||
- GoogleToolboxForMac/NSString+URLArguments (2.1.1)
|
||||
- GTMSessionFetcher/Core (1.1.9)
|
||||
- Protobuf (3.2.0)
|
||||
- React (0.40.0):
|
||||
- React/Core (= 0.40.0)
|
||||
- React/Core (0.40.0):
|
||||
- React/cxxreact
|
||||
- React/yoga
|
||||
- React/cxxreact (0.40.0):
|
||||
- React/jschelpers
|
||||
- React/jschelpers (0.40.0)
|
||||
- React/RCTActionSheet (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTAnimation (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTCameraRoll (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTImage
|
||||
- React/RCTGeolocation (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTImage (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTNetwork
|
||||
- React/RCTLinkingIOS (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTNetwork (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTPushNotification (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTSettings (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTText (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTVibration (0.40.0):
|
||||
- React/Core
|
||||
- React/RCTWebSocket (0.40.0):
|
||||
- React/Core
|
||||
- React/yoga (0.40.0)
|
||||
- RNFirebase (1.0.0-alpha12):
|
||||
- Firebase/Auth
|
||||
- Firebase/Core
|
||||
- Firebase/Database
|
||||
- Firebase/Messaging
|
||||
- Firebase/RemoteConfig
|
||||
- Firebase/Storage
|
||||
- React
|
||||
|
||||
DEPENDENCIES:
|
||||
- Firebase/Analytics
|
||||
- Firebase/AppIndexing
|
||||
- Firebase/Auth
|
||||
- Firebase/Core
|
||||
- Firebase/Crash
|
||||
- Firebase/Database
|
||||
- Firebase/DynamicLinks
|
||||
- Firebase/Messaging
|
||||
- Firebase/RemoteConfig
|
||||
- Firebase/Storage
|
||||
- React/Core (from `../node_modules/react-native`)
|
||||
- React/RCTActionSheet (from `../node_modules/react-native`)
|
||||
- React/RCTAnimation (from `../node_modules/react-native`)
|
||||
- React/RCTCameraRoll (from `../node_modules/react-native`)
|
||||
- React/RCTGeolocation (from `../node_modules/react-native`)
|
||||
- React/RCTImage (from `../node_modules/react-native`)
|
||||
- React/RCTLinkingIOS (from `../node_modules/react-native`)
|
||||
- React/RCTNetwork (from `../node_modules/react-native`)
|
||||
- React/RCTPushNotification (from `../node_modules/react-native`)
|
||||
- React/RCTSettings (from `../node_modules/react-native`)
|
||||
- React/RCTText (from `../node_modules/react-native`)
|
||||
- React/RCTVibration (from `../node_modules/react-native`)
|
||||
- React/RCTWebSocket (from `../node_modules/react-native`)
|
||||
- RNFirebase (from `../node_modules/react-native-firebase`)
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
React:
|
||||
:path: "../node_modules/react-native"
|
||||
RNFirebase:
|
||||
:path: "../node_modules/react-native-firebase"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Firebase: 2b1cdfba1cda8589f32904a697cc753322bff9d8
|
||||
FirebaseAnalytics: 0d1b7d81d5021155be37702a94ba1ec16d45365d
|
||||
FirebaseAppIndexing: d0fa52ce0ad13f4b5b2f09e4b47fb0dc2213f4e9
|
||||
FirebaseAuth: cc8a1824170adbd351edb7f994490a3fb5c18be6
|
||||
FirebaseCore: a024587e43778508700af8c6b1209f7c4516ba02
|
||||
FirebaseCrash: db4c05d9c75baa050744d31b36357c8f1efba481
|
||||
FirebaseDatabase: 05c96d7b43a7368dc91c07791adb49683e1738d1
|
||||
FirebaseDynamicLinks: 30fb0856dd9ae6d8ba4da00972141a5c293a27b2
|
||||
FirebaseInstanceID: 2d0518b1378fe9d685ef40cbdd63d2fdc1125339
|
||||
FirebaseMessaging: df8267f378580a24174ce7861233aa11d5c90109
|
||||
FirebaseRemoteConfig: af3003f4e8daa2bd1d5cf90d3cccc1fe224f8ed9
|
||||
FirebaseStorage: a5c55b23741a49a72af8f30f95b3bb5ddbeda12d
|
||||
GoogleToolboxForMac: 8e329f1b599f2512c6b10676d45736bcc2cbbeb0
|
||||
GTMSessionFetcher: 5c046c76a1f859bc9c187e918f18e4fc7bb57b5e
|
||||
Protobuf: 745f59e122e5de98d4d7ef291e264a0eef80f58e
|
||||
React: 6dfb2f72edb1d74a800127ae157af038646673ce
|
||||
RNFirebase: 228c16667a3ed1ba3b9ff0702449dca3be1c3618
|
||||
|
||||
PODFILE CHECKSUM: 23445e2727726988c7338fa2f396980d6fd3906f
|
||||
|
||||
COCOAPODS: 1.2.0
|
@ -1,3 +1,4 @@
|
||||
import { Platform } from 'react-native';
|
||||
import should from 'should';
|
||||
import sinon from 'sinon';
|
||||
|
||||
@ -89,9 +90,10 @@ function offTests({ describe, it, xcontext, context, firebase }) {
|
||||
|
||||
// Check childAddedCallback is really attached
|
||||
await ref.push(DatabaseContents.DEFAULT.number);
|
||||
// Android Note: There is definitely a single listener, but value is called three times
|
||||
// TODO: Android: There is definitely a single listener, but value is called three times
|
||||
// rather than the two you'd perhaps expect
|
||||
valueCallback.should.be.callCount(3);
|
||||
const expectedCount = Platform.OS === 'ios' ? 2 : 3;
|
||||
valueCallback.should.be.callCount(expectedCount);
|
||||
childAddedCallback.should.be.callCount(arrayLength + 1);
|
||||
|
||||
// Returns nothing
|
||||
@ -104,7 +106,7 @@ function offTests({ describe, it, xcontext, context, firebase }) {
|
||||
await ref.push(DatabaseContents.DEFAULT.number);
|
||||
|
||||
// Callbacks should have been unbound and not called again
|
||||
valueCallback.should.be.callCount(3);
|
||||
valueCallback.should.be.callCount(expectedCount);
|
||||
childAddedCallback.should.be.callCount(arrayLength + 1);
|
||||
});
|
||||
});
|
||||
@ -265,9 +267,10 @@ function offTests({ describe, it, xcontext, context, firebase }) {
|
||||
|
||||
// Callback should have been called only once because one of the attachments
|
||||
// has been removed
|
||||
// Android Note: There is definitely a single listener, but value is called twice
|
||||
// TODO: Android: There is definitely a single listener, but value is called twice
|
||||
// rather than the once you'd perhaps expect
|
||||
spyA.should.be.callCount(4);
|
||||
const expectedCount = Platform.OS === 'ios' ? 3 : 4;
|
||||
spyA.should.be.callCount(expectedCount);
|
||||
|
||||
// Undo the second attachment
|
||||
const resp2 = await ref.off('value', callbackA);
|
||||
@ -277,7 +280,7 @@ function offTests({ describe, it, xcontext, context, firebase }) {
|
||||
await ref.set(DatabaseContents.DEFAULT.number);
|
||||
|
||||
// Callback should not have been called any more times
|
||||
spyA.should.be.callCount(4);
|
||||
spyA.should.be.callCount(expectedCount);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user