Search code examples
react-nativepush-notificationreact-native-router-flux

Where to put push notification component in React Native


I'm making simple News Notification App with React Native. It just send push notification to user when certain condition news comes up.

I made UI first, and basic functions. so there are some components to login, register, and add condition components, etc. and It works well.

Then finally I want to apply Push Notification to my app, so I use Firebase Cloud Messaging(FCM). and It works well fortunately. when I request post with some data (key header, token, etc), the app receive push notification successfully.

But the problem is, when I test Push Notification to my app, I just followed example source. so I don't know how to apply it my exist app.

The app looks like,

export default class App extends Component {
    render() {

        return (

            <Provider store={configureStore()}>
                <MenuContext>
                    <Router>
                        <Scene key="root">
                            <Scene key="login" hideNavBar component={LoginComponent} initial/>
                            <Scene key="register" hideNavBar component={RegisterComponent}/>
                            <Scene key="resetPassword" hideNavBar component={ResetPasswordComponent}/>
                            <Scene key="main" tabs
                                   tabBarStyle={{ top: 72, height: 76, backgroundColor: API.SECOND_COLOR, borderColor: API.BORDER_COLOR, borderBottomWidth: 1}}
                                   tabBarSelectedItemStyle={{ marginBottom: -1, height: 76, borderBottomWidth: 4, borderBottomColor: API.FIRST_COLOR }}
                            >
                                <Scene key="newsConditionsList" title="First Tab" iconName="alarm" icon={TabIcon}>
                                    <Scene key="scarlet" component={TabComponent1} hideNavBar initial/>
                                </Scene>
                                <Scene key="news" title="Second Tab" iconName="chat" icon={TabIcon}>
                                    <Scene key="scarlet2" component={TabComponent2} hideNavBar initial/>
                                </Scene>
                                <Scene key="settings" title="Third Tab" iconName="settings" icon={TabIcon}>
                                    <Scene key="scarlet3" component={TabComponent3} hideNavBar initial/>
                                </Scene>
                            </Scene>
                            <Scene key="addCondition" title="Add Todo" component={AddConditionComponent} hideNavBar/>
                            <Scene key="room" title="In Room" component={RoomComponent} hideNavBar/>

                        </Scene>
                    </Router>
                </MenuContext>
            </Provider>
        );
    }
}

At this point, where to put my PushController.js? I think PushController should be executed in background whether app is running or not.

The PushController.js code is below.

I don't know where to put this component. Where to put that? Please Help me!

import React, { Component } from "react";

import FCM, {FCMEvent, RemoteNotificationResult, WillPresentNotificationResult, NotificationType} from "react-native-fcm";

import firebaseClient from  "./FirebaseClient";

export default class PushController extends Component {
    constructor(props) {
        super(props);
    }

    componentDidMount() {
        FCM.requestPermissions();

        FCM.getFCMToken().then(token => {
            console.log("TOKEN (getFCMToken)", token);
            this.props.onChangeToken(token);
        });

        FCM.getInitialNotification().then(notif => {
            console.log("INITIAL NOTIFICATION", notif)
        });

        this.notificationListner = FCM.on(FCMEvent.Notification, notif => {
            console.log("Notification", notif);
            if(notif.local_notification){
                return;
            }
            if(notif.opened_from_tray){
                return;
            }

            if(Platform.OS ==='ios'){
                //optional
                //iOS requires developers to call completionHandler to end notification process. If you do not call it your background remote notifications could be throttled, to read more about it see the above documentation link.
                //This library handles it for you automatically with default behavior (for remote notification, finish with NoData; for WillPresent, finish depend on "show_in_foreground"). However if you want to return different result, follow the following code to override
                //notif._notificationType is available for iOS platfrom
                switch(notif._notificationType){
                    case NotificationType.Remote:
                        notif.finish(RemoteNotificationResult.NewData) //other types available: RemoteNotificationResult.NewData, RemoteNotificationResult.ResultFailed
                        break;
                    case NotificationType.NotificationResponse:
                        notif.finish();
                        break;
                    case NotificationType.WillPresent:
                        notif.finish(WillPresentNotificationResult.All) //other types available: WillPresentNotificationResult.None
                        break;
                }
            }
            this.showLocalNotification(notif);
        });

        this.refreshTokenListener = FCM.on(FCMEvent.RefreshToken, token => {
            console.log("TOKEN (refreshUnsubscribe)", token);
            this.props.onChangeToken(token);
        });
    }

    showLocalNotification(notif) {
        FCM.presentLocalNotification({ 
            title: notif.title,
            body: notif.body,
            priority: "high",
            click_action: notif.click_action,
            show_in_foreground: true,
            local: true
        });
    }

    componentWillUnmount() {
        this.notificationListner.remove();
        this.refreshTokenListener.remove();
    }


    render() {
        return null;
    }
}

Solution

  • It does not matter where you put your PushController component as long as it stays mounted. In fact you don't need a special component at all but you can have it :)

    So simple answer might be put it into your App. eg.

    <View>
      <PushController />
      <Provider store={configureStore()}>
        ...
      </Provider>
    </View>
    

    Only important thing is that you execute proper registration of your device at the application startup via FCM calls.