【问题标题】:How do payloads and notification work in firestore messaging有效载荷和通知如何在 Firestore 消息传递中工作
【发布时间】:2018-11-10 11:28:06
【问题描述】:

我正在使用 Firestore 制作消息应用程序,我想在发送新消息时发送通知。为此,我正在使用 FCM。

现在我要声明 2 个有效负载:一个通知有效负载和一个数据有效负载。当用户发送消息时,如果应用程序在后台,收件人会收到 2 条通知,如果应用程序在前台,则收到一条通知。如果我删除通知负载,无论应用程序是在前台还是后台,收件人都会收到一条通知。

我想要发生的是,当应用程序处于后台或前台时,用户只会收到一个通知,而如果应用程序处于与发件人的聊天活动中,则不会收到通知。我的理解是,当我声明通知和数据有效负载时,这应该是默认行为。

在后台应用中处理通知消息

当您的应用处于后台时,Android 会将通知消息定向到系统托盘。默认情况下,用户点击通知会打开应用启动器。

这包括同时包含通知和数据负载的消息(以及从通知控制台发送的所有消息)。在这些情况下,通知会传送到设备的系统托盘,而数据负载会在启动器 Activity 的 Intent 的附加部分中传送。

有人可以帮忙吗?我已阅读 thisthis 但它似乎对我不起作用,所以也许还有其他我不知道的东西这里是我的清单条目

    <service
        android:name=".MyFirebaseMessagingService">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT"/>
        </intent-filter>
    </service>
    <service
        android:name=".MyFirebaseInstanceIDService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT"/>
        </intent-filter>
    </service>

这是我的云功能,包含通知和数据负载

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();

exports.notifyNewMessage = 
functions.firestore
.document('users/{ID}/contacts/{contactID}/messages/{messageID}')
.onCreate((docSnapshot , context) => {
const message = docSnapshot.data()
const recipientId = message['recipientId']
const senderId = message['sender']
const senderName = message['senderName']

return admin.firestore().doc('users/' + recipientId).get().then(userDoc =>{
    const registrationTokens = userDoc.get('registeredToken')
    const notificationBody = (message['data_type'] === "TEXT") ? 
    message['message'] : "You received a new image message."
    const payload = {
        notification : {
            title : senderName + " sent you a message.",
            body : notificationBody
        },
        data : {
            TITLE : senderName + " sent you a message.",
            BODY : notificationBody,
            USER_NAME : senderName,
            USER_NUMBER : message['sender'],
            CLICK_ACTION : "MessageListActivity",
            MESSAGE : message['message'],
        }
    }

    return 
    admin.messaging().sendToDevice(registrationTokens,payload).then(response 
     => {


    })
  })
})

这是我的消息服务,我现在发送非常基本的通知

public class MyFirebaseMessagingService extends FirebaseMessagingService {


private static final int NOTIFICATION_MAX_CHARACTERS = 30;

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Map<String, String> data = remoteMessage.getData();
        if (data.size() > 0) {
            sendNotification(data);
        }
    }
    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {

    }
}

private void sendNotification(Map<String, String> data) {

    String author = data.get("USER_NAME");
    String title = data.get("TITLE");
    String body = data.get("BODY");
    String id = data.get("USER_NUMBER");
    String message = data.get("MESSAGE");

    Intent intent = new Intent(this, MessageListActivity.class);
    intent.putExtra(Constants.USER_NAME, author);
    intent.putExtra(Constants.USER_NUMBER, id);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    // Create the pending intent to launch the activity
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
            PendingIntent.FLAG_ONE_SHOT);
    if (message.length() > NOTIFICATION_MAX_CHARACTERS) {
        message = message.substring(0, NOTIFICATION_MAX_CHARACTERS) + 
        "\u2026";
    }

    Uri defaultSoundUri = 
    RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder = new 
    NotificationCompat.Builder(this)
            .setSmallIcon(R.drawable.ic_email_black_24dp)

   .setContentTitle(String.format(getString(R.string.notification_message), 
   author))
            .setContentText(message)
            .setAutoCancel(true)
            .setSound(defaultSoundUri)
            .setContentIntent(pendingIntent);

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

    notificationManager.notify(0 /* ID of notification */, 
    notificationBuilder.build());
  }
}

【问题讨论】:

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


【解决方案1】:

如果您想避免显示通知,您应该在 FirebaseMessagingService 上控制它。您的情况看起来是您的应用程序在特定活动中打开。

如果您想在应用不在前台时避免通知,那么您应该检查服务中的 ActivityManager。您可以使用此方法:

public boolean isForeground(String myPackage) {
    ActivityManager manager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
    List<ActivityManager.RunningTaskInfo> runningTaskInfo = manager.getRunningTasks(1); 
    ComponentName componentInfo = runningTaskInfo.get(0).topActivity;
    return componentInfo.getPackageName().equals(myPackage);
}

还将&lt;uses-permission android:name="android.permission. REAL_GET_TASKS" /&gt; 添加到您的清单中。

如果您只想在特定活动中避免它。然后,您需要找出一种方法来跟踪该活动的生命周期。使用SharedPreferences,一个static 变量,您可以在这个post 中看到多个示例。

【讨论】:

    【解决方案2】:

    鉴于您的用例,我认为您需要向 FCM 消息服务传达您的聊天活动状态,并根据该状态决定是否显示通知。然后您可以只发送带有有效负载的数据部分。

    您可以尝试在 FCM 服务中设置广播接收器,并从聊天活动生命周期事件中广播意图,以通知服务是否应生成通知。

    在您的消息服务中:

    private boolean chatActive = false;
    private String senderID;
    
    @Override
    public void onCreate() {
        super.onCreate();
        LocalBroadcastManager.getInstance(this).registerReceiver(chatReceiver,new IntentFilter("com.mypackage.CHAT_LIFECYCLE_EVENT"));
    }
    
    @Override
    public void onDestroy() {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(chatReceiver);
        super.onDestroy();
    }
    
    
    private BroadcastReceiver chatReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            chatActive = intent.getBooleanExtra("active",false);
            senderID = intent.getStringExtra("sender");
        }
    };
    
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        //Check for whether chat is active with sender
        if(!(chatActive && remoteMessage.getData().get("USER_NAME").equals(senderID)){
        //sendNotification
        }
    }
    

    然后在您的聊天活动中,您可以在生命周期事件期间发送广播。

    @Override
    protected void onPause() {
        super.onPause();
        Intent startNotificationIntent = new Intent();
        startNotificationIntent.setAction("com.mypackage.CHAT_LIFECYCLE_EVENT");
        startNotificationIntent.putExtra("active",false);
        LocalBroadcastManager.getInstance(this).sendBroadcast(startNotificationIntent);
    }
    
    @Override
    protected void onResume() {
        super.onResume();
        Intent stopNotificationIntent = new Intent();
        stopNotificationIntent.setAction("com.mypackage.CHAT_LIFECYCLE_EVENT");
        stopNotificationIntent.putExtra("active",true);
        stopNotificationIntent.putExtra("sender",someSenderVariable);
        LocalBroadcastManager.getInstance(this).sendBroadcast(stopNotificationIntent);
    }
    

    【讨论】:

    • 哇,好吧,我已经让自己只使用数据有效负载并拒绝基于聊天活动的通知,但不知道我将如何检查谁在使用它,这将非常有效,谢谢非常
    • 经过深思熟虑,我担心这不会按预期工作。如果在聊天活动处于活动状态时创建 FCM 服务,它将不会收到广播。如果您发现这是真的,您可以尝试使用静态变量来代替,就像在弗朗西斯科的回答中那样。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-07
    • 1970-01-01
    • 1970-01-01
    • 2021-05-26
    • 1970-01-01
    • 1970-01-01
    • 2021-02-19
    相关资源
    最近更新 更多