带有新 Firebase 云消息系统的通知图标

Notification Icon with the new Firebase Cloud Messaging system

昨天 Google 在 Google I/O 上展示了基于新 Firebase 的新通知系统。我用 Github.

上的示例尝试了这个新的 FCM(Firebase Cloud Messaging)

通知的图标总是ic_launcher,尽管我声明了一个特定的drawable

为什么? 下面是处理消息的官方代码

public class AppFirebaseMessagingService extends FirebaseMessagingService {

    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // If the application is in the foreground handle both data and notification messages here.
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
        sendNotification(remoteMessage);
    }
    // [END receive_message]

    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param remoteMessage FCM RemoteMessage received.
     */
    private void sendNotification(RemoteMessage remoteMessage) {

        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);

        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

// this is a my insertion looking for a solution
        int icon = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? R.drawable.myicon: R.mipmap.myicon;
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(icon)
                .setContentTitle(remoteMessage.getFrom())
                .setContentText(remoteMessage.getNotification().getBody())
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

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

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

}

不幸的是,这是 SDK 9.0.0-9.6.1 中 Firebase 通知的限制。当应用程序在后台时,启动器图标用于从控制台发送的消息清单(具有必要的 Android 着色)。

但是,使用 SDK 9.8.0,您可以覆盖默认设置!在您的 AndroidManifest.xml 中,您可以设置以下字段来自定义图标和颜色:

<meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/notification_icon" />
<meta-data android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/google_blue" />

请注意,如果应用程序在前台(或发送数据消息),您完全可以使用自己的逻辑来自定义显示。如果从 HTTP/XMPP API 发送消息,您也可以随时自定义图标。

我正在从 FCM 控制台和通过 HTTP/JSON 触发我的通知......结果相同。

我可以处理标题、完整消息,但图标始终是默认的白色圆圈:

Notification screenshot

而不是代码中的自定义图标(setSmallIcon 或 setSmallIcon)或应用程序中的默认图标:

 Intent intent = new Intent(this, MainActivity.class);
    // use System.currentTimeMillis() to have a unique ID for the pending intent
    PendingIntent pIntent = PendingIntent.getActivity(this, (int) System.currentTimeMillis(), intent, 0);

    if (Build.VERSION.SDK_INT < 16) {
        Notification n  = new Notification.Builder(this)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentIntent(pIntent)
                .setAutoCancel(true).getNotification();
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //notificationManager.notify(0, n);
        notificationManager.notify(id, n);
    } else {
        Bitmap bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);

        Notification n  = new Notification.Builder(this)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setLargeIcon(bm)
                .setContentIntent(pIntent)
                .setAutoCancel(true).build();

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
        //notificationManager.notify(0, n);
        notificationManager.notify(id, n);
    }

atm 他们正在解决这个问题 https://github.com/firebase/quickstart-android/issues/4

when you send a notification from the Firebase console is uses your app icon by default, and the Android system will turn that icon solid white when in the notification bar.

If you are unhappy with that result you should implement FirebaseMessagingService and create the notifications manually when you receive a message. We are working on a way to improve this but for now that's the only way.

编辑:使用 SDK 9.8.0 添加到 AndroidManifest.xml

<meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/my_favorite_pic"/>

使用服务器实现向您的客户端发送消息并使用 data 类型的消息而不是 notification 消息类型。

这将帮助您获得 onMessageReceived 的回调,无论您的应用是在后台还是前台,然后您就可以生成自定义通知

只需将targetSdkVersion设置为19,通知图标就会变色。 然后等待 Firebase 修复此问题。

还有一种丑陋但有效的方法。反编译 FirebaseMessagingService.class 并修改它的行为。然后只需将 class 放入你的应用程序中的正确包中,dex 使用它而不是消息传递库本身中的 class 。它非常简单且有效。

有方法:

private void zzo(Intent intent) {
    Bundle bundle = intent.getExtras();
    bundle.remove("android.support.content.wakelockid");
    if (zza.zzac(bundle)) {  // true if msg is notification sent from FirebaseConsole
        if (!zza.zzdc((Context)this)) { // true if app is on foreground
            zza.zzer((Context)this).zzas(bundle); // create notification
            return;
        }
        // parse notification data to allow use it in onMessageReceived whe app is on foreground
        if (FirebaseMessagingService.zzav(bundle)) {
            zzb.zzo((Context)this, intent);
        }
    }
    this.onMessageReceived(new RemoteMessage(bundle));
}

此代码来自9.4.0版本,由于混淆,方法在不同版本中会有不同的名称。

我的解决方案与 ATom 的类似,但更容易实现。您不需要创建一个完全隐藏 FirebaseMessagingService 的 class,您只需覆盖接收 Intent 的方法(即 public,至少在 9.6.1 版本中是这样)并将信息获取到从临时演员中显示出来。 "hacky" 部分是方法名称确实被混淆了,每次您将 Firebase sdk 更新到新版本时都会更改,但是您可以通过使用 Android Studio 检查 FirebaseMessagingService 并查找来快速查找它对于将 Intent 作为唯一参数的 public 方法。在 9.6.1 版本中,它被称为 zzm。 这是我的服务的样子:

public class MyNotificationService extends FirebaseMessagingService {

    public void onMessageReceived(RemoteMessage remoteMessage) {
        // do nothing
    }

    @Override
    public void zzm(Intent intent) {
        Intent launchIntent = new Intent(this, SplashScreenActivity.class);
        launchIntent.setAction(Intent.ACTION_MAIN);
        launchIntent.addCategory(Intent.CATEGORY_LAUNCHER);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* R    equest code */, launchIntent,
                PendingIntent.FLAG_ONE_SHOT);
        Bitmap rawBitmap = BitmapFactory.decodeResource(getResources(),
                R.mipmap.ic_launcher);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_notification)
                .setLargeIcon(rawBitmap)
                .setContentTitle(intent.getStringExtra("gcm.notification.title"))
                .setContentText(intent.getStringExtra("gcm.notification.body"))
                .setAutoCancel(true)
                .setContentIntent(pendingIntent);

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

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

如果您的应用程序在后台,通知图标将设置为 onMessage Receive 方法,但如果您的应用程序在前台,通知图标将是您在清单中定义的图标

写这个

<meta-data 
         android:name="com.google.firebase.messaging.default_notification_icon"
         android:resource="@drawable/ic_notification" />

右下方<application.....>

以为我会添加一个答案,因为我的问题很简单但很难注意到。特别是在创建 com.google.firebase.messaging.default_notification_icon 时,我有一个 copy/pasted 现有的 meta-data 元素,它使用 android:value 标记来指定其值。这不适用于通知图标,一旦我将其更改为 android:resource 一切都按预期工作。