[ios] Add multiple listener support

This commit is contained in:
Chris Bianca 2017-04-26 17:34:16 +01:00
parent 312b7b37b1
commit 6d4b5bc406
6 changed files with 352 additions and 316 deletions

11
.gitignore vendored
View File

@ -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/

View File

@ -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
View File

@ -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
View 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
View 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

View File

@ -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);
});
});
});