firebase / quickstart-android

Firebase Quickstart Samples for Android
https://firebase.google.com
Apache License 2.0
8.78k stars 7.32k forks source link

Google FCM getIntent returns null when app is not running or when app is in background #96

Closed thomasdsouza closed 7 years ago

thomasdsouza commented 7 years ago

though, the notification does appear in the system tray, the data is NOT available in the intent... either in onNewIntent or in onCreate, the extras is null.

Expected Results:

According to the Firebase Notifications docs, when App State is Background and a Notification with data is sent, the notification appears in the system try and the data will be available in the extras of the intent.

@Override public void onCreatet() { Bundle extras = getintent().getExtras(); ---> extras is always null when app is not running or when app is in background }

@Override
public void onNewIntent(Intent intent) {
    Bundle extras = intent.getExtras();
    ---> extras is always null when app is not running or when app is in background
}

Remarks: The data is available when App State is in the Foreground. But the notification console is pretty much unusable with this bug because ALL (background, app not running, foreground) users need to be able to get the data in a notification. Otherwise, how does a developer know what data a user saw or didn't see (e.g. whether a user was shown the discount 10% or not).

2ndGAB commented 7 years ago

Hello, I didn't tried to receive data when the app is in background from the intent but from onMessageReceive() only because an app in backkground is supposed to receive data-message in background from this callback. Such kind of message for example, if you send it with Google Advanced REST Client to https://fcm.googleapis.com/fcm/send:

{
  "to" : "c_Tzsc5zYY0:APA91bGWj8vv-fz...EOsaawtYcar40M31CxhBgLhh",
  "data": {
    "id": 19,
    "title": "Title test",
    "msg": "Text of the test",
  },
  "delay_while_idle" : false,
  "priority" : "high",
  "content_available" : true  // for iOS only can be ignored for Android
}

So that way, you are able to create yourself even a custom notification whether the application is in foreground or background.

But just a question, what Android Studio version do you use?

thomasdsouza commented 7 years ago

Hi @2ndGAB , I am aware of the data only msgs being received in onMessageReceived( ) and i use that for certain purposes and it works correctly for me. But there are cases where we want the "target" (the "to") to be chosen from the console and not maintain a list of millions of FCM device tokens. Also, console provides useful options such being able to time the delivery based on recipient's time zone etc,

Android Studio 2.1.2

2ndGAB commented 7 years ago

@thomasdsouza I'm very surprised that your projects built from Studio 2.1.2 are able to receive data messages in onMessageReceive() because that really don't work for me. Only if I build the project from Studio 1.5 https://code.google.com/p/android/issues/detail?id=217489

kroikie commented 7 years ago

Hi @thomasdsouza you should be getting that data in the launched intent. I just sent a notification from the console that contained a custom data pair like you specified and here is the output from the extras of my intent:

D/MainActivity: Key: google.sent_time Value: 1469632806844
D/MainActivity: Key: from Value: /topics/news
D/MainActivity: Key: discount Value: 10
D/MainActivity: Key: google.message_id Value: 0:1469632807251042%31bd1c9631bd1c96
D/MainActivity: Key: collapse_key Value: com.google.firebase.quickstart.fcm

Have you made any changes to the quickstart?

thomasdsouza commented 7 years ago

Hi @kroikie, thank you for your reply. [apologies for the delay in replying... have been traveling past couple of days...] i just set up new project with the quickstart code (no modifications) and wanted to test the issue but now i am receiving an error when trying to sending a notification in the console. err

kroikie commented 7 years ago

HI @thomasdsouza there was an outage of the Firebase console, I think that could have been the reason for your issue. This issue has been resolved and the console should be working as expected now. Before going deeper into this issue could you confirm that you are indeed unable to send messages from the console?

thomasdsouza commented 7 years ago

Hi @kroikie, thank you for your reply. I can confirm that i can send messages from the console. Also, I can confirm that, the data is now available in the intent... in onNewIntent( ) or in onCreate( ) as the case may be. At this point i can say that i have thoroughly tested my scenarios and the functionality is working in accordance with your specification/documentation. Thank you very much for your help!

kroikie commented 7 years ago

The console should be working as expected now.

nibha181 commented 7 years ago

@kroikie :- Can you help me on this!!

I have created a project including FCM notifications, when I send notifications from console and my app is on background I always get null on onNewIntent method.

When My app is already open then only my onMessageReceived method from FirebaseMessagingService get called,so I handled the same thing in MainActivity too.

I have called onNewIntent method for performing some task.

     public void onNewIntent(Intent intent) {
      Bundle extras = intent.getExtras(); // always null

       if (extras != null) {
         //perform some task 
      }
     }

Android Studio 2.1.1

gradle dependencies :

compile 'com.google.firebase:firebase-analytics:9.2.0'
compile 'com.google.firebase:firebase-messaging:9.2.0'
compile 'com.google.firebase:firebase-ads:9.2.0'
compile 'com.google.firebase:firebase-auth:9.2.0'
compile 'com.google.firebase:firebase-crash:9.2.0'

Thanks!!

kroikie commented 7 years ago

I don't think the data from a message sent from the console will be available in an intent that results in onNewIntent being called. If your app is in the background and you send a message from the console then that would result in a notification being displayed on the device and if tapped the data will be in the intent of the Activity that launches. Try getting the extras from the onCreate method of the MainActivity.

nibha181 commented 7 years ago

you are right @kroikie If your app is in the background and you send a message from the console then that would result in a notification being displayed on the device and if tapped the data will be in the intent of the Activity that launches

I am calling the onNewIntent on onCreate only but the problem is I am getting null when I send notifications from console.

nibha181 commented 7 years ago

@kroikie : Is there any possibility to solve this issue? could you suggest what could be wrong with my app? Why I am getting null when received notification from FireBase console?

saurabh-sablok commented 7 years ago

@thomasdsouza how did u solve this issue, i am still facing the same, when app is in background. Working fine when app is closed.

pmuraus commented 7 years ago

Same here. Any updates? My main activity is splash activity.

My steps:

  1. App is killed
  2. Notification is received and I tap on notification in notification tray
  3. App is opened and intent with all push notification extras are there as expected. After that splash activity is finished and home activity is opened.
  4. I minimize the app and wait for a new notification.
  5. I press on notification and the app just maximizes and only onResume from home activity is called with empty intent extras. The Splash activity wasn't started.

Any solutions?

mrrocco commented 7 years ago

I am having the same problem as @pmuraus

ClarkNguyen commented 7 years ago

I'm working to flow like @pmuraus and stuck on 3rd step, when app opened, the intent from notification extras alway null. I can't debug at all because when app is in background or killed and received push notification, the method onMessageReceived() not trigger.

Any solutions?

zmarwa commented 7 years ago

Same as @clarkNguyen, Intent from notif is null. ANY solutions plz ?

Hardik-mehta commented 7 years ago

i am also facing same issue as @pmuraus . on moto e 2nd gen.

sayoojvalsan-demandmedia commented 7 years ago

Same issue. Tried sending notification with custom data from firebase console. The intent has to no extras.

tushar2812 commented 7 years ago

i got a solution for that. just put below code in oncreate method of launcher activity.

if (bundle != null) {
        String value = bundle.getString("key");
        if (value != null) {

            startActivity(new Intent(MainActivity.this, secActivity.class));
        }
}

when app is in background or killed,FCM will not call onmessagerecieved method,but it will send data to system tray to display notification.so datapayload(sent from fcm console) will not be handled by onmessagerecieved method.when user click on notification,it will launch default activity of app and datapayload will be passed by intent .so making change in oncreate method of launcher activity(as above)we can get datapayload even when app is in background or killed.(ex key is sent by fcm console).when app is in foreground datapayload and will be handled by onmessagerecieved method of fcm service.

zmarwa commented 7 years ago

Hello, To receive notification when app is in background, there are two tricks:

Tested and it works !

mrroccodev commented 7 years ago

The problem reported by @pmuraus was fixed by Firebase.

Update your app to support the latest version of Firebase and google Play "10.2.1". Try to do the same steps told by @pmuraus

And now it works. It receives. Because now the app behaved as it was killed by the system, even in background.

If you downgrade the library to "10.0.1" the problema appears again.

On the release of the Google Play Services description they told the fix on the Message Received lifecycle.

Google Play services updated to 10.2.1

"This release includes updates to provide compatibility with Android O Developer Preview 1. The most significant updates are internal changes to the Google Cloud Messaging (GCM) and Firebase Cloud Messaging (FCM) libraries and a change in the guaranteed lifecycle of GCM and FCM callbacks (such as onMessageReceived() and onTokenRefresh()) to 10 seconds. After 10 seconds, Android O considers such callbacks eligible for termination. To avoid having your process terminated before your callback is completed, perform only quick operations (like updating a local database) inside the callback, and use JobScheduler to schedule longer background processes (like syncing a database with a remote source)."

rasik1010 commented 6 years ago

@thomasdsouza i have same problem even after V10.2.1 what to do any idea? i am using bellow library: compile 'com.google.android.gms:play-services-gcm:10.2.1' compile 'com.google.android.gms:play-services-location:10.2.1' compile 'com.google.android.gms:play-services:10.2.1' compile 'com.google.firebase:firebase-messaging:10.2.1'

naeemg commented 6 years ago

I was facing same issue and I got this solution: You can get getIntent().getExtras() values in the very activity that you use to be launched at start. See in you manifest file which activity you have used to launch and in that activity in onCreate function you will get keys and values in getIntent().getExtras().

fierysolid commented 6 years ago

For those that come here looking for a solution to this. Check if the extras exist on the SplashActivity and put them into the MainActivity intent if they so.

public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(this, MainActivity.class);  
        if (getIntent().getExtras() != null) {
            intent.putExtras(getIntent().getExtras());
        }
        startActivity(intent);
        finish();
    }
}
abhishekgargx commented 5 years ago

Solved Problem of getting no custom data when app is in background and swiped from recents.

to get custom data (key, and values ) from firebase console when app is in background, for swiped from recent apps,

i used getIntent().getExtras() in my app launcher activity (Splash Activity) in onCreate method in following way

public class SplashActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (getIntent().getExtras() != null) {
             Bundle bundle = getIntent().getExtras();
                    if(bundle != null) { 
                       String  value = bundle.getString("your_key_name");
                         if( value != null){
                             // perform any condition you want to execute based on value
                             // i am starting google.com in web browser
                          switch(value){
                                case "google":{
                                  startActivity(new Intent(Intent.ACTION_VIEW,Uri.parse("https://www.google.com")));
                                  break;
                                 }
                                 default:{
                                    startActivity(new Intent(this, MainActivity.class) );
                                    break;
                                }
                              }
                        }else{
                           startActivity(new Intent(this, MainActivity.class) );
                         }
                    }
                    else{
                       startActivity(new Intent(this, MainActivity.class) );
                   }
        }
        else{
           startActivity(new Intent(this, MainActivity.class) );
       }
    }
}

i also put stopWithTask = false in firebase service in manifest

<!--Firebase Messaging service-->
        <service android:name=".services.fcm.FirebaseNotificationService" android:stopWithTask="false">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT"/>
            </intent-filter>
        </service>

Hope this will help others.

NidhinVasudev commented 5 years ago

@Abhishekgarg727 I checked the same in one plus 3. Unfortunately, it doesn't work. intent.extras is not working.

abhishekgargx commented 5 years ago

@NidhinVasudev have you tried on other devices other than op3?

NidhinVasudev commented 5 years ago

@Abhishekgarg727 : it is working Samsung devices earlier. I faced the issue in One plus 3. This device has an issue with many apps. Not only this one. But after the app kills when the app opens the FirebaseMessagingService is not working, this one works. Not working in the background.

abhishekgargx commented 5 years ago

@NidhinVasudev Not sure but it looks like oxygen OS handles , this different way, it may be possible oxygen OS , kills (force stop ) app when we swipe it from recent tasks , to save battery or to free up ram. I tried above code on samsung devices and stock android devices , plus custom rom devices like MIUI.

NidhinVasudev commented 5 years ago

@Abhishekgarg727 I will check this on more device and let you know.

abhishekgargx commented 5 years ago

@NidhinVasudev , that will be great, have you tried to put stopWithTask = false in manifest. also it will more easy to detect problem if you share your fcm service code snippet.

NidhinVasudev commented 5 years ago

@Abhishekgarg727 : already done that.

`class FireBaseMessagingService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
    Log.d("TAG", "From: ${remoteMessage?.from}")
    sendNotification(remoteMessage?.notification?.title!!, remoteMessage.notification?.body!!)
}

override fun onNewToken(token: String?) {
   // sendRegistrationToServer(token)
    Log.d("FireBaseMessaging", token)
}

private fun sendNotification(title: String, message: String) {
    val notificationManager =
        applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    val notificationSound = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
    val notificationIntent = Intent(applicationContext, HomeActivity::class.java)
    notificationIntent.flags = Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_SINGLE_TOP
    val intent = PendingIntent.getActivity(applicationContext, 0, notificationIntent, 0)

    //If on Oreo then notification required a notification channel.
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
        val channel = NotificationChannel(
            App.instance.getAppContext().getString(R.string.notification_default_message),
            App.instance.getAppContext().getString(R.string.notification_default_message),
            NotificationManager.IMPORTANCE_DEFAULT
        )
        channel.enableLights(true)
        channel.lightColor = Color.YELLOW
        notificationManager.createNotificationChannel(channel)
    }

    val notification = NotificationCompat.Builder(
        applicationContext,
        App.instance.getAppContext().getString(R.string.notification_default_message)
    )
        .setContentTitle(title)
        .setContentText(message)
        .setSmallIcon(R.mipmap.ic_launcher)
        .setContentIntent(intent)
        .setSound(notificationSound)

    notificationManager.notify(1, notification.build())
}}`
abhishekgargx commented 5 years ago

@NidhinVasudev , please also try get title and body also from

JSONObject json = new JSONObject(remoteMessage.getData()); String title = json.getString("your_key_name");

actually i found when, app is foreground , and you send data from firebase console , than title and body is received using

if(remoteMessage.getNotification() != null){
            title = remoteMessage.getNotification().getTitle();
            body =  remoteMessage.getNotification().getBody();
        }

but if app is background or removed from recent task than it is received in such way

JSONObject json = new JSONObject(remoteMessage.getData()); String title = json.getString("your_key_name");

here is my code snippet you can use,

https://gist.github.com/Abhishekgarg727/e8c5b48cfc621f9c53edbb4a12e452db

NidhinVasudev commented 5 years ago

@Abhishekgarg727 If i am sending data like "notification":{ "title":"Portugal vs. Denmark", "body":"great match Mannn!" } String value = bundle.getString("your_key_name"); what will be your_key_name

abhishekgargx commented 5 years ago

@NidhinVasudev key will be title and body , no matter you are sending data using notification but still when app is in background or removed from recents , it will be recieved in remoteMessage.getData() as JsonObject

rasik1010 commented 5 years ago

i had some problem related notification data.... while Background and kill app , so read this carefully About FCM Mesages

NidhinVasudev commented 5 years ago

@rasik1010 did you solve the issue

rasik1010 commented 5 years ago

@NidhinVasudev yes, just pass only DATA key from php side code and get that data keys in our service class and handle click event accordingly

NidhinVasudev commented 5 years ago

@rasik1010 : Did you chek on oneplus 3

abhishekgargx commented 5 years ago

@NidhinVasudev i update my gist for notification using Firebase in android , try to copy and paste in your code , and tell me how it works for you.

https://gist.github.com/Abhishekgarg727/e8c5b48cfc621f9c53edbb4a12e452db

KORuL commented 5 years ago

In Meizu M1 Note data-only push comes if app is foreground/background? but if app is killed onMessageRecieved is not call.

KORuL commented 5 years ago

error W/GCM: broadcast intent callback: result=CANCELLED forIntent { act=com.google.android.c2dm.intent.RECEIVE pkg=net.korul.hbbft (has extras) }

fredhuha commented 5 years ago
  • => in my case app launcher was Splashactivity

Thank you !!!!!!!!!!!!!!!!!!!!

abhishekgargx commented 5 years ago

I have read other threads and try to get on hands on these devices as well to test them as well, and found that these devices have custom layer of third-party services on top of Android, and have unpredictable behaviour for eg. when you remove app from recent this custom layer just not remove app from recent it also force stops all its services and app completely, hence making fcm service not working properly, however, I have seen apps like WhatsApp or facebook working fine even when they are closed, for that a developer from popular app company told me, their company contacted these Chinese companies and whitelist their app on their custom operating system. Now I do not where to apply for this whitelisting. I test device like Mi, oppo, one plus etc.

On Tue, 18 Jun, 2019, 5:38 AM Fredeinfo, notifications@github.com wrote:

  • => in my case app launcher was Splashactivity

Thank you !!!!!!!!!!!!!!!!!!!!

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/firebase/quickstart-android/issues/96?email_source=notifications&email_token=AHFX6AWEHHGB7DHWVWLV3PLP3ARPPA5CNFSM4CKSVEJ2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODX4ZD6Q#issuecomment-502895098, or mute the thread https://github.com/notifications/unsubscribe-auth/AHFX6AX4FACJ4FZD2QZGSV3P3ARPPANCNFSM4CKSVEJQ .

akinsete commented 5 years ago

Was on this same issue for hours but eventually figured it out. So take note that the intent extra is delivered to the launcher activity.

So if you have a SplashScreen as the launcher activity declared in you manifest file the notification payload will be delivered there.

So pass the intent data from that activity to the next activity where you need to use it.

public class SplashScreenActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        Intent intent = new Intent(this, MainActivity.class);  
        if (getIntent().getExtras() != null) {
           intent.putExtras(getIntent().getExtras());
        }
        startActivity(intent);
       finish();
    }
}

Note again The Notification payload will be delivered to the launcher activity declared here

    <activity
        android:name=".SplashScreenActivity"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
rifairizqy commented 4 years ago

i got a solution for that. just put below code in oncreate method of launcher activity.

if (bundle != null) {
        String value = bundle.getString("key");
        if (value != null) {

            startActivity(new Intent(MainActivity.this, secActivity.class));
        }
}

when app is in background or killed,FCM will not call onmessagerecieved method,but it will send data to system tray to display notification.so datapayload(sent from fcm console) will not be handled by onmessagerecieved method.when user click on notification,it will launch default activity of app and datapayload will be passed by intent .so making change in oncreate method of launcher activity(as above)we can get datapayload even when app is in background or killed.(ex key is sent by fcm console).when app is in foreground datapayload and will be handled by onmessagerecieved method of fcm service.

Correction on this. When your app is in the background, Android directs notification messages to the system tray. A user tap on the notification opens the app launcher by default. You have to get the extras in your launcher by using 'data' as a key and send it to your MainActivity.

String notification = getIntent().getStringExtra("data");
Intent intent = new Intent(Splash.this, HomeActivity.class);
if (notification != null) {
          intent.putExtra(YOUR_INTENT_KEY, notification);
}
startActivity(intent);
finish();