Giới thiệu
Firebase Cloud Messaging (FCM) cho phép gửi thông báo (notification) và dữ liệu (data message) từ server đến thiết bị Android. Hướng dẫn này dùng Firebase Messaging SDK mới nhất.
Thiết lập Firebase
- Tạo project tại Firebase Console.
- Thêm Android app: điền package name, tải
google-services.jsonvàoapp/. - Thêm plugin & dependency:
// build.gradle (project)
dependencies {
classpath 'com.google.gms:google-services:4.4.0'
}
// build.gradle (app)
apply plugin: 'com.google.gms.google-services'
dependencies {
implementation platform('com.google.firebase:firebase-bom:32.7.0')
implementation 'com.google.firebase:firebase-messaging'
implementation 'com.google.firebase:firebase-analytics'
}
Triển khai Client
1. FirebaseMessagingService (Nhận message khi foreground)
package com.example.myapplication;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String CHANNEL_ID = "fcm_default_channel";
@Override
public void onNewToken(@NonNull String token) {
super.onNewToken(token);
// Gửi token lên server của bạn
sendTokenToServer(token);
}
@Override
public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
// 1. Data message (tùy chỉnh)
if (remoteMessage.getData().size() > 0) {
handleDataMessage(remoteMessage.getData());
}
// 2. Notification message (khi app foreground)
if (remoteMessage.getNotification() != null) {
sendNotification(remoteMessage.getNotification().getTitle(),
remoteMessage.getNotification().getBody());
}
}
private void handleDataMessage(java.util.Map<String, String> data) {
// Xử lý data payload tùy ý
}
private void sendNotification(String title, String body) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent,
PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
createNotificationChannel();
Uri soundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification) // Icon trắng trong suốt
.setContentTitle(title)
.setContentText(body)
.setAutoCancel(true)
.setSound(soundUri)
.setContentIntent(pendingIntent)
.setPriority(NotificationCompat.PRIORITY_HIGH);
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(0, builder.build());
}
private void createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID, "FCM Notifications", NotificationManager.IMPORTANCE_HIGH);
channel.setDescription("Kênh thông báo từ Firebase");
NotificationManager manager = getSystemService(NotificationManager.class);
manager.createNotificationChannel(channel);
}
}
private void sendTokenToServer(String token) {
// Gọi API server lưu token
}
}
2. Khai báo Service trong AndroidManifest.xml
<service
android:name=".MyFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<!-- Metadata cho notification mặc định (khi app background) -->
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_color"
android:resource="@color/colorAccent" />
<meta-data
android:name="com.google.firebase.messaging.default_notification_channel_id"
android:value="fcm_default_channel" />
3. MainActivity - Lấy token & xử lý click notification
package com.example.myapplication;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import com.google.firebase.messaging.FirebaseMessaging;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Lấy token đăng ký
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
String token = task.getResult();
// Log hoặc gửi server
}
});
// Xử lý data từ notification click (khi app killed)
if (getIntent().getExtras() != null) {
for (String key : getIntent().getExtras().keySet()) {
String value = getIntent().getExtras().getString(key);
// Xử lý data
}
}
}
}
Gửi tin nhắn từ Server (Backend)
Sử dụng Firebase Admin SDK (Node.js, Python, Java, Go) hoặc HTTP v1 API.
Ví dụ Node.js (Admin SDK)
const admin = require('firebase-admin');
admin.initializeApp();
// Gửi đến token cụ thể
const message = {
token: 'DEVICE_FCM_TOKEN',
notification: {
title: 'Tiêu đề',
body: 'Nội dung thông báo'
},
data: {
key1: 'value1',
key2: 'value2'
},
android: {
priority: 'high',
notification: {
channelId: 'fcm_default_channel',
icon: 'ic_notification'
}
}
};
admin.messaging().send(message)
.then(response => console.log('Sent:', response))
.catch(error => console.error('Error:', error));
Gửi đến Topic
// Client đăng ký topic
FirebaseMessaging.getInstance().subscribeToTopic("news");
// Server gửi đến topic
const message = {
topic: 'news',
notification: { title: 'Tin tức mới', body: 'Có bài viết mới!' }
};
Chạy ứng dụng
- Build & Run app trên thiết bị thật (emulator cần Google Play Services).
- Vào Firebase Console → Cloud Messaging → New Notification.
- Nhập tiêu đề, nội dung → chọn app → Send.
- Thiết bị nhận được notification (background) hoặc xử lý trong onMessageReceived (foreground).

Lưu ý quan trọng
- Icon notification: Phải là trắng trong suốt (alpha only), không thì hiện hình vuông trắng.
- Notification Channel: Bắt buộc từ Android 8.0 (API 26).
- Token thay đổi: Luôn xử lý
onNewToken(). - Doze mode: Ưu tiên
high priority+data messageđể đánh thức app. - Payload limit: 4KB cho notification, 4KB cho data.