React Native iOS应用:RN与嵌入原生模块共用Firebase Storage上传方案
实现React Native iOS端与原生模块共用Firebase Storage上传的方案
1. 确保Firebase初始化的一致性
- 确认RN项目已集成
@react-native-firebase/storage,同时iOS原生项目通过CocoaPods引入Firebase/Storage依赖(RN Firebase集成后通常已自动配置,可检查Podfile确认)。 - 原生模块不要重复初始化Firebase,直接复用RN侧启动时初始化的默认实例:
Swift版本:// Objective-C 示例 FIRApp *defaultApp = [FIRApp defaultApp]; if (!defaultApp) { // 极端场景下RN未初始化时才手动配置,优先依赖RN侧初始化 [FIRApp configure]; }guard FirebaseApp.defaultApp() != nil else { FirebaseApp.configure() return }
2. React Native端上传实现
直接使用@react-native-firebase/storage标准API完成上传:
import storage from '@react-native-firebase/storage'; const uploadViaRN = async (localFilePath, storageBucketPath) => { const storageRef = storage().ref(storageBucketPath); const uploadTask = storageRef.putFile(localFilePath); // 监听上传进度 uploadTask.on('state_changed', snapshot => { const progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100; console.log(`RN上传进度: ${progress.toFixed(2)}%`); }); try { await uploadTask; const downloadUrl = await storageRef.getDownloadURL(); return downloadUrl; } catch (error) { console.error('RN上传失败:', error.message); throw error; } };
3. 原生iOS模块上传实现
在自定义原生模块中调用Firebase Storage原生API完成上传:
Objective-C示例
#import <FirebaseStorage/FirebaseStorage.h> #import <React/RCTBridgeModule.h> @interface CustomStorageModule : NSObject <RCTBridgeModule> @end @implementation CustomStorageModule RCT_EXPORT_MODULE(); RCT_EXPORT_METHOD(uploadViaNative:(NSString *)localPath storagePath:(NSString *)storagePath resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) { FIRStorage *storage = [FIRStorage storage]; FIRStorageReference *storageRef = [storage referenceWithPath:storagePath]; NSURL *fileUrl = [NSURL fileURLWithPath:localPath]; FIRStorageUploadTask *uploadTask = [storageRef putFile:fileUrl metadata:nil completion:^(FIRStorageMetadata * _Nullable metadata, NSError * _Nullable error) { if (error) { reject(@"NATIVE_UPLOAD_FAILED", @"原生上传出错", error); return; } [storageRef downloadURLWithCompletion:^(NSURL * _Nullable URL, NSError * _Nullable error) { if (error) { reject(@"GET_URL_FAILED", @"获取下载链接失败", error); return; } resolve(URL.absoluteString); }]; }]; // 监听上传进度 [uploadTask observeStatus:FIRStorageTaskStatusProgress handler:^(FIRStorageTaskSnapshot *snapshot) { double progress = (double)snapshot.progress.completedUnitCount / snapshot.progress.totalUnitCount; NSLog(@"原生上传进度: %.2f%%", progress * 100); }]; } @end
Swift示例
import FirebaseStorage import React @objc(CustomStorageModule) class CustomStorageModule: NSObject, RCTBridgeModule { static func moduleName() -> String { return "CustomStorageModule" } static func requiresMainQueueSetup() -> Bool { return true } @objc func uploadViaNative(_ localPath: String, storagePath: String, resolver resolve: @escaping RCTPromiseResolveBlock, rejecter reject: @escaping RCTPromiseRejectBlock) { let storage = Storage.storage() let storageRef = storage.reference(withPath: storagePath) let fileUrl = URL(fileURLWithPath: localPath) let uploadTask = storageRef.putFile(from: fileUrl, metadata: nil) { _, error in guard error == nil else { reject("NATIVE_UPLOAD_FAILED", "原生上传出错", error) return } storageRef.downloadURL { url, error in guard let downloadUrl = url?.absoluteString else { reject("GET_URL_FAILED", "获取下载链接失败", error) return } resolve(downloadUrl) } } // 监听上传进度 uploadTask.observe(.progress) { snapshot in guard let progress = snapshot.progress else { return } let progressPercent = Double(progress.completedUnitCount) / Double(progress.totalUnitCount) * 100 print("原生上传进度: \(progressPercent.toFixed(2))%") } } } extension Double { func toFixed(_ places: Int) -> String { return String(format: "%.\(places)f", self) } }
4. 核心注意事项
- 权限统一:RN和原生端共用同一Firebase项目,确保Storage安全规则对两端上传路径、操作权限的限制一致。
- 路径规范:两端使用的存储桶路径格式要统一(比如是否带开头斜杠),避免出现路径解析错误。
- 错误处理:两端都要覆盖网络异常、文件不存在、权限不足等场景的错误捕获与反馈。
- 禁止重复初始化:必须保证RN侧优先完成Firebase初始化,原生模块复用默认实例,否则会导致配置冲突。
内容的提问来源于stack exchange,提问作者VIKASH SR
相关产品推荐
相关产品推荐

