Skip to content

馃敟 [馃悰] isHeadless flag on iOS unreliable聽#5388

Closed as not planned
Closed as not planned

Description

@helenaford

The issue is that the isHeadless flag included in @react-native-firebase/messaging is unreliable and causes the app to render null when the app is opened. The flag can be true initially when the app is launching but does not update to false when the app is in the foreground.

Please see this code snippet which is taken from the docs:

// index.js
import { AppRegistry } from 'react-native';
import messaging from '@react-native-firebase/messaging';

messaging().setBackgroundMessageHandler(async remoteMessage => {
  console.log('Message handled in the background!', remoteMessage);
});

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

  return <App />;
}

function App() {
  // Your application
}

AppRegistry.registerComponent('app', () => HeadlessCheck);

There have been previous discussions around the usage of this flag:
#4163
#4304

Some suggestions to listen to AppState rather than use the isHeadless flag but it's unclear what the best solution is to prevent the app from rendering when it's in a headless state.

From reading the discussions, it's clear the isHeadless flag causes unpredictable results, is there anything that can be done in the library to fix the flag?

Or, can the docs be updated to show a recommended solution?


Project Files

Javascript

Click To Expand

package.json:

# N/A

firebase.json for react-native-firebase v6:

# N/A

iOS

Click To Expand

ios/Podfile:

  • I'm not using Pods
  • I'm using Pods and my Podfile looks like:
# N/A

AppDelegate.m:

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    ...
    if ([FIRApp defaultApp] == nil) {
        [FIRApp configure];
    }
    ...

    NSDictionary *appProperties = [RNFBMessagingModule addCustomPropsToUserProps:nil withLaunchOptions:launchOptions];

    RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge
                                                     moduleName:@"xxx"
                                              initialProperties:appProperties];

    ...

    [RNBootSplash initWithStoryboard:@"BootSplash" rootView:rootView];

    return YES;
}


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:

// N/A

android/app/build.gradle:

// N/A

android/settings.gradle:

// N/A

MainApplication.java:

// N/A

AndroidManifest.xml:

<!-- N/A -->


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:
    • e.g. 5.4.3
  • Firebase module(s) you're using that has the issue:
    • e.g. Instance ID Messaging
  • Are you using TypeScript?
    • Y/N & VERSION Y


Activity

  1. miallo commented on Jul 7, 2021

    @miallo

    Is there a place where I can look into this thing and see if I can find the problem? This bug is causing us quite some troubles...

  2. mikehardy commented on Jul 7, 2021

    @mikehardy
    Collaborator

    This is an area of some pain that I've looked into a bit yes. We use detox as our testing solution in the e2e app and unfortunately it does not allow for running on-device on iOS devices, so near as I can tell there is no way to make an automated test for it.

    So I think the best path is actually to carefully (that is, take care not to npm/yarn install as it will potentially blow away your changes) reach right into node_modules and then roll up the sleeves and get dirty with the .m and .js files directly in the messaging module

    It appears based on my understanding of the problem that there are a couple of things:

    This may actually fail if used on android? There is no android implementation - but this is a tangent:

    getIsHeadless() {
    return this.native.getIsHeadless();
    }

    This implementation which is checking for foreground or background:

    if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) {
    appProperties[@"isHeadless"] = @([RCTConvert BOOL:@(YES)]);
    }

    Is probably best not as a property that is accessed but as something that is determined each time here:

    RCT_EXPORT_METHOD(getIsHeadless
    :(RCTPromiseResolveBlock) resolve
    :(RCTPromiseRejectBlock) reject
    ) {
    RNFBMessagingNSNotificationCenter* notifCenter = [RNFBMessagingNSNotificationCenter sharedInstance];
    return resolve(@([RCTConvert BOOL:@(notifCenter.isHeadless)]));
    }

    Then it would accurately reflect whether the app is in the background or not?

  3. mikehardy commented on Jul 7, 2021

    @mikehardy
    Collaborator

    (hit enter too soon, updated comment above - https://github.com/ds300/patch-package may be used to test your changes more reliably, and then the same work can be proposed as a PR here?)

  4. miallo commented on Jul 8, 2021

    @miallo

    A bit of debugging later...
    Here we successfully register the listener for getting into foreground

    [[NSNotificationCenter defaultCenter] addObserver:strongSelf selector:@selector(application_onDidEnterForeground) name:UIApplicationWillEnterForegroundNotification object:nil];

    The docs say that the selector function

    must have one and only one argument

    but even if we add that, it does not change that this function is never called


    So here we never set the isHeadless to false
    appPropertiesDict[@"isHeadless"] = @([RCTConvert BOOL:@(isHeadless)]);

    The default YES value is also never called and the only reference we could find for the addCustomPropsToUserProps function is in the respective .h file.

    + (NSDictionary *)addCustomPropsToUserProps:(NSDictionary *_Nullable)userProps withLaunchOptions:(NSDictionary *_Nullable)launchOptions {

    I have to say my knowledge about how RN works is even less than how ObjC is working but maybe this is a first hint?

  5. miallo commented on Jul 8, 2021

    @miallo

    Right... If I only followed the instructions to update the AppDelegate.m I would have called the addCustomPropsToUserProps myself... Sorry for my stupidity...

  6. ease-space commented on Sep 18, 2021

    @ease-space

    This code fixed bug
    小薪懈屑芯泻 褝泻褉邪薪邪 2021-09-18 胁 17 20 25

  7. mym0404 commented on Feb 17, 2022

    @mym0404

    if i send message with content-available in quit state, isHeadless is true during next app open time

  8. stale commented on Apr 16, 2022

    @stale

    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.

  9. added
    Type: StaleIssue has become stale - automatically added by Stale bot
    on Apr 16, 2022
  10. stale commented on May 1, 2022

    @stale

    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.

  11. orange-brother commented on Dec 13, 2022

    @orange-brother

    if i send message with content-available in quit state, isHeadless is true during next app open time

    Same here. If i remove content-available in json, isHeadless works fine.

  12. yuvraj-scalex commented on Apr 4, 2023

    @yuvraj-scalex

    This issue is surfacing in our production app and redirects users to the blank screen as isHeadless is true when the app is launched from the quit state. Even though we return <App /> component when isHeadless is true, it is completely messing up with the navigation of the App.
    Is there any way we can fix this?
    RN version: 0.68.5
    react-native-firebase: 17.4.1
    react: 17.0.2

  13. yuvraj-scalex commented on Apr 14, 2023

    @yuvraj-scalex

    Hello @mikehardy, can you pl suggest something to get rid of this issue?
    We've upgraded the react-native-firebase packages but still have no luck with this issue, should we upgrade the react-native version as well?

  14. removed
    Type: StaleIssue has become stale - automatically added by Stale bot
    on Apr 14, 2023
  15. github-actions commented on May 12, 2023

    @github-actions
    Contributor

    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 attention?

    This issue will be closed in 15 days if no further activity occurs.

    Thank you for your contributions.

  16. miladdev85 commented on May 31, 2023

    @miladdev85

    Is there any progress here? This issue should not be closed.
    isHeadless does not change or get updated.

  17. Alex1899 commented on Jun 13, 2023

    @Alex1899

    I am experiencing the same issue. When the app opens from pressing the background notification, isHeadless stays true

  18. humaidk2 commented on Nov 29, 2023

    @humaidk2

    Hi,

    I spent some time investigating this issue and found the solution.

    The problem comes from updating app properties while the bridge has not been loaded.

    It's an issue that comes from react native, react/react-native#20115

    but react-native suggested that they won't be solving it,

    Screenshot 2023-11-29 at 7 58 27鈥疉M

    There's 2 suggested solutions:

    1 is to wait for js to load then set the props, but this didn't work for us

    [[NSNotificationCenter defaultCenter] addObserverForName:RCTJavaScriptDidLoadNotification object:nil queue:nil usingBlock:^(NSNotification * _Nonnull note) {
     
    }];
    

    2 is to patch react native, which did work for us

    https://github.com/facebook/react-native/pull/20116/files

  19. mikehardy commented on Nov 29, 2023

    @mikehardy
    Collaborator

    @humaidk2 react-native-firebase definitely has some things that only load after the javascript environment comes up and to my knowledge it has been working reliably. Patching react-native in those files implies a local fork / build of react-native is very painful from a maintenance perspective making a javascript observer a strong preference

    This notification is used internally in react-native I'm surprised it's not working, they appear to be specifying the bridge as the object to observe though, I wonder if you follow their addObserver pattern it might work better? Examples:

    https://github.com/search?q=repo%3Afacebook%2Freact-native+RCTJavaScriptDidLoadNotification&type=code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type: StaleIssue has become stale - automatically added by Stale botWorkflow: Needs ReviewPending feedback or review from a maintainer.help: needs-triageIssue needs additional investigation/triaging.platform: iostype: bugNew bug report

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions