2
0
mirror of synced 2025-01-10 22:26:02 +00:00

ios - initial build

This commit is contained in:
Salakar 2017-03-09 15:26:28 +00:00
parent 2d1015d205
commit 05a35b7b82
19 changed files with 3024 additions and 0 deletions

71
ios/Podfile Normal file
View File

@ -0,0 +1,71 @@
source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
platform :ios, '8.0'
def common_pods
# pod 'RNFirebase', :path => '../'
# pod 'React', :path => '../node_modules/react-native'
[
'Firebase',
'Firebase/Core',
'Firebase/Auth',
'Firebase/Storage',
'Firebase/Database',
'Firebase/RemoteConfig',
'Firebase/Messaging'
].each do |lib|
pod lib
end
end
def test_pods
pod 'Quick', '~> 0.8.0'
pod 'Nimble', '~> 3.0.0'
end
def setup
post_install do |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |configuration|
# configuration.build_settings['EXPANDED_CODE_SIGN_IDENTITY'] = ""
# configuration.build_settings['CODE_SIGNING_REQUIRED'] = "YES"
# configuration.build_settings['CODE_SIGNING_ALLOWED'] = "YES"
target.build_settings(configuration.name)['OTHER_LDFLAGS'] = '$(inherited)'
target.build_settings(configuration.name)['USER_HEADER_SEARCH_PATHS'] = "$(BUILT_PRODUCTS_DIR)"
target.build_settings(configuration.name)['LD_DYLIB_INSTALL_NAME'] = '@rpath/${EXECUTABLE_NAME}'
target.build_settings(configuration.name)['LD_RUNPATH_SEARCH_PATHS'] = '$(inherited) @rpath @loader_path/../Frameworks @executable_path/Frameworks'
target.build_settings(configuration.name)['ONLY_ACTIVE_ARCH'] = 'NO'
target.build_settings(configuration.name)['HEADER_SEARCH_PATHS'] = [
"$(inherited)",
"${PODS_ROOT}/Headers/**",
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../../react-native/React/**",
'$(RN_ROOT)/React/**',
'$(PODS_ROOT)/Headers'
].join(' ')
target.build_settings(configuration.name)['FRAMEWORK_SEARCH_PATHS'] = [
"$(inherited)",
'$(PODS_ROOT)/**',
'$(PODS_CONFIGURATION_BUILD_DIR)/**'
].join(' ')
target.build_settings(configuration.name)['OTHER_LDFLAGS'] = "$(inherited)"
end
end
end
end
# target 'RNFirebase' do
# common_pods
# project "RNFirebase.xcodeproj"
# setup
# end
target 'RNFirebaseTests' do
use_frameworks!
common_pods
test_pods
pod 'React', :path => '../node_modules/react-native'
setup
end

15
ios/Podfile.template Normal file
View File

@ -0,0 +1,15 @@
source 'https://github.com/CocoaPods/Specs.git'
use_frameworks!
platform :ios, '8.0'
[
'Firebase',
'Firebase/Core',
'Firebase/Auth',
'Firebase/Storage',
'Firebase/Database',
'Firebase/RemoteConfig',
'Firebase/Messaging'
].each do |lib|
pod lib
end

View File

@ -0,0 +1,325 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
D90882D61D89C18C00FB6742 /* RNFirebaseMessaging.m in Sources */ = {isa = PBXBuildFile; fileRef = D90882D51D89C18C00FB6742 /* RNFirebaseMessaging.m */; };
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */ = {isa = PBXBuildFile; fileRef = D950369D1D19C77400F7094D /* RNFirebase.m */; };
D962903F1D6D15B00099A3EC /* RNFirebaseErrors.m in Sources */ = {isa = PBXBuildFile; fileRef = D962903E1D6D15B00099A3EC /* RNFirebaseErrors.m */; };
D96290451D6D16100099A3EC /* RNFirebaseAnalytics.m in Sources */ = {isa = PBXBuildFile; fileRef = D96290441D6D16100099A3EC /* RNFirebaseAnalytics.m */; };
D96290851D6D28B80099A3EC /* RNFirebaseDatabase.m in Sources */ = {isa = PBXBuildFile; fileRef = D96290841D6D28B80099A3EC /* RNFirebaseDatabase.m */; };
D9D62E7C1D6D86FD003D826D /* RNFirebaseStorage.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D62E7B1D6D86FD003D826D /* RNFirebaseStorage.m */; };
D9D62E801D6D8717003D826D /* RNFirebaseAuth.m in Sources */ = {isa = PBXBuildFile; fileRef = D9D62E7F1D6D8717003D826D /* RNFirebaseAuth.m */; };
/* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */
58B511D91A9E6C8500147676 /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
134814201AA4EA6300B7C361 /* libRNFirebase.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNFirebase.a; sourceTree = BUILT_PRODUCTS_DIR; };
D90882D41D89C18C00FB6742 /* RNFirebaseMessaging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseMessaging.h; path = RNFirebase/RNFirebaseMessaging.h; sourceTree = "<group>"; };
D90882D51D89C18C00FB6742 /* RNFirebaseMessaging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseMessaging.m; path = RNFirebase/RNFirebaseMessaging.m; sourceTree = "<group>"; };
D950369C1D19C77400F7094D /* RNFirebase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebase.h; path = RNFirebase/RNFirebase.h; sourceTree = "<group>"; };
D950369D1D19C77400F7094D /* RNFirebase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebase.m; path = RNFirebase/RNFirebase.m; sourceTree = "<group>"; };
D96290391D6D152A0099A3EC /* RNFirebaseEvents.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseEvents.h; path = RNFirebase/RNFirebaseEvents.h; sourceTree = "<group>"; };
D962903D1D6D15B00099A3EC /* RNFirebaseErrors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseErrors.h; path = RNFirebase/RNFirebaseErrors.h; sourceTree = "<group>"; };
D962903E1D6D15B00099A3EC /* RNFirebaseErrors.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseErrors.m; path = RNFirebase/RNFirebaseErrors.m; sourceTree = "<group>"; };
D96290431D6D16100099A3EC /* RNFirebaseAnalytics.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseAnalytics.h; path = RNFirebase/RNFirebaseAnalytics.h; sourceTree = "<group>"; };
D96290441D6D16100099A3EC /* RNFirebaseAnalytics.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseAnalytics.m; path = RNFirebase/RNFirebaseAnalytics.m; sourceTree = "<group>"; };
D96290831D6D28B80099A3EC /* RNFirebaseDatabase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseDatabase.h; path = RNFirebase/RNFirebaseDatabase.h; sourceTree = "<group>"; };
D96290841D6D28B80099A3EC /* RNFirebaseDatabase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseDatabase.m; path = RNFirebase/RNFirebaseDatabase.m; sourceTree = "<group>"; };
D9D62E7A1D6D86FD003D826D /* RNFirebaseStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseStorage.h; path = RNFirebase/RNFirebaseStorage.h; sourceTree = "<group>"; };
D9D62E7B1D6D86FD003D826D /* RNFirebaseStorage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseStorage.m; path = RNFirebase/RNFirebaseStorage.m; sourceTree = "<group>"; };
D9D62E7E1D6D8717003D826D /* RNFirebaseAuth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RNFirebaseAuth.h; path = RNFirebase/RNFirebaseAuth.h; sourceTree = "<group>"; };
D9D62E7F1D6D8717003D826D /* RNFirebaseAuth.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = RNFirebaseAuth.m; path = RNFirebase/RNFirebaseAuth.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
58B511D81A9E6C8500147676 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
134814211AA4EA7D00B7C361 /* Products */ = {
isa = PBXGroup;
children = (
134814201AA4EA6300B7C361 /* libRNFirebase.a */,
);
name = Products;
sourceTree = "<group>";
};
58B511D21A9E6C8500147676 = {
isa = PBXGroup;
children = (
D96290351D6D145F0099A3EC /* Modules */,
D950369C1D19C77400F7094D /* RNFirebase.h */,
D950369D1D19C77400F7094D /* RNFirebase.m */,
134814211AA4EA7D00B7C361 /* Products */,
);
sourceTree = "<group>";
};
D96290351D6D145F0099A3EC /* Modules */ = {
isa = PBXGroup;
children = (
D90882D41D89C18C00FB6742 /* RNFirebaseMessaging.h */,
D90882D51D89C18C00FB6742 /* RNFirebaseMessaging.m */,
D9D62E7E1D6D8717003D826D /* RNFirebaseAuth.h */,
D9D62E7F1D6D8717003D826D /* RNFirebaseAuth.m */,
D96290391D6D152A0099A3EC /* RNFirebaseEvents.h */,
D962903D1D6D15B00099A3EC /* RNFirebaseErrors.h */,
D962903E1D6D15B00099A3EC /* RNFirebaseErrors.m */,
D96290431D6D16100099A3EC /* RNFirebaseAnalytics.h */,
D96290441D6D16100099A3EC /* RNFirebaseAnalytics.m */,
D96290831D6D28B80099A3EC /* RNFirebaseDatabase.h */,
D96290841D6D28B80099A3EC /* RNFirebaseDatabase.m */,
D9D62E7A1D6D86FD003D826D /* RNFirebaseStorage.h */,
D9D62E7B1D6D86FD003D826D /* RNFirebaseStorage.m */,
);
name = Modules;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
58B511DA1A9E6C8500147676 /* RNFirebase */ = {
isa = PBXNativeTarget;
buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNFirebase" */;
buildPhases = (
58B511D71A9E6C8500147676 /* Sources */,
58B511D81A9E6C8500147676 /* Frameworks */,
58B511D91A9E6C8500147676 /* CopyFiles */,
);
buildRules = (
);
dependencies = (
);
name = RNFirebase;
productName = RCTDataManager;
productReference = 134814201AA4EA6300B7C361 /* libRNFirebase.a */;
productType = "com.apple.product-type.library.static";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
58B511D31A9E6C8500147676 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
ORGANIZATIONNAME = Invertase;
TargetAttributes = {
58B511DA1A9E6C8500147676 = {
CreatedOnToolsVersion = 6.1.1;
};
};
};
buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNFirebase" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 58B511D21A9E6C8500147676;
productRefGroup = 58B511D21A9E6C8500147676;
projectDirPath = "";
projectRoot = "";
targets = (
58B511DA1A9E6C8500147676 /* RNFirebase */,
);
};
/* End PBXProject section */
/* Begin PBXSourcesBuildPhase section */
58B511D71A9E6C8500147676 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
D9D62E801D6D8717003D826D /* RNFirebaseAuth.m in Sources */,
D96290451D6D16100099A3EC /* RNFirebaseAnalytics.m in Sources */,
D9D62E7C1D6D86FD003D826D /* RNFirebaseStorage.m in Sources */,
D962903F1D6D15B00099A3EC /* RNFirebaseErrors.m in Sources */,
D950369E1D19C77400F7094D /* RNFirebase.m in Sources */,
D90882D61D89C18C00FB6742 /* RNFirebaseMessaging.m in Sources */,
D96290851D6D28B80099A3EC /* RNFirebaseDatabase.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
58B511ED1A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_BITCODE = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
58B511EE1A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_BITCODE = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 9.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
58B511F01A9E6C8500147676 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
DEFINES_MODULE = NO;
EMBEDDED_CONTENT_CONTAINS_SWIFT = NO;
ENABLE_BITCODE = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"${BUILT_PRODUCTS_DIR}",
"${PROJECT_DIR}/../../../ios/Pods/**",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../../node_modules/react-native/React/**",
"$(SRCROOT)/../../react-native/React/**",
"${SRCROOT}/../../../ios/Pods/**",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = "$(inherited)";
MACH_O_TYPE = staticlib;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_NAME = RNFirebase;
SKIP_INSTALL = YES;
};
name = Debug;
};
58B511F11A9E6C8500147676 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES;
DEFINES_MODULE = NO;
EMBEDDED_CONTENT_CONTAINS_SWIFT = NO;
ENABLE_BITCODE = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"${BUILT_PRODUCTS_DIR}",
"${PROJECT_DIR}/../../../ios/Pods/**",
);
HEADER_SEARCH_PATHS = (
"$(inherited)",
"$(SRCROOT)/../../React/**",
"$(SRCROOT)/../../node_modules/react-native/React/**",
"$(SRCROOT)/../../react-native/React/**",
"${SRCROOT}/../../../ios/Pods/**",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LIBRARY_SEARCH_PATHS = "$(inherited)";
MACH_O_TYPE = staticlib;
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_NAME = RNFirebase;
SKIP_INSTALL = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNFirebase" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511ED1A9E6C8500147676 /* Debug */,
58B511EE1A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNFirebase" */ = {
isa = XCConfigurationList;
buildConfigurations = (
58B511F01A9E6C8500147676 /* Debug */,
58B511F11A9E6C8500147676 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 58B511D31A9E6C8500147676 /* Project object */;
}

View File

@ -0,0 +1,31 @@
#ifndef RNFirebase_h
#define RNFirebase_h
#import <UIKit/UIKit.h>
#import "RCTBridgeModule.h"
#import "RCTEventDispatcher.h"
#import "RCTEventEmitter.h"
@interface RNFirebase : RCTEventEmitter <RCTBridgeModule> {
}
// + (void) registerForNotification:(NSString *) typeStr andToken:(NSData *)deviceToken;
+ (void) setup:(UIApplication *) application
withLaunchOptions: (NSDictionary *) launchOptions;
+ (id) sharedInstance;
- (void) debugLog:(NSString *)title
msg:(NSString *)msg;
- (void) sendJSEvent:(NSString *)title
props:(NSDictionary *)props;
@property (nonatomic) BOOL debug;
@property (atomic) BOOL configured;
@property (nonatomic, strong) NSDictionary *configuration;
@end
#endif

380
ios/RNFirebase/RNFirebase.m Normal file
View File

@ -0,0 +1,380 @@
#import "RNFirebase.h"
#import "RNFirebaseErrors.h"
#import "RNFirebaseEvents.h"
static RNFirebase *_sharedInstance = nil;
static dispatch_once_t onceToken;
@implementation RNFirebase
typedef void (^UserWithTokenResponse)(NSDictionary *, NSError *);
- (void)dealloc
{
NSLog(@"Dealloc called on RNFirebase: %@", self);
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
// TODO: Implement
+ (void) setup:(UIApplication *) application
withLaunchOptions: (NSDictionary *) launchOptions
{
NSLog(@"Called setup for RNFirebase");
dispatch_once(&onceToken, ^{
[application registerForRemoteNotifications];
[[NSNotificationCenter defaultCenter]
postNotificationName:kRNFirebaseInitialized
object:nil];
});
}
- (id) init
{
self = [super init];
if (self != nil) {
NSLog(@"Setting up RNFirebase instance");
[RNFirebase initializeRNFirebase:self];
}
return self;
}
+ (void) initializeRNFirebase:(RNFirebase *) instance
{
dispatch_once(&onceToken, ^{
_sharedInstance = instance;
[[NSNotificationCenter defaultCenter]
postNotificationName:kRNFirebaseInitialized
object:nil];
});
}
+ (instancetype) sharedInstance
{
return _sharedInstance;
}
- (FIRApp *) firebaseApp
{
return [FIRApp defaultApp];
}
RCT_EXPORT_MODULE(RNFirebase);
RCT_EXPORT_METHOD(serverValue:(RCTResponseSenderBlock) callback)
{
callback(@[[NSNull null], @{
@"TIMESTAMP": [FIRServerValue timestamp]
}]);
}
RCT_EXPORT_METHOD(configureWithOptions:(NSDictionary *) opts
callback:(RCTResponseSenderBlock)callback)
{
dispatch_async(dispatch_get_main_queue(),^{
// Are we debugging, yo?
self.debug = [opts valueForKey:@"debug"] != nil ? YES : NO;
NSLog(@"options passed into configureWithOptions: %@", [opts valueForKey:@"debug"]);
NSDictionary *keyMapping = @{
@"GOOGLE_APP_ID": @[
@"appId",
@"googleAppId",
@"applicationId"
],
@"BUNDLE_ID": @[
@"bundleId",
@"bundleID"
],
@"GCM_SENDER_ID": @[
@"gcmSenderID",
@"GCMSenderID"
],
@"API_KEY": @[
@"apiKey"
],
@"CLIENT_ID": @[
@"clientId",
@"clientID"
],
@"TRACKING_ID": @[
@"trackingID",
@"trackingId"
],
@"ANDROID_CLIENT_ID": @[
@"applicationId",
@"clientId",
@"clientID",
@"androidClientID",
@"androidClientId"
],
@"DATABASE_URL": @[
@"databaseUrl",
@"databaseURL"
],
@"STORAGE_BUCKET": @[
@"storageBucket"
],
@"PROJECT_ID": @[
@"projectId",
@"projectID"
],
@"TRACKING_ID": @[
@"trackingID",
@"trackingId"
],
@"DEEP_LINK_SCHEME": @[
@"deepLinkScheme"
],
@"MESSAGING_SENDER_ID": @[
@"messagingSenderId",
@"messagingSenderID"
]
};
NSArray *optionKeys = [keyMapping allKeys];
NSMutableDictionary *props;
NSString *plistPath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist"];
if ([[NSFileManager defaultManager] fileExistsAtPath:plistPath]) {
// If the Firebase plist is included
props = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
} else {
props = [[NSMutableDictionary alloc] initWithCapacity:[optionKeys count]];
}
// Bundle ID either from options OR from the main bundle
NSString *bundleID;
if ([opts valueForKey:@"bundleID"]) {
bundleID = [opts valueForKey:@"bundleID"];
} else {
bundleID = [[NSBundle mainBundle] bundleIdentifier];
}
[props setValue:bundleID forKey:@"BUNDLE_ID"];
// Prefer the user configuration options over the default options
for (int i=0; i < [optionKeys count]; i++) {
// Traditional for loop here
@try {
NSString *key = [optionKeys objectAtIndex:i];
// If the name is capitalized
if ([opts valueForKey:key] != nil) {
NSString *value = [opts valueForKey:key];
[props setValue:value forKey:key];
}
NSArray *possibleNames = [keyMapping objectForKey:key];
for (NSString *name in possibleNames) {
if ([opts valueForKey:name] != nil) {
// The user passed this option in
NSString *value = [opts valueForKey:name];
[props setValue:value forKey:key];
}
}
}
@catch (NSException *err) {
// Uh oh?
NSLog(@"An error occurred: %@", err);
}
}
@try {
if (self.debug) {
NSLog(@"props ->: %@", props);
NSLog(@"GOOGLE_APP_ID: %@", [props valueForKey:@"GOOGLE_APP_ID"]);
NSLog(@"BUNDLE_ID: %@", [props valueForKey:@"BUNDLE_ID"]);
NSLog(@"GCM_SENDER_ID: %@", [props valueForKey:@"GCM_SENDER_ID"]);
NSLog(@"API_KEY: %@", [props valueForKey:@"API_KEY"]);
NSLog(@"CLIENT_ID: %@", [props valueForKey:@"CLIENT_ID"]);
NSLog(@"TRACKING_ID: %@", [props valueForKey:@"TRACKING_ID"]);
NSLog(@"ANDROID_CLIENT_ID: %@", [props valueForKey:@"ANDROID_CLIENT_ID"]);
NSLog(@"DATABASE_URL: %@", [props valueForKey:@"DATABASE_URL"]);
NSLog(@"STORAGE_BUCKET: %@", [props valueForKey:@"STORAGE_BUCKET"]);
NSLog(@"DEEP_LINK_SCHEME: %@", [props valueForKey:@"DEEP_LINK_SCHEME"]);
}
FIROptions *finalOptions = [[FIROptions alloc]
initWithGoogleAppID:[props valueForKey:@"GOOGLE_APP_ID"]
bundleID:[props valueForKey:@"BUNDLE_ID"]
GCMSenderID:[props valueForKey:@"GCM_SENDER_ID"]
APIKey:[props valueForKey:@"API_KEY"]
clientID:[props valueForKey:@"CLIENT_ID"]
trackingID:[props valueForKey:@"TRACKING_ID"]
androidClientID:[props valueForKey:@"ANDROID_CLIENT_ID"]
databaseURL:[props valueForKey:@"DATABASE_URL"]
storageBucket:[props valueForKey:@"STORAGE_BUCKET"]
deepLinkURLScheme:[props valueForKey:@"DEEP_LINK_SCHEME"]];
// Save configuration option
// NSDictionary *cfg = [self getConfig];
// [cfg setValuesForKeysWithDictionary:props];
// if (!self.configured) {
if ([FIRApp defaultApp] == NULL) {
[FIRApp configureWithOptions:finalOptions];
}
[RNFirebase initializeRNFirebase:self];
callback(@[[NSNull null], props]);
}
@catch (NSException *exception) {
NSLog(@"Exception occurred while configuring: %@", exception);
[self debugLog:@"Configuring error"
msg:[NSString stringWithFormat:@"An error occurred while configuring: %@", [exception debugDescription]]];
NSDictionary *errProps = @{
@"error": [exception name],
@"description": [exception debugDescription]
};
callback(@[errProps]);
}
});
}
RCT_EXPORT_METHOD(configure:(RCTResponseSenderBlock)callback)
{
NSDictionary *props = @{};
[self configureWithOptions:props
callback:callback];
}
#pragma mark - Storage
#pragma mark RemoteConfig
// RCT_EXPORT_METHOD(setDefaultRemoteConfig:(NSDictionary *)props
// callback:(RCTResponseSenderBlock) callback)
// {
// if (!self.remoteConfigInstance) {
// // Create remote Config instance
// self.remoteConfigInstance = [FIRRemoteConfig remoteConfig];
// }
// [self.remoteConfigInstance setDefaults:props];
// callback(@[[NSNull null], props]);
// }
// RCT_EXPORT_METHOD(setDev:(RCTResponseSenderBlock) callback)
// {
// FIRRemoteConfigSettings *remoteConfigSettings = [[FIRRemoteConfigSettings alloc] initWithDeveloperModeEnabled:YES];
// self.remoteConfigInstance.configSettings = remoteConfigSettings;
// callback(@[[NSNull null], @"ok"]);
// }
// RCT_EXPORT_METHOD(configValueForKey:(NSString *)name
// callback:(RCTResponseSenderBlock) callback)
// {
// if (!self.remoteConfigInstance) {
// NSDictionary *err = @{
// @"error": @"No configuration instance",
// @"msg": @"No configuration instance set. Please call setDefaultRemoteConfig before using this feature"
// };
// callback(@[err]);
// }
// FIRRemoteConfigValue *value = [self.remoteConfigInstance configValueForKey:name];
// NSString *valueStr = value.stringValue;
// if (valueStr == nil) {
// valueStr = @"";
// }
// callback(@[[NSNull null], valueStr]);
// }
// RCT_EXPORT_METHOD(fetchWithExpiration:(NSNumber*)expirationSeconds
// callback:(RCTResponseSenderBlock) callback)
// {
// if (!self.remoteConfigInstance) {
// NSDictionary *err = @{
// @"error": @"No configuration instance",
// @"msg": @"No configuration instance set. Please call setDefaultRemoteConfig before using this feature"
// };
// callback(@[err]);
// }
// NSTimeInterval expirationDuration = [expirationSeconds doubleValue];
// [self.remoteConfigInstance fetchWithExpirationDuration:expirationDuration completionHandler:^(FIRRemoteConfigFetchStatus status, NSError *error) {
// if (status == FIRRemoteConfigFetchStatusSuccess) {
// NSLog(@"Config fetched!");
// [self.remoteConfigInstance activateFetched];
// callback(@[[NSNull null], @(YES)]);
// } else {
// NSLog(@"Error %@", error.localizedDescription);
// NSDictionary *err = @{
// @"error": @"No configuration instance",
// @"msg": [error localizedDescription]
// };
// callback(@[err]);
// }
// }];
// }
#pragma mark Database
#pragma mark Messaging
#pragma mark Helpers
- (NSDictionary *) getConfig
{
if (self.configuration == nil) {
self.configuration = [[NSMutableDictionary alloc] initWithCapacity:20];
}
return self.configuration;
}
- (NSDictionary *) handleFirebaseError:(NSString *) name
error:(NSError *) error
withUser:(FIRUser *) user
{
return [RNFirebaseErrors handleFirebaseError:name
error:error
withUser:user];
}
- (void) handleException:(NSException *)exception
withCallback:(RCTResponseSenderBlock)callback
{
[RNFirebaseErrors handleException:exception
withCallback:callback];
}
- (void) debugLog:(NSString *)title
msg:(NSString *)msg
{
if (self.debug) {
NSLog(@"%@: %@", title, msg);
}
}
// Not sure how to get away from this... yet
- (NSArray<NSString *> *)supportedEvents {
return @[
INITIALIZED_EVENT,
DEBUG_EVENT,
AUTH_CHANGED_EVENT];
}
- (void) sendJSEvent:(NSString *)title
props:(NSDictionary *)props
{
@try {
[self sendEventWithName:title
body:props];
}
@catch (NSException *err) {
NSLog(@"An error occurred in sendJSEvent: %@", [err debugDescription]);
}
}
@end

View File

@ -0,0 +1,12 @@
#ifndef RNFirebaseAnalytics_h
#define RNFirebaseAnalytics_h
#import "RCTBridgeModule.h"
@interface RNFirebaseAnalytics : NSObject <RCTBridgeModule> {
}
@end
#endif

View File

@ -0,0 +1,59 @@
#import "RNFirebase.h"
#import "RNFirebaseEvents.h"
#import "RNFirebaseAnalytics.h"
#import "Firebase.h"
@implementation RNFirebaseAnalytics
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
RCT_EXPORT_MODULE(RNFirebaseAnalytics);
// Implementation
RCT_EXPORT_METHOD(logEvent:(NSString *)name
props:(NSDictionary *)props)
{
NSString *debugMsg = [NSString stringWithFormat:@"%@: %@ with %@",
@"RNFirebaseAnalytics", name, props];
[[RNFirebase sharedInstance] debugLog:@"logEventWithName called"
msg:debugMsg];
[FIRAnalytics logEventWithName:name parameters:props];
}
RCT_EXPORT_METHOD(setAnalyticsCollectionEnabled:(BOOL) enabled)
{
[[FIRAnalyticsConfiguration sharedInstance] setAnalyticsCollectionEnabled:enabled];
}
RCT_EXPORT_METHOD(setCurrentScreen:(NSString *) screenName
screenClass:(NSString *) screenClassOverriew)
{
[FIRAnalytics setScreenName:screenName screenClass:screenClassOverriew];
}
RCT_EXPORT_METHOD(setMinimumSessionDuration:(NSNumber *) milliseconds)
{
//Not implemented on iOS
}
RCT_EXPORT_METHOD(setSessionTimeoutDuration:(NSNumber *) milliseconds)
{
//Not implemented on iOS
}
RCT_EXPORT_METHOD(setUserId: (NSString *) id
props:(NSDictionary *) props)
{
[FIRAnalytics setUserID:id];
}
RCT_EXPORT_METHOD(setUserProperty: (NSString *) name
value:(NSString *) value)
{
[FIRAnalytics setUserPropertyString:value forName:name];
}
@end

View File

@ -0,0 +1,15 @@
#ifndef RNFirebaseAuth_h
#define RNFirebaseAuth_h
#import "Firebase.h"
#import "RCTEventEmitter.h"
#import "RCTBridgeModule.h"
@interface RNFirebaseAuth : RCTEventEmitter <RCTBridgeModule> {
FIRAuthStateDidChangeListenerHandle authListenerHandle;
Boolean listening;
}
@end
#endif

View File

@ -0,0 +1,503 @@
#import "RNFirebaseAuth.h"
#import "RNFirebaseErrors.h"
#import "RNFirebaseEvents.h"
@implementation RNFirebaseAuth
typedef void (^UserWithTokenResponse)(NSDictionary *, NSError *);
RCT_EXPORT_MODULE(RNFirebaseAuth);
RCT_EXPORT_METHOD(signInAnonymously:
(RCTResponseSenderBlock) callBack)
{
@try {
[[FIRAuth auth] signInAnonymouslyWithCompletion
:^(FIRUser *user, NSError *error) {
if (!user) {
NSDictionary *evt = @{
@"eventName": AUTH_ANONYMOUS_ERROR_EVENT,
@"msg": [error localizedDescription]
};
[self sendJSEvent:AUTH_CHANGED_EVENT
props: evt];
callBack(@[evt]);
} else {
[self userCallback:callBack user:user];
}
}];
} @catch(NSException *ex) {
NSDictionary *eventError = @{
@"eventName": AUTH_ANONYMOUS_ERROR_EVENT,
@"msg": ex.reason
};
[self sendJSEvent:AUTH_ERROR_EVENT
props:eventError];
NSLog(@"An exception occurred: %@", ex);
callBack(@[eventError]);
}
}
RCT_EXPORT_METHOD(signInWithCustomToken:
(NSString *)customToken
callback:(RCTResponseSenderBlock) callback)
{
[[FIRAuth auth]
signInWithCustomToken:customToken
completion:^(FIRUser *user, NSError *error) {
if (user != nil) {
[self userCallback:callback user:user];
} else {
[self userErrorCallback:callback error:error user:user msg:AUTH_ERROR_EVENT];
}
}];
}
RCT_EXPORT_METHOD(signInWithProvider:
(NSString *)provider
token:(NSString *)authToken
secret:(NSString *)authTokenSecret
callback:(RCTResponseSenderBlock)callback)
{
FIRAuthCredential *credential = [self getCredentialForProvider:provider
token:authToken
secret:authTokenSecret];
if (credential == nil) {
NSDictionary *err = @{
@"error": @"Unhandled provider"
};
return callback(@[err]);
}
@try {
[[FIRAuth auth] signInWithCredential:credential
completion:^(FIRUser *user, NSError *error) {
if (user != nil) {
// User is signed in.
[self userCallback:callback user:user];
} else {
NSLog(@"An error occurred: %@", [error localizedDescription]);
// No user is signed in.
NSDictionary *err = @{
@"error": @"No user signed in",
@"description": [error localizedDescription]
};
callback(@[err]);
}
}];
} @catch (NSException *exception) {
[RNFirebaseErrors handleException:exception
withCallback:callback];
}
}
RCT_EXPORT_METHOD(signOut:(RCTResponseSenderBlock)callback)
{
NSError *error;
[[FIRAuth auth] signOut:&error];
if (!error) {
// Sign-out succeeded
callback(@[[NSNull null], @YES]);
} else {
NSDictionary *err = @{
@"error": @"Signout error",
@"name": @([error code]),
@"description": [error description]
};
callback(@[err]);
}
}
RCT_EXPORT_METHOD(listenForAuth)
{
self->listening = true;
self->authListenerHandle =
[[FIRAuth auth] addAuthStateDidChangeListener:^(FIRAuth *_Nonnull auth,
FIRUser *_Nullable user) {
if (user != nil) {
// User is signed in.
[self userPropsFromFIRUserWithToken:user
andCallback:^(NSDictionary *userProps, NSError * error) {
if (error != nil) {
[self
sendJSEvent:AUTH_CHANGED_EVENT
props: @{
@"eventName": @"userTokenError",
@"msg": [error localizedDescription]
}];
} else {
[self
sendJSEvent:AUTH_CHANGED_EVENT
props: @{
@"eventName": @"user",
@"authenticated": @(true),
@"user": userProps
}];
}
}];
} else {
// TODO: Update this with different error states
NSDictionary *err = @{
@"error": @"No user logged in"
};
[self sendJSEvent:AUTH_CHANGED_EVENT
props:@{
@"eventName": @"no_user",
@"authenticated": @(false),
@"error": err
}];
}
}];
}
RCT_EXPORT_METHOD(unlistenForAuth:(RCTResponseSenderBlock)callback)
{
if (self->authListenerHandle != nil) {
[[FIRAuth auth] removeAuthStateDidChangeListener:self->authListenerHandle];
self->listening = false;
callback(@[[NSNull null]]);
}
}
RCT_EXPORT_METHOD(getCurrentUser:(RCTResponseSenderBlock)callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
if (user != nil) {
[self userCallback:callback user:user];
} else {
// No user is signed in.
NSDictionary *err = @{
@"user": @"No user logged in"
};
callback(@[err]);
}
}
RCT_EXPORT_METHOD(createUserWithEmail:(NSString *)email
pass:(NSString *)password
callback:(RCTResponseSenderBlock) callback)
{
[[FIRAuth auth]
createUserWithEmail:email
password:password
completion:^(FIRUser *_Nullable user,
NSError *_Nullable error) {
if (user != nil) {
[self userCallback:callback user:user];
} else {
NSDictionary *err = @{
@"error": @"createUserWithEmailError",
@"name": @([error code]),
@"description": [error localizedDescription]
};
callback(@[err]);
}
}];
}
RCT_EXPORT_METHOD(signInWithEmail:(NSString *)email
pass:(NSString *)password
callback:(RCTResponseSenderBlock) callback)
{
[[FIRAuth auth] signInWithEmail:email
password:password
completion:^(FIRUser *user, NSError *error) {
if (user != nil) {
[self userCallback:callback user:user];
} else {
[self userErrorCallback:callback error:error user:user msg:@"signinError"];
}
}];
}
RCT_EXPORT_METHOD(updateUserEmail:(NSString *)email
callback:(RCTResponseSenderBlock) callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
if (user) {
[user updateEmail:email completion:^(NSError *_Nullable error) {
if (error) {
// An error happened.
[self userErrorCallback:callback error:error user:user msg:@"updateEmailError"];
} else {
// Email updated.
[self userCallback:callback user:user];
}
}];
} else {
[self noUserCallback:callback isError:true];
}
}
RCT_EXPORT_METHOD(updateUserPassword:(NSString *)newPassword
callback:(RCTResponseSenderBlock) callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
if (user) {
[user updatePassword:newPassword completion:^(NSError *_Nullable error) {
if (error) {
// An error happened.
[self userErrorCallback:callback error:error user:user msg:@"updateUserPasswordError"];
} else {
// Email updated.
[self userCallback:callback user:user];
}
}];
} else {
[self noUserCallback:callback isError:true];
}
}
RCT_EXPORT_METHOD(sendPasswordResetWithEmail:(NSString *)email
callback:(RCTResponseSenderBlock) callback)
{
[[FIRAuth auth] sendPasswordResetWithEmail:email
completion:^(NSError *_Nullable error) {
if (error) {
// An error happened.
NSDictionary *err = @{
@"error": @"sendPasswordResetWithEmailError",
@"description": error.localizedDescription
};
callback(@[err]);
} else {
// Email updated.
callback(@[[NSNull null], @{
@"result": @(true)
}]);
}
}];
}
RCT_EXPORT_METHOD(deleteUser:(RCTResponseSenderBlock) callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
if (user) {
[user deleteWithCompletion:^(NSError *_Nullable error) {
if (error) {
[self userErrorCallback:callback error:error user:user msg:@"deleteUserError"];
} else {
callback(@[[NSNull null], @{@"result": @(true)}]);
}
}];
} else {
[self noUserCallback:callback isError:true];
}
}
RCT_EXPORT_METHOD(getToken:(RCTResponseSenderBlock) callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
if (user) {
[user getTokenWithCompletion:^(NSString *token, NSError *_Nullable error) {
if (error) {
[self userErrorCallback:callback error:error user:user msg:@"getTokenError"];
} else {
callback(@[[NSNull null], token]);
}
}];
} else {
[self noUserCallback:callback isError:true];
}
}
RCT_EXPORT_METHOD(getTokenWithCompletion:(RCTResponseSenderBlock) callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
if (user) {
[user getTokenWithCompletion:^(NSString *token , NSError *_Nullable error) {
if (error) {
[self userErrorCallback:callback error:error user:user msg:@"getTokenWithCompletion"];
} else {
callback(@[[NSNull null], token]);
}
}];
} else {
[self noUserCallback:callback isError:true];
}
}
RCT_EXPORT_METHOD(reauthenticateWithCredentialForProvider:
(NSString *)provider
token:(NSString *)authToken
secret:(NSString *)authTokenSecret
callback:(RCTResponseSenderBlock)callback)
{
FIRAuthCredential *credential = [self getCredentialForProvider:provider
token:authToken
secret:authTokenSecret];
if (credential == nil) {
NSDictionary *err = @{
@"error": @"Unhandled provider"
};
return callback(@[err]);
}
FIRUser *user = [FIRAuth auth].currentUser;
[user reauthenticateWithCredential:credential completion:^(NSError *_Nullable error) {
if (error) {
[self userErrorCallback:callback error:error user:user msg:@"reauthenticateWithCredentialForProviderError"];
} else {
callback(@[[NSNull null], @{@"result": @(true)}]);
}
}];
}
RCT_EXPORT_METHOD(updateUserProfile:(NSDictionary *)userProps
callback:(RCTResponseSenderBlock) callback)
{
FIRUser *user = [FIRAuth auth].currentUser;
if (user) {
FIRUserProfileChangeRequest *changeRequest = [user profileChangeRequest];
NSMutableArray *allKeys = [[userProps allKeys] mutableCopy];
for (NSString *key in allKeys) {
// i.e. changeRequest.displayName = userProps[displayName];
@try {
if ([key isEqualToString:@"photoURL"]) {
NSURL *url = [NSURL URLWithString:[userProps valueForKey:key]];
[changeRequest setValue:url forKey:key];
} else {
[changeRequest setValue:[userProps objectForKey:key] forKey:key];
}
}
@catch (NSException *exception) {
NSLog(@"Exception occurred while configuring: %@", exception);
}
@finally {
[changeRequest commitChangesWithCompletion:^(NSError *_Nullable error) {
if (error) {
// An error happened.
[self userErrorCallback:callback error:error user:user msg:@"updateEmailError"];
} else {
// Profile updated.
[self userCallback:callback user:user];
}
}];
}
}
} else {
[self noUserCallback:callback isError:true];
}
}
- (NSDictionary *) userPropsFromFIRUser:(FIRUser *) user
{
NSMutableDictionary *userProps = [@{
@"uid": user.uid,
@"email": user.email ? user.email : @"",
@"emailVerified": @(user.emailVerified),
@"anonymous": @(user.anonymous),
@"displayName": user.displayName ? user.displayName : @"",
@"refreshToken": user.refreshToken,
@"providerID": user.providerID
} mutableCopy];
if ([user valueForKey:@"photoURL"] != nil) {
[userProps setValue: [NSString stringWithFormat:@"%@", user.photoURL]
forKey:@"photoURL"];
}
return userProps;
}
- (void) userPropsFromFIRUserWithToken:(FIRUser *) user
andCallback:(UserWithTokenResponse) callback
{
NSMutableDictionary *userProps = [[self userPropsFromFIRUser:user] mutableCopy];
[user getTokenWithCompletion:^(NSString * _Nullable token, NSError * _Nullable error) {
if (error != nil) {
return callback(nil, error);
}
[userProps setValue:token forKey:@"idToken"];
callback(userProps, nil);
}];
}
- (FIRAuthCredential *)getCredentialForProvider:(NSString *)provider
token:(NSString *)authToken
secret:(NSString *)authTokenSecret
{
FIRAuthCredential *credential;
if ([provider compare:@"twitter" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
credential = [FIRTwitterAuthProvider credentialWithToken:authToken
secret:authTokenSecret];
} else if ([provider compare:@"facebook" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
credential = [FIRFacebookAuthProvider credentialWithAccessToken:authToken];
} else if ([provider compare:@"google" options:NSCaseInsensitiveSearch] == NSOrderedSame) {
credential = [FIRGoogleAuthProvider credentialWithIDToken:authToken
accessToken:authTokenSecret];
} else {
NSLog(@"Provider not yet handled: %@", provider);
}
return credential;
}
// Not sure how to get away from this... yet
- (NSArray<NSString *> *)supportedEvents {
return @[AUTH_CHANGED_EVENT, AUTH_ANONYMOUS_ERROR_EVENT, AUTH_ERROR_EVENT];
}
- (void) sendJSEvent:(NSString *)title
props:(NSDictionary *)props
{
@try {
if (self->listening) {
[self sendEventWithName:title
body:props];
}
}
@catch (NSException *err) {
NSLog(@"An error occurred in sendJSEvent: %@", [err debugDescription]);
}
}
- (void) userCallback:(RCTResponseSenderBlock) callback
user:(FIRUser *) user {
NSDictionary *userProps = [self userPropsFromFIRUser:user];
callback(@[[NSNull null], userProps]);
}
- (void) noUserCallback:(RCTResponseSenderBlock) callback
isError:(Boolean) isError {
if (isError) {
NSDictionary *err = @{
@"error": @"Unhandled provider"
};
return callback(@[err]);
}
return callback(@[[NSNull null], [NSNull null]]);
}
- (void) userErrorCallback:(RCTResponseSenderBlock) callback
error:(NSError *)error
user:(FIRUser *) user
msg:(NSString *) msg {
// An error happened.
NSDictionary *err = [RNFirebaseErrors handleFirebaseError:msg
error:error
withUser:user];
callback(@[err]);
}
@end

View File

@ -0,0 +1,16 @@
#ifndef RNFirebaseDatabase_h
#define RNFirebaseDatabase_h
#import "Firebase.h"
#import "RCTEventEmitter.h"
#import "RCTBridgeModule.h"
@interface RNFirebaseDatabase : RCTEventEmitter <RCTBridgeModule> {
}
@property NSMutableDictionary *dbReferences;
@end
#endif

View File

@ -0,0 +1,640 @@
#import "RNFirebase.h"
#import "RNFirebaseDatabase.h"
#import "RNFirebaseEvents.h"
@interface RNFirebaseDBReference : NSObject
@property RCTEventEmitter *emitter;
@property FIRDatabaseQuery *query;
@property NSString *path;
@property NSString *modifiersString;
@property NSMutableDictionary *listeners;
@property FIRDatabaseHandle childAddedHandler;
@property FIRDatabaseHandle childModifiedHandler;
@property FIRDatabaseHandle childRemovedHandler;
@property FIRDatabaseHandle childMovedHandler;
@property FIRDatabaseHandle childValueHandler;
@end
@implementation RNFirebaseDBReference
- (id) initWithPathAndModifiers:(RCTEventEmitter *) emitter
database:(FIRDatabase *) database
path:(NSString *) path
modifiers:(NSArray *) modifiers
modifiersString:(NSString *) modifiersString
{
self = [super init];
if (self) {
_emitter = emitter;
_path = path;
_modifiersString = modifiersString;
_query = [self buildQueryAtPathWithModifiers:database path:path modifiers:modifiers];
_listeners = [[NSMutableDictionary alloc] init];
}
return self;
}
- (void) addEventHandler:(NSString *) eventName
{
if (![self isListeningTo:eventName]) {
id withBlock = ^(FIRDataSnapshot * _Nonnull snapshot) {
NSDictionary *props = [self snapshotToDict:snapshot];
[self sendJSEvent:DATABASE_DATA_EVENT
title:eventName
props: @{
@"eventName": eventName,
@"path": _path,
@"modifiersString": _modifiersString,
@"snapshot": props
}];
};
id errorBlock = ^(NSError * _Nonnull error) {
NSLog(@"Error onDBEvent: %@", [error debugDescription]);
[self getAndSendDatabaseError:error
path:_path
modifiersString:_modifiersString];
};
int eventType = [self eventTypeFromName:eventName];
FIRDatabaseHandle handle = [_query observeEventType:eventType
withBlock:withBlock
withCancelBlock:errorBlock];
[self setEventHandler:handle forName:eventName];
} else {
NSLog(@"Warning Trying to add duplicate listener for type: %@ with modifiers: %@ for path: %@", eventName, _modifiersString, _path);
}
}
- (void) addSingleEventHandler:(RCTResponseSenderBlock) callback
{
[_query observeSingleEventOfType:FIRDataEventTypeValue
withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
NSDictionary *props = [self snapshotToDict:snapshot];
callback(@[[NSNull null], @{
@"eventName": @"value",
@"path": _path,
@"modifiersString": _modifiersString,
@"snapshot": props
}]);
}
withCancelBlock:^(NSError * _Nonnull error) {
NSLog(@"Error onDBEventOnce: %@", [error debugDescription]);
callback(@[@{
@"eventName": DATABASE_ERROR_EVENT,
@"path": _path,
@"modifiers": _modifiersString,
@"code": @([error code]),
@"details": [error debugDescription],
@"message": [error localizedDescription],
@"description": [error description]
}]);
}];
}
- (void) removeEventHandler:(NSString *) name
{
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;
}
[self unsetListeningOn:name];
}
- (NSDictionary *) snapshotToDict:(FIRDataSnapshot *) snapshot
{
NSMutableDictionary *dict = [[NSMutableDictionary alloc] init];
[dict setValue:snapshot.key forKey:@"key"];
NSDictionary *val = snapshot.value;
[dict setObject:val forKey:@"value"];
// Snapshot ordering
NSMutableArray *childKeys = [NSMutableArray array];
if (snapshot.childrenCount > 0) {
// Since JS does not respect object ordering of keys
// we keep a list of the keys and their ordering
// in the snapshot event
NSEnumerator *children = [snapshot children];
FIRDataSnapshot *child;
while(child = [children nextObject]) {
[childKeys addObject:child.key];
}
}
[dict setObject:childKeys forKey:@"childKeys"];
[dict setValue:@(snapshot.hasChildren) forKey:@"hasChildren"];
[dict setValue:@(snapshot.exists) forKey:@"exists"];
[dict setValue:@(snapshot.childrenCount) forKey:@"childrenCount"];
[dict setValue:snapshot.priority forKey:@"priority"];
return dict;
}
- (NSDictionary *) getAndSendDatabaseError:(NSError *) error
path:(NSString *) path
modifiersString:(NSString *) modifiersString
{
NSDictionary *event = @{
@"eventName": DATABASE_ERROR_EVENT,
@"path": path,
@"modifiers": modifiersString,
@"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];
}
@catch (NSException *err) {
NSLog(@"An error occurred in getAndSendDatabaseError: %@", [err debugDescription]);
NSLog(@"Tried to send: %@ with %@", DATABASE_ERROR_EVENT, event);
}
return event;
}
- (void) sendJSEvent:(NSString *)type
title:(NSString *)title
props:(NSDictionary *)props
{
@try {
[_emitter sendEventWithName:type
body:@{
@"eventName": title,
@"body": props
}];
}
@catch (NSException *err) {
NSLog(@"An error occurred in sendJSEvent: %@", [err debugDescription]);
NSLog(@"Tried to send: %@ with %@", title, props);
}
}
- (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];
}
} 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 ([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];
}
}
}
return query;
}
- (id) getIdValue:(NSString *) value
type:(NSString *) type
{
if ([type isEqualToString:@"number"]) {
return [NSNumber numberWithInteger:value.integerValue];
} else if ([type isEqualToString:@"boolean"]) {
return [NSNumber numberWithBool:value.boolValue];
} else {
return value;
}
}
- (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]) {
eventType = FIRDataEventTypeChildAdded;
} else if ([name isEqualToString:DATABASE_CHILD_MODIFIED_EVENT]) {
eventType = FIRDataEventTypeChildChanged;
} else if ([name isEqualToString:DATABASE_CHILD_REMOVED_EVENT]) {
eventType = FIRDataEventTypeChildRemoved;
} else if ([name isEqualToString:DATABASE_CHILD_MOVED_EVENT]) {
eventType = FIRDataEventTypeChildMoved;
}
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
@implementation RNFirebaseDatabase
RCT_EXPORT_MODULE(RNFirebaseDatabase);
- (id) init
{
self = [super init];
if (self != nil) {
_dbReferences = [[NSMutableDictionary alloc] init];
}
return self;
}
RCT_EXPORT_METHOD(enablePersistence:(BOOL) enable
callback:(RCTResponseSenderBlock) callback)
{
BOOL isEnabled = [FIRDatabase database].persistenceEnabled;
if ( isEnabled != enable) {
[FIRDatabase database].persistenceEnabled = enable;
}
callback(@[[NSNull null], @{
@"result": @"success"
}]);
}
RCT_EXPORT_METHOD(keepSynced:(NSString *) path
withEnable:(BOOL) enable
callback:(RCTResponseSenderBlock) callback)
{
FIRDatabaseReference *ref = [self getPathRef:path];
[ref keepSynced:enable];
callback(@[[NSNull null], @{
@"status": @"success",
@"path": path
}]);
}
RCT_EXPORT_METHOD(set:(NSString *) path
data:(NSDictionary *)data
callback:(RCTResponseSenderBlock) callback)
{
FIRDatabaseReference *ref = [self getPathRef:path];
[ref setValue:[data valueForKey:@"value"] withCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
[self handleCallback:@"set" callback:callback databaseError:error];
}];
}
RCT_EXPORT_METHOD(update:(NSString *) path
value:(NSDictionary *)value
callback:(RCTResponseSenderBlock) callback)
{
FIRDatabaseReference *ref = [self getPathRef:path];
[ref updateChildValues:value withCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
[self handleCallback:@"update" callback:callback databaseError:error];
}];
}
RCT_EXPORT_METHOD(remove:(NSString *) path
callback:(RCTResponseSenderBlock) callback)
{
FIRDatabaseReference *ref = [self getPathRef:path];
[ref removeValueWithCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
[self handleCallback:@"remove" callback:callback databaseError:error];
}];
}
RCT_EXPORT_METHOD(push:(NSString *) path
data:(NSDictionary *) data
callback:(RCTResponseSenderBlock) callback)
{
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) {
// Error handling
NSDictionary *evt = @{
@"code": @([error code]),
@"details": [error debugDescription],
@"message": [error localizedDescription],
@"description": [error description]
};
callback(@[evt]);
} else {
callback(@[[NSNull null], @{
@"status": @"success",
@"ref": newPath
}]);
}
}];
} else {
callback(@[[NSNull null], @{
@"status": @"success",
@"ref": newPath
}]);
}
}
RCT_EXPORT_METHOD(on:(NSString *) path
modifiersString:(NSString *) modifiersString
modifiers:(NSArray *) modifiers
name:(NSString *) eventName
callback:(RCTResponseSenderBlock) callback)
{
RNFirebaseDBReference *ref = [self getDBHandle:path modifiers:modifiers modifiersString:modifiersString];
[ref addEventHandler:eventName];
callback(@[[NSNull null], @{
@"status": @"success",
@"handle": path
}]);
}
RCT_EXPORT_METHOD(once:(NSString *) path
modifiersString:(NSString *) modifiersString
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];
if (![ref hasListeners]) {
[_dbReferences removeObjectForKey:key];
}
}
listenerKeys = [ref listenerKeys];
}
callback(@[[NSNull null], @{
@"result": @"success",
@"handle": path,
@"modifiersString": modifiersString,
@"remainingListeners": listenerKeys,
}]);
}
// On disconnect
RCT_EXPORT_METHOD(onDisconnectSetObject:(NSString *) path
props:(NSDictionary *) props
callback:(RCTResponseSenderBlock) callback)
{
FIRDatabaseReference *ref = [self getPathRef:path];
[ref onDisconnectSetValue:props
withCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
[self handleCallback:@"onDisconnectSetObject" callback:callback databaseError:error];
}];
}
RCT_EXPORT_METHOD(onDisconnectSetString:(NSString *) path
val:(NSString *) val
callback:(RCTResponseSenderBlock) callback)
{
FIRDatabaseReference *ref = [self getPathRef:path];
[ref onDisconnectSetValue:val
withCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
[self handleCallback:@"onDisconnectSetString" callback:callback databaseError:error];
}];
}
RCT_EXPORT_METHOD(onDisconnectRemove:(NSString *) path
callback:(RCTResponseSenderBlock) callback)
{
FIRDatabaseReference *ref = [self getPathRef:path];
[ref onDisconnectRemoveValueWithCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
[self handleCallback:@"onDisconnectRemove" callback:callback databaseError:error];
}];
}
RCT_EXPORT_METHOD(onDisconnectCancel:(NSString *) path
callback:(RCTResponseSenderBlock) callback)
{
FIRDatabaseReference *ref = [self getPathRef:path];
[ref cancelDisconnectOperationsWithCompletionBlock:^(NSError * _Nullable error, FIRDatabaseReference * _Nonnull ref) {
[self handleCallback:@"onDisconnectCancel" callback:callback databaseError:error];
}];
}
RCT_EXPORT_METHOD(goOffline)
{
[FIRDatabase database].goOffline;
}
RCT_EXPORT_METHOD(goOnline)
{
[FIRDatabase database].goOnline;
}
- (FIRDatabaseReference *) getPathRef:(NSString *) path
{
return [[[FIRDatabase database] reference] child:path];
}
- (void) handleCallback:(NSString *) methodName
callback:(RCTResponseSenderBlock) callback
databaseError:(NSError *) databaseError
{
if (databaseError != nil) {
NSDictionary *evt = @{
@"code": [NSNumber numberWithInt:[databaseError code]],
@"details": [databaseError debugDescription],
@"message": [databaseError localizedDescription],
@"description": [databaseError description]
};
callback(@[evt]);
} else {
callback(@[[NSNull null], @{
@"status": @"success",
@"method": methodName
}]);
}
}
- (RNFirebaseDBReference *) getDBHandle:(NSString *) path
modifiers:modifiers
modifiersString:modifiersString
{
NSString *key = [self getDBListenerKey:path withModifiers:modifiersString];
RNFirebaseDBReference *ref = [_dbReferences objectForKey:key];
if (ref == nil) {
ref = [[RNFirebaseDBReference alloc] initWithPathAndModifiers:self
database:[FIRDatabase database]
path:path
modifiers:modifiers
modifiersString:modifiersString];
[_dbReferences setObject:ref forKey:key];
}
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];
}
@end

View File

@ -0,0 +1,19 @@
#ifndef RNFirebaseErrors_h
#define RNFirebaseErrors_h
#import "RCTBridgeModule.h"
#import "Firebase.h"
@interface RNFirebaseErrors : NSObject <RCTBridgeModule> {
}
+ (void) handleException:(NSException *)exception
withCallback:(RCTResponseSenderBlock)callback;
+ (NSDictionary *) handleFirebaseError:(NSString *) name
error:(NSError *) error
withUser:(FIRUser *) user;
@end
#endif

View File

@ -0,0 +1,52 @@
#import "RNFirebaseErrors.h"
@implementation RNFirebaseErrors
RCT_EXPORT_MODULE(RNFirebaseErrors);
+ (void) handleException:(NSException *)exception
withCallback:(RCTResponseSenderBlock)callback
{
NSString *errDesc = [exception description];
NSLog(@"An error occurred: %@", errDesc);
// No user is signed in.
NSDictionary *err = @{
@"error": @"No user signed in",
@"description": errDesc
};
callback(@[err]);
}
+ (NSDictionary *) handleFirebaseError:(NSString *) name
error:(NSError *) error
withUser:(FIRUser *) user
{
NSMutableDictionary *err = [NSMutableDictionary dictionaryWithObjectsAndKeys:
name, @"name",
@([error code]), @"code",
[error localizedDescription], @"rawDescription",
[[error userInfo] description], @"userInfo",
nil];
NSString *description = @"Unknown error";
switch (error.code) {
case FIRAuthErrorCodeInvalidEmail:
description = @"Invalid email";
break;
case FIRAuthErrorCodeUserNotFound:
description = @"User not found";
break;
case FIRAuthErrorCodeNetworkError:
description = @"Network error";
break;
case FIRAuthErrorCodeInternalError:
description = @"Internal error";
break;
default:
break;
}
[err setValue:description forKey:@"description"];
return [NSDictionary dictionaryWithDictionary:err];
}
@end

View File

@ -0,0 +1,49 @@
#ifndef RNFirebaseEvents_h
#define RNFirebaseEvents_h
#import <Foundation/Foundation.h>
#define SYSTEM_VERSION_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedSame)
#define SYSTEM_VERSION_GREATER_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedDescending)
#define SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] == NSOrderedAscending)
#define SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(v) ([[[UIDevice currentDevice] systemVersion] compare:v options:NSNumericSearch] != NSOrderedDescending)
#define RNFIREBASE_QUEUE_NAME "com.invertase.firebase.WorkerQueue"
static NSString *const kRNFirebaseInitialized = @"RNFirebaseInitializedEvent";
static NSString *const INITIALIZED_EVENT = @"RNFirebaseInitialized";
static NSString *const AUTH_CHANGED_EVENT = @"listenForAuth";
static NSString *const AUTH_ERROR_EVENT = @"authError";
static NSString *const AUTH_ANONYMOUS_ERROR_EVENT = @"authAnonymousError";
static NSString *const DEBUG_EVENT = @"debug";
// Database
static NSString *const DATABASE_DATA_EVENT = @"database_event";
static NSString *const DATABASE_ERROR_EVENT = @"database_error";
static NSString *const DATABASE_VALUE_EVENT = @"value";
static NSString *const DATABASE_CHILD_ADDED_EVENT = @"child_added";
static NSString *const DATABASE_CHILD_MODIFIED_EVENT = @"child_changed";
static NSString *const DATABASE_CHILD_REMOVED_EVENT = @"child_removed";
static NSString *const DATABASE_CHILD_MOVED_EVENT = @"child_moved";
// Storage
static NSString *const STORAGE_EVENT = @"storage_event";
static NSString *const STORAGE_ERROR = @"storage_error";
static NSString *const STORAGE_STATE_CHANGED = @"state_changed";
static NSString *const STORAGE_UPLOAD_SUCCESS = @"upload_success";
static NSString *const STORAGE_UPLOAD_FAILURE = @"upload_failure";
static NSString *const STORAGE_DOWNLOAD_SUCCESS = @"download_success";
static NSString *const STORAGE_DOWNLOAD_FAILURE = @"download_failure";
// Messaging
static NSString *const MESSAGING_SUBSYSTEM_EVENT = @"messaging_event";
static NSString *const MESSAGING_SUBSYSTEM_ERROR = @"messaging_error";
static NSString *const MESSAGING_TOKEN_REFRESH = @"messaging_token_refresh";
static NSString *const MESSAGING_MESSAGE_RECEIVED_REMOTE = @"messaging_remote_event_received";
static NSString *const MESSAGING_MESSAGE_RECEIVED_LOCAL = @"messaging_local_event_received";
#endif

View File

@ -0,0 +1,17 @@
#ifndef RNFirebaseMessaging_h
#define RNFirebaseMessaging_h
#import "Firebase.h"
#import "RCTEventEmitter.h"
#import "RCTBridgeModule.h"
#import "RCTUtils.h"
@interface RNFirebaseMessaging : RCTEventEmitter <RCTBridgeModule> {
}
+ (void) setup:(UIApplication *)application;
@end
#endif

View File

@ -0,0 +1,323 @@
#import <Foundation/Foundation.h>
#import <NotificationCenter/NotificationCenter.h>
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
#import <UserNotifications/UserNotifications.h>
#endif
#import "RNFirebaseMessaging.h"
#import "RNFirebaseEvents.h"
#import "RCTConvert.h"
// https://github.com/facebook/react-native/blob/master/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
@implementation RCTConvert (UILocalNotification)
+ (UILocalNotification *)UILocalNotification:(id)json
{
NSDictionary<NSString *, id> *details = [self NSDictionary:json];
UILocalNotification *notification = [UILocalNotification new];
notification.fireDate = [RCTConvert NSDate:details[@"fireDate"]] ?: [NSDate date];
notification.alertBody = [RCTConvert NSString:details[@"alertBody"]];
notification.alertAction = [RCTConvert NSString:details[@"alertAction"]];
notification.soundName = [RCTConvert NSString:details[@"soundName"]] ?: UILocalNotificationDefaultSoundName;
notification.userInfo = [RCTConvert NSDictionary:details[@"userInfo"]];
notification.category = [RCTConvert NSString:details[@"category"]];
if (details[@"applicationIconBadgeNumber"]) {
notification.applicationIconBadgeNumber = [RCTConvert NSInteger:details[@"applicationIconBadgeNumber"]];
}
return notification;
}
@end
@implementation RNFirebaseMessaging
// https://github.com/facebook/react-native/blob/master/Libraries/PushNotificationIOS/RCTPushNotificationManager.m
static NSDictionary *RCTFormatLocalNotification(UILocalNotification *notification)
{
NSMutableDictionary *formattedLocalNotification = [NSMutableDictionary dictionary];
if (notification.fireDate) {
NSDateFormatter *formatter = [NSDateFormatter new];
[formatter setDateFormat:@"yyyy-MM-dd'T'HH:mm:ss.SSSZZZZZ"];
NSString *fireDateString = [formatter stringFromDate:notification.fireDate];
formattedLocalNotification[@"fireDate"] = fireDateString;
}
formattedLocalNotification[@"alertAction"] = RCTNullIfNil(notification.alertAction);
formattedLocalNotification[@"alertBody"] = RCTNullIfNil(notification.alertBody);
formattedLocalNotification[@"applicationIconBadgeNumber"] = @(notification.applicationIconBadgeNumber);
formattedLocalNotification[@"category"] = RCTNullIfNil(notification.category);
formattedLocalNotification[@"soundName"] = RCTNullIfNil(notification.soundName);
formattedLocalNotification[@"userInfo"] = RCTNullIfNil(RCTJSONClean(notification.userInfo));
formattedLocalNotification[@"remote"] = @NO;
return formattedLocalNotification;
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
}
+ (void) setup:(UIApplication *) application
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(connectToFirebase)
name: UIApplicationDidEnterBackgroundNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(disconnectFromFirebase)
name: UIApplicationDidBecomeActiveNotification
object: nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleRemoteNotificationReceived:)
name:MESSAGING_MESSAGE_RECEIVED_REMOTE
object: nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleLocalNotificationReceived:)
name:MESSAGING_MESSAGE_RECEIVED_LOCAL
object: nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleTokenRefresh)
name:kFIRInstanceIDTokenRefreshNotification
object: nil];
if (SYSTEM_VERSION_LESS_THAN_OR_EQUAL_TO(@"9.0")) {
UIUserNotificationType allNotificationTypes =
(UIUserNotificationTypeSound | UIUserNotificationTypeAlert | UIUserNotificationTypeBadge);
UIUserNotificationSettings *settings =
[UIUserNotificationSettings settingsForTypes:allNotificationTypes categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:settings];
} else {
// iOS 10 or later
#if defined(__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
UNAuthorizationOptions authOptions =
UNAuthorizationOptionAlert
| UNAuthorizationOptionSound
| UNAuthorizationOptionBadge;
[[UNUserNotificationCenter currentNotificationCenter]
requestAuthorizationWithOptions:authOptions
completionHandler:^(BOOL granted, NSError * _Nullable error) {
}
];
// For iOS 10 display notification (sent via APNS)
[[UNUserNotificationCenter currentNotificationCenter] setDelegate:self];
// For iOS 10 data message (sent via FCM)
[[FIRMessaging messaging] setRemoteMessageDelegate:self];
#endif
}
[[UIApplication sharedApplication] registerForRemoteNotifications];
}
#pragma mark callbacks
- (void) connectToFirebase
{
[[FIRMessaging messaging] connectWithCompletion:^(NSError *error) {
NSDictionary *evt;
NSString *evtName;
if (error != nil) {
NSLog(@"Error connecting: %@", [error debugDescription]);
evtName = MESSAGING_SUBSYSTEM_ERROR;
evt = @{
@"eventName": MESSAGING_SUBSYSTEM_ERROR,
@"msg": [error debugDescription]
};
} else {
NSLog(@"Connected to Firebase messaging");
evtName = MESSAGING_SUBSYSTEM_EVENT;
evt = @{
@"result": @"connected"
};
[self
sendJSEvent:evtName
props: evt];
}
}];
}
- (void) disconnectFromFirebase
{
[[FIRMessaging messaging] disconnect];
NSLog(@"Disconnect from Firebase");
[self
sendJSEvent:MESSAGING_SUBSYSTEM_EVENT
props: @{
@"status": @"disconnected"
}];
}
- (void) handleRemoteNotificationReceived:(NSNotification *) n
{
NSMutableDictionary *props = [[NSMutableDictionary alloc] initWithDictionary: n.userInfo];
[self sendJSEvent:MESSAGING_MESSAGE_RECEIVED_REMOTE props: props];
}
- (void) handleLocalNotificationReceived:(NSNotification *) n
{
NSMutableDictionary *props = [[NSMutableDictionary alloc] initWithDictionary: n.userInfo];
[self sendJSEvent:MESSAGING_MESSAGE_RECEIVED_LOCAL props: props];
}
- (void) handleTokenRefresh
{
NSDictionary *props = @{
@"status": @"token_refreshed",
@"token": [[FIRInstanceID instanceID] token]
};
[self sendJSEvent:MESSAGING_TOKEN_REFRESH props: props];
}
RCT_EXPORT_MODULE(RNFirebaseMessaging);
RCT_EXPORT_METHOD(getToken:(RCTResponseSenderBlock)callback)
{
NSString *token = [[FIRInstanceID instanceID] token];
callback(@[[NSNull null], @{
@"status": @"success",
@"token": token
}]);
}
RCT_EXPORT_METHOD(sendLocal:(UILocalNotification *)notification
callback:(RCTResponseSenderBlock) callback)
{
NSLog(@"sendLocal called with notification: %@", notification);
[RCTSharedApplication() presentLocalNotificationNow:notification];
}
RCT_EXPORT_METHOD(scheduleLocal:(UILocalNotification *)notification
callback:(RCTResponseSenderBlock) callback)
{
[RCTSharedApplication() scheduleLocalNotification:notification];
}
RCT_EXPORT_METHOD(cancelAllLocalNotifications)
{
[RCTSharedApplication() cancelAllLocalNotifications];
}
RCT_EXPORT_METHOD(cancelLocalNotifications:(NSDictionary<NSString *, id> *)userInfo)
{
for (UILocalNotification *notification in [UIApplication sharedApplication].scheduledLocalNotifications) {
__block BOOL matchesAll = YES;
NSDictionary<NSString *, id> *notificationInfo = notification.userInfo;
// Note: we do this with a loop instead of just `isEqualToDictionary:`
// because we only require that all specified userInfo values match the
// notificationInfo values - notificationInfo may contain additional values
// which we don't care about.
[userInfo enumerateKeysAndObjectsUsingBlock:^(NSString *key, id obj, BOOL *stop) {
if (![notificationInfo[key] isEqual:obj]) {
matchesAll = NO;
*stop = YES;
}
}];
if (matchesAll) {
[[UIApplication sharedApplication] cancelLocalNotification:notification];
}
}
}
RCT_EXPORT_METHOD(sendRemote:(UILocalNotification *)notification
callback:(RCTResponseSenderBlock) callback)
{
}
RCT_EXPORT_METHOD(send:(NSString *) senderId
messageId:(NSString *) messageId
messageType:(NSString *) messageType
msg: (NSString *) msg
callback:(RCTResponseSenderBlock)callback)
{
}
RCT_EXPORT_METHOD(listenForTokenRefresh:(RCTResponseSenderBlock)callback)
{}
RCT_EXPORT_METHOD(unlistenForTokenRefresh:(RCTResponseSenderBlock)callback)
{}
RCT_EXPORT_METHOD(subscribeToTopic:(NSString *) topic
callback:(RCTResponseSenderBlock)callback)
{
[[FIRMessaging messaging] subscribeToTopic:topic];
callback(@[[NSNull null], @{
@"result": @"success",
@"topic": topic
}]);
}
RCT_EXPORT_METHOD(unsubscribeFromTopic:(NSString *) topic
callback: (RCTResponseSenderBlock)callback)
{
[[FIRMessaging messaging] unsubscribeFromTopic:topic];
callback(@[[NSNull null], @{
@"result": @"success",
@"topic": topic
}]);
}
RCT_EXPORT_METHOD(setBadge:(NSInteger) number
callback:(RCTResponseSenderBlock) callback)
{
RCTSharedApplication().applicationIconBadgeNumber = number;
callback(@[[NSNull null], @{
@"result": @"success",
@"number": @(number)
}]);
}
RCT_EXPORT_METHOD(getBadge:(RCTResponseSenderBlock) callback)
{
callback(@[[NSNull null], @{
@"result": @"success",
@"number": @(RCTSharedApplication().applicationIconBadgeNumber)
}]);
}
RCT_EXPORT_METHOD(listenForReceiveNotification:(RCTResponseSenderBlock)callback)
{}
RCT_EXPORT_METHOD(unlistenForReceiveNotification:(RCTResponseSenderBlock)callback)
{}
RCT_EXPORT_METHOD(listenForReceiveUpstreamSend:(RCTResponseSenderBlock)callback)
{}
RCT_EXPORT_METHOD(unlistenForReceiveUpstreamSend:(RCTResponseSenderBlock)callback)
{}
// Not sure how to get away from this... yet
- (NSArray<NSString *> *)supportedEvents {
return @[
MESSAGING_SUBSYSTEM_EVENT,
MESSAGING_SUBSYSTEM_ERROR,
MESSAGING_TOKEN_REFRESH,
MESSAGING_MESSAGE_RECEIVED_LOCAL,
MESSAGING_MESSAGE_RECEIVED_REMOTE];
}
- (void) sendJSEvent:(NSString *)title
props:(NSDictionary *)props
{
@try {
[self sendEventWithName:title
body:@{
@"eventName": title,
@"body": props
}];
}
@catch (NSException *err) {
NSLog(@"An error occurred in sendJSEvent: %@", [err debugDescription]);
NSLog(@"Tried to send: %@ with %@", title, props);
}
}
@end

View File

@ -0,0 +1,16 @@
#ifndef RNFirebaseStorage_h
#define RNFirebaseStorage_h
#import "Firebase.h"
#import "RCTBridgeModule.h"
#import "RCTEventEmitter.h"
@interface RNFirebaseStorage : RCTEventEmitter <RCTBridgeModule> {
}
@property (nonatomic) NSString *_storageUrl;
@end
#endif

View File

@ -0,0 +1,468 @@
#import "RNFirebaseStorage.h"
#import "RNFirebaseEvents.h"
#import <Photos/Photos.h>
@implementation RNFirebaseStorage
RCT_EXPORT_MODULE(RNFirebaseStorage);
// Run on a different thread
- (dispatch_queue_t)methodQueue
{
return dispatch_queue_create("com.invertase.firebase.storage", DISPATCH_QUEUE_SERIAL);
}
RCT_EXPORT_METHOD(delete: (NSString *) path
callback:(RCTResponseSenderBlock) callback)
{
FIRStorageReference *fileRef = [self getReference:path];
[fileRef deleteWithCompletion:^(NSError * _Nullable error) {
if (error == nil) {
NSDictionary *resp = @{
@"status": @"success",
@"path": path
};
callback(@[[NSNull null], resp]);
} else {
NSDictionary *evt = @{
@"status": @"error",
@"path": path,
@"message": [error debugDescription]
};
callback(@[evt]);
}
}];
}
RCT_EXPORT_METHOD(getDownloadURL: (NSString *) path
callback:(RCTResponseSenderBlock) callback)
{
FIRStorageReference *fileRef = [self getReference:path];
[fileRef downloadURLWithCompletion:^(NSURL * _Nullable URL, NSError * _Nullable error) {
if (error != nil) {
NSDictionary *evt = @{
@"status": @"error",
@"path": path,
@"message": [error debugDescription]
};
callback(@[evt]);
} else {
callback(@[[NSNull null], [URL absoluteString]]);
}
}];
}
RCT_EXPORT_METHOD(getMetadata: (NSString *) path
callback:(RCTResponseSenderBlock) callback)
{
FIRStorageReference *fileRef = [self getReference:path];
[fileRef metadataWithCompletion:^(FIRStorageMetadata * _Nullable metadata, NSError * _Nullable error) {
if (error != nil) {
NSDictionary *evt = @{
@"status": @"error",
@"path": path,
@"message": [error debugDescription]
};
callback(@[evt]);
} else {
NSDictionary *resp = [metadata dictionaryRepresentation];
callback(@[[NSNull null], resp]);
}
}];
}
RCT_EXPORT_METHOD(updateMetadata: (NSString *) path
metadata:(NSDictionary *) metadata
callback:(RCTResponseSenderBlock) callback)
{
FIRStorageReference *fileRef = [self getReference:path];
FIRStorageMetadata *firmetadata = [[FIRStorageMetadata alloc] initWithDictionary:metadata];
[fileRef updateMetadata:firmetadata completion:^(FIRStorageMetadata * _Nullable metadata, NSError * _Nullable error) {
if (error != nil) {
NSDictionary *evt = @{
@"status": @"error",
@"path": path,
@"message": [error debugDescription]
};
callback(@[evt]);
} else {
NSDictionary *resp = [metadata dictionaryRepresentation];
callback(@[[NSNull null], resp]);
}
}];
}
RCT_EXPORT_METHOD(downloadFile: (NSString *) path
localPath:(NSString *) localPath
callback:(RCTResponseSenderBlock) callback)
{
FIRStorageReference *fileRef = [self getReference:path];
NSURL *localFile = [NSURL fileURLWithPath:localPath];
FIRStorageDownloadTask *downloadTask = [fileRef writeToFile:localFile];
// Listen for state changes, errors, and completion of the download.
[downloadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// Download resumed, also fires when the upload starts
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
[downloadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
// Download paused
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
[downloadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
// Download reported progress
NSDictionary *event = [self getDownloadTaskAsDictionary:snapshot];
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
[downloadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
// Download completed successfully
NSDictionary *resp = [self getDownloadTaskAsDictionary:snapshot];
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_DOWNLOAD_SUCCESS props:resp];
callback(@[[NSNull null], resp]);
}];
[downloadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
if (snapshot.error != nil) {
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
NSLog(@"Error in download: %@", snapshot.error);
switch (snapshot.error.code) {
case FIRStorageErrorCodeObjectNotFound:
// File doesn't exist
[errProps setValue:@"File does not exist" forKey:@"message"];
break;
case FIRStorageErrorCodeUnauthorized:
// User doesn't have permission to access file
[errProps setValue:@"You do not have permissions" forKey:@"message"];
break;
case FIRStorageErrorCodeCancelled:
// User canceled the upload
[errProps setValue:@"Download canceled" forKey:@"message"];
break;
case FIRStorageErrorCodeUnknown:
// Unknown error occurred, inspect the server response
[errProps setValue:@"Unknown error" forKey:@"message"];
break;
}
//TODO: Error event
callback(@[errProps]);
}}];
}
RCT_EXPORT_METHOD(putFile:(NSString *) path
localPath:(NSString *)localPath
metadata:(NSDictionary *)metadata
callback:(RCTResponseSenderBlock) callback)
{
if ([localPath hasPrefix:@"assets-library://"] || [localPath hasPrefix:@"ph://"]) {
PHFetchResult* assets;
if ([localPath hasPrefix:@"assets-library://"]) {
NSURL *localFile = [[NSURL alloc] initWithString:localPath];
assets = [PHAsset fetchAssetsWithALAssetURLs:@[localFile] options:nil];
} else {
NSString *assetId = [localPath substringFromIndex:@"ph://".length];
assets = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetId] options:nil];
}
PHAsset *asset = [assets firstObject];
//NOTE: This is all based on http://stackoverflow.com/questions/35241449
if (asset.mediaType == PHAssetMediaTypeImage && (asset.mediaSubtypes & PHAssetMediaSubtypePhotoLive)) {
//TODO: This is untested as I don't have an iPhone 6s/7
PHLivePhotoRequestOptions *options = [PHLivePhotoRequestOptions new];
options.networkAccessAllowed = YES;
[[PHImageManager defaultManager] requestLivePhotoForAsset:asset
targetSize:CGSizeZero
contentMode:PHImageContentModeAspectFill
options:options
resultHandler:^(PHLivePhoto * _Nullable livePhoto, NSDictionary * _Nullable info) {
if ([info objectForKey:PHImageErrorKey] == nil) {
NSData *livePhotoData = [NSKeyedArchiver archivedDataWithRootObject:livePhoto];
[self uploadData:livePhotoData metadata:metadata path:path callback:callback];
} else {
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
[errProps setValue:@"Could not obtain live image data" forKey:@"message"];
//TODO: Error event
callback(@[errProps]);
}
}];
} else if (asset.mediaType == PHAssetMediaTypeImage) {
PHImageRequestOptions *options = [PHImageRequestOptions new];
options.networkAccessAllowed = true;
[[PHImageManager defaultManager] requestImageDataForAsset:asset
options:options
resultHandler:^(NSData * imageData, NSString * dataUTI, UIImageOrientation orientation, NSDictionary * info) {
if ([info objectForKey:PHImageErrorKey] == nil) {
[self uploadData:imageData metadata:metadata path:path callback:callback];
} else {
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
[errProps setValue:@"Could not obtain image data" forKey:@"message"];
//TODO: Error event
callback(@[errProps]);
}
}];
} else if (asset.mediaType == PHAssetMediaTypeVideo) {
PHVideoRequestOptions *options = [PHVideoRequestOptions new];
options.networkAccessAllowed = true;
[[PHImageManager defaultManager] requestExportSessionForVideo:asset
options:options
exportPreset:AVAssetExportPresetHighestQuality
resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
if ([info objectForKey:PHImageErrorKey] == nil) {
NSURL *tempUrl = [self temporaryFileUrl];
exportSession.outputURL = tempUrl;
NSArray<PHAssetResource *> *resources = [PHAssetResource assetResourcesForAsset:asset];
for (PHAssetResource *resource in resources)
{
exportSession.outputFileType = resource.uniformTypeIdentifier;
if (exportSession.outputFileType != nil)
break;
}
[exportSession exportAsynchronouslyWithCompletionHandler:^{
if (exportSession.status == AVAssetExportSessionStatusCompleted)
{
[self uploadFile:tempUrl metadata:metadata path:path callback:callback];
//NOTE: we're not cleaning up the temporary file at the moment, just relying on the OS to do that in it's own time
} else {
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
[errProps setValue:@"Could not create temporary file for upload" forKey:@"message"];
//TODO: Error event
callback(@[errProps]);
}
}];
} else {
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
[errProps setValue:@"Could not create export session for asset" forKey:@"message"];
//TODO: Error event
callback(@[errProps]);
}
}];
}
} else {
NSURL *fileUrl = [NSURL fileURLWithPath:localPath];
[self uploadFile:fileUrl metadata:metadata path:path callback:callback];
}
}
- (NSURL *) temporaryFileUrl
{
NSString *filename = [NSString stringWithFormat:@"%@.tmp", [[NSProcessInfo processInfo] globallyUniqueString]];
return [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:filename];
}
- (void) uploadFile:(NSURL *) url
metadata:(NSDictionary *) metadata
path:(NSString *) path
callback:(RCTResponseSenderBlock) callback
{
FIRStorageReference *fileRef = [self getReference:path];
FIRStorageMetadata *firmetadata = [[FIRStorageMetadata alloc] initWithDictionary:metadata];
FIRStorageUploadTask *uploadTask = [fileRef putFile:url metadata:firmetadata];
[self addUploadObservers:uploadTask path:path callback:callback];
}
- (void) uploadData:(NSData *) data
metadata:(NSDictionary *) metadata
path:(NSString *) path
callback:(RCTResponseSenderBlock) callback
{
FIRStorageReference *fileRef = [self getReference:path];
FIRStorageMetadata *firmetadata = [[FIRStorageMetadata alloc] initWithDictionary:metadata];
FIRStorageUploadTask *uploadTask = [fileRef putData:data metadata:firmetadata];
[self addUploadObservers:uploadTask path:path callback:callback];
}
- (void) addUploadObservers:(FIRStorageUploadTask *) uploadTask
path:(NSString *) path
callback:(RCTResponseSenderBlock) callback
{
// Listen for state changes, errors, and completion of the upload.
[uploadTask observeStatus:FIRStorageTaskStatusResume handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload resumed, also fires when the upload starts
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
[uploadTask observeStatus:FIRStorageTaskStatusPause handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload paused
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
[uploadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload reported progress
NSDictionary *event = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_STATE_CHANGED props:event];
}];
[uploadTask observeStatus:FIRStorageTaskStatusSuccess handler:^(FIRStorageTaskSnapshot *snapshot) {
// Upload completed successfully
NSDictionary *resp = [self getUploadTaskAsDictionary:snapshot];
[self sendJSEvent:STORAGE_EVENT path:path title:STORAGE_UPLOAD_SUCCESS props:resp];
callback(@[[NSNull null], resp]);
}];
[uploadTask observeStatus:FIRStorageTaskStatusFailure handler:^(FIRStorageTaskSnapshot *snapshot) {
if (snapshot.error != nil) {
NSDictionary *errProps = [[NSMutableDictionary alloc] init];
switch (snapshot.error.code) {
case FIRStorageErrorCodeObjectNotFound:
// File doesn't exist
[errProps setValue:@"File does not exist" forKey:@"message"];
break;
case FIRStorageErrorCodeUnauthorized:
// User doesn't have permission to access file
[errProps setValue:@"You do not have permissions" forKey:@"message"];
break;
case FIRStorageErrorCodeCancelled:
// User canceled the upload
[errProps setValue:@"Upload cancelled" forKey:@"message"];
break;
case FIRStorageErrorCodeUnknown:
// Unknown error occurred, inspect the server response
[errProps setValue:@"Unknown error" forKey:@"message"];
break;
}
//TODO: Error event
callback(@[errProps]);
}}];
}
//Firebase.Storage methods
RCT_EXPORT_METHOD(setMaxDownloadRetryTime:(NSNumber *) milliseconds)
{
[[FIRStorage storage] setMaxDownloadRetryTime:[milliseconds doubleValue]];
}
RCT_EXPORT_METHOD(setMaxOperationRetryTime:(NSNumber *) milliseconds)
{
[[FIRStorage storage] setMaxOperationRetryTime:[milliseconds doubleValue]];
}
RCT_EXPORT_METHOD(setMaxUploadRetryTime:(NSNumber *) milliseconds)
{
[[FIRStorage storage] setMaxUploadRetryTime:[milliseconds doubleValue]];
}
- (FIRStorageReference *)getReference:(NSString *)path
{
if ([path hasPrefix:@"url::"]) {
NSString *url = [path substringFromIndex:5];
return [[FIRStorage storage] referenceForURL:url];
} else {
return [[FIRStorage storage] referenceWithPath:path];
}
}
- (NSDictionary *)getDownloadTaskAsDictionary:(FIRStorageTaskSnapshot *)task {
return @{
@"bytesTransferred": @(task.progress.completedUnitCount),
@"ref": task.reference.fullPath,
@"status": [self getTaskStatus:task.status],
@"totalBytes": @(task.progress.totalUnitCount)
};
}
- (NSDictionary *)getUploadTaskAsDictionary:(FIRStorageTaskSnapshot *)task
{
NSString *downloadUrl = [task.metadata.downloadURL absoluteString];
FIRStorageMetadata *metadata = [task.metadata dictionaryRepresentation];
return @{
@"bytesTransferred": @(task.progress.completedUnitCount),
@"downloadUrl": downloadUrl != nil ? downloadUrl : [NSNull null],
@"metadata": metadata != nil ? metadata : [NSNull null],
@"ref": task.reference.fullPath,
@"state": [self getTaskStatus:task.status],
@"totalBytes": @(task.progress.totalUnitCount)
};
}
- (NSString *)getTaskStatus:(FIRStorageTaskStatus)status
{
if (status == FIRStorageTaskStatusResume || status == FIRStorageTaskStatusProgress) {
return @"RUNNING";
} else if (status == FIRStorageTaskStatusPause) {
return @"PAUSED";
} else if (status == FIRStorageTaskStatusSuccess) {
return @"SUCCESS";
} else if (status == FIRStorageTaskStatusFailure) {
return @"ERROR";
} else {
return @"UNKNOWN";
}
}
// This is just too good not to use, but I don't want to take credit for
// this work from RNFS
// https://github.com/johanneslumpe/react-native-fs/blob/master/RNFSManager.m
- (NSString *)getPathForDirectory:(int)directory
{
NSArray *paths = NSSearchPathForDirectoriesInDomains(directory, NSUserDomainMask, YES);
return [paths firstObject];
}
- (NSDictionary *)constantsToExport
{
return @{
@"MAIN_BUNDLE_PATH": [[NSBundle mainBundle] bundlePath],
@"CACHES_DIRECTORY_PATH": [self getPathForDirectory:NSCachesDirectory],
@"DOCUMENT_DIRECTORY_PATH": [self getPathForDirectory:NSDocumentDirectory],
@"EXTERNAL_DIRECTORY_PATH": [NSNull null],
@"EXTERNAL_STORAGE_DIRECTORY_PATH": [NSNull null],
@"TEMP_DIRECTORY_PATH": NSTemporaryDirectory(),
@"LIBRARY_DIRECTORY_PATH": [self getPathForDirectory:NSLibraryDirectory],
@"FILETYPE_REGULAR": NSFileTypeRegular,
@"FILETYPE_DIRECTORY": NSFileTypeDirectory
};
}
// Not sure how to get away from this... yet
- (NSArray<NSString *> *)supportedEvents {
return @[STORAGE_EVENT, STORAGE_ERROR];
}
- (void) sendJSError:(NSError *) error
withPath:(NSString *) path
{
NSDictionary *evt = @{
@"path": path,
@"message": [error debugDescription]
};
[self sendJSEvent:STORAGE_ERROR path:path title:STORAGE_ERROR props: evt];
}
- (void) sendJSEvent:(NSString *)type
path:(NSString *)path
title:(NSString *)title
props:(NSDictionary *)props
{
@try {
[self sendEventWithName:type
body:@{
@"eventName": title,
@"path": path,
@"body": props
}];
}
@catch (NSException *err) {
NSLog(@"An error occurred in sendJSEvent: %@", [err debugDescription]);
NSLog(@"Tried to send: %@ with %@", title, props);
}
}
@end

13
ios/buildScript.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
frameworks="Firebase FirebaseAnalytics"
source "${SRCROOT}/Pods/Target Support Files/Pods-Firestack/Pods-Firestack-frameworks.sh"
FRAMEWORKS_FOLDER_PATH=""
for framework in $frameworks
do
install_framework "${SRCROOT}/Pods/$framework"
done