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

💦Getting 0 instead of #ffffff from remote config Firebase at first launch #3139

Closed medmo7 closed 4 years ago

medmo7 commented 4 years ago

Issue

I'm using firebase remote config to set the color of an Icon. The first time the app is loaded the value loaded from firebase is 0, if a reload the app i get the correct color value #ffffff. You can see the result in Xcode console in this screenShot:

image

Here is my remoteConfig config file:


async getRemoteConfig(t) {
    // const { t, i18n } = useTranslation();
    if (__DEV__) {
      firebase.config().enableDeveloperMode();
      console.log('running in dev mode');
    }

    // Set default values
    firebase.config().setDefaults({
      share_button_color:'#fff'
    });

    firebase
      .config() 
      .fetch(0) // call like this fetch(0) to reset cache load new params from firebase,without this it takes 12h
      .then(() => {
        return firebase.config().activateFetched();
      })
      .then(async activated => {
        if (!activated) console.log('Fetched data not activated');
        else console.log('Fetched data activated');
      })
      //   .then(snapshot => {
      //     const hasExperimentalFeature = snapshot.val();

      //     if (hasExperimentalFeature) {
      //       enableSuperCoolFeature();
      //     }

      //     // continue booting app
      //   })
      .catch(console.error);
  },
};

Also here is my component:

export default class ShareIcon extends Component {
  constructor(props) {
    super(props);
    this.state = {
      buttonColor: 'white',
    };
  }

  async componentDidMount() {
    await this.getShareButtonColor();
  }

  async getShareButtonColor() {
    const remoteButtonColorData = await firebase
      .config()
      .getValue('share_button_color');
    const buttonColor = remoteButtonColorData.val();
    console.log('buttonColor',buttonColor) // <===this is the console.log we see 
    this.setState({buttonColor});          // in screenshot
  }

  render() {
    return (
      <TouchableOpacity
        hitSlop={{top: 10, left: 10, bottom: 10, right: 10}}
        style={styles.container}
        onPress={() => shareApp()}
        style={{marginLeft: 20}}>
        <Icon name="share-2" type="feather" color={this.state.buttonColor} />
      </TouchableOpacity>
    );
  }
}

Project Files

iOS

Click To Expand

#### `ios/Podfile`: - [] I'm not using Pods - [x] I'm using Pods and my Podfile looks like: ```ruby # Uncomment the next line to define a global platform for your project # platform :ios, '9.0' platform :ios, '9.0' target 'MdcIos' do pod 'yoga', :path => '../node_modules/react-native/ReactCommon/yoga/Yoga.podspec' pod 'React', path: '../node_modules/react-native', :subspecs => [ 'Core', 'ART', 'DevSupport', 'RCTAnimation', 'RCTImage', 'RCTLinkingIOS', 'RCTNetwork', 'RCTPushNotification', 'RCTText', 'RCTWebSocket', 'RCTGeolocation', ] pod 'GoogleAnalytics' # Uncomment the next line if you're using Swift or would like to use dynamic frameworks # use_frameworks! # Pods for MdcIos pod 'RNLanguages', :path => '../node_modules/react-native-languages' pod 'RNIap', :path => '../node_modules/react-native-iap' pod 'Firebase/Core', '~> 5.2.0' pod 'Firebase/Messaging', '~> 5.2.0' pod 'Firebase/AdMob' pod 'Fabric', '~> 1.9.0' pod 'Crashlytics', '~> 3.12.0' pod 'Firebase/RemoteConfig' pod 'RNBackgroundFetch', :path => '../node_modules/react-native-background-fetch' pod 'react-native-orientation', :path => '../node_modules/react-native-orientation' pod 'rn-fetch-blob', :path => '../node_modules/rn-fetch-blob' pod 'RNReanimated', :path => '../node_modules/react-native-reanimated' pod 'RNGestureHandler', :path => '../node_modules/react-native-gesture-handler' pod 'RNScreens', :path => '../node_modules/react-native-screens' pod 'RNZipArchive', :path => '../node_modules/react-native-zip-archive' pod 'RNCAsyncStorage', :path => '../node_modules/@react-native-community/async-storage' pod 'react-native-netinfo', :path => '../node_modules/@react-native-community/netinfo' pod 'react-native-splash-screen', :path => '../node_modules/react-native-splash-screen' pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons' pod 'RNCPushNotificationIOS', :path => '../node_modules/@react-native-community/push-notification-ios' pod 'react-native-settings', :path => '../node_modules/react-native-settings' end post_install do |installer| installer.pods_project.targets.each do |target| if target.name == 'react-native-google-maps' target.build_configurations.each do |config| config.build_settings['CLANG_ENABLE_MODULES'] = 'No' end end if target.name == "React" target.remove_from_project end if target.name == 'yoga' target.remove_from_project target.build_configurations.each do |config| config.build_settings['GCC_TREAT_WARNINGS_AS_ERRORS'] = 'NO' config.build_settings['GCC_WARN_64_TO_32_BIT_CONVERSION'] = 'NO' end end end end ``` #### `AppDelegate.m`: ```objc /** * Copyright (c) 2015-present, Facebook, Inc. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ #import "AppDelegate.h" #import #import #import "RNFirebaseNotifications.h" #import "RNFirebaseMessaging.h" #import "Orientation.h" #import "RNSplashScreen.h" #import #import #import #import @implementation AppDelegate // 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]; } // Required for the localNotification event. - (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { [RNCPushNotificationIOS didReceiveLocalNotification:notification]; } - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { NSURL *jsCodeLocation; [FIRApp configure]; [[UNUserNotificationCenter currentNotificationCenter] setDelegate:self]; [RNFirebaseNotifications configure]; jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil]; RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@"MdcIos" initialProperties:nil launchOptions:launchOptions]; 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]; [RNSplashScreen show]; return YES; } //- (void)application:(UIApplication *)application didReceiveRemoteNotification:(nonnull NSDictionary *)userInfo //fetchCompletionHandler:(nonnull void (^)(UIBackgroundFetchResult))completionHandler{ // [[RNFirebaseNotifications instance] didReceiveRemoteNotification:userInfo fetchCompletionHandler:completionHandler]; //} //- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings { // [[RNFirebaseMessaging instance] didRegisterUserNotificationSettings:notificationSettings]; //} //- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification { // [[RNFirebaseNotifications instance] didReceiveLocalNotification:notification]; //} - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation { return [RCTLinkingManager application:application openURL:url sourceApplication:sourceApplication annotation:annotation]; } -(void) userNotificationCenter:(UNUserNotificationCenter *)center didReceiveNotificationResponse:(UNNotificationResponse *)response withCompletionHandler:(void (^)(void))completionHandler { [[RNFirebaseMessaging instance] didReceiveRemoteNotification:response.notification.request.content.userInfo]; completionHandler(); } - (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window { return [Orientation getOrientation]; } @end ```


Android

Click To Expand

#### `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:** ``` React Native Environment Info: System: OS: macOS 10.14.6 CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz Memory: 765.18 MB / 8.00 GB Shell: 5.3 - /bin/zsh Binaries: Node: 12.9.0 - /usr/local/bin/node npm: 6.10.3 - /usr/local/bin/npm Watchman: 4.9.0 - /usr/local/bin/watchman SDKs: iOS SDK: Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1 Android SDK: API Levels: 23, 24, 27, 28, 29 Build Tools: 27.0.3, 28.0.2, 28.0.3, 29.0.2 System Images: android-28 | Intel x86 Atom_64, android-28 | Google APIs Intel x86 Atom, android-28 | Google APIs Intel x86 Atom_64, android-29 | Google APIs Intel x86 Atom, android-29 | Google Play Intel x86 Atom IDEs: Android Studio: 3.5 AI-191.8026.42.35.5900203 Xcode: 11.3.1/11C504 - /usr/bin/xcodebuild npmPackages: react: 16.8.3 => 16.8.3 react-native: 0.59.9 => 0.59.9 npmGlobalPackages: react-native-cli: 2.0.1 react-native-fbsdk: 1.0.4 react-native-gesture-handler: 1.4.1 react-native-git-upgrade: 0.2.7 react-native-languages: 3.0.2 react-native-reanimated: 1.3.0 ``` - **Platform that you're experiencing the issue on**: - [x] iOS - [x] 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:** - `e.g. Instance ID` - **Are you using `TypeScript`?** - `Y/N`


Think react-native-firebase is great? Please consider supporting all of the project maintainers and contributors by donating via our Open Collective where all contributors can submit expenses. [Learn More]

Ehesp commented 4 years ago

What version of React Native Firebase are you using?

medmo7 commented 4 years ago

I have the 5.2.1, sorry forgot to mention that.

mikehardy commented 4 years ago

In general I think those versions are unsupportably old as there was a bit of work done in the google SDKs to make everything work on iOS 13, and to access the newer SDKs you need to be on current react-native-firebase v5 at least (5.6.0 right now). It does actually still work on react-native 0.59 in case you can't make that leap yet.

In practice remote config is doing work over the network though, I wonder if you're just not waiting enough. I would add more logging, and then also watch either unfiltered adb logcat (if android) or launch from Xcode and watch the console there to see what the underlying SDKs are telling you. For remote config I see lots of interesting messages when I do that...

medmo7 commented 4 years ago

Thanks for your response @mikehardy.I dont know how to wait more, i've used await firebase.config().getValue('share_button_color');. I've watched the Xcode console, i cant see some explicit warning about firebase remoteConfig, but there is a bunch of errors just before my console.log('buttonColor'). Here is a screenshot:

Capture d’écran 2020-01-28 à 15 43 26
medmo7 commented 4 years ago

I updated RNFirebase to 5.6.0 but still getting this issue.

mikehardy commented 4 years ago

Can you reproduce this on android? You might get more / more interesting information from an unfiltered adb logcat on android vs ios logging

medmo7 commented 4 years ago

thanks for the quick answer. There is definitely more informations, but dont see something related to my issue. RemoteConfig is logged two times with RNFirebaseRemoteConfig: New instance and FirebaseRemoteConfig: Fetch succeeded!

mikehardy commented 4 years ago

All I can think of is to open up the java file in node_modules and add System.out calls to log every bit of relevant activity, then watch closely. Brute force approach but might be effective, the code in question is not that complicated https://github.com/invertase/react-native-firebase/blob/v5.x.x/android/src/main/java/io/invertase/firebase/config/RNFirebaseRemoteConfig.java

medmo7 commented 4 years ago

Just followed your advice and look to the RNFirebaseRemoteConfig.java, and im printing System.out.println(convertRemoteConfigValue(value));. When the value is 0 the result is:

image and when its #FFFFFF :

image

medmo7 commented 4 years ago

If i get this right, the first time the app run, remote config tries to get the local value of the colorButton, but fails:

image after app is refreshed we get the good value from remote:

image

mikehardy commented 4 years ago

So perhaps you need to set defaults. then fetch, then behave differently based on the source of the data (static - which is uninitialized / no default in your current set) vs remote etc. Are those values exposed in the javascript such that you can inspect and act on source?

That's what I was referring to at least with regard to async and waiting - you're doing the async code correctly assuming that it isn't what I think of as "two levels of async", one being the method signature and promise return, the other layer being that even after the promise returns it is actually doing a network-level async thing and a future call might be different. Device tokens are similar if I recall correctly. The solution (read as: "hack") is to either add a real timer wait, of just accept that even after the Promise returns success you may have stale info, and future checks can always return something different.

medmo7 commented 4 years ago

What i do for now is check if received value is a valid hex color, otherwise hard code the color. I think the fact that this value is requested on app launch causes the bug, because i have other values in the app i get from remoteConfig and it works great.

mikehardy commented 4 years ago

sounds like exactly what the remote config setDefaults would be for? Then you just have normal RemoteConfig flow

medmo7 commented 4 years ago

I do set setDefaults: firebase.config().setDefaults({ share_button_color:'#fff' });

stale[bot] commented 4 years ago

Hello 👋, to help manage issues we automatically close stale issues. This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs. Thank you for your contributions.

matamicen commented 4 years ago

@mikehardy @Ehesp @medmo7 We have similar problem after Publish and update on the Remote config console, the info doesn't come updated in the next Fetch (came the old values of the remote console) but it works on the second time when we call the fetch.

Info:

Platform: iOS & Android React Native Version: 0.60.4 react-native-firebase (all modules) : 6.0.4

here is the code:

            remoteConfig.fetch(0).then(
              remoteConfig.fetchAndActivate().then((spot) => { 

                configData = remoteConfig.getValue("urlInternet1");
               if (configData.source==='default')
               {
                 console.log('default#');
                 console.log(configData.value)
                 url1 = configData.value;
               }
                 else{
                 console.log('remote#');
                 console.log(configData);
                 let obj = JSON.parse(configData.value);
                 console.log(obj.url);
                 url1 = obj.url;

                 }

              })).catch((err) => {

                console.log('catch fetch URL remoteConfig: '+err)
              })

Any idea? should be the Firebase Version?

mikehardy commented 4 years ago

Any idea? should be the Firebase Version?

probably not, but I usually don't see value in time investment troubleshooting old versions. Risk of wasting time troubleshooting already fixed issue, and if a fix is developed you have to upgrade to get it anyway. I'd start being on current stable of everything, then if you can reproduce we have confirmation at least. That said, this feels like either a slow network / async type thing, or an upstream SDK issue.

Note that if you adopt the most up to date Firebase SDKs (like so: https://github.com/mikehardy/rnfbdemo/blob/master/make-demo-v6.sh#L33) you will need a temporary workaround until the PR linked here is released (it's already merged) for in-app-messaging to compile, if you're using that: https://github.com/mikehardy/rnfbdemo/blob/master/make-demo-v6.sh#L146 - you can ignore this if you don't use in-app-messaging

matamicen commented 4 years ago

@mikehardy yeah, it is a smart advice ... We upgraded to latest version 6.3.4 but still have the same issue ... anyway we will do a workaround .... but just to let you know ... I dont know may be it doesn't fail on PRD when the default refresh time es 12 hours. (I am using Fetch(0) in dev right now) ...

Mike thanks as always!

stale[bot] commented 4 years ago

Hello 👋, to help manage issues we automatically close stale issues. This issue has been automatically marked as stale because it has not had activity for quite some time. Has this issue been fixed, or does it still require the community's attention?

This issue will be closed in 15 days if no further activity occurs. Thank you for your contributions.

stale[bot] commented 4 years ago

Closing this issue after a prolonged period of inactivity. If this is still present in the latest release, please feel free to create a new issue with up-to-date information.