Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[🐛] 🔥 Database will not load on IOS Release - Works fine on debug mode (IOS Only) #4535

Closed
1 of 8 tasks
rezasazesh opened this issue Nov 11, 2020 · 11 comments · Fixed by #4563
Closed
1 of 8 tasks
Labels
help: needs-triage Issue needs additional investigation/triaging. type: bug New bug report

Comments

@rezasazesh
Copy link

rezasazesh commented Nov 11, 2020

Issue

So I just migrated from V5 to V6 and I am using realtime database and push notification in my project. Everything worked fine in Debug mode for IOS but when I tested over test flight or build a release version on a device the content for the database just does not load. This is only for IOS, everything works perfectly for android and everything works perfectly in debug mode

my usage is very standard, below is an example of the way I used the code for my chat page

import database from '@react-native-firebase/database';
componentDidMount() {
 database()
      .ref(`messaging/users/${this.props.state.userReducer.info.id}/chats/`)
      .orderByChild('last_message_datetime')
      .limitToLast(this.state.load_limit)
      .on('value', (childSnapShot) => {
        let messages = [];
        childSnapShot.forEach((doc) => {
          messages.push(doc.toJSON());
        });
    
        this.props.dispatchAction('UPDATE_MESSAGES_REDUCER_PROPERTY', {
          key: 'messages',
          val: messages,
        });

        setTimeout(() => {
          this.getAllChatUserDetails();
          //for first time users we send welcome message
          if (messages.length == 0) {
            sendWelcomeMessage(this.props);
          }

          this.updateMessagesBadge();
        }, 200);
      });
}


Project Files

Javascript

Click To Expand

package.json:

    "react-native": "0.63.2",
    "@react-native-firebase/analytics": "^8.0.1",
    "@react-native-firebase/app": "^9.0.0",
    "@react-native-firebase/auth": "^9.3.2",
    "@react-native-firebase/database": "^7.5.15",
    "@react-native-firebase/firestore": "^7.10.3",
    "@react-native-firebase/functions": "^7.4.12",
    "@react-native-firebase/in-app-messaging": "^7.5.10",
    "@react-native-firebase/messaging": "^8.0.1",
    "react-native-navigation": "^6.12.2",
    "firebase": "^7.7.0",
     "react-native-code-push": "^6.3.0",

firebase.json for react-native-firebase v6:

{
    "react-native": {
      "analytics_auto_collection_enabled": false
    }
}

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

platform :ios, '10.0'

target 'Woofly' do
  config = use_native_modules!

  use_react_native!(:path => config["reactNativePath"])

  # Set up Firebase SDK version
  $FirebaseSDKVersion = '6.34.0'
  # # OPTIONAL include this if you want to try speeding up Firestore compile times. May cause Xcode 12 to have issues. OPTIONAL.
  # pod 'FirebaseFirestore', :git => 'https://github.com/invertase/firestore-ios-sdk-frameworks.git', :tag => $FirebaseSDKVersion
  # # Include temporary fix already merged upstream but not released, to get tokens on first app open
  # pod 'FirebaseInstanceID', :git => 'https://github.com/invertase/firebase-ios-sdk.git', :branch => 'release-6.34.0-patched'

  # pod 'ReactNativeNavigation', :podspec => '../node_modules/react-native-navigation/ReactNativeNavigation.podspec'

  pod 'react-native-geolocation', path: '../node_modules/@react-native-community/geolocation'


  #Instructions from React-native-device-info  START
  pod 'RNDeviceInfo', :path => '../node_modules/react-native-device-info'


  # react native permissions
  permissions_path = '../node_modules/react-native-permissions/ios'
  
  pod 'Permission-AppTrackingTransparency', :path => "#{permissions_path}/AppTrackingTransparency.podspec"
  pod 'Permission-Camera', :path => "#{permissions_path}/Camera.podspec"
  pod 'Permission-FaceID', :path => "#{permissions_path}/FaceID.podspec"
  pod 'Permission-LocationAlways', :path => "#{permissions_path}/LocationAlways.podspec"
  pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse.podspec"
  pod 'Permission-Microphone', :path => "#{permissions_path}/Microphone.podspec"
  pod 'Permission-Motion', :path => "#{permissions_path}/Motion.podspec"
  pod 'Permission-Notifications', :path => "#{permissions_path}/Notifications.podspec"
  pod 'Permission-PhotoLibrary', :path => "#{permissions_path}/PhotoLibrary.podspec"


  # React-Native is not great about React double-including from the Podfile
  # post_install do |installer|
  #   installer.pods_project.targets.each do |target|
  #     if target.name == "React"
  #       target.remove_from_project
  #     end
  
  #     # It removes React & Yoga from the Pods project, as it is already included in the main project.
  #     targets_to_ignore = %w(React yoga)
  #     if targets_to_ignore.include? target.name
  #       target.remove_from_project
  #     end
  #   end
  # end
  #Instructions from React-native-device-info  END

  use_flipper!
  post_install do |installer|
    installer.pods_project.targets.each do |target|

      # The following is needed to ensure the "archive" step works in XCode.
      # It removes React & Yoga from the Pods project, as it is already included in the main project.
      # Without this, you'd see errors when you archive like:
      # "Multiple commands produce ... libReact.a"
      # "Multiple commands produce ... libyoga.a"



      targets_to_ignore = %w(React yoga)
      
      if targets_to_ignore.include? target.name
        target.remove_from_project
      end

      # Enables Flipper.
      #
      # Note that if you have use_frameworks! enabled, Flipper will not work and
      # you should disable these next few lines.
      flipper_post_install(installer)

    end
  end

  # Google Maps
  pod 'GoogleMaps'
  pod 'Google-Maps-iOS-Utils'
  pod 'react-native-google-maps', :path => '../node_modules/react-native-maps'

  pod 'GoogleIDFASupport', '~> 3.14.0'

  target 'WooflyTests' do
    inherit! :complete
    # Pods for testing
  end
end

target 'Woofly-tvOS' do
  # Pods for Woofly-tvOS

  target 'Woofly-tvOSTests' do
    inherit! :search_paths
    # Pods for testing
  end

end

AppDelegate.m:

#import "AppDelegate.h"
#import <React/RCTBridge.h>
#import <React/RCTBundleURLProvider.h>
#import <React/RCTRootView.h>
#import <GoogleMaps/GoogleMaps.h>
#import <Firebase.h>
#import <FBSDKCoreKit/FBSDKCoreKit.h>
#import <ReactNativeNavigation/ReactNativeNavigation.h>
#import <CodePush/CodePush.h>
#import <RNCPushNotificationIOS.h>
#import "RNSplashScreen.h"

#ifdef FB_SONARKIT_ENABLED
#import <FlipperKit/FlipperClient.h>
#import <FlipperKitLayoutPlugin/FlipperKitLayoutPlugin.h>
#import <FlipperKitUserDefaultsPlugin/FKUserDefaultsPlugin.h>
#import <FlipperKitNetworkPlugin/FlipperKitNetworkPlugin.h>
#import <SKIOSNetworkPlugin/SKIOSNetworkAdapter.h>
#import <FlipperKitReactPlugin/FlipperKitReactPlugin.h>
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
{
  #ifdef FB_SONARKIT_ENABLED
    InitializeFlipper(application);
  #endif
  [GMSServices provideAPIKey:@"AIzaSyDqNw_1Z83J144WkEBWp4emSngpf3kBdgg"];
  
  if ([FIRApp defaultApp] == nil) {
    [FIRApp configure];
  }
  
  // You can skip this line if you have the latest version of the SDK installed
  [[FBSDKApplicationDelegate sharedInstance] application:application
    didFinishLaunchingWithOptions:launchOptions];
  
  RCTBridge *bridge = [[RCTBridge alloc] initWithDelegate:self launchOptions:launchOptions];
  [ReactNativeNavigation bootstrap:[self sourceURLForBridge: bridge] launchOptions:launchOptions];
  
  [RNSplashScreen show];

  return YES;
}

//FB
- (BOOL)application:(UIApplication *)application
            openURL:(NSURL *)url
            options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options {

  BOOL handled =  [[FBSDKApplicationDelegate sharedInstance] application:application openURL:url options:options];
  // Add any custom logic here.
  return handled;
}

- (NSURL *)sourceURLForBridge:(RCTBridge *)bridge
{
#if DEBUG
  return [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
  //return [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"];
  return [CodePush bundleURL];
#endif
}

//Firebase

// - (void)messaging:(FIRMessaging *)messaging didReceiveRegistrationToken:(NSString *)fcmToken {
//     NSLog(@"FCM registration token: %@", fcmToken);
//     // Notify about received token.
//     NSDictionary *dataDict = [NSDictionary dictionaryWithObject:fcmToken forKey:@"token"];
//     [[NSNotificationCenter defaultCenter] postNotificationName:
//      @"FCMToken" object:nil userInfo:dataDict];
// }

// - (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {
//   [FIRMessaging messaging].APNSToken = deviceToken;
//   [RNCPushNotificationIOS didRegisterForRemoteNotificationsWithDeviceToken:deviceToken];
// }

// - (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
// {
//   [RNCPushNotificationIOS didRegisterUserNotificationSettings:notificationSettings];
// }

// // 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
// {
//   [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
//   [RNCPushNotificationIOS didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler];
// }

// // Required for the registrationError event.
// - (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
// {
//   [RNCPushNotificationIOS didFailToRegisterForRemoteNotificationsWithError:error];
// }

// // Required for the localNotification event.
// - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
// {
//   [RNCPushNotificationIOS didReceiveLocalNotification:notification];
// }

// // Called when a notification is delivered to a foreground app.
// -(void)userNotificationCenter:(UNUserNotificationCenter *)center willPresentNotification:(UNNotification *)notification withCompletionHandler:(void (^)(UNNotificationPresentationOptions options))completionHandler
//   {
//     NSDictionary *userInfo = notification.request.content.userInfo;
//     [[FIRMessaging messaging] appDidReceiveMessage:userInfo];
//     completionHandler(UNAuthorizationOptionSound | UNAuthorizationOptionAlert | UNAuthorizationOptionBadge);
//   }

@end


Android

Click To Expand

Have you converted to AndroidX?

  • [ X ] 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:

ISSUE IS IOS ONLY

android/app/build.gradle:

ISSUE IS IOS ONLY

android/settings.gradle:

ISSUE IS IOS ONLY

MainApplication.java:

ISSUE IS IOS ONLY

AndroidManifest.xml:

ISSUE IS IOS ONLY


Environment

Click To Expand

react-native info output:

 OUTPUT GOES HERE
  • 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
  • react-native-firebase version you're using that has this issue:
    • "@react-native-firebase/app": "^9.0.0"
  • Firebase module(s) you're using that has the issue:
    • "@react-native-firebase/database": "^7.5.15"
  • Are you using TypeScript?
    • N


@rezasazesh rezasazesh added help: needs-triage Issue needs additional investigation/triaging. type: bug New bug report labels Nov 11, 2020
@rezasazesh
Copy link
Author

rezasazesh commented Nov 11, 2020

Okay the problem seems to be limited to database().ref().on() I can run database().ref().once() and I can get data from the database

@mikehardy
Copy link
Collaborator

mikehardy commented Nov 11, 2020

[EDIT: We discovered that database tests were only running /*/*e2e.js not /**/*.e2e.js so the tests below were not executing and thus were not proof that it should work, in fact they appear to have problems after discovering the test execution oversight - we are investigating]

Interesting, all our e2e tests with limitToLast do once's https://github.com/invertase/react-native-firebase/blob/master/packages/database/e2e/query/limitToLast.e2e.js

and all the e2e tests with on specifically do activities afterwards https://github.com/invertase/react-native-firebase/blob/master/packages/database/e2e/query/on.e2e.js

...and they only are called once. I wonder if your use cases in testing are just slightly different and nothing is triggering the 'on' somehow?

If you can reproduce this, we can fix it but I doubt it will be a difference between debug and release in fact - those differences are rare on iOS - something else to look at is upstream in firebase-ios-sdk to see how they use and test the package: https://github.com/firebase/quickstart-ios/tree/master/database

@rezasazesh
Copy link
Author

rezasazesh commented Nov 11, 2020

Thanks for your help @mikehardy! I am certain limitToLast has little to do with it due to the examples below.

I have been testing some code to alert (as I cannot log in release) results on release mode so I can pinpoint the issue, for example:

Below does gives me results in debug and release mode:

database()
  .ref(`accepted_requests/`)
  .once('value', (childSnapShot) => {
    let requests = [];
    childSnapShot.forEach((doc) => {
      requests.push(doc.toJSON());
    });

    alert(`ONCE RESULT: ${requests.length}`);
  });

Same exact code but with .on() instead gives me no result in release but works fine in debug

database()
  .ref(`accepted_requests/`)
  .once('value', (childSnapShot) => {
    let requests = [];
    childSnapShot.forEach((doc) => {
      requests.push(doc.toJSON());
    });

    alert(`ONCE RESULT: ${requests.length}`);
  });

One more thing I noticed is that I am alerting the firebase app instances in both release and debug more with the code below and in release mode I get a [DEFAULT] app initialised natively by react-native-firebase (I don't initialise it with JS) but in debug mode I always get a [DEFAULT] and firebaseInit app. Not sure why this is. but even when I initialise the database on JS in release mode I still have no luck with .on() and also the notifications are having the same issue of not working in release

//Again only because I don't know of any other way to test this on release mode 😂
alert(JSON.stringify(firebase.apps));
console.log(firebase.apps);

@rezasazesh
Copy link
Author

I tried initialising a secondary app with JS only and in debug .on() it only works after reloading and in release still .on() never works on IOS, again everything is great on android!

@mikehardy
Copy link
Collaborator

We just discovered that the wonderful tests I linked have actually not been executing - we thought they were but there was a glob issue in test discovery prior to execution, so they've been skipped. And wouldn't you know (since you logged this issue!) - it appears there is an issue here. I have not done triage yet, but you are on to something: #4563

@mikehardy mikehardy linked a pull request Nov 18, 2020 that will close this issue
8 tasks
@rezasazesh
Copy link
Author

I ended up moving back to v5 as I needed to make an update for my app but now moved back to 10.0.3 version and the problem still exists 😢 I still cannot load data from realtime database with .on() on release mode and on the first load of debug mode

@mikehardy
Copy link
Collaborator

@rezasazesh do you mean v10.3.1 here (current stable) or actually 10.0.3 ?

I am pretty sure you mean 10.3.0 (which is fine, it should be working)

Here is what we'll need to move forward:

  • build a skeleton app from https://github.com/mikehardy/rnfbdemo/blob/master/make-demo.sh
  • start up the firebase database emulator (this will mean it doesn't even matter if you are connected to a real project or anything)
  • make an App.js that is completely standalone, creates a data test fixture, and then demonstrates the problem

We actually do have testing that is supposed to exercise this stuff, so alternatively you follow the README in the tests directory here, and create a new e2e test for your issue and post it as a PR, when we see it fail we can use it as the success criteria as well. You can use it.only('issue4535 - not loading on snapshot' etc etc so it is a fast development cycle and yarn tests:ios:test-reuse to just run that one .only test in a fast cycle. That is how we develop + fix things, it's quite efficient

https://github.com/invertase/react-native-firebase/blob/master/tests/README.md
https://github.com/invertase/react-native-firebase/blob/master/packages/database/e2e/issues.e2e.js

@rezasazesh
Copy link
Author

Thanks @mikehardy I built the skeleton app and my code worked fine there which meant there are things wrong with my project maybe other packages. I am using react-native-splash-screen and seems like commenting out the [RNSplashScreen show]; in App delegate that this package instructs users to do fixed my issue!

I know this has nothing to do with RNFB just thought it is quite interesting! Need to look further and see why!

@mikehardy
Copy link
Collaborator

@rezasazesh One of my strongest recommendations is to stop using the buggy unmaintained react-native-splash-screen immediately and convert to https://github.com/zoontek/react-native-bootsplash which is maintained and does not suffer this problem.

Bonus: bootsplash has a little CLI tool packaged with it that makes integrating it a breeze.

Reference: My history making react-native-splash-screen work, but then giving up on it: crazycodeboy/react-native-splash-screen#289 (comment)

@rezasazesh
Copy link
Author

@mikehardy Oh wow I had no idea how many problems this was causing! Only problem is that library does not work with React Native Navigation which I have in my project from the sound of it 😢

@mikehardy
Copy link
Collaborator

You can't be the only one who is using react-native-navigation with it and I'd be surprised if it's a total failure or just something that happens with the buggy splash screen but no one mentions it, the standard on boot splash is much higher. I encourage you to try it in a test branch as the integration is almost automatic anyway. Then you will have actual test results

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help: needs-triage Issue needs additional investigation/triaging. type: bug New bug report
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants