ios - initial build
This commit is contained in:
parent
2d1015d205
commit
05a35b7b82
71
ios/Podfile
Normal file
71
ios/Podfile
Normal 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
15
ios/Podfile.template
Normal 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
|
325
ios/RNFirebase.xcodeproj/project.pbxproj
Normal file
325
ios/RNFirebase.xcodeproj/project.pbxproj
Normal 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 */;
|
||||
}
|
31
ios/RNFirebase/RNFirebase.h
Normal file
31
ios/RNFirebase/RNFirebase.h
Normal 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
380
ios/RNFirebase/RNFirebase.m
Normal 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
|
12
ios/RNFirebase/RNFirebaseAnalytics.h
Normal file
12
ios/RNFirebase/RNFirebaseAnalytics.h
Normal file
@ -0,0 +1,12 @@
|
||||
#ifndef RNFirebaseAnalytics_h
|
||||
#define RNFirebaseAnalytics_h
|
||||
|
||||
#import "RCTBridgeModule.h"
|
||||
|
||||
@interface RNFirebaseAnalytics : NSObject <RCTBridgeModule> {
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
59
ios/RNFirebase/RNFirebaseAnalytics.m
Normal file
59
ios/RNFirebase/RNFirebaseAnalytics.m
Normal 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
|
15
ios/RNFirebase/RNFirebaseAuth.h
Normal file
15
ios/RNFirebase/RNFirebaseAuth.h
Normal 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
|
503
ios/RNFirebase/RNFirebaseAuth.m
Normal file
503
ios/RNFirebase/RNFirebaseAuth.m
Normal 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
|
16
ios/RNFirebase/RNFirebaseDatabase.h
Normal file
16
ios/RNFirebase/RNFirebaseDatabase.h
Normal 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
|
640
ios/RNFirebase/RNFirebaseDatabase.m
Normal file
640
ios/RNFirebase/RNFirebaseDatabase.m
Normal 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
|
19
ios/RNFirebase/RNFirebaseErrors.h
Normal file
19
ios/RNFirebase/RNFirebaseErrors.h
Normal 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
|
52
ios/RNFirebase/RNFirebaseErrors.m
Normal file
52
ios/RNFirebase/RNFirebaseErrors.m
Normal 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
|
49
ios/RNFirebase/RNFirebaseEvents.h
Normal file
49
ios/RNFirebase/RNFirebaseEvents.h
Normal 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
|
17
ios/RNFirebase/RNFirebaseMessaging.h
Normal file
17
ios/RNFirebase/RNFirebaseMessaging.h
Normal 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
|
323
ios/RNFirebase/RNFirebaseMessaging.m
Normal file
323
ios/RNFirebase/RNFirebaseMessaging.m
Normal 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
|
16
ios/RNFirebase/RNFirebaseStorage.h
Normal file
16
ios/RNFirebase/RNFirebaseStorage.h
Normal 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
|
468
ios/RNFirebase/RNFirebaseStorage.m
Normal file
468
ios/RNFirebase/RNFirebaseStorage.m
Normal 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
13
ios/buildScript.sh
Executable 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
|
Loading…
x
Reference in New Issue
Block a user