invertase / react-native-firebase

🔥 A well-tested feature-rich modular Firebase implementation for React Native. Supports both iOS & Android platforms for all Firebase services.
https://rnfirebase.io
Other
11.73k stars 2.22k forks source link

🔥 [IOS] putFile throws 'URI must be in the form of gs://<bucket>/' Exception #4105

Closed francisleigh closed 4 years ago

francisleigh commented 4 years ago

Issue

On IOS When attempting to upload a file to the cloud via the storage API with react-native-image-crop-picker i am getting an Exception Exception 'URI must be in the form of gs://<bucket>/' was thrown while invoking putFile on target RNFBStorageModule with params

Screenshot 2020-08-19 at 11 13 56

On Android the upload works smoothly, the only thing i can see that is different is that on Android, the file's path is understandably different to the file path provided on IOS.

IOS File structure

Screenshot 2020-08-19 at 11 14 16

Android file structure

Code

export const ProfileImage = ({ withEdit, size = void 0 }) => {
    const uid = useSelector(({ firebase }) => firebase.auth.uid);
    const profile = useSelector(({ firebase }) => firebase.profile);
    const storageRefName = `${uid}-profile-picture.jpg`;

    const firebase = useFirebase();
    const reference = storage().ref(storageRefName);
    async function handleProfilePictureUpload() {
        const imageObj = await ImagePicker.openPicker({
            width: 300,
            height: 300,
            cropping: true,
        });

        if (imageObj) {
            const pathToFile = imageObj.path;

            await reference.putFile(pathToFile);
            const ImageStorageURL = await storage().ref(storageRefName).getDownloadURL();

            firebase.updateProfile({ displayPicture: ImageStorageURL });
        }
    }

   ...
};

Project Files

iOS

Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby platform :ios, '11.0' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' def add_flipper_pods!(versions = {}) versions['Flipper'] ||= '~> 0.33.1' versions['DoubleConversion'] ||= '1.1.7' versions['Flipper-Folly'] ||= '~> 2.1' versions['Flipper-Glog'] ||= '0.3.6' versions['Flipper-PeerTalk'] ||= '~> 0.0.4' versions['Flipper-RSocket'] ||= '~> 1.0' pod 'FlipperKit', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FlipperKitLayoutPlugin', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/SKIOSNetworkPlugin', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FlipperKitUserDefaultsPlugin', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FlipperKitReactPlugin', versions['Flipper'], :configuration => 'Debug' # List all transitive dependencies for FlipperKit pods # to avoid them being linked in Release builds pod 'Flipper', versions['Flipper'], :configuration => 'Debug' pod 'Flipper-DoubleConversion', versions['DoubleConversion'], :configuration => 'Debug' pod 'Flipper-Folly', versions['Flipper-Folly'], :configuration => 'Debug' pod 'Flipper-Glog', versions['Flipper-Glog'], :configuration => 'Debug' pod 'Flipper-PeerTalk', versions['Flipper-PeerTalk'], :configuration => 'Debug' pod 'Flipper-RSocket', versions['Flipper-RSocket'], :configuration => 'Debug' pod 'FlipperKit/Core', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/CppBridge', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FBCxxFollyDynamicConvert', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FBDefines', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FKPortForwarding', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FlipperKitHighlightOverlay', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FlipperKitLayoutTextSearchable', versions['Flipper'], :configuration => 'Debug' pod 'FlipperKit/FlipperKitNetworkPlugin', versions['Flipper'], :configuration => 'Debug' end # Post Install processing for Flipper def flipper_post_install(installer) installer.pods_project.targets.each do |target| if target.name == 'YogaKit' target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '4.1' end end end end target 'appName' do # Pods for appName pod 'FBLazyVector', :path => "../node_modules/react-native/Libraries/FBLazyVector" pod 'FBReactNativeSpec', :path => "../node_modules/react-native/Libraries/FBReactNativeSpec" pod 'RCTRequired', :path => "../node_modules/react-native/Libraries/RCTRequired" pod 'RCTTypeSafety', :path => "../node_modules/react-native/Libraries/TypeSafety" pod 'React', :path => '../node_modules/react-native/' pod 'React-Core', :path => '../node_modules/react-native/' pod 'React-CoreModules', :path => '../node_modules/react-native/React/CoreModules' pod 'React-Core/DevSupport', :path => '../node_modules/react-native/' pod 'React-RCTActionSheet', :path => '../node_modules/react-native/Libraries/ActionSheetIOS' pod 'React-RCTAnimation', :path => '../node_modules/react-native/Libraries/NativeAnimation' pod 'React-RCTBlob', :path => '../node_modules/react-native/Libraries/Blob' pod 'React-RCTImage', :path => '../node_modules/react-native/Libraries/Image' pod 'React-RCTLinking', :path => '../node_modules/react-native/Libraries/LinkingIOS' pod 'React-RCTNetwork', :path => '../node_modules/react-native/Libraries/Network' pod 'React-RCTSettings', :path => '../node_modules/react-native/Libraries/Settings' pod 'React-RCTText', :path => '../node_modules/react-native/Libraries/Text' pod 'React-RCTVibration', :path => '../node_modules/react-native/Libraries/Vibration' pod 'React-Core/RCTWebSocket', :path => '../node_modules/react-native/' pod 'React-cxxreact', :path => '../node_modules/react-native/ReactCommon/cxxreact' pod 'React-jsi', :path => '../node_modules/react-native/ReactCommon/jsi' pod 'React-jsiexecutor', :path => '../node_modules/react-native/ReactCommon/jsiexecutor' pod 'React-jsinspector', :path => '../node_modules/react-native/ReactCommon/jsinspector' pod 'ReactCommon/callinvoker', :path => "../node_modules/react-native/ReactCommon" pod 'ReactCommon/turbomodule/core', :path => "../node_modules/react-native/ReactCommon" pod 'Yoga', :path => '../node_modules/react-native/ReactCommon/yoga', :modular_headers => true pod 'DoubleConversion', :podspec => '../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec' pod 'glog', :podspec => '../node_modules/react-native/third-party-podspecs/glog.podspec' pod 'Folly', :podspec => '../node_modules/react-native/third-party-podspecs/Folly.podspec' pod 'react-native-maps', path: '../node_modules/react-native-maps' pod 'react-native-google-maps', path: '../node_modules/react-native-maps' # Remove this line if you don't want to support GoogleMaps on iOS pod 'GoogleMaps' # Remove this line if you don't want to support GoogleMaps on iOS pod 'Google-Maps-iOS-Utils' # Remove this line if you don't want to support GoogleMaps on iOS # React Native Maps dependencies # https://github.com/react-native-community/react-native-maps/blob/master/docs/installation.md#enabling-google-maps-on-ios-react-native-all-versions # rn_maps_path = '../node_modules/react-native-maps' # pod 'react-native-google-maps', :path => rn_maps_path # pod 'GoogleMaps' # pod 'Google-Maps-iOS-Utils' pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo' pod 'appcenter-core', :path => '../node_modules/appcenter/ios/appcenter-core.podspec' target 'appNameTests' do inherit! :complete # Pods for testing end use_native_modules! # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable these next few lines. add_flipper_pods! post_install do |installer| flipper_post_install(installer) # https://developer.apple.com/forums/thread/656509 # installer.pods_project.targets.each do |target| # target.build_configurations.each do |config| # config.build_settings['ONLY_ACTIVE_ARCH'] = 'YES' # end # end end end target 'appName-tvOS' do # Pods for appName-tvOS target 'appName-tvOSTests' do inherit! :search_paths # Pods for testing end end ``` #### `AppDelegate.m`: ```objc #import "AppDelegate.h" #import #import #import #import #import #import #import #import #import #if DEBUG #import #import #import #import #import #import static void InitializeFlipper(UIApplication *application) { FlipperClient *client = [FlipperClient sharedClient]; SKDescriptorMapper *layoutDescriptorMapper = [[SKDescriptorMapper alloc] initWithDefaults]; [client addPlugin:[[FlipperKitLayoutPlugin alloc] initWithRootNode:application withDescriptorMapper:layoutDescriptorMapper]]; [client addPlugin:[[FKUserDefaultsPlugin alloc] initWithSuiteName:nil]]; [client addPlugin:[FlipperKitReactPlugin new]]; [client addPlugin:[[FlipperKitNetworkPlugin alloc] initWithNetworkAdapter:[SKIOSNetworkAdapter new]]]; [client start]; } #endif @implementation AppDelegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { #if DEBUG InitializeFlipper(application); #endif [GMSServices provideAPIKey:@"AIzaSyB7QxNG6fKwikyPvW5eKiiBrsfOzLDYmBs"]; RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions]; RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge moduleName:@"appName" initialProperties:nil]; rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIViewController *rootViewController = [UIViewController new]; rootViewController.view = rootView; self.window.rootViewController = rootViewController; [self.window makeKeyAndVisible]; // Define UNUserNotificationCenter UNUserNotificationCenter *center = [UNUserNotificationCenter currentNotificationCenter]; [center requestAuthorizationWithOptions:(UNAuthorizationOptionAlert + UNAuthorizationOptionSound + UNAuthorizationOptionBadge)completionHandler:^(BOOL granted, NSError * _Nullable error) { if (granted) { center.delegate = self; } }]; [AppCenterReactNative register]; [AppCenterReactNativeAnalytics registerWithInitiallyEnabled:true]; [AppCenterReactNativeCrashes registerWithAutomaticProcessing]; return YES; } //Called when a notification is delivered to a foreground app. -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler { completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge); } - (NSURL *)sourceURLForBridge:(RCTBridge *)bridge { #if DEBUG return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; #else return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; #endif } // Required to register for notifications - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings]; } // Required for the register event. - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken]; } // Required for the notification event. You must call the completion handler after handling the remote notification. - (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; } // Required for the registrationError event. - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error]; } // IOS 10+ Required for localNotification event - (void)userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [RNCPushNotificationIOS didReceiveNotificationResponse:response]; completionHandler(); } // IOS 4-10 Required for the localNotification event. - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { [RNCPushNotificationIOS didReceiveLocalNotification:notification]; } @end ```


Environment

Click To Expand

**`react-native info` output:** ``` System: OS: macOS 10.15.5 CPU: (8) x64 Intel(R) Core(TM) i7-6820HQ CPU @ 2.70GHz Memory: 134.08 MB / 16.00 GB Shell: 5.7.1 - /bin/zsh Binaries: Node: 8.12.0 - ~/.nvm/versions/node/v8.12.0/bin/node Yarn: 1.3.2 - /usr/local/bin/yarn npm: 6.14.5 - ~/.nvm/versions/node/v8.12.0/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman Managers: CocoaPods: 1.9.3 - /usr/local/bin/pod SDKs: iOS SDK: Not Found Android SDK: Not Found IDEs: Android Studio: 3.4 AI-183.6156.11.34.5522156 Xcode: /undefined - /usr/bin/xcodebuild Languages: Java: javac 11 - /usr/bin/javac Python: 2.7.16 - /usr/bin/python npmPackages: @react-native-community/cli: Not Found react: 16.11.0 => 16.11.0 react-native: 0.62.2 => 0.62.2 npmGlobalPackages: *react-native*: Not Found ``` - **Platform that you're experiencing the issue on**: - [ x] iOS - [ ] Android - [ ] **iOS** but have not tested behavior on Android - [ ] **Android** but have not tested behavior on iOS - [ ] Both - **`Firebase` module(s) you're using that has the issue:** - `Cloud Storage` - **Are you using `TypeScript`?** - `N`

package.json

{
  "name": "appName",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@material-ui/core": "^4.3.0",
    "@react-native-community/async-storage": "^1.11.0",
    "@react-native-community/geolocation": "^2.0.2",
    "@react-native-community/masked-view": "^0.1.10",
    "@react-native-community/netinfo": "^5.9.4",
    "@react-native-community/push-notification-ios": "^1.2.2",
    "@react-native-firebase/analytics": "^6.3.4",
    "@react-native-firebase/app": "^6.3.4",
    "@react-native-firebase/auth": "^6.3.4",
    "@react-native-firebase/database": "^6.3.4",
    "@react-native-firebase/firestore": "^6.3.4",
    "@react-native-firebase/messaging": "^6.3.4",
    "@react-native-firebase/storage": "^6.3.4",
    "@react-navigation/bottom-tabs": "^5.5.2",
    "@react-navigation/drawer": "^5.8.2",
    "@react-navigation/native": "^5.5.1",
    "@react-navigation/stack": "^5.5.1",
    "add": "^2.0.6",
    "appcenter": "3.1.1",
    "appcenter-analytics": "3.1.1",
    "appcenter-crashes": "3.1.1",
    "geofirestore": "^3.6.0",
    "react": "16.11.0",
    "react-devtools": "^3.6.1",
    "react-native": "0.62.2",
    "react-native-appearance": "^0.3.4",
    "react-native-geolocation-service": "^4.0.0",
    "react-native-gesture-handler": "^1.6.1",
    "react-native-gifted-chat": "^0.16.0",
    "react-native-image-crop-picker": "^0.32.2",
    "react-native-maps": "0.27.1",
    "react-native-modal": "^11.5.4",
    "react-native-push-notification": "^3.5.2",
    "react-native-reanimated": "^1.9.0",
    "react-native-responsive-screen": "^1.4.1",
    "react-native-safe-area-context": "^3.0.3",
    "react-native-screens": "^2.8.0",
    "react-native-sound": "^0.11.0",
    "react-native-svg": "^12.1.0",
    "react-navigation": "^3.11.1",
    "react-redux": "^7.2.0",
    "react-redux-firebase": "^3.1.2",
    "reactotron-react-native": "^3.6.4",
    "reactotron-redux": "^3.1.2",
    "redux": "^4.0.5",
    "redux-firestore": "^0.13.0",
    "redux-logger": "^3.0.6",
    "redux-persist": "^6.0.0",
    "styled-components": "^5.1.0",
    "truncate": "^2.1.0",
    "yarn": "^1.22.4"
  },
  "devDependencies": {
    "@babel/core": "^7.10.2",
    "@babel/runtime": "^7.10.2",
    "@react-native-community/eslint-config": "^2.0.0",
    "babel-jest": "^26.0.1",
    "babel-plugin-module-resolver": "^4.0.0",
    "eslint": "^7.2.0",
    "fs-extra": "^7.0.1",
    "jest": "^26.0.1",
    "metro-react-native-babel-preset": "^0.59.0",
    "react-test-renderer": "16.11.0",
    "replace-in-file": "^3.4.4"
  },
  "jest": {
    "preset": "react-native"
  }
}

Error in raw text

ExceptionsManager.js:173 Exception 'URI must be in the form of gs://<bucket>/' was thrown while invoking putFile on target RNFBStorageModule with params (
    "[DEFAULT]",
    "gs:///J6NcK8cNyngBQoDOamDhvCRfGxz2-profile-picture.jpg",
    "/Users/francisleigh/Library/Developer/CoreSimulator/Devices/1E628CFB-47F9-4504-802E-6F98B864C1BB/data/Containers/Data/Application/1CDD523B-1348-4A6C-89C9-B01BF410243A/tmp/react-native-image-crop-picker/5300F7C0-2D01-407D-8501-CC2DF844F795.jpg",
    "<null>",
    0,
    14132,
    14133
)
callstack: (
    0   CoreFoundation                      0x00007fff20438fda __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007fff2017712e objc_exception_throw + 48
    2   CoreFoundation                      0x00007fff20438eb8 -[NSException initWithCoder:] + 0
    3   tonsr                               0x000000010f506528 +[FIRStorage storageForApp:URL:] + 568
    4   tonsr                               0x000000010fa9e0be -[RNFBStorageModule getReferenceFromUrl:app:] + 414
    5   tonsr                               0x000000010fa9b80e -[RNFBStorageModule putFile:::::::] + 350
    6   CoreFoundation                      0x00007fff2043f7dc __invoking___ + 140
    7   CoreFoundation                      0x00007fff2043cc9a -[NSInvocation invoke] + 303
    8   CoreFoundation                      0x00007fff2043cf2b -[NSInvocation invokeWithTarget:] + 70
    9   tonsr                               0x000000010fbe2174 -[RCTModuleMethod invokeWithBridge:module:arguments:] + 2660
    10  tonsr                               0x000000010fbe631e _ZN8facebook5reactL11invokeInnerEP9RCTBridgeP13RCTModuleDatajRKN5folly7dynamicE + 814
    11  tonsr                               0x000000010fbe5de6 _ZZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEiENK3$_0clEv + 134
    12  tonsr                               0x000000010fbe5d4c ___ZN8facebook5react15RCTNativeModule6invokeEjON5folly7dynamicEi_block_invoke + 28
    13  libdispatch.dylib                   0x00000001166228ac _dispatch_call_block_and_release + 12
    14  libdispatch.dylib                   0x0000000116623a88 _dispatch_client_callout + 8
    15  libdispatch.dylib                   0x000000011662a356 _dispatch_lane_serial_drain + 796
    16  libdispatch.dylib                   0x000000011662b027 _dispatch_lane_invoke + 439
    17  libdispatch.dylib                   0x0000000116636e90 _dispatch_workloop_worker_thread + 882
    18  libsystem_pthread.dylib             0x00007fff5d92ba3d _pthread_wqthread + 290
    19  libsystem_pthread.dylib             0x00007fff5d92ab77 start_wqthread + 15
mikehardy commented 4 years ago

Hi there!

The information you have posted is confusing to me, that's not the way I would expect an AppDelegate to look, for instance it is not configuring Firebase at all (e.g. https://github.com/mikehardy/rnfbdemo/blob/eda24a71990e95e8a91b17b27b0cc1417031808b/make-demo.sh#L19-L22) - how is that working? That is very confusing to me.

The Podfile is not what I'd expect either, it looks like it's manual linking in many places when auto-linking should what's happening, in some places. But I don't think that's the problem.

Nowhere in the data posted is package.json so I am not sure what versions you are on.

In the iOS error message (text preferred, that graphic is really hard to read) I see gs:/// indicating the bucket is indeed just missing. In the E2E tests, delete is exercised which necessarily puts the file first, what is different in the API usage between that one (which I think works?) and your code https://github.com/invertase/react-native-firebase/blob/18b4740f3991c5efd78a687f24839f4ae917b1c6/packages/storage/e2e/StorageReference.e2e.js#L102-L112

Those tests have been disabled on the master branch for a while unfortunately: https://github.com/invertase/react-native-firebase/blob/18b4740f3991c5efd78a687f24839f4ae917b1c6/tests/e2e/mocha.opts#L42

But there is a PR to re-enable them and I think the code is exercised again and works: https://github.com/invertase/react-native-firebase/pull/3691/files#diff-a7383b412532a6a7e736f864e5509bcdR42 / https://github.com/invertase/react-native-firebase/pull/3691/checks?check_run_id=1004439470 - I was hoping to merge that PR shortly - the only functional change I can see it in this https://github.com/invertase/react-native-firebase/pull/3691/files#diff-01e35650050125e73aaffb563eb39b9d

Perhaps that last patch would affect things for you, perhaps not. I suspect this is still in project code somehow as the ability to put a file is of course the most basic storage feature

francisleigh commented 4 years ago

@mikehardy thank you for your reply!

I see what you mean, theres no initialisation of the FirApp in the AppDelegate which is weird because my app runs fine with all other firebase parts e.g auth, cloud firestore...

I have added my package.json at the bottom of the original ticket - sorry for missing that out.

I'll add the error message as text also at the bottom of the issue.

mikehardy commented 4 years ago

Your @react-native-firebase dependencies are quite of date - I would definitely update them to current. The release notes for each package (from rnfirebase.io docs site, release notes link) contain all the breaking changes - there are not very many at all, nothing like v5-v6, v7 was more a versioning change internal to the repo and the couple of v8s are small

francisleigh commented 4 years ago

@mikehardy Phew! i updated my RNFB dependancies and also configured the AppDelegate properly and now working as normal.

Thank you again for your swift responses!

mikehardy commented 4 years ago

Glad that's working @FrancisLeigh - thanks for reporting back