【问题标题】:onMessageSent of FirebaseMessagingService is not called accordinglyFirebaseMessagingService 的 onMessageSent 没有被相应地调用
【发布时间】:2017-07-20 09:48:32
【问题描述】:

我正在尝试使用FCM 发送UpStream Message,所以我按照谷歌上的教程进行操作。

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

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

请告诉我为什么在发送UpStream message 后没有显示onMessageSent 中的日志消息?以及如何解决它。

主要活动

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());
}

}

【问题讨论】:

  • 我引用的问题的答案和 cmets 表明,由于 Firebase 中的错误,onMessageSent() 不会被调用,除非 RemoteMessage 是使用 setTtl() 构建的。我没有在 11.0.2 中观察到这一点。请注意,在调用 onMessageSent() 之前有大约 20 分钟的延迟。这是explained in the docs为了优化网络使用,FCM 会批量响应 onMessageSent 和 onSendError,因此每条消息的 ack 可能不是立即的
  • 但是您提供的链接没有回答我的问题,因为在您提供的链接中我应该使用RemoteMessage 并且它没有在我的代码中定义..知道如何导入/使用@987654349 @类
  • 我更新了我的评论。如果您使用的是 11.0.2 版,则不需要 setTtl()。您是否要等待 20 分钟才能呼叫 onMessageSent()
  • 我正在使用 10.0.1.... 编译 'com.google.firebase:firebase-messaging:10.0.1' 编译 'com.google.android.gms:play-services:10.0. 1'

标签: android firebase firebase-realtime-database push-notification firebase-cloud-messaging


【解决方案1】:

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

但有必要更改默认的 Firebase 行为,先拦截 Intent 请求。


** 重要提示 **

这是 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,从intent 中删除所有"gcm.notification.%""gcm.n.%" extras,并将"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"));
            }
        }
    }

您可以查看my entire solution here

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-10-01
    • 1970-01-01
    • 2020-06-07
    • 1970-01-01
    • 2020-04-17
    • 1970-01-01
    • 2011-02-02
    • 1970-01-01
    相关资源
    最近更新 更多