不会相应地调用FirebaseMessagingService的onMessageSent [英] onMessageSent of FirebaseMessagingService is not called accordingly

本文介绍了不会相应地调用FirebaseMessagingService的onMessageSent的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正尝试使用FCM发送UpStream Message,所以我按照google上的教程进行了操作.

如下面MainActivity中的代码所示,当单击按钮时,我发送Upstream message,然后在MyAndroidFirebaseMsgService中,我应该看到一条Log消息,如下所示 在MyAndroidFirebaseMsgService下.

但是发生的是,即使我多次按下按钮,也不会显示onMessageSentMyAndroidFirebaseMsgService中的Log消息. 仅当从FCM向应用程序发送downstream message时,才能显示onMessageSentMyAndroidFirebaseMsgServiceLog中的Log消息,在这种情况下, 将显示MyAndroidFirebaseMsgService中的内容.

请让我知道为什么发送UpStream message后为什么onMessageSent中的Log消息没有显示?以及如何解决.

主要活动:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mBtnSendUpstreamMsg = (Button) findViewById(R.id.btn_send_upstream_message);
    mBtnSendUpstreamMsg.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            FirebaseMessaging fm = FirebaseMessaging.getInstance();
            fm.send(new RemoteMessage.Builder("673xxxxx" + "@gcm.googleapis.com")
                    .setMessageId("2")
                    .addData("my_message", "Hello World")
                    .addData("my_action","SAY_HELLO")
                    .build());
        }
    });
}

MyAndroidFirebaseMsgService :

public class MyAndroidFirebaseMsgService extends FirebaseMessagingService {
private final static String TAG = MyAndroidFirebaseMsgService.class.getSimpleName();

@Override
public void onMessageSent(String s) {
    super.onMessageSent(s);
    Log.d(TAG, "onMessageSent: upstream message");
}

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Log.d(TAG, "onMessageReceived: downstream message");
    //Log data to Log Cat
    Log.d(TAG, "onMessageReceived->From: " + remoteMessage.getFrom());
    Log.d(TAG, "onMessageReceived->Notification Message Body: " + remoteMessage.getNotification().getBody());
    //create notification
    createNotification(remoteMessage.getNotification().getBody());
}

private void createNotification( String messageBody) {
    Intent intent = new Intent( this , ResultActivity.class );
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent resultIntent = PendingIntent.getActivity( this , 0, intent,
            PendingIntent.FLAG_ONE_SHOT);

    Uri notificationSoundURI = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder mNotificationBuilder = new NotificationCompat.Builder( this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("Android Tutorial Point FCM Tutorial")
            .setContentText(messageBody)
            .setAutoCancel( true )
            .setSound(notificationSoundURI)
            .setContentIntent(resultIntent);

    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0, mNotificationBuilder.build());
}

}

解决方案

是的,可以发送Firebase消息推送通知并使用onMessageReceived在所有应用程序生命周期中接收它. >

但是有必要更改默认的Firebase行为,先拦截意图请求.


** 重要提示 **

这是Firebase的愚蠢想法,方法是:当FCM消息以notification message格式出现时,取消开发人员的处理能力,但对于data message则不行.

这创建了一堆"解决方法";在许多解决方案中,使得分析学和其他所有东西都弄糟了.

如果我已经设计了此解决方案,那么我总是会用completion handle调用onMessageReceived方法.让开发人员决定该怎么做(免费的技巧,Firebase).

使用onMessageReceived是正确的方法.此方法是唯一带来RemoteMessage对象的方法,该对象具有您需要的所有信息.它是专为此设计的.您在正确的路径上.


** 如何做 **

在扩展了FirebaseMessagingService的Firebase类MyAndroidFirebaseMsgService中,重写公共方法handleIntent以在Firebase捕获意图请求之前对其进行拦截.

    @Override
    public void handleIntent(Intent intent){

        if(intent.hasExtra("google.message_id")){
            intent = handleFirebaseIntent(intent);
        }

        super.handleIntent(intent);
    }

之后,将notification message程序包转换为data message,从意图中删除所有"gcm.notification.%""gcm.n.%"附加功能,然后将"gcm.notification.title""gcm.notification.body""gcm.notification.image"元素转换为所需的内容:

    // Thank you Google, for that brilliant idea to treat notification message and notification data
    // differently on Android, depending of what app life cycle is. Because of that, all the developers
    // are doing "workarounds", using data to send push notifications, and that's not what you planned for.
    // Let the developers decide what to do on their apps and ALWAYS deliver the notification
    // to "onMessageReceived" method. Its simple, is freedom and its what the creative ones need.
    private Intent handleFirebaseIntent(Intent intent){

        //printIntentExtras(intent);

        String FCM_TITLE_KEY = "gcm.notification.title";
        String FCM_BODY_KEY = "gcm.notification.body";
        String FCM_IMAGE_KEY = "gcm.notification.image";

        String title = intent.getStringExtra(FCM_TITLE_KEY);
        String body = intent.getStringExtra(FCM_BODY_KEY);
        String image = intent.getStringExtra(FCM_IMAGE_KEY);

        // Remove the key extras that identifies an Notification type message
        Bundle bundle = intent.getExtras();
        if (bundle != null) {
            for (String key : bundle.keySet()) {
                if (key.startsWith("gcm.notification.") || key.startsWith("gcm.n."))
                {
                    intent.removeExtra(key);
                }
            }
        }

        Boolean isTitleEmpty = StringUtils.isNullOrEmpty(title);
        Boolean isBodyEmpty = StringUtils.isNullOrEmpty(body);
        Boolean isImageEmpty = StringUtils.isNullOrEmpty(image);

        // Notification title and body has prevalence over Data title and body
        if(
            !isTitleEmpty || !isBodyEmpty || !isImageEmpty
        ){

            // This is my personalized translation method, designed for my solution.
            // Probably you gonna need to do it by your own

            String contentData = intent.getStringExtra(Definitions.PUSH_NOTIFICATION_CONTENT);

            Map<String, Object> content;
            if(StringUtils.isNullOrEmpty(contentData)){

                content = new HashMap<String, Object>();

                content.put(Definitions.NOTIFICATION_ID, new Random().nextInt(65536) - 32768);
                content.put(Definitions.NOTIFICATION_CHANNEL_KEY, "basic_channel" );

            } else {
                content = JsonUtils.fromJson(new TypeToken<Map<String, Object>>(){}.getType(),contentData);
            }

            if(!isTitleEmpty) content.put(Definitions.NOTIFICATION_TITLE, title);
            if(!isBodyEmpty) content.put(Definitions.NOTIFICATION_BODY, body);
            if(!isImageEmpty){
                content.put(Definitions.NOTIFICATION_BIG_PICTURE, image);
                content.put(Definitions.NOTIFICATION_LAYOUT, NotificationLayout.BigPicture.toString());
            }

            contentData = JsonUtils.toJson(content);
            intent.putExtra(Definitions.PUSH_NOTIFICATION_CONTENT, contentData);
        }

        //printIntentExtras(intent);

        return intent;
    }

    private void printIntentExtras(Intent intent){
        Bundle bundle;
        if ((bundle = intent.getExtras()) != null) {
            for (String key : bundle.keySet()) {
                System.out.println(key + " : " + (bundle.get(key) != null ? bundle.get(key) : "NULL"));
            }
        }
    }

您可以在此处查看我的整个解决方案.

I am trying to use FCM to send UpStream Message, so I followed the tutorial on google and it works.

As shown in the code below in MainActivity, I send Upstream message when the button is clicked, then in MyAndroidFirebaseMsgService I should see a Log message as shown below in MyAndroidFirebaseMsgService.

But what happen is, the Log messages in MyAndroidFirebaseMsgService in onMessageSent in do not get displayed even I kept pressing the button several times. the Log message in MyAndroidFirebaseMsgService in onMessageSent can be displayed only if sent a downstream messagefrom FCM to the App, in this case, both the Logs in in MyAndroidFirebaseMsgService will be displayed.

Please let me know why the Log message in onMessageSent is not getting displayed once there is an UpStream message sent?and how to fix it.

Mainactivity:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mBtnSendUpstreamMsg = (Button) findViewById(R.id.btn_send_upstream_message);
    mBtnSendUpstreamMsg.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {

            FirebaseMessaging fm = FirebaseMessaging.getInstance();
            fm.send(new RemoteMessage.Builder("673xxxxx" + "@gcm.googleapis.com")
                    .setMessageId("2")
                    .addData("my_message", "Hello World")
                    .addData("my_action","SAY_HELLO")
                    .build());
        }
    });
}

MyAndroidFirebaseMsgService:

public class MyAndroidFirebaseMsgService extends FirebaseMessagingService {
private final static String TAG = MyAndroidFirebaseMsgService.class.getSimpleName();

@Override
public void onMessageSent(String s) {
    super.onMessageSent(s);
    Log.d(TAG, "onMessageSent: upstream message");
}

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    Log.d(TAG, "onMessageReceived: downstream message");
    //Log data to Log Cat
    Log.d(TAG, "onMessageReceived->From: " + remoteMessage.getFrom());
    Log.d(TAG, "onMessageReceived->Notification Message Body: " + remoteMessage.getNotification().getBody());
    //create notification
    createNotification(remoteMessage.getNotification().getBody());
}

private void createNotification( String messageBody) {
    Intent intent = new Intent( this , ResultActivity.class );
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent resultIntent = PendingIntent.getActivity( this , 0, intent,
            PendingIntent.FLAG_ONE_SHOT);

    Uri notificationSoundURI = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder mNotificationBuilder = new NotificationCompat.Builder( this)
            .setSmallIcon(R.mipmap.ic_launcher)
            .setContentTitle("Android Tutorial Point FCM Tutorial")
            .setContentText(messageBody)
            .setAutoCancel( true )
            .setSound(notificationSoundURI)
            .setContentIntent(resultIntent);

    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0, mNotificationBuilder.build());
}

}

解决方案

Yes, is possible to send a Firebase messaging push notification and receive it in all app life cycles using onMessageReceived.

But is necessary to change the default Firebase behaviour, intercepting the intent request before everything else.


** IMPORTANT NOTE **

This was a pretty stupid idea from Firebase by remove the developers processment capability when the FCM message arives with the notification message format, but not for data message.

This created a bunch of "workarounds" in many solutions, which made the analythics and everything else being messed up.

If I had designed this solution, I would always call the onMessageReceived method with a completion handle. Let the developer decide what to do (free tip for you, Firebase).

Use onMessageReceived is the correct way to do. This method is the only one who brings RemoteMessage object, that have every information what you need. It was designed for it. You are on correct path.


** HOW TO DO **

In your Firebase Class MyAndroidFirebaseMsgService, which extends FirebaseMessagingService, override the public method handleIntent to intercep the intent request before Firebase catch it.

    @Override
    public void handleIntent(Intent intent){

        if(intent.hasExtra("google.message_id")){
            intent = handleFirebaseIntent(intent);
        }

        super.handleIntent(intent);
    }

After, transform the notification message package into an data message, removing all "gcm.notification.%" and "gcm.n.%" extras from intent, and translating "gcm.notification.title", "gcm.notification.body" and "gcm.notification.image" elements into what you need:

    // Thank you Google, for that brilliant idea to treat notification message and notification data
    // differently on Android, depending of what app life cycle is. Because of that, all the developers
    // are doing "workarounds", using data to send push notifications, and that's not what you planned for.
    // Let the developers decide what to do on their apps and ALWAYS deliver the notification
    // to "onMessageReceived" method. Its simple, is freedom and its what the creative ones need.
    private Intent handleFirebaseIntent(Intent intent){

        //printIntentExtras(intent);

        String FCM_TITLE_KEY = "gcm.notification.title";
        String FCM_BODY_KEY = "gcm.notification.body";
        String FCM_IMAGE_KEY = "gcm.notification.image";

        String title = intent.getStringExtra(FCM_TITLE_KEY);
        String body = intent.getStringExtra(FCM_BODY_KEY);
        String image = intent.getStringExtra(FCM_IMAGE_KEY);

        // Remove the key extras that identifies an Notification type message
        Bundle bundle = intent.getExtras();
        if (bundle != null) {
            for (String key : bundle.keySet()) {
                if (key.startsWith("gcm.notification.") || key.startsWith("gcm.n."))
                {
                    intent.removeExtra(key);
                }
            }
        }

        Boolean isTitleEmpty = StringUtils.isNullOrEmpty(title);
        Boolean isBodyEmpty = StringUtils.isNullOrEmpty(body);
        Boolean isImageEmpty = StringUtils.isNullOrEmpty(image);

        // Notification title and body has prevalence over Data title and body
        if(
            !isTitleEmpty || !isBodyEmpty || !isImageEmpty
        ){

            // This is my personalized translation method, designed for my solution.
            // Probably you gonna need to do it by your own

            String contentData = intent.getStringExtra(Definitions.PUSH_NOTIFICATION_CONTENT);

            Map<String, Object> content;
            if(StringUtils.isNullOrEmpty(contentData)){

                content = new HashMap<String, Object>();

                content.put(Definitions.NOTIFICATION_ID, new Random().nextInt(65536) - 32768);
                content.put(Definitions.NOTIFICATION_CHANNEL_KEY, "basic_channel" );

            } else {
                content = JsonUtils.fromJson(new TypeToken<Map<String, Object>>(){}.getType(),contentData);
            }

            if(!isTitleEmpty) content.put(Definitions.NOTIFICATION_TITLE, title);
            if(!isBodyEmpty) content.put(Definitions.NOTIFICATION_BODY, body);
            if(!isImageEmpty){
                content.put(Definitions.NOTIFICATION_BIG_PICTURE, image);
                content.put(Definitions.NOTIFICATION_LAYOUT, NotificationLayout.BigPicture.toString());
            }

            contentData = JsonUtils.toJson(content);
            intent.putExtra(Definitions.PUSH_NOTIFICATION_CONTENT, contentData);
        }

        //printIntentExtras(intent);

        return intent;
    }

    private void printIntentExtras(Intent intent){
        Bundle bundle;
        if ((bundle = intent.getExtras()) != null) {
            for (String key : bundle.keySet()) {
                System.out.println(key + " : " + (bundle.get(key) != null ? bundle.get(key) : "NULL"));
            }
        }
    }

You can check my entire solution here.

这篇关于不会相应地调用FirebaseMessagingService的onMessageSent的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆