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.7k stars 2.22k forks source link

[🐛] Calling getToken When Notifications and Background App Refresh Disabled Blocks All Network Requests #5803

Closed aminosman closed 3 years ago

aminosman commented 3 years ago

Issue

To start, we have only verified this bug in iOS.

So this one is an interesting one. As soon as we launched the updated from version 5 to 12 we started seeing a flurry of issue tickets saying their app was not loading. We spent days debugging and discovered the issue stemmed form users with the iOS settings "Notification" and "Background App Refresh" disabled. If either one was enabled network requests work, otherwise they do not.

Now, how this connects to react native firebase. We also noticed that when the device is in this state we happened to get the following error:

You must be registered for remote messages before calling getToken, see messaging().registerDeviceForRemoteMessages()

And any network requests that happen after this call/error stall and never return (seemingly blocked)

This lead us down a path where removing calls to messaging().getToken() resulted in network requests going through again even with both those setts disabled.

That said, this issue did not exist on the older version of the library. Users were able to have those setting disabled and everything worked.


Project Files

Javascript

Click To Expand ``` yield firebaseMessaging().getToken() ``` #### `package.json`: ```json { "dependencies": { "@apollo/client": "^3.4.7", "@formatjs/cli": "^1.1.20", "@invertase/react-native-apple-authentication": "^1.1.1", "@notifee/react-native": "^2.0.0", "@ptomasroos/react-native-multi-slider": "^1.0.0", "@react-native-community/art": "https://github.com/Brewskey/art.git", "@react-native-community/async-storage": "^1.12.1", "@react-native-community/audio-toolkit": "^2.0.3", "@react-native-community/blur": "^3.6.0", "@react-native-community/cameraroll": "^1.3.0", "@react-native-community/geolocation": "^2.0.2", "@react-native-community/google-signin": "git+https://github.com/aminosman/google-signin.git", "@react-native-community/netinfo": "^4.4.0", "@react-native-community/segmented-control": "^1.6.1", "@react-native-community/slider": "^2.0.2", "@react-native-firebase/app": "^12.7.2", "@react-native-firebase/auth": "^12.7.2", "@react-native-firebase/database": "^12.7.2", "@react-native-firebase/messaging": "^12.7.2", "@typescript-eslint/eslint-plugin": "^4.19.0", "@typescript-eslint/parser": "^4.19.0", "@yfuks/react-native-action-sheet": "0.0.4", "agora-react-native-rtm": "^1.2.2-alpha.2", "buffer": "^5.1.0", "bugsnag-react-native": "^2.23.2", "circular-json": "^0.5.3", "eslint-config-prettier": "^2.9.0", "graphql": "^14.7.0", "graphql-tag": "^2.10.1", "hoist-non-react-statics": "^3.3.2", "jsc-android": "^241213.1.0", "lodash": "^4.17.11", "lodash.memoize": "^4.1.2", "lottie-ios": "3.1.8", "lottie-react-native": "4.0.2", "moment": "^2.22.1", "prop-types": "^15.6.1", "qs": "^6.5.2", "react": "17.0.1", "react-devtools": "^4.5.0", "react-intl": "^5.8.5", "react-native": "0.64.2", "react-native-adjust": "^4.29.4", "react-native-agora": "^3.4.6", "react-native-android-call-notification": "git+https://github.com/aminosman/react-native-android-call-notification.git", "react-native-android-open-settings": "^1.2.0", "react-native-appsflyer": "5.1.3", "react-native-billing": "^2.10.0", "react-native-callkeep": "^3.1.1", "react-native-camera": "^4.0.3", "react-native-code-push": "^6.2.1", "react-native-config": "1.4.1", "react-native-contacts": "^5.0.4", "react-native-date-picker": "^3.2.3", "react-native-datepicker": "^1.7.2", "react-native-deprecated-custom-components": "^0.1.2", "react-native-device-info": "^7.0.2", "react-native-fast-image": "^8.3.2", "react-native-fbsdk-next": "^3.0.1", "react-native-fs": "^2.14.1", "react-native-geolocation-service": "^3.1.0", "react-native-gesture-handler": "^1.8.1", "react-native-google-analytics": "^1.3.2", "react-native-haptic-feedback": "^1.8.2", "react-native-iap": "5.1.1", "react-native-image-crop-picker": "^0.26.0", "react-native-image-picker": "^2.3.4", "react-native-image-progress": "^1.1.1", "react-native-image-resizer": "^1.0.0", "react-native-image-zoom-viewer": "^3.0.1", "react-native-in-app-review": "^1.0.5", "react-native-incall-manager": "^3.3.0", "react-native-indicators": "^0.17.0", "react-native-intercom": "^17.0.0", "react-native-keyboard-aware-scroll-view": "^0.9.1", "react-native-keychain": "^3.1.1", "react-native-linear-gradient": "^2.5.6", "react-native-localize": "^1.3.3", "react-native-maps": "0.26.1", "react-native-message-compose": "0.0.6", "react-native-modal": "^11.5.6", "react-native-navigation": "6.9.1", "react-native-pager-view": "^5.0.11", "react-native-permissions": "^2.1.5", "react-native-photo-view": "git://github.com/alwx/react-native-photo-view.git#c58fd6b30d627fa23e39520d4fc3325ade8b0a51", "react-native-popup-menu-android": "^1.0.3", "react-native-progress": "^5.0.0", "react-native-reanimated": "^1.9.0", "react-native-recaptcha-v3": "0.0.16", "react-native-render-html": "^4.2.3", "react-native-restart": "0.0.17", "react-native-segmented-control-tab": "^3.2.2", "react-native-shake": "^3.4.0", "react-native-showdown": "^1.0.1", "react-native-snap-carousel": "^3.9.1", "react-native-store-review": "^0.1.5", "react-native-svg": "^9.13.3", "react-native-swipe-list-view": "^2.0.3", "react-native-swipeable": "^0.6.0", "react-native-swipeout": "^2.3.3", "react-native-tab-navigator": "^0.3.4", "react-native-tab-view": "2.14.4", "react-native-uuid": "^1.4.9", "react-native-vector-icons": "^4.6.0", "react-native-video": "^5.0.0", "react-native-voip-push-notification": "^2.1.0", "react-native-webview": "^7.4.2", "react-redux": "^7.1.1", "recompose": "^0.30.0", "redux": "^4.0.0", "redux-devtools-extension": "^2.13.8", "redux-persist": "^6.0.0", "redux-persist-filesystem-storage": "^2.0.0", "redux-saga": "^1.1.1", "reselect": "^3.0.1", "rn-fetch-blob": "^0.11.2", "sendbird": "^3.0.108", "speedometer": "^1.1.0", "warna": "^0.2.4" }, "devDependencies": { "@babel/core": "^7.12.9", "@babel/plugin-proposal-decorators": "^7.4.0", "@babel/polyfill": "^7.0.0", "@babel/preset-typescript": "^7.8.3", "@babel/runtime": "^7.12.5", "@graphql-codegen/cli": "^1.8.3", "@graphql-codegen/introspection": "1.8.3", "@graphql-codegen/typescript": "1.8.3", "@graphql-codegen/typescript-operations": "1.8.3", "@graphql-codegen/typescript-react-apollo": "1.8.3", "@react-native-community/eslint-config": "^2.0.0", "@types/react": "^16.11.0", "@types/react-native": "^0.61.16", "babel-eslint": "^8.2.3", "babel-jest": "^26.6.3", "babel-plugin-module-resolver": "^4.0.0", "babel-register": "^6.26.0", "bugsnag-sourcemaps": "^1.1.0", "eslint": "7.14.0", "eslint-config-airbnb": "^16.1.0", "eslint-config-react-app": "^2.1.0", "eslint-plugin-babel": "^5.1.0", "eslint-plugin-import": "^2.12.0", "eslint-plugin-jsx-a11y": "^6.0.3", "eslint-plugin-react": "^7.9.0", "eslint-plugin-react-native": "^3.2.1", "extract-react-intl-messages": "^2.3.5", "husky": "^0.14.3", "jest": "^26.6.3", "jest-haste-map": "^23.6.0", "lint-staged": "^9.4.2", "metro-react-native-babel-preset": "^0.64.0", "patch-package": "^6.1.0", "prettier": "^2.0.5", "react-native-mock": "^0.3.1", "react-native-typescript-transformer": "^1.2.13", "react-test-renderer": "17.0.1", "react-native-codegen": "0.0.7", "remote-redux-devtools": "^0.5.16", "remotedev-rn-debugger": "^0.8.4", "typescript": "^3.7.5" }, } ``` #### `firebase.json` for react-native-firebase v6: ```json # N/A ```

iOS

Click To Expand

#### `ios/Podfile`: - [ ] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby platform :ios, '10' require_relative '../node_modules/react-native/scripts/react_native_pods' require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules' project 'Minder.xcodeproj', 'Staging' => :release def shared_pods pod 'FBSDKCoreKit' , '~> 9.0' pod 'FBSDKLoginKit' , '~> 9.0' pod 'FBSDKShareKit' , '~> 9.0' pod 'FBSDKMessengerShareKit' pod 'Intercom', '7.1.0' pod 'RSKImageCropper', '2.0.1' rn_maps_path = '../node_modules/react-native-maps' pod 'react-native-google-maps', :path => rn_maps_path pod 'GoogleMaps', '3.2.0' pod 'Google-Maps-iOS-Utils' pod 'react-native-appsflyer', :path => '../node_modules/react-native-appsflyer' pod 'react-native-config', :path => '../node_modules/react-native-config' pod 'react-native-contacts', :path => '../node_modules/react-native-contacts' pod 'react-native-geolocation', path: '../node_modules/@react-native-community/geolocation' pod 'react-native-date-picker', :path => '../node_modules/react-native-date-picker' pod 'ReactNativeAudioToolkit', :path => '../node_modules/@react-native-community/audio-toolkit' pod 'Permission-Microphone', :path => '../node_modules/react-native-permissions/ios/Microphone.podspec' pod 'MultiSlider', '~> 1.10.3' pod 'CodePush', :path => '../node_modules/react-native-code-push' pod 'react-native-camera', path: '../node_modules/react-native-camera', subspecs: [ 'FaceDetectorMLKit' ] config = use_native_modules! end target 'Minder' do shared_pods pod 'ReactNativeAudioToolkit', :path => '../node_modules/@react-native-community/audio-toolkit' permissions_path = '../node_modules/react-native-permissions/ios' pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone.podspec" pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec" pod 'react-native-agora', :path => '../node_modules/react-native-agora' pod 'RNFastImage', :path => '../node_modules/react-native-fast-image' pod 'react-native-date-picker', :path => '../node_modules/react-native-date-picker' config = use_native_modules! use_react_native!( :path => config[:reactNativePath], # to enable hermes on iOS, change `false` to `true` and then install pods :hermes_enabled => false ) # Enables Flipper. # # Note that if you have use_frameworks! enabled, Flipper will not work and # you should disable the next line. use_flipper!({ 'Flipper-Folly' => '2.5.3', 'Flipper' => '0.87.0', 'Flipper-RSocket' => '1.3.1' }) target 'MinderTests' do inherit! :complete # Pods for testing end post_install do |installer| react_native_post_install(installer) installer.pods_project.build_configurations.each do |config| if config.name == 'Staging' config.build_settings['CONFIGURATION_TEMP_DIR'] = '$(PROJECT_TEMP_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)' config.build_settings['CONFIGURATION_BUILD_DIR'] = '$(BUILD_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)' end end installer.pods_project.targets.each do |target| # Because: https://github.com/luggit/react-native-config/issues/365 # if target.name == 'react-native-config' # phase = target.project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase) # phase.shell_script = "cd ../../"\ # " && RNC_ROOT=./node_modules/react-native-config/"\ # " && export SYMROOT=$RNC_ROOT/ios/ReactNativeConfig"\ # " && ruby $RNC_ROOT/ios/ReactNativeConfig/BuildDotenvConfig.ruby" # target.build_phases << phase # target.build_phases.move(phase,0) # end # end if target.name == "React-Core.common-AccessibilityResources" target.remove_from_project end target.build_configurations.each do |config| if config.name == 'Staging' config.build_settings['CONFIGURATION_TEMP_DIR'] = '$(PROJECT_TEMP_DIR)/Release$(EFFECTIVE_PLATFORM_NAME)' config.build_settings['PODS_CONFIGURATION_BUILD_DIR'] = '${PODS_BUILD_DIR}/Release$(EFFECTIVE_PLATFORM_NAME)' if target.name == 'QBImagePickerController-QBImagePicker' config.build_settings['CONFIGURATION_BUILD_DIR'] = '${PODS_CONFIGURATION_BUILD_DIR}/QBImagePickerController' end if target.name == 'MLKitFaceDetection-GoogleMVFaceDetectorResources' config.build_settings['CONFIGURATION_BUILD_DIR'] = '${PODS_CONFIGURATION_BUILD_DIR}/MLKitFaceDetection' end if target.name == 'React-Core-AccessibilityResources' config.build_settings['CONFIGURATION_BUILD_DIR'] = '${PODS_CONFIGURATION_BUILD_DIR}/React-Core' end end end end end end ``` #### `AppDelegate.m`: ```objc #import "AppDelegate.h" #import #import #import #import #import #import #import #import #import #import @import GoogleMaps; #if __has_include() // from Pod #import #else #import "AppsFlyerTracker.h" #endif #import #import #import "RNVoipPushNotificationManager.h" #import "RNCallKeep.h" #ifdef FB_SONARKIT_ENABLED #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 { [BugsnagReactNative start]; #ifdef FB_SONARKIT_ENABLED InitializeFlipper(application); #endif NSLog([NSString stringWithFormat: @"[FIREBASE] %@ mode.", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"FirebaseDir"]]); NSString *filePath = [[NSBundle mainBundle] pathForResource:@"GoogleService-Info" ofType:@"plist" inDirectory:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"FirebaseDir"]]; if ([FIRApp defaultApp] == nil) { FIROptions *options = [[FIROptions alloc] initWithContentsOfFile:filePath]; [FIRApp configureWithOptions:options]; } NSLog(@"IntercomAppId %@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"IntercomAppId"]); NSLog(@"GoogleAPIKey %@", [[NSBundle mainBundle] objectForInfoDictionaryKey:@"GoogleApiKey"]); // [GMSPlacesClient provideAPIKey:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"GoogleApiKey"]]; [GMSServices provideAPIKey:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"GoogleApiKey"]]; [Intercom setApiKey:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"IntercomApiKey"] forAppId:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"IntercomAppId"]]; [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; NSURL *jsCodeLocation; #ifdef DEBUG jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; #else jsCodeLocation = [CodePush bundleURL]; #endif self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; [ReactNativeNavigation bootstrap:jsCodeLocation launchOptions:launchOptions]; self.window.backgroundColor = [UIColor blackColor]; [self voipRegistration]; return [[FBSDKApplicationDelegate sharedInstance] application:application didFinishLaunchingWithOptions:launchOptions]; } - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary *)options { [[AppsFlyerTracker sharedTracker] handleOpenUrl:url options:options]; BOOL handled = [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url sourceApplication:options[UIApplicationOpenURLOptionsSourceApplicationKey] annotation:options[UIApplicationOpenURLOptionsAnnotationKey]]; if (!handled) { return [RCTLinkingManager application:application openURL:url options:options]; } return handled; } - (void)applicationDidBecomeActive:(UIApplication *)application { [FBSDKAppEvents activateApp]; // Track Installs, updates & sessions(app opens) (You must include this API to enable tracking) [[AppsFlyerTracker sharedTracker] trackAppLaunch]; } - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { [[AppsFlyerTracker sharedTracker] handleOpenURL:url sourceApplication:sourceApplication withAnnotation:annotation]; if ([[FBSDKApplicationDelegate sharedInstance] application:application openURL:url sourceApplication:sourceApplication annotation:annotation]) return YES; return [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation]; } - (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void (^)(NSArray *restorableObjects))restorationHandler { [[AppsFlyerTracker sharedTracker] continueUserActivity:userActivity restorationHandler:restorationHandler]; return YES; } - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken { // Pass device token to auth. [[FIRAuth auth] setAPNSToken:deviceToken type:FIRAuthAPNSTokenTypeUnknown]; [Intercom setDeviceToken:deviceToken]; [[AppsFlyerTracker sharedTracker] registerUninstall:deviceToken]; } - (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{ if ([Intercom isIntercomPushNotification:userInfo]) { [Intercom handleIntercomPushNotification:userInfo]; return; } if ([[FIRAuth auth] canHandleNotification:userInfo]) { completionHandler(UIBackgroundFetchResultNoData); return; } } - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { NSLog(@"%@", error); } // --- Handle updated push credentials - (void)pushRegistry:(PKPushRegistry *)registry didUpdatePushCredentials:(PKPushCredentials *)credentials forType:(PKPushType)type { // Register VoIP push token (a property of PKPushCredentials) with server [RNVoipPushNotificationManager didUpdatePushCredentials:credentials forType:(NSString *)type]; } - (void)pushRegistry:(PKPushRegistry *)registry didInvalidatePushTokenForType:(PKPushType)type { // --- The system calls this method when a previously provided push token is no longer valid for use. No action is necessary on your part to reregister the push type. Instead, use this method to notify your server not to send push notifications using the matching push token. } // --- Handle incoming pushes (for ios <= 10) - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type { NSLog(@"didReceiveIncomingPushWithPayload called"); [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type]; } // --- Handle incoming pushes (for ios >= 11) - (void)pushRegistry:(PKPushRegistry *)registry didReceiveIncomingPushWithPayload:(PKPushPayload *)payload forType:(PKPushType)type withCompletionHandler:(void (^)(void))completion { // --- Retrieve information from your voip push payload NSString *uuid = payload.dictionaryPayload[@"uuid"]; NSString *callerName = [NSString stringWithFormat:@"%@", payload.dictionaryPayload[@"name"]]; BOOL video = [[payload.dictionaryPayload objectForKey:@"video"] boolValue]; NSString *notificationType = payload.dictionaryPayload[@"type"]; if ([notificationType isEqualToString:@"missed"]) { [RNCallKeep endCallWithUUID:uuid reason: 6]; } else { // --- Process the received push [RNVoipPushNotificationManager didReceiveIncomingPushWithPayload:payload forType:(NSString *)type]; // --- You should make sure to report to callkit BEFORE execute completion() [RNCallKeep reportNewIncomingCall:uuid handle:uuid handleType:@"generic" hasVideo: video localizedCallerName:callerName fromPushKit: YES payload:payload.dictionaryPayload withCompletionHandler:completion]; } // --- this is optional, only required if you want to call `completion()` on the js side [RNVoipPushNotificationManager addCompletionHandler:uuid completionHandler:completion]; completion(); } // Register for VoIP notifications - (void) voipRegistration { dispatch_queue_t mainQueue = dispatch_get_main_queue(); // Create a push registry object PKPushRegistry * voipRegistry = [[PKPushRegistry alloc] initWithQueue: mainQueue]; // Set the registry's delegate to self voipRegistry.delegate = self; // Set the push type to VoIP voipRegistry.desiredPushTypes = [NSSet setWithObject:PKPushTypeVoIP]; } @end ```


Android

Click To Expand

#### Have you converted to AndroidX? - [ ] my application is an AndroidX application? - [ ] I am using `android/gradle.settings` `jetifier=true` for Android compatibility? - [ ] I am using the NPM package `jetifier` for react-native compatibility? #### `android/build.gradle`: ```groovy // N/A ``` #### `android/app/build.gradle`: ```groovy // N/A ``` #### `android/settings.gradle`: ```groovy // N/A ``` #### `MainApplication.java`: ```java // N/A ``` #### `AndroidManifest.xml`: ```xml ```


Environment

Click To Expand

**`react-native info` output:** ``` OUTPUT GOES HERE ``` - **Platform that you're experiencing the issue on**: - [X] iOS - [ ] Android - [X] **iOS** but have not tested behavior on Android - [ ] **Android** but have not tested behavior on iOS - [ ] Both - **`react-native-firebase` version you're using that has this issue:** - `12.7.2` - **`Firebase` module(s) you're using that has the issue:** - `e.g. Instance ID` - **Are you using `TypeScript`?** - `Y` & `3.7.5`


mikehardy commented 3 years ago

Very strange - can you try using current stable just to see if that makes a difference? When you say any network requests, you mean you could just try to fetch some random URL like a web request and that would fail? You don't include the full package.json or Podfile so it's impossible to say what other items might be perturbing things. Does it reproduce if you have nothing but react-native-firebase in there (e.g., start with https://github.com/mikehardy/rnfbdemo/blob/master/make-demo.sh, then alter the index.js / App.js to do nothing but reproduce the issue? Then post it if it reproduces?)

I can't say I've seen this in my app personally and it would be a huge deal if it happened in normal circumstances as getToken is vital for any app that does user messaging, and it's common for users to turn off notifications and background refersh, the behavior is certainly surprising

aminosman commented 3 years ago

I will attempt to reproduce from a new project. Yes all network requests that I can see stop. Its strange since the first few network requests work right up until the point where we call getToken. Then everything from there hangs. I have also update package.json and podfile

efstathiosntonas commented 3 years ago

@mikehardy I’ve had some users complaining that the app won’t load after the splash screen is hidden, it takes approx 25-30 seconds for it to load on iOS. I followed the whole app initialization (it’s a huge process) and it stucked exactly on the first call to firestore (we’re using v12.9).

Sorry for hijacking this issue with that info but it seems to me that this issue and mine might be related, I ll investigate further tomorrow.

On the other hand, on some android users the app won’t load at all, they just get a blank screen. This was never the issue for both Platforms some versions back.

mikehardy commented 3 years ago

I will be really interested to see a reproduction here, I hope we can see enough info to get to the bottom of it

kmsbernard commented 3 years ago

I also received some user reports that similar to this issue. I'm not sure, but I don't think it's directly related with react-native-firebase because the reports started after where the RNFB was not changed in my app. I'm trying to reproduce this issue, no concrete results so far.

I'm currently using RN v0.65.1 and RNFB v12.9.1.

mikehardy commented 3 years ago

The only other times we've seen reports of hangs like this - and apologies in advance this is so vague - it was related to people using redux, and some bizarre (to me!) interaction between hooks, redux and firebase and the network. At this point I'm just trying to add any tiny hunch I have, though it may not be relevant. I can imagine this issue is frustrating

aminosman commented 3 years ago

Ok on further investigation I noticed we lost a try catch around the call to getToken which caused an exception to be thrown in a redux saga of ours when we requested push notification permissions. I am assuming when background data on this does not throw an exception like it does when both background data and notifications are disabled. I greatly appreciate your attention and apologize for the confusion.

mikehardy commented 3 years ago

Glad that at least "rhymed" with something from the past and maybe helped diagnose, but most importantly that you fixed it. There were two others listening in here, perhaps the same thought process / investigation may yield results for everyone :crossed_fingers:

efstathiosntonas commented 3 years ago

@mikehardy did some digging on my issue and it turns out that the caching was the issue. It always took 25sec to load the app because at some point during initialisation I have this code witch decides if the user has completed the signup process (it's the first call to firestore during init):

export const userFinishedSignup = async (userId: string) => {
  if (userId) {
    try {
      const server = await firestore().collection("profiles").doc(userId).get(); <----- this takes 25secs

      // console.log({ serverExists: server.exists });
      if (!server.exists) {
        return false;
      }
      const profile = server.data() as Profile;

      return Boolean(
        profile.published && profile.firstName && profile.lastName && profile.email
      );
    } catch (e) {
      console.log(e);
      return false;
    }
  }
};

And this is my index.js (check the comments after "<-----")

import "react-native-gesture-handler";
import * as React from "react";
import { CacheManager } from "@georstat/react-native-image-cache";
import { Dirs } from "react-native-file-access";
import messaging from "@react-native-firebase/messaging";
import { AppRegistry, Text, TextInput } from "react-native";
import App from "./src/App";
import { name as appName } from "./app.json";
import ThemeManager from "./src/themes";
import { useEffect } from "react";
import firestore from "@react-native-firebase/firestore";
import { notify } from "./src/utils/utils";

messaging().setBackgroundMessageHandler(() => Promise.resolve());

CacheManager.config = {
  baseDir: `${Dirs.CacheDir}/xxxx/images_cache/`,
  blurRadius: 15,
  sourceAnimationDuration: 800,
  thumbnailAnimationDuration: 800
};

// function HeadlessCheck({ isHeadless }) {
//   if (isHeadless) {
//     // App has been launched in the background by iOS, ignore
//     return null;
//   }
//   return <App />;
// }

// if (__DEV__) {
//   const {
//     setupDefaultFlipperReporter
//   } = require("react-native-performance-flipper-reporter");
//   setupDefaultFlipperReporter();
// }

const ThemedApp = () => {
  useEffect(() => {
    // Create an scoped async function in the hook
    async function applyFirestoreSettings() {
      await firestore().settings({
        ignoreUndefinedProperties: true,
        persistence: false <------- After adding this setting, app starts immediately
        // cacheSizeBytes: 25 * 1000000 <---------- If I set persistance to true and uncomment this line the app still takes 25secs to launch.
      });
    }
    // Execute the created function directly
    applyFirestoreSettings().catch((e) => {
      console.log(e);
      notify(e, "error", "while applying Firestore settings");
    });
  }, []);

  return (
    <ThemeManager>
      <App />
    </ThemeManager>
  );
};

AppRegistry.registerComponent(appName, () => ThemedApp);

I'll try to play around with cacheSizeBytes a bit to see if it improves things out.

ps. If you think I should create another issue for this please let me know.

*edit: even after setting `cacheSizeBytes: 1 1048576` (1MB) it still takes 25 secs to load**

edit2: i think it's related: https://github.com/firebase/firebase-ios-sdk/issues/8791

edit3: here's the fix and according to file history this exists since 22 Jul, @mikehardy not being a dick here, can you please rush 8.9.0 when it's released? This seems like a major deal in some cases

mikehardy commented 3 years ago

I generally release SDK updates same day, or next day. you may also override the SDK version in podfile any time to go forward or backwards

mikehardy commented 3 years ago

Great digging to find the issue and PR though - I'm on my desktop now (not mobile) and followed through the links. Looks like 8.9.0 should be any moment now...

I will say that the firestore Pod is open source and using Podfile post-install tricks you may actually apply this patch yourself - file is here

mike@osxvm:~/work/Invertase/react-native-firebase/tests (master) % find ios | grep leveldb_migrations.cc
ios/Pods/FirebaseFirestore/Firestore/core/src/local/leveldb_migrations.cc

Before you dismiss that, note that I've done a similarly distasteful-but-necessary thing and it's actually integrated in react-native at the moment :fearful: :sweat_smile:

https://github.com/facebook/react-native/blob/d48ed4a4bb8cf1db78b72d370b64cd120bdb9099/scripts/react_native_pods.rb#L216-L249

efstathiosntonas commented 3 years ago

Thanks for the info @mikehardy (I was thinking if a patch-package exists for pods 😂), I’m the only dev so no need to apply patch via pod, I’ve just added the missing part on the leveldb_migrations.cc and everything seems fine now.

efstathiosntonas commented 3 years ago

just for reference the issue on this comment has been fixed in v13.0.0

thanks @mikehardy for your hard work! keep it up!

mikehardy commented 3 years ago

Great to hear it! And yes it was a major version bump but the changes probably affect almost no one at this point, should be easy to adopt