[英]How to handle notifications with FCM when app is in either foreground or background
我用 firebase 來構建我的項目。
它還將使用 FCM(firebase 雲消息)。
但有一個問題。
當應用程序處於后台時,我無法處理 FCM(創建我的自定義通知)。
官網教程是這么說的
情況 1:應用程序前台 -> 覆蓋“onMessageReceived()”以創建您的自定義通知。
案例二:App后台->系統會直接創建通知。 我們不需要也不能做任何事情。 因為在這種情況下它不會觸發“onMessageReceived()”。
但是,如果當應用程序處於后台時我無能為力,我將無法創建自定義通知。 (例如用戶點擊通知后會彈出一個window顯示詳細信息。)
那么,當應用程序處於后台時,我如何使用 FCM 處理通知?
有一個壞消息。
Google 更改了“com.google.firebase:firebase-messaging:11.6.0”版本中的 Firebase 源代碼。
handelIntent 現在是“public final void 方法”。 這意味着我們不能覆蓋它。
如果要使用該解決方案,請將版本更改為“com.google.firebase:firebase-messaging:11.4.2”
試試我的方法。 它可以完美地在項目構建版本為Android 6.0以上(api級別23)上運行,我已經嘗試過了。
有比官方網站教程更好的方法
官網說,當應用程序在后台時,系統會創建通知。 所以你不能通過覆蓋“onMessageReceived()”來處理它。 因為“onMessageReceived()”僅在應用程序處於前台時觸發。
但事實並非如此。 實際上通知(當應用程序在后台時)是由 Firebase 庫創建的。
在我跟蹤了 firebase 庫代碼之后。 我找到了更好的方法。
步驟 1. 覆蓋 FirebaseMessagingService 中的“handleIntent()”而不是“onMessageReceived()”
為什么:
因為該方法將觸發應用程序在前台或后台。 因此,我們可以在兩種情況下處理 FCM 消息並創建自定義通知。
@Override
public void handleIntent(Intent intent) {
Log.d( "FCM", "handleIntent ");
}
步驟 2. 解析來自 FCM 的消息
如何:
如果您不知道您設置的消息格式。 打印它並嘗試解析它。
這是基本插圖
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
Log.d("FCM", "Key: " + key + " Value: " + value);
}
}
步驟 2. 刪除應用在后台時 Firebase 庫創建的通知
為什么:
我們可以創建自定義通知。 但是 Firebase 庫創建的通知仍然存在(實際上它是由 ""super.handleIntent(intent)"" 創建的。下面有詳細說明。)。 然后我們會有兩個通知。 這就比較奇怪了。 所以我們必須刪除 Firebase 庫創建的通知
如何(項目構建級別為 Android 6.0 以上):
識別我們要刪除的通知並獲取信息。 並使用“notificationManager.cancel()”來刪除它們。
private void removeFirebaseOrigianlNotificaitons() {
//check notificationManager is available
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null )
return;
//check api level for getActiveNotifications()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//if your Build version is less than android 6.0
//we can remove all notifications instead.
//notificationManager.cancelAll();
return;
}
//check there are notifications
StatusBarNotification[] activeNotifications =
notificationManager.getActiveNotifications();
if (activeNotifications == null)
return;
//remove all notification created by library(super.handleIntent(intent))
for (StatusBarNotification tmp : activeNotifications) {
Log.d("FCM StatusBarNotification",
"StatusBarNotification tag/id: " + tmp.getTag() + " / " + tmp.getId());
String tag = tmp.getTag();
int id = tmp.getId();
//trace the library source code, follow the rule to remove it.
if (tag != null && tag.contains("FCM-Notification"))
notificationManager.cancel(tag, id);
}
}
我的整個示例代碼:
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static int notificationCount=0;
@Override
public void handleIntent(Intent intent) {
//add a log, and you'll see the method will be triggered all the time (both foreground and background).
Log.d( "FCM", "handleIntent");
//if you don't know the format of your FCM message,
//just print it out, and you'll know how to parse it
Bundle bundle = intent.getExtras();
if (bundle != null) {
for (String key : bundle.keySet()) {
Object value = bundle.get(key);
Log.d("FCM", "Key: " + key + " Value: " + value);
}
}
//the background notification is created by super method
//but you can't remove the super method.
//the super method do other things, not just creating the notification
super.handleIntent(intent);
//remove the Notificaitons
removeFirebaseOrigianlNotificaitons();
if (bundle ==null)
return;
//pares the message
CloudMsg cloudMsg = parseCloudMsg(bundle);
//if you want take the data to Activity, set it
Bundle myBundle = new Bundle();
myBundle.putSerializable(TYPE_FCM_PLATFORM, cloudMsg);
Intent myIntent = new Intent(this, NotificationActivity.class);
myIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
myIntent.putExtras(myBundle);
PendingIntent pendingIntent = PendingIntent.getActivity(this, notificationCount, myIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//set the Notification
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.icon)
.setContentTitle(cloudMsg.getTitle())
.setContentText(cloudMsg.getMessage())
.setAutoCancel(true)
.setContentIntent(pendingIntent);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(notificationCount++, notificationBuilder.build());
}
/**
* parse the message which is from FCM
* @param bundle
*/
private CloudMsg parseCloudMsg(Bundle bundle) {
String title = null, msg=null;
//if the message is sent from Firebase platform, the key will be that
msg = (String) bundle.get("gcm.notification.body");
if(bundle.containsKey("gcm.notification.title"))
title = (String) bundle.get("gcm.notification.title");
//parse your custom message
String testValue=null;
testValue = (String) bundle.get("testKey");
//package them into a object(CloudMsg is your own structure), it is easy to send to Activity.
CloudMsg cloudMsg = new CloudMsg(title, msg, testValue);
return cloudMsg;
}
/**
* remove the notification created by "super.handleIntent(intent)"
*/
private void removeFirebaseOrigianlNotificaitons() {
//check notificationManager is available
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (notificationManager == null )
return;
//check api level for getActiveNotifications()
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
//if your Build version is less than android 6.0
//we can remove all notifications instead.
//notificationManager.cancelAll();
return;
}
//check there are notifications
StatusBarNotification[] activeNotifications =
notificationManager.getActiveNotifications();
if (activeNotifications == null)
return;
//remove all notification created by library(super.handleIntent(intent))
for (StatusBarNotification tmp : activeNotifications) {
Log.d("FCM StatusBarNotification",
"tag/id: " + tmp.getTag() + " / " + tmp.getId());
String tag = tmp.getTag();
int id = tmp.getId();
//trace the library source code, follow the rule to remove it.
if (tag != null && tag.contains("FCM-Notification"))
notificationManager.cancel(tag, id);
}
}
}
但是,如果當應用程序處於后台時我什么都不做,我就無法創建我的自定義通知。 (例如,當用戶點擊通知后,它會彈出一個窗口顯示詳細信息。)
那么當應用程序在后台時如何使用 FCM 處理通知?
首先,您需要創建發送到 fcm 服務器的正確消息負載。 示例:
{
"to": "topic_name",
"priority": "high",
"data": {
"field1": "field1 value"
"field2": "field2 value"
}
"notification" : {
"body" : "Lorem ipsum",
"title" : "sampke title"
"click_action": "SHOW_DETAILS"
}
}
data
負載是您希望在用戶單擊通知后顯示為消息詳細信息的實際數據, notification
負載表示生成的通知的外觀(可以設置更多屬性),您不需要自己構建通知,您只需需要在這里設置它的屬性。
要在用戶點擊通知后顯示您的活動,您需要設置與click_action
對應的意圖過濾器:
<intent-filter>
<action android:name="SHOW_DETAILS"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
因此,當用戶點擊通知時,將自動啟動具有上述意圖過濾器的活動。 最后一步是在點擊通知后啟動活動時檢索數據。 這很容易。 自定義數據通過包傳遞給活動。 在您的活動的onCreate
方法中執行以下操作:
Bundle bundle = getIntent().getExtras();
if(bundle.getString("action").equals("SHOW_DETAILS")) /*This indicates activity is launched from notification, not directly*/
{
//Data retrieved from notification payload send
String filed1 = bundle.getString("field1");
String filed2 = bundle.getString("field2");
}
如果應用程序未運行或在后台,則上述所有內容均有效。 如果您的應用程序處於前台,則不會創建通知。 相反,您將收到onMessageReceived()
事件,以便您可以在那里處理相同的數據(我想您知道如何)。
參考:
https://firebase.google.com/docs/cloud-messaging/http-server-ref https://github.com/firebase/quickstart-android/tree/master/messaging
您需要使用 FCM 數據消息才能在 android 應用程序中創建自定義通知。即使您的應用程序在后台,也會調用onMessageReceived
,因此您可以處理數據並顯示自定義通知。
https://firebase.google.com/docs/cloud-messaging/android/receive
必須從服務器發送的數據消息格式:
{"message":{
"token":"Your Device Token",
"data":{
"Nick" : "Mario",
"body" : "great match!",
"Room" : "PortugalVSDenmark"
}
}
}
如果您的應用程序被handleIntent()
, FCM將不會發送后台通知,正如您在關於handleIntent()
解決方案的回答中所述,它可能適用於某些設備和某些舊版本的FCM ,如果您使用@override
方法firebase 的官方文檔中沒有描述,您可能會在這里遇到一些問題,使用它的風險自負!
解決辦法是什么?
您需要在FCM旁邊使用自己的推送通知服務,例如Telegram 。
或者在GCM旁邊使用SyncAdapter ,比如Gmail 。
因此,如果您需要它像那些應用程序一樣成功運行,則必須使用自己的 hack 。
當您的應用終止運行或后台運行時, 永遠不會觸發onMessageReceive
你該怎么辦
推送時,僅在以下示例中添加數據項; 你可以用郵遞員
首先需要以下網址: https : //fcm.googleapis.com/fcm/send發送時,您可以選擇POST
在添加標題后,應這樣:
內容類型:application / json
授權:key =“您的服務器密鑰”
{
"to": "/topics/yourTopics",
"data": {
"title": "BlaBla",
"body":"BlaBla"
}
}
處理;
class PushService : FirebaseMessagingService() {
override fun onMessageReceived(remoteMessage: RemoteMessage?) {
for (i in remoteMessage!!.data.keys) {
//Your maps here you can do something..
}
val contentIntent = PendingIntent.getActivity(this,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
val uri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION)
// Your notification set here!!
val b = NotificationCompat.Builder(this, "1")
val n = b.setTicker(remoteMessage!!.data["title"])
.setWhen(0)
.setAutoCancel(true)
.setContentTitle(remoteMessage.data["title"])
.setContentText(remoteMessage.data["body"])
.setShowWhen(true)
.setContentIntent(contentIntent)
.setSound(uri)
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
.setStyle(NotificationCompat.BigTextStyle().bigText(remoteMessage.data["body"]))
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
b.setSmallIcon(R.drawable.ic_push_notification_transparent)
b.color = ContextCompat.getColor(this, R.color.colorAccent)
} else {
b.setSmallIcon(R.mipmap.ic_launcher)
}
val notificationManager = this.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel("1",
"ic_notification",
NotificationManager.IMPORTANCE_DEFAULT)
notificationManager.createNotificationChannel(channel)
}
if (notificationManager != null) {
notificationManager.cancel(1)
notificationManager.notify(1, n.build())
}
}
}
公共 class FirebaseMessageReceiver 擴展 FirebaseMessagingService {
private static final String TAG = "main";
String s12;
String channel_id = "general";
Intent intent;
@Override
public void onNewToken(@NonNull String token)
{
Log.d(TAG, "Refreshed token: " + token);
}
@Override
public void
onMessageReceived(RemoteMessage remoteMessage) {
s12=remoteMessage.getNotification().getClickAction();
Log.d("tttt",(remoteMessage.getData().toString()));
Log.d("ttttttt",(remoteMessage.getNotification().toString()));
if (remoteMessage.getNotification() != null) {
showNotification(remoteMessage.getNotification().getTitle(), remoteMessage.getNotification().getBody());
}
//
}
public void handleIntent(Intent intent)
{
try
{
if (intent.getExtras() != null)
{
RemoteMessage.Builder builder = new RemoteMessage.Builder("FirebaseMessageReceiver");
for (String key : intent.getExtras().keySet())
{
builder.addData(key, intent.getExtras().get(key).toString());
}
onMessageReceived(builder.build());
}
else
{
super.handleIntent(intent);
}
}
catch (Exception e)
{
super.handleIntent(intent);
}
}
private RemoteViews getCustomDesign(String title, String message) {
RemoteViews remoteViews = new RemoteViews(getApplicationContext().getPackageName(), R.layout.notification);
remoteViews.setTextViewText(R.id.title111, title);
remoteViews.setTextViewText(R.id.message111, message);
remoteViews.setImageViewResource(R.id.icon111, R.drawable.favicon);
return remoteViews;
}
// Method to display the notifications
public void showNotification(String title, String message) {
intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(s12));
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent notifyIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
Log.d("notifyy",notifyIntent.toString());
NotificationCompat.Builder builder
= new NotificationCompat
.Builder(getApplicationContext(),
channel_id)
.setSmallIcon(R.drawable.favicon)
.setAutoCancel(true)
.setVibrate(new long[]{1000, 1000, 1000, 1000, 1000})
.setOnlyAlertOnce(true)
.setContentIntent(notifyIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
builder = builder.setContent(getCustomDesign(title, message));
}
else {
builder = builder.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.drawable.favicon);
}
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// Check if the Android Version is greater than Oreo
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel notificationChannel = new NotificationChannel(channel_id, "web_app",
NotificationManager.IMPORTANCE_HIGH);
notificationManager.createNotificationChannel(
notificationChannel);
}
notificationManager.notify(0, builder.build());
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.