Firebase Cloud Messaging (FCM)

1. Tổng quan về Firebase Cloud Messaging

Firebase Cloud Messaging (FCM) là dịch vụ nhắn tin đám mây do Google cung cấp, cho phép ứng dụng gửi và nhận thông báo hoặc dữ liệu từ máy chủ đến các thiết bị như điện thoại Android, iPhone và trình duyệt web. FCM là một phần của hệ sinh thái Firebase, thường được sử dụng để xây dựng chức năng thông báo đẩy (Push Notification) trong các ứng dụng di động và website.

Trong quá trình phát triển phần mềm, việc duy trì kết nối liên tục giữa máy chủ và mọi thiết bị người dùng là một nhiệm vụ phức tạp. Nếu tự xây dựng hệ thống thông báo, lập trình viên có thể phải xử lý kết nối mạng, quản lý thiết bị, định tuyến thông điệp, xử lý trạng thái trực tuyến và tối ưu việc gửi thông báo trên nhiều nền tảng. FCM giúp giảm bớt phần lớn công việc này bằng cách cung cấp hạ tầng gửi thông điệp do Google quản lý.

FCM hỗ trợ hai nhóm thông điệp chính:

  • Notification message: Thông điệp chứa nội dung thông báo, thường được dùng để hiển thị tiêu đề, nội dung và thông tin bổ sung cho người dùng.

  • Data message: Thông điệp chứa dữ liệu để ứng dụng tự xử lý, chẳng hạn như mã đơn hàng, loại sự kiện hoặc thông tin cần cập nhật.

Tùy theo nền tảng và trạng thái của ứng dụng, thông điệp có thể được hệ điều hành hiển thị thành thông báo hoặc được ứng dụng tiếp nhận để thực hiện một tác vụ phù hợp. FCM hỗ trợ Android, iOS và nền tảng Web, giúp lập trình viên xây dựng hệ thống thông báo đa nền tảng mà không cần thiết kế một cơ chế truyền thông điệp riêng cho từng thiết bị.

FCM đặc biệt hữu ích trong các hệ thống thương mại điện tử, mạng xã hội, ứng dụng nhắn tin, ứng dụng học tập, hệ thống quản lý công việc và các nền tảng cần cập nhật trạng thái theo sự kiện.

2. Vai trò của FCM trong kiến trúc ứng dụng

FCM đóng vai trò trung gian trong quá trình truyền thông điệp từ máy chủ đến thiết bị người dùng. Thay vì để máy chủ ứng dụng tự duy trì kết nối với hàng nghìn hoặc hàng triệu thiết bị, hệ thống có thể gửi yêu cầu đến FCM để dịch vụ này thực hiện việc định tuyến thông điệp.

Integrating Push Notifications into Angular Applications with Firebase Cloud Messaging - ClearPeaks

Trong một kiến trúc điển hình, hệ thống gồm ba thành phần chính:

Ứng dụng phía người dùng (Client Application)

Đây là ứng dụng chạy trên thiết bị Android, iOS hoặc trình duyệt web. Ứng dụng tích hợp Firebase Messaging SDK để đăng ký nhận thông điệp và lấy mã định danh đăng ký tương ứng với thiết bị hoặc phiên cài đặt ứng dụng.

Máy chủ ứng dụng (Application Server)

Máy chủ chứa nghiệp vụ chính của hệ thống, chẳng hạn như xử lý đơn hàng, quản lý tài khoản, cập nhật trạng thái giao hàng hoặc tiếp nhận tin nhắn. Khi có sự kiện cần thông báo, máy chủ sẽ tạo thông điệp và gửi yêu cầu đến FCM thông qua Firebase Admin SDK hoặc FCM HTTP v1 API.

Firebase Cloud Messaging

FCM tiếp nhận yêu cầu gửi thông điệp, xác định đích nhận dựa trên token, topic hoặc điều kiện gửi được hỗ trợ, sau đó định tuyến thông điệp đến nền tảng tương ứng. Quá trình phân phối phụ thuộc vào trạng thái thiết bị, kết nối mạng, cấu hình nền tảng và các chính sách của hệ điều hành.

Ví dụ, trong một website bán hàng, khi khách hàng đặt mua sản phẩm thành công, máy chủ có thể phát sinh sự kiện order_created. Hệ thống sử dụng sự kiện này để gửi thông báo đến thiết bị của khách hàng. Nội dung thông báo có thể là “Đơn hàng của bạn đã được tiếp nhận”.

Cách thiết kế này giúp tách biệt nghiệp vụ của ứng dụng khỏi cơ chế truyền thông báo. Máy chủ chỉ cần xác định ai cần nhận thông điệp, nội dung cần gửi và thời điểm gửi; phần phân phối thông điệp được giao cho FCM.

3. Cơ chế hoạt động của Firebase Cloud Messaging

FCM hoạt động dựa trên quy trình đăng ký thiết bị, tạo thông điệp, gửi yêu cầu và phân phối đến đích nhận. Mặc dù các bước cụ thể khác nhau giữa Android, iOS và Web, kiến trúc tổng quát có thể mô tả như sau:

1. Ứng dụng đăng ký FCM

Ứng dụng khởi tạo Firebase Messaging và nhận registration token.

2. Máy chủ lưu token

Token được liên kết với người dùng hoặc phiên cài đặt trong hệ thống.

3. Máy chủ tạo thông điệp

Nghiệp vụ phát sinh sự kiện và máy chủ gọi FCM API.

4. FCM định tuyến thông điệp

Thông điệp được chuyển đến đích nhận tương ứng.

5. Thiết bị xử lý thông báo

Hệ điều hành hiển thị thông báo hoặc ứng dụng xử lý dữ liệu theo trạng thái thực tế.

3.1. Khởi tạo Firebase trong ứng dụng

Trước tiên, lập trình viên tạo một dự án trên Firebase Console, đăng ký ứng dụng tương ứng với nền tảng và cấu hình Firebase SDK.

Đối với Android, cấu hình thường bao gồm tệp google-services.json. Đối với Apple, ứng dụng sử dụng cấu hình Firebase phù hợp và cần thiết lập các khả năng liên quan đến thông báo đẩy. Đối với Web, ứng dụng cấu hình Firebase Web SDK, quyền thông báo và service worker theo yêu cầu.

Sau khi khởi tạo Firebase, ứng dụng có thể yêu cầu quyền nhận thông báo và lấy FCM registration token. Token này được sử dụng để xác định đích nhận thông điệp trong các yêu cầu gửi tương ứng.

3.2. Đăng ký và quản lý token

FCM registration token là mã định danh được sử dụng để gửi thông điệp đến một phiên cài đặt ứng dụng hoặc đích nhận tương ứng. Token không nên được xem là mã định danh người dùng cố định vĩnh viễn.

Token có thể thay đổi trong quá trình sử dụng ứng dụng. Vì vậy, ứng dụng cần theo dõi sự kiện cập nhật token và gửi token mới lên máy chủ để đồng bộ dữ liệu.

Ví dụ, một tài khoản có thể đăng nhập trên điện thoại và máy tính bảng. Mỗi phiên cài đặt có thể có token riêng. Nếu muốn gửi thông báo đến tất cả thiết bị của tài khoản đó, hệ thống cần lưu và quản lý danh sách token tương ứng.

Trong thực tế, bảng lưu token có thể gồm các trường:

Trường dữ liệu Ý nghĩa
id Mã bản ghi token
user_id Người dùng sở hữu thiết bị
fcm_token Token dùng để gửi thông điệp
platform Android, iOS hoặc Web
device_name Tên thiết bị nếu có
created_at Thời điểm tạo bản ghi
updated_at Thời điểm cập nhật token gần nhất
last_seen_at Thời điểm thiết bị hoạt động gần nhất

Khi đăng xuất, người dùng có thể cần hủy liên kết token khỏi tài khoản hiện tại. Máy chủ cũng nên loại bỏ những token đã hết hiệu lực khi FCM trả về lỗi cho biết đích nhận không còn hợp lệ.

3.3. Tạo và gửi thông điệp

Khi nghiệp vụ phát sinh một sự kiện cần thông báo, máy chủ tạo payload chứa nội dung và thông tin đích nhận. Sau đó, máy chủ gửi yêu cầu thông qua FCM HTTP v1 API hoặc Firebase Admin SDK.

Payload có thể chứa tiêu đề, nội dung, dữ liệu bổ sung, thông tin nền tảng và các tùy chọn điều khiển việc phân phối. Nội dung cần được thiết kế phù hợp với giới hạn kích thước và quy định của từng nền tảng.

3.4. Phân phối và xử lý thông điệp

Sau khi tiếp nhận yêu cầu, FCM thực hiện định tuyến thông điệp đến đích nhận. Tuy nhiên, việc yêu cầu gửi được chấp nhận không đồng nghĩa thông báo chắc chắn đã xuất hiện trên màn hình thiết bị.

Nếu thiết bị mất kết nối, thông điệp có thể được lưu giữ tạm thời theo cấu hình và chính sách của dịch vụ. Nếu ứng dụng bị hạn chế chạy nền, người dùng chưa cấp quyền thông báo hoặc hệ điều hành áp dụng các chính sách tiết kiệm năng lượng, hành vi nhận và hiển thị có thể khác nhau.

Do đó, khi thiết kế hệ thống, cần phân biệt rõ ba trạng thái: máy chủ đã gửi yêu cầu, FCM đã chấp nhận yêu cầu và thiết bị thực tế đã nhận hoặc hiển thị thông báo. Đây là các trạng thái khác nhau và không phải lúc nào cũng có thể xác nhận đầy đủ chỉ bằng một phản hồi API.

4. Các loại thông điệp trong FCM

FCM cung cấp nhiều cách xây dựng thông điệp để đáp ứng các nhu cầu khác nhau. Hai loại thông điệp cơ bản nhất là Notification Message và Data Message. Ngoài ra, lập trình viên có thể kết hợp cả hai loại trong cùng một payload để vừa hiển thị thông báo vừa truyền dữ liệu phục vụ xử lý nghiệp vụ.

4.1. Notification Message

Notification Message là thông điệp chứa nội dung dành cho người dùng, thường gồm tiêu đề và phần mô tả. Đây là lựa chọn phù hợp khi ứng dụng cần thông báo một sự kiện mà không yêu cầu xây dựng toàn bộ giao diện thông báo từ đầu.

Ví dụ, ứng dụng thương mại điện tử có thể gửi thông báo như sau:

{
  "message": {
    "token": "FCM_REGISTRATION_TOKEN",
    "notification": {
      "title": "Đơn hàng đã được xác nhận",
      "body": "Đơn hàng DH001 của bạn đang được chuẩn bị."
    }
  }
}

Trong ví dụ này:

  • token xác định đích nhận thông điệp.

  • notification.title chứa tiêu đề thông báo.

  • notification.body chứa nội dung thông báo.

Khi ứng dụng ở trạng thái nền, SDK và hệ điều hành thường có thể xử lý việc hiển thị thông báo theo cấu hình nền tảng. Khi ứng dụng đang mở ở phía trước, lập trình viên cần xử lý sự kiện nhận thông điệp để quyết định cách hiển thị phù hợp.

Notification Message phù hợp với thông báo đơn hàng, tin nhắn mới, thông báo khuyến mãi, nhắc nhở lịch học hoặc cảnh báo trạng thái tài khoản.

4.2. Data Message

Data Message là thông điệp chỉ chứa các cặp khóa và giá trị do ứng dụng tự định nghĩa. Khác với Notification Message, loại thông điệp này không tự cung cấp nội dung thông báo để hệ điều hành hiển thị theo cơ chế mặc định. Ứng dụng nhận dữ liệu và tự quyết định cách xử lý.

Ví dụ:

{
  "message": {
    "token": "FCM_REGISTRATION_TOKEN",
    "data": {
      "type": "order_updated",
      "order_id": "DH001",
      "status": "shipping",
      "screen": "order_detail"
    }
  }
}

Payload trên có thể được sử dụng để thông báo rằng đơn hàng đã chuyển sang trạng thái giao hàng. Ứng dụng đọc trường type để xác định loại sự kiện, sử dụng order_id để tìm đơn hàng tương ứng và quyết định có cần tải lại dữ liệu từ máy chủ hay không.

Một số ưu điểm của Data Message:

  • Cho phép xây dựng logic xử lý riêng trong ứng dụng.

  • Hỗ trợ điều hướng đến màn hình tương ứng với sự kiện.

  • Giúp phân tách dữ liệu nghiệp vụ khỏi nội dung hiển thị.

  • Phù hợp với các ứng dụng có quy trình xử lý thông điệp phức tạp.

Tuy nhiên, Data Message không phải cơ chế bảo đảm ứng dụng luôn chạy nền hoặc thực thi mã ngay lập tức. Khả năng xử lý phụ thuộc vào hệ điều hành, trạng thái ứng dụng, quyền chạy nền và chính sách phân phối thông điệp.

4.3. Combined Message

Combined Message là thông điệp kết hợp cả notification và data. Cách tiếp cận này giúp hệ thống gửi nội dung hiển thị cho người dùng đồng thời cung cấp dữ liệu để ứng dụng xử lý sự kiện.

{
  "message": {
    "token": "FCM_REGISTRATION_TOKEN",
    "notification": {
      "title": "Cập nhật đơn hàng",
      "body": "Đơn hàng DH001 đang trên đường giao."
    },
    "data": {
      "type": "order_updated",
      "order_id": "DH001",
      "status": "shipping"
    }
  }
}

Khi ứng dụng ở trạng thái nền, thông báo có thể được hiển thị trong khu vực thông báo của hệ điều hành. Phần dữ liệu bổ sung thường được xử lý khi người dùng tương tác với thông báo. Khi ứng dụng đang ở trạng thái foreground, ứng dụng có thể tiếp nhận cả hai phần để quyết định cách cập nhật giao diện.

Cách kết hợp này hữu ích khi cần vừa thông báo cho người dùng vừa hỗ trợ điều hướng đến trang chi tiết đơn hàng. Lập trình viên cần kiểm tra trạng thái ứng dụng và thiết kế xử lý phù hợp để tránh hiển thị thông báo trùng lặp.

4.4. So sánh các loại thông điệp

Tiêu chí Notification Message Data Message Combined Message
Có nội dung hiển thị mặc định Có Không Có
Có dữ liệu tùy chỉnh Có thể có Có Có
Cần logic xử lý riêng Tùy trường hợp Có Có
Phù hợp với Thông báo thông thường Sự kiện nghiệp vụ Thông báo kèm dữ liệu
Kiểm soát cách hiển thị Theo nền tảng và cấu hình Do ứng dụng quyết định Kết hợp hai cơ chế

FCM giới hạn payload thông điệp thông thường ở mức 4096 byte đối với các phương thức gửi được tài liệu quy định; Firebase Console có giới hạn riêng cho trình soạn thông báo. Vì vậy, không nên truyền các đối tượng dữ liệu quá lớn, toàn bộ thông tin đơn hàng hoặc dữ liệu nhạy cảm trực tiếp trong payload. Ứng dụng có thể chỉ gửi mã định danh rồi gọi API để lấy thông tin đầy đủ.

5. Các phương thức gửi thông điệp trong FCM

FCM hỗ trợ nhiều cách xác định đích nhận. Việc lựa chọn phụ thuộc vào nghiệp vụ, quy mô hệ thống và cách quản lý người dùng.

5.1. Gửi đến một thiết bị bằng Registration Token

Đây là phương thức gửi thông điệp đến một đích nhận cụ thể thông qua token tương ứng.

Ví dụ, khi một khách hàng có đơn hàng được cập nhật, máy chủ có thể tìm token của thiết bị đang liên kết với tài khoản đó và gửi thông báo riêng.

Phương thức này phù hợp với:

  • Thông báo trạng thái đơn hàng.

  • Tin nhắn cá nhân.

  • Cảnh báo bảo mật tài khoản.

  • Nhắc nhở lịch học hoặc lịch làm việc.

  • Thông báo dành riêng cho một phiên cài đặt ứng dụng.

Nếu người dùng đăng nhập trên nhiều thiết bị, máy chủ cần xác định chính xác danh sách token cần gửi. Một tài khoản có thể có nhiều token và một token không nên được giả định là đại diện vĩnh viễn cho toàn bộ tài khoản.

5.2. Gửi thông điệp đến Topic

Topic là cơ chế cho phép nhóm nhiều thiết bị có cùng mối quan tâm. Thiết bị đăng ký nhận thông điệp từ một topic, sau đó máy chủ có thể gửi một thông điệp đến topic đó thay vì gửi lần lượt cho từng token.

Ví dụ, một ứng dụng tin tức có thể sử dụng các topic như:

  • technology: tin tức công nghệ.

  • sports: tin tức thể thao.

  • promotions: chương trình khuyến mãi.

  • system_updates: thông báo cập nhật hệ thống.

Khi có bài viết công nghệ mới, máy chủ gửi thông điệp đến topic technology. Các thiết bị đã đăng ký topic này sẽ là nhóm đích nhận thông điệp.

Topic phù hợp với thông báo có cùng nội dung dành cho nhiều người dùng. Tuy nhiên, không nên sử dụng topic thay cho cơ chế phân quyền hoặc gửi dữ liệu riêng tư. Việc đăng ký topic phải được thiết kế phù hợp với quyền và lựa chọn của người dùng.

5.3. Gửi theo Condition

Condition cho phép gửi thông điệp đến các nhóm thiết bị dựa trên biểu thức kết hợp nhiều topic.

Ví dụ, một ứng dụng có thể nhắm đến các thiết bị đăng ký topic technology nhưng không đăng ký topic promotions. Điều kiện được xây dựng bằng cú pháp mà FCM hỗ trợ.

Cách gửi này phù hợp với hệ thống cần phân phối thông báo theo nhiều nhóm sở thích. Tuy nhiên, điều kiện càng phức tạp thì việc quản lý và kiểm thử càng cần được chú ý.

5.4. Lựa chọn phương thức gửi phù hợp

Nhu cầu Phương thức đề xuất
Gửi trạng thái đơn hàng riêng Registration Token
Gửi tin nhắn cho một thiết bị Registration Token
Gửi thông báo tin tức theo chuyên mục Topic
Gửi chương trình khuyến mãi theo nhóm sở thích Topic hoặc Condition
Gửi cảnh báo bảo mật riêng tư Registration Token
Gửi thông báo bảo trì chung Topic

Các đích nhận phổ biến của FCM HTTP v1 gồm registration token, topic và condition. Việc lựa chọn đúng phương thức giúp giảm số lượng yêu cầu gửi và đơn giản hóa quy trình quản lý thông báo.

6. FCM HTTP v1 API và Firebase Admin SDK

FCM cung cấp giao diện lập trình để máy chủ gửi thông điệp đến thiết bị. Hai cách triển khai phổ biến là sử dụng FCM HTTP v1 API trực tiếp hoặc sử dụng Firebase Admin SDK.

6.1. FCM HTTP v1 API

HTTP v1 API cho phép máy chủ gửi yêu cầu HTTP đến endpoint của FCM. Yêu cầu cần được xác thực bằng thông tin xác thực phù hợp, thường sử dụng OAuth 2.0 và tài khoản dịch vụ trong môi trường máy chủ đáng tin cậy.

Endpoint có dạng:

POST https://fcm.googleapis.com/v1/projects/PROJECT_ID/messages:send

Trong đó, PROJECT_ID là mã dự án Firebase cần gửi thông điệp.

Một yêu cầu gửi thông báo cơ bản có thể sử dụng cấu trúc sau:

{
  "message": {
    "token": "FCM_REGISTRATION_TOKEN",
    "notification": {
      "title": "Thông báo mới",
      "body": "Bạn có một cập nhật mới."
    },
    "data": {
      "type": "general_update",
      "screen": "notifications"
    }
  }
}

Khi yêu cầu hợp lệ, API có thể trả về mã định danh thông điệp. Phản hồi thành công cho biết FCM đã chấp nhận yêu cầu gửi, không phải bằng chứng rằng thông báo chắc chắn đã được người dùng nhìn thấy.

HTTP v1 API phù hợp với hệ thống cần kiểm soát trực tiếp yêu cầu HTTP, xây dựng tích hợp tùy chỉnh hoặc sử dụng ngôn ngữ chưa có Admin SDK tương ứng.

6.2. Firebase Admin SDK

Firebase Admin SDK cung cấp thư viện phía máy chủ giúp lập trình viên gửi thông điệp mà không cần tự triển khai toàn bộ quy trình xác thực và xây dựng HTTP request.

SDK có các thư viện dành cho những môi trường máy chủ phổ biến như Node.js, Python, Java, Go và C#. Đây là lựa chọn thuận tiện cho ứng dụng backend sử dụng các ngôn ngữ được hỗ trợ.

Ví dụ với Node.js và JavaScript:

const admin = require("firebase-admin");

admin.initializeApp({
  credential: admin.credential.applicationDefault(),
});

async function sendNotification(token) {
  const message = {
    token,
    notification: {
      title: "Đơn hàng đã cập nhật",
      body: "Đơn hàng của bạn đang được giao.",
    },
    data: {
      type: "order_updated",
      orderId: "DH001",
      status: "shipping",
    },
  };

  try {
    const messageId = await admin.messaging().send(message);

    console.log("FCM accepted message:", messageId);
    return messageId;
  } catch (error) {
    console.error("Failed to send FCM message:", error);
    throw error;
  }
}

module.exports = { sendNotification };

Trong ví dụ trên, admin.initializeApp() khởi tạo Firebase Admin SDK với thông tin xác thực mặc định của môi trường. Hàm sendNotification() nhận token, tạo thông điệp rồi gửi qua FCM.

Để chạy đoạn mã, máy chủ cần cài đặt gói firebase-admin, cấu hình thông tin xác thực và sử dụng token hợp lệ thuộc dự án Firebase tương ứng.

Không nên đặt thông tin xác thực quản trị trong mã nguồn phía client. Khóa tài khoản dịch vụ, thông tin xác thực và quyền gửi thông báo phải được bảo vệ trong môi trường máy chủ.

6.3. Lựa chọn giữa HTTP v1 API và Admin SDK

Admin SDK thường phù hợp khi backend sử dụng ngôn ngữ được hỗ trợ và cần triển khai nhanh. HTTP v1 API phù hợp khi hệ thống cần chủ động kiểm soát giao thức gửi, xây dựng tích hợp riêng hoặc sử dụng môi trường chưa có SDK tương ứng.

Dù lựa chọn cách nào, hệ thống vẫn cần quản lý token, xác thực yêu cầu, xử lý lỗi, giới hạn tần suất gửi và ghi nhận kết quả để phục vụ việc giám sát.

7. Tích hợp FCM với Flutter

Flutter là framework phát triển ứng dụng đa nền tảng, vì vậy FCM thường được tích hợp thông qua gói firebase_messaging. Gói này cung cấp các API giúp lấy token, đăng ký nhận thông điệp và xử lý những sự kiện liên quan đến thông báo.

7.1. Cài đặt các gói cần thiết

Trong dự án Flutter, có thể sử dụng lệnh:

flutter pub add firebase_core
flutter pub add firebase_messaging

firebase_core được sử dụng để khởi tạo Firebase. firebase_messaging cung cấp các chức năng liên quan đến FCM.

Sau khi thêm thư viện, cần cấu hình dự án Firebase theo hướng dẫn dành cho Flutter và nền tảng mục tiêu. Dự án Android và iOS có những yêu cầu cấu hình riêng, bao gồm thông tin dự án, quyền thông báo và thiết lập push notification của nền tảng.

7.2. Khởi tạo Firebase và yêu cầu quyền thông báo

Ví dụ dưới đây minh họa cách khởi tạo Firebase, yêu cầu quyền nhận thông báo và lấy token:

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/material.dart';

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await Firebase.initializeApp();

  final messaging = FirebaseMessaging.instance;

  final settings = await messaging.requestPermission(
    alert: true,
    badge: true,
    sound: true,
  );

  debugPrint(
    'Notification permission: ${settings.authorizationStatus}',
  );

  final token = await messaging.getToken();

  debugPrint('FCM Token: $token');

  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: Scaffold(
        body: Center(
          child: Text('FCM Demo'),
        ),
      ),
    );
  }
}

Đoạn mã minh họa các bước cơ bản:

  • Chờ Flutter khởi tạo binding trước khi gọi API bất đồng bộ.

  • Khởi tạo Firebase.

  • Yêu cầu quyền thông báo theo cấu hình nền tảng.

  • Lấy token của phiên cài đặt ứng dụng.

  • Khởi chạy giao diện.

Trong dự án thực tế, nên sử dụng cấu hình Firebase được tạo bởi FlutterFire CLI nếu phù hợp với quy trình của dự án. Trên iOS, cần cấu hình APNs và các khả năng thông báo đẩy theo yêu cầu của Apple. Trên Android, cách yêu cầu quyền và hiển thị thông báo còn phụ thuộc phiên bản Android và cấu hình notification channel.

Token lấy được nên được gửi lên backend để liên kết với tài khoản hoặc phiên cài đặt. Không nên chỉ in token ra console rồi bỏ qua bước quản lý vòng đời token.

7.3. Nhận thông điệp khi ứng dụng đang mở

Khi ứng dụng đang chạy ở foreground, lập trình viên có thể lắng nghe stream FirebaseMessaging.onMessage.

import 'dart:async';

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';

class FcmService {
  StreamSubscription<RemoteMessage>? _messageSubscription;

  void listenToForegroundMessages() {
    _messageSubscription =
        FirebaseMessaging.onMessage.listen((RemoteMessage message) {
      final notification = message.notification;
      final data = message.data;

      debugPrint('Title: ${notification?.title}');
      debugPrint('Body: ${notification?.body}');
      debugPrint('Data: $data');
    });
  }

  Future<void> dispose() async {
    await _messageSubscription?.cancel();
  }
}

Trong ví dụ này, ứng dụng nhận đối tượng RemoteMessage, đọc thông tin thông báo và dữ liệu bổ sung. Từ đó, ứng dụng có thể cập nhật giao diện, hiển thị banner nội bộ hoặc sử dụng thư viện local notification để hiển thị thông báo khi cần.

Cần lưu ý rằng nhận được thông điệp trong foreground không đồng nghĩa hệ điều hành sẽ tự động hiển thị notification banner theo cách mong muốn. Hành vi hiển thị phải được thiết kế riêng theo nền tảng.

7.4. Xử lý khi người dùng nhấn vào thông báo

Thông báo đẩy thường có mục tiêu đưa người dùng đến đúng nội dung. Ví dụ, khi nhấn vào thông báo đơn hàng, ứng dụng cần mở trang chi tiết của đơn hàng tương ứng.

Flutter cung cấp FirebaseMessaging.onMessageOpenedApp để xử lý trường hợp ứng dụng đang ở nền và người dùng nhấn vào thông báo. Đối với trường hợp ứng dụng được khởi chạy từ trạng thái đã đóng bởi thao tác nhấn thông báo, cần kiểm tra thêm getInitialMessage().

Ví dụ:

import 'dart:async';

import 'package:firebase_messaging/firebase_messaging.dart';
import 'package:flutter/foundation.dart';

class NotificationNavigationService {
  StreamSubscription<RemoteMessage>? _openedSubscription;

  Future<void> initialize() async {
    final initialMessage =
        await FirebaseMessaging.instance.getInitialMessage();

    if (initialMessage != null) {
      _handleMessage(initialMessage);
    }

    _openedSubscription =
        FirebaseMessaging.onMessageOpenedApp.listen(_handleMessage);
  }

  void _handleMessage(RemoteMessage message) {
    final type = message.data['type'];
    final orderId = message.data['orderId'];

    if (type == 'order_updated' && orderId != null) {
      debugPrint('Open order detail: $orderId');

      // Điều hướng đến màn hình chi tiết đơn hàng
      // bằng Navigator hoặc hệ thống routing của ứng dụng.
    }
  }

  Future<void> dispose() async {
    await _openedSubscription?.cancel();
  }
}

Đây là ví dụ về cách phân tích dữ liệu để điều hướng; phần gọi Navigator hoặc router thực tế cần được kết nối với kiến trúc điều hướng của dự án.

Không nên mặc định mọi thông điệp đều có orderId hoặc luôn hợp lệ. Ứng dụng cần kiểm tra dữ liệu, xác thực quyền truy cập và tải thông tin mới nhất từ backend trước khi hiển thị dữ liệu nghiệp vụ.

7.5. Xử lý thông điệp ở background

Với Flutter, ứng dụng có thể đăng ký hàm xử lý thông điệp nền thông qua FirebaseMessaging.onBackgroundMessage. Hàm xử lý cần tuân thủ các yêu cầu của phiên bản Flutter, plugin và nền tảng đang sử dụng; trên các cấu hình phổ biến, hàm này phải là hàm cấp cao nhất, không phải phương thức instance và cần được đánh dấu phù hợp với cơ chế tree shaking.

Ví dụ khung xử lý:

import 'package:firebase_core/firebase_core.dart';
import 'package:firebase_messaging/firebase_messaging.dart';

@pragma('vm:entry-point')
Future<void> firebaseMessagingBackgroundHandler(
  RemoteMessage message,
) async {
  await Firebase.initializeApp();

  // Xử lý dữ liệu nền phù hợp với giới hạn nền tảng.
  // Không thực hiện tác vụ dài hoặc phụ thuộc giao diện tại đây.
}

Future<void> configureMessaging() async {
  FirebaseMessaging.onBackgroundMessage(
    firebaseMessagingBackgroundHandler,
  );
}

Hàm xử lý nền nên được đăng ký trong giai đoạn khởi tạo phù hợp của ứng dụng. Không nên đặt các tác vụ nặng, vòng lặp kéo dài hoặc logic phụ thuộc BuildContext vào callback nền.

Việc thực thi trong background có giới hạn và khác nhau giữa Android, iOS và Web. Nếu ứng dụng bị người dùng buộc dừng, bị hệ điều hành chấm dứt hoặc chịu các giới hạn chạy nền, không thể bảo đảm mọi callback sẽ được thực thi ngay lập tức.

8. Tích hợp FCM với React Native

Trong React Native, FCM có thể được triển khai bằng các thư viện tương thích với nền tảng, chẳng hạn như @react-native-firebase/messaging. Nếu sử dụng Expo, cần kiểm tra mô hình phát triển và khả năng tương thích của phiên bản Expo, vì việc sử dụng push notification trên thiết bị thật có thể yêu cầu development build hoặc cấu hình native tương ứng.

Các bước triển khai thường gồm:

  1. Tạo dự án Firebase và đăng ký ứng dụng Android hoặc iOS.

  2. Cấu hình Firebase cho dự án React Native.

  3. Cài đặt thư viện Messaging tương thích.

  4. Thiết lập quyền thông báo và cấu hình push notification.

  5. Lấy token và đồng bộ token với backend.

  6. Đăng ký callback nhận thông điệp ở foreground, background và sự kiện nhấn thông báo.

  7. Kiểm thử trên thiết bị thật với các trạng thái ứng dụng khác nhau.

Ví dụ minh họa với React Native Firebase:

import messaging from '@react-native-firebase/messaging';

export async function registerForPushNotifications() {
  const authorizationStatus =
    await messaging().requestPermission();

  const enabled =
    authorizationStatus === messaging.AuthorizationStatus.AUTHORIZED ||
    authorizationStatus === messaging.AuthorizationStatus.PROVISIONAL;

  if (!enabled) {
    return null;
  }

  const token = await messaging().getToken();

  // Gửi token lên backend để liên kết với tài khoản.
  return token;
}

Đây là đoạn mã minh họa cho thư viện React Native Firebase, không phải API dùng trực tiếp trong mọi dự án Expo. Dự án cần cài đặt native tương ứng và thực hiện các bước cấu hình theo thư viện đã chọn.

Trong ứng dụng React Native, việc nhận thông điệp, hiển thị notification và điều hướng khi nhấn thông báo nên được tách thành các module riêng. Cách tổ chức này giúp tránh để logic FCM phụ thuộc quá nhiều vào màn hình cụ thể.

9. Tích hợp FCM với Backend Node.js

Backend là thành phần quan trọng trong kiến trúc FCM vì đây là nơi xác định sự kiện nào cần gửi thông báo, người dùng nào được nhận và nội dung nào được phép truyền đi.

Đối với ứng dụng thương mại điện tử, backend có thể gửi thông báo khi đơn hàng được xác nhận, thanh toán thành công, chuyển sang trạng thái giao hàng hoặc có chương trình khuyến mãi mới. Với ứng dụng quản lý phòng gym, backend có thể gửi thông báo nhắc ngày hết hạn hội viên hoặc xác nhận lượt check-in.

9.1. Cài đặt Firebase Admin SDK

Trong dự án Node.js, cài đặt thư viện:

npm install firebase-admin

Tiếp theo, tạo một module riêng để khởi tạo Firebase Admin SDK. Không nên khởi tạo Firebase lặp lại ở nhiều module hoặc để mỗi API route tự quản lý thông tin xác thực.

Ví dụ với TypeScript:

// src/config/firebase.ts

import { applicationDefault, initializeApp, getApps } from 'firebase-admin/app';
import { getMessaging } from 'firebase-admin/messaging';

const firebaseApp =
  getApps().length > 0
    ? getApps()[0]
    : initializeApp({
        credential: applicationDefault(),
      });

export const firebaseMessaging = getMessaging(firebaseApp);

Cách khởi tạo trên sử dụng Application Default Credentials. Khi triển khai, cần cấu hình thông tin xác thực hợp lệ cho môi trường máy chủ. Không đưa khóa riêng của service account vào ứng dụng frontend hoặc commit khóa vào Git.

9.2. Xây dựng service gửi thông báo

Tách nghiệp vụ gửi thông báo thành một service giúp các module đơn hàng, tài khoản và thanh toán sử dụng chung.

// src/services/notification.service.ts

import { firebaseMessaging } from '../config/firebase';

interface PushNotificationInput {
  token: string;
  title: string;
  body: string;
  data?: Record<string, string>;
}

export async function sendPushNotification(
  input: PushNotificationInput,
) {
  const message = {
    token: input.token,
    notification: {
      title: input.title,
      body: input.body,
    },
    data: input.data ?? {},
  };

  return firebaseMessaging.send(message);
}

Ví dụ gọi service sau khi một đơn hàng được xác nhận:

await sendPushNotification({
  token: customerFcmToken,
  title: 'Đơn hàng đã được xác nhận',
  body: 'Đơn hàng của bạn đang được chuẩn bị.',
  data: {
    type: 'order_confirmed',
    orderId: order.id,
  },
});

Đoạn mã trên minh họa cách tích hợp với nghiệp vụ. Trong hệ thống thực tế, customerFcmToken phải được lấy từ dữ liệu thiết bị đã đăng ký và người nhận phải được xác định từ dữ liệu đáng tin cậy của backend.

9.3. Kết hợp FCM với cơ chế xử lý sự kiện

Một thiết kế tốt không nên phụ thuộc hoàn toàn vào việc gửi thông báo ngay trong quá trình xử lý API.

Ví dụ, khi khách hàng đặt hàng, hệ thống có thể thực hiện:

  1. Kiểm tra dữ liệu đơn hàng.

  2. Xác thực tài khoản và thông tin thanh toán.

  3. Lưu đơn hàng vào cơ sở dữ liệu.

  4. Ghi nhận sự kiện order_created.

  5. Đưa công việc gửi thông báo vào hàng đợi.

  6. Worker xử lý sự kiện và gọi FCM.

  7. Ghi nhận kết quả gửi để phục vụ giám sát.

Việc sử dụng hàng đợi như Redis với BullMQ hoặc một hệ thống message broker phù hợp giúp tách biệt nghiệp vụ chính khỏi tác vụ gửi thông báo. Nếu FCM tạm thời gặp lỗi, worker có thể thử lại theo chính sách được thiết kế trước.

Tuy nhiên, cần tránh gửi thông báo thành công trước khi giao dịch tạo đơn hàng được xác nhận. Trong hệ thống có yêu cầu nhất quán dữ liệu cao, có thể sử dụng Transactional Outbox để lưu sự kiện cùng giao dịch nghiệp vụ rồi xử lý gửi thông báo sau.

10. Quản lý trạng thái và vòng đời thông báo

FCM không thay thế toàn bộ hệ thống quản lý thông báo của ứng dụng. Đối với những ứng dụng có nhiều nghiệp vụ, backend thường cần lưu lịch sử thông báo và trạng thái xử lý để có thể tra cứu, hiển thị danh sách thông báo và xử lý sự cố.

10.1. Phân biệt Push Notification và In-App Notification

Push Notification là thông báo được gửi đến thiết bị thông qua cơ chế phân phối thông điệp. In-App Notification là thông báo được hiển thị bên trong giao diện ứng dụng, chẳng hạn như danh sách thông báo trong tài khoản.

Hai cơ chế có thể kết hợp với nhau nhưng không đồng nghĩa.

Ví dụ, khi đơn hàng chuyển sang trạng thái giao hàng, backend có thể lưu một bản ghi thông báo vào cơ sở dữ liệu. Đồng thời, backend gửi FCM để thiết bị nhận được thông báo đẩy.

Nếu người dùng đang ngoại tuyến, họ vẫn có thể xem thông báo đã lưu trong ứng dụng khi đăng nhập lại và tải dữ liệu từ backend, dù thông báo đẩy không xuất hiện đúng thời điểm.

10.2. Thiết kế bảng thông báo

Một bảng notifications có thể bao gồm các trường:

Trường Mục đích
id Định danh thông báo
user_id Người nhận thông báo
title Tiêu đề
body Nội dung
type Loại sự kiện
reference_id Mã đối tượng liên quan
is_read Trạng thái đã đọc
created_at Thời điểm tạo

Bảng này phục vụ lịch sử thông báo trong ứng dụng. Có thể xây dựng thêm bảng notification_deliveries để lưu trạng thái gửi đến từng thiết bị, mã thông điệp FCM, số lần thử lại và thông tin lỗi.

Việc tách lịch sử nghiệp vụ khỏi trạng thái phân phối giúp hệ thống quản lý được trường hợp một thông báo liên quan đến một người dùng nhưng cần gửi đến nhiều thiết bị.

10.3. Xử lý thông báo trùng lặp

Trong hệ thống phân tán, một sự kiện có thể được xử lý lại do worker thử lại, lỗi mạng hoặc cơ chế phục hồi. Vì vậy, backend cần thiết kế cơ chế chống gửi trùng khi nghiệp vụ yêu cầu.

Các giải pháp có thể gồm:

  • Gán mã định danh duy nhất cho sự kiện.

  • Lưu trạng thái xử lý trong cơ sở dữ liệu.

  • Sử dụng khóa idempotency cho tác vụ gửi.

  • Kiểm tra trạng thái đơn hàng trước khi phát sinh thông báo.

  • Thiết kế ứng dụng nhận thông điệp có thể xử lý lặp mà không làm sai dữ liệu.

Không nên coi FCM là một hàng đợi nghiệp vụ bảo đảm mỗi sự kiện chỉ được xử lý đúng một lần. Với những tác vụ quan trọng, dữ liệu chuẩn phải được lưu ở backend và ứng dụng cần đồng bộ lại trạng thái từ API.

11. Bảo mật trong hệ thống FCM

Bảo mật là yếu tố quan trọng khi triển khai hệ thống thông báo đẩy. Nếu thiết kế không đúng, thông báo có thể bị gửi trái phép, lộ dữ liệu hoặc bị lợi dụng để giả mạo nội dung.

11.1. Bảo vệ thông tin xác thực máy chủ

Thông tin xác thực có quyền gửi thông điệp phải được lưu ở môi trường backend đáng tin cậy. Không được nhúng khóa riêng của service account vào mã nguồn ứng dụng Android, iOS, Flutter, React Native hoặc website.

Các biện pháp cần áp dụng:

  • Sử dụng biến môi trường hoặc dịch vụ quản lý bí mật.

  • Giới hạn quyền IAM theo nguyên tắc đặc quyền tối thiểu.

  • Không đưa tệp khóa lên GitHub.

  • Luân chuyển hoặc thu hồi thông tin xác thực khi có dấu hiệu bị lộ.

  • Không ghi token truy cập hoặc khóa bí mật vào log.

Firebase client configuration không tương đương với khóa quản trị máy chủ. Tuy nhiên, các dịch vụ Firebase liên quan vẫn phải được cấu hình Security Rules, IAM và cơ chế xác thực phù hợp.

11.2. Bảo vệ FCM token

Token cần được quản lý như dữ liệu định danh của phiên cài đặt. Không nên cho phép client tự ý gửi yêu cầu để gửi thông báo đến token bất kỳ.

Backend cần xác thực người dùng, kiểm tra quyền sở hữu thiết bị và chỉ liên kết token với tài khoản theo quy trình hợp lệ.

Khi token thay đổi, ứng dụng cần cập nhật bản ghi trên máy chủ. Khi người dùng đăng xuất, hệ thống nên xử lý liên kết token với tài khoản cũ để tránh thông báo riêng tư xuất hiện trên thiết bị không còn thuộc phiên đăng nhập đó.

11.3. Hạn chế dữ liệu nhạy cảm trong payload

FCM hỗ trợ truyền dữ liệu để ứng dụng xử lý, nhưng không nên xem payload là nơi lưu trữ an toàn cho thông tin bí mật.

Ví dụ, thay vì gửi toàn bộ thông tin thanh toán hoặc thông tin cá nhân trong payload, backend chỉ nên gửi mã tham chiếu:

{
  "type": "payment_updated",
  "paymentId": "PAY001"
}

Sau đó, ứng dụng xác thực người dùng và gọi API để lấy thông tin cần thiết.

Tài liệu Firebase lưu ý rằng kết nối FCM được mã hóa nhưng bản thân cơ chế này không cung cấp mã hóa đầu cuối cho nội dung thông điệp. Nếu ứng dụng có yêu cầu bảo mật cao, cần triển khai cơ chế mã hóa đầu cuối phù hợp với mô hình đe dọa.

11.4. Chống giả mạo và lạm dụng thông báo

Hệ thống không nên cho phép người dùng thông thường tự do tạo thông điệp hệ thống hoặc gửi thông báo đến các tài khoản khác.

Cần phân quyền các nghiệp vụ gửi thông báo, giới hạn tần suất gửi và xác thực nguồn phát sinh sự kiện. Với thông báo khuyến mãi, hệ thống cũng nên có cơ chế kiểm soát số lượng, lịch gửi và tùy chọn nhận thông báo của người dùng.

Ngoài ra, ứng dụng phải kiểm tra dữ liệu nhận được trước khi điều hướng. Không nên tin tưởng tuyệt đối vào các trường như screen, orderId hoặc userId được truyền trong payload.

12. Xử lý lỗi và tối ưu hiệu năng

Khi gửi thông điệp, FCM có thể trả về lỗi liên quan đến token, quyền truy cập, payload hoặc giới hạn tần suất. Một hệ thống ổn định cần phân loại lỗi để lựa chọn cách xử lý tương ứng.

12.1. Các nhóm lỗi thường gặp

Nhóm lỗi Hướng xử lý
Token không hợp lệ hoặc không còn đăng ký Loại bỏ hoặc cập nhật bản ghi token
Thông tin xác thực không hợp lệ Kiểm tra credential và quyền IAM
Payload không hợp lệ Kiểm tra cấu trúc, trường dữ liệu và kích thước
Bị giới hạn tần suất Áp dụng backoff và điều chỉnh tốc độ gửi
Lỗi tạm thời phía dịch vụ Thử lại có kiểm soát
Thiết bị không nhận được thông báo Kiểm tra quyền, trạng thái ứng dụng và cấu hình nền tảng

Không phải lỗi nào cũng nên được thử lại. Ví dụ, token không còn hợp lệ cần được xử lý bằng cách cập nhật dữ liệu thay vì gửi lại liên tục. Ngược lại, một số lỗi tạm thời có thể được thử lại sau khoảng thời gian tăng dần.

12.2. Retry với Exponential Backoff

Exponential Backoff là chiến lược tăng dần khoảng thời gian chờ giữa các lần thử lại. Cách tiếp cận này giúp giảm tải cho hệ thống khi xảy ra lỗi tạm thời hoặc bị giới hạn tốc độ.

Ví dụ, khoảng chờ có thể tăng theo các mức 1 giây, 2 giây, 4 giây và 8 giây, kết hợp thêm độ trễ ngẫu nhiên (jitter). Các giá trị thực tế cần được thiết kế theo loại lỗi, giới hạn của dịch vụ và yêu cầu nghiệp vụ.

Khi triển khai, nên giới hạn số lần thử lại, thời gian chờ tối đa và tổng thời gian xử lý. Những tác vụ hết thời hạn cần được ghi nhận để kiểm tra hoặc đưa vào hàng đợi xử lý lỗi riêng.

12.3. Tối ưu khi gửi số lượng lớn

Khi hệ thống cần gửi hàng nghìn hoặc hàng triệu thông báo, việc gửi đồng bộ từng thông điệp trong một vòng lặp có thể gây nghẽn backend.

Các biện pháp tối ưu bao gồm:

  • Sử dụng hàng đợi và worker để phân phối công việc.

  • Giới hạn số tác vụ chạy đồng thời.

  • Gửi theo nhóm token phù hợp với API và SDK.

  • Loại bỏ token không hợp lệ.

  • Tránh gửi thông báo trùng do sự kiện bị xử lý lại.

  • Theo dõi tỷ lệ lỗi, thời gian gửi và số thông điệp bị từ chối.

  • Phân biệt thông báo khẩn cấp với thông báo có thể trì hoãn.

Topic messaging có thể giảm công việc quản lý danh sách đích nhận đối với thông báo chung. Tuy nhiên, gửi theo topic không thay thế được việc phân quyền và kiểm soát nội dung ở backend.

13. Kiểm thử và giám sát FCM

Một hệ thống thông báo không nên chỉ được kiểm tra bằng cách gửi thử một thông báo từ Firebase Console. Cần đánh giá toàn bộ quy trình từ lúc phát sinh sự kiện đến khi ứng dụng xử lý thông điệp.

13.1. Các trường hợp kiểm thử

Danh sách kiểm thử nên bao gồm:

  • Thiết bị đã cấp quyền nhận thông báo.

  • Người dùng từ chối quyền thông báo.

  • Ứng dụng đang mở ở foreground.

  • Ứng dụng đang ở background.

  • Ứng dụng được mở sau khi người dùng nhấn thông báo.

  • Thiết bị tạm thời mất kết nối mạng.

  • Token thay đổi sau khi cài đặt lại ứng dụng.

  • Tài khoản đăng nhập trên nhiều thiết bị.

  • Token không hợp lệ hoặc đã bị xóa.

  • Payload thiếu trường hoặc chứa dữ liệu không đúng định dạng.

  • Thông điệp bị gửi lại nhiều lần.

  • Máy chủ nhận lỗi xác thực hoặc lỗi giới hạn tốc độ.

Đối với iOS, cần kiểm thử cấu hình APNs và quyền thông báo trên thiết bị thực. Đối với Android, cần kiểm tra notification channel, quyền thông báo theo phiên bản hệ điều hành và các giới hạn chạy nền.

13.2. Các chỉ số giám sát

Một hệ thống có thể theo dõi các chỉ số như:

  • Tổng số yêu cầu gửi.

  • Số yêu cầu được FCM chấp nhận.

  • Số yêu cầu thất bại theo từng nhóm lỗi.

  • Tỷ lệ token không hợp lệ.

  • Thời gian xử lý trung bình của worker.

  • Số tác vụ đang chờ trong hàng đợi.

  • Số lần thử lại trung bình.

  • Tỷ lệ người dùng mở thông báo, nếu có cơ chế đo lường phù hợp.

Cần phân biệt chỉ số chấp nhận yêu cầu gửi với chỉ số phân phối thực tế và tương tác của người dùng. Không phải mọi thông báo đều có thể xác nhận đã được nhìn thấy.

FCM cung cấp các tài liệu và công cụ báo cáo giúp theo dõi hoạt động gửi thông điệp. Với hệ thống lớn, có thể kết hợp log backend, hệ thống giám sát và dữ liệu phân tích để tìm ra các điểm nghẽn trong quá trình phân phối.

14. Ứng dụng thực tế của Firebase Cloud Messaging

FCM được sử dụng trong nhiều loại hệ thống vì khả năng gửi thông điệp đến thiết bị và hỗ trợ nhiều nền tảng.

14.1. Thương mại điện tử

Trong website bán hàng hoặc ứng dụng mua sắm, FCM có thể gửi thông báo xác nhận đơn hàng, cập nhật giao hàng, thông báo thanh toán và chương trình khuyến mãi.

Ví dụ, với một nền tảng Smart Commerce, khi đơn hàng chuyển từ confirmed sang shipping, backend ghi nhận sự kiện, lưu lịch sử thông báo và gửi FCM đến các thiết bị của khách hàng.

Thông báo chỉ chứa thông tin cần thiết; ứng dụng sử dụng mã đơn hàng để mở trang chi tiết và tải trạng thái mới nhất từ API.

14.2. Mạng xã hội và ứng dụng nhắn tin

FCM có thể được sử dụng để thông báo tin nhắn mới, lượt thích, bình luận hoặc lời mời kết bạn. Đối với ứng dụng nhắn tin, payload nên hạn chế thông tin riêng tư và cần kết hợp cơ chế đồng bộ dữ liệu từ máy chủ.

FCM không thay thế hoàn toàn WebSocket hoặc các giao thức giao tiếp thời gian thực. Những ứng dụng cần luồng dữ liệu liên tục, trạng thái trực tuyến tức thời hoặc trao đổi hai chiều có thể kết hợp FCM với WebSocket tùy theo kiến trúc.

14.3. Giáo dục và quản lý công việc

Các hệ thống học trực tuyến có thể gửi thông báo lịch học, hạn nộp bài và kết quả học tập. Ứng dụng quản lý công việc có thể gửi lời nhắc, thông báo nhiệm vụ mới hoặc cập nhật tiến độ.

Topic có thể hỗ trợ thông báo chung theo lớp hoặc nhóm. Trong khi đó, các thông báo cá nhân như điểm số hoặc lịch riêng nên được gửi đến đúng tài khoản và xử lý bằng cơ chế phân quyền phù hợp.

14.4. Quản lý hội viên phòng gym

Trong một hệ thống quản lý phòng gym, FCM có thể gửi thông báo khi gói hội viên sắp hết hạn, xác nhận lượt check-in hoặc nhắc lịch tập.

Backend chịu trách nhiệm xác định thời điểm gửi, kiểm tra trạng thái hội viên và lưu lịch sử thông báo. FCM chỉ đảm nhiệm việc truyền thông điệp đến thiết bị, không phải nơi lưu trạng thái hội viên hay xác thực lượt check-in.

15. Ưu điểm và hạn chế của FCM

15.1. Ưu điểm

  • Hỗ trợ đa nền tảng: Có thể triển khai thông báo cho Android, iOS và Web.

  • Giảm độ phức tạp của backend: Không cần tự xây dựng toàn bộ hạ tầng phân phối thông điệp đến thiết bị.

  • Nhiều cách gửi: Hỗ trợ gửi đến token, topic và condition.

  • Tích hợp với hệ sinh thái Firebase: Có thể kết hợp với các dịch vụ Firebase khác tùy nhu cầu.

  • Hỗ trợ tùy chỉnh: Cho phép sử dụng notification payload, data payload và cấu hình riêng theo nền tảng.

  • Phù hợp với hệ thống sự kiện: Có thể kết nối với backend, worker và hàng đợi để gửi thông báo theo nghiệp vụ.

15.2. Hạn chế

  • Không bảo đảm hiển thị tức thời trong mọi trường hợp: Thiết bị ngoại tuyến, hệ điều hành hoặc quyền thông báo có thể ảnh hưởng đến việc phân phối.

  • Phụ thuộc cấu hình nền tảng: Android, iOS và Web có những yêu cầu khác nhau.

  • Cần quản lý token: Token có thể thay đổi hoặc không còn hợp lệ.

  • Không thay thế cơ sở dữ liệu nghiệp vụ: FCM không phải hệ thống lưu lịch sử thông báo đầy đủ cho ứng dụng.

  • Không cung cấp mã hóa đầu cuối mặc định: Dữ liệu nhạy cảm cần được bảo vệ theo yêu cầu riêng.

  • Cần xử lý lỗi và giới hạn tốc độ: Backend phải có cơ chế retry, giám sát và quản lý tải.

FCM phù hợp với nhiều hệ thống cần thông báo đẩy, nhưng thiết kế tốt vẫn cần kết hợp với backend có phân quyền rõ ràng, cơ sở dữ liệu, cơ chế xử lý sự kiện và quy trình giám sát.

16. Các nguyên tắc triển khai FCM hiệu quả

Để xây dựng hệ thống thông báo ổn định, có thể áp dụng những nguyên tắc sau:

  1. Tách nghiệp vụ khỏi cơ chế gửi thông báo. Các module đơn hàng, tài khoản hoặc thanh toán không nên phụ thuộc trực tiếp vào toàn bộ logic FCM.

  2. Quản lý token theo phiên cài đặt. Hỗ trợ cập nhật token, đăng xuất, nhiều thiết bị và loại bỏ token không hợp lệ.

  3. Không coi push notification là nguồn dữ liệu chính. Backend và cơ sở dữ liệu mới là nguồn dữ liệu chuẩn.

  4. Bảo vệ thông tin xác thực. Chỉ backend đáng tin cậy mới được sử dụng quyền gửi thông điệp.

  5. Thiết kế payload ngắn gọn. Chỉ truyền dữ liệu cần thiết và tải thông tin chi tiết qua API.

  6. Xử lý lỗi có kiểm soát. Phân loại lỗi, giới hạn retry và sử dụng exponential backoff khi phù hợp.

  7. Kiểm thử đa nền tảng. Kiểm tra foreground, background, trạng thái ứng dụng đã đóng và quyền thông báo.

  8. Ghi nhận lịch sử và theo dõi kết quả. Phân biệt yêu cầu được chấp nhận, thông điệp được phân phối và hành động của người dùng.

  9. Chống xử lý trùng lặp. Thiết kế sự kiện có định danh và xử lý idempotent đối với các nghiệp vụ quan trọng.

  10. Tôn trọng quyền riêng tư. Cho phép người dùng quản lý tùy chọn thông báo và hạn chế gửi nội dung nhạy cảm.

17. Tổng kết

Firebase Cloud Messaging là dịch vụ nhắn tin đa nền tảng giúp ứng dụng gửi thông báo đẩy và truyền dữ liệu đến các thiết bị Android, iOS và Web. FCM cung cấp cơ chế đăng ký đích nhận, định tuyến thông điệp, gửi theo token hoặc topic và tích hợp với backend thông qua HTTP v1 API hoặc Firebase Admin SDK.

Để sử dụng hiệu quả, lập trình viên cần hiểu sự khác nhau giữa Notification Message và Data Message, quản lý token đúng cách, xử lý thông điệp theo trạng thái ứng dụng và thiết kế quy trình bảo mật phù hợp. Đối với các hệ thống lớn, việc kết hợp FCM với hàng đợi, cơ sở dữ liệu thông báo, cơ chế chống trùng lặp và hệ thống giám sát sẽ giúp nâng cao độ tin cậy.

FCM không thay thế backend, WebSocket hay cơ sở dữ liệu. Đây là một thành phần trong kiến trúc tổng thể, đảm nhiệm việc phân phối thông điệp để kết nối các sự kiện của hệ thống với trải nghiệm người dùng trên thiết bị.

Bài viết khác

API Error Handling

API Error Handling 1. Tổng quan về API Error Handling API Error Handling là kỹ thuật xử lý lỗi trong quá trình giao tiếp giữa các thành phần của hệ thống thông qua API (Application Programming Interface). Kỹ thuật này bao gồm việc phát hiện lỗi, phân loại nguyên nhân, trả về thông tin phù […]

Boundary Value Analysis(Phân tích giá trị biên)

1.Boundary Value Analysis là gì? Trong quá trình xây dựng và phát triển phần mềm, mặc dù đội ngũ lập trình viên luôn cố gắng viết mã nguồn thật chuẩn xác, nhưng thực tế kiểm thử từ nhiều thập kỷ qua đã đúc kết một quy luật kinh điển: Phần lớn các lỗi logic (logic […]

Sanity Testing(Kiểm thử sự hợp lý)

Sanity Testing là gì? Trong quá trình phát triển và vận hành một dự án phần mềm, hoạt động lập trình không bao giờ dừng lại ở lần phát hành đầu tiên. Sau khi nhận được phản hồi từ đội ngũ QC hoặc người dùng thực tế, các lập trình viên sẽ liên tục tiến […]

Test Types(Các loại kiểm thử phần mềm)

1. Lời mở đầu và vai trò định hình phạm vi của Test Types trong kiểm thử phần mềm: Trong quy trình phát triển và kiểm định chất lượng phần mềm, nếu như Testing Levels (Các cấp độ kiểm thử như Unit, Integration, System, Acceptance) giải quyết câu hỏi kiểm thử được thực hiện ở […]

Testing Principles & Testing Levels

Testing Principles & Testing Levels là gì? Trong kiểm thử phần mềm, Testing Principles (Các nguyên tắc kiểm thử) là kim chỉ nam giúp định hướng cách thực hiện kiểm thử hiệu quả, trong khi Testing Levels (Các cấp độ kiểm thử) là các giai đoạn phân loại phạm vi kiểm thử từ nhỏ đến […]

QA & QC vs Tester

1. Tester là gì? Bản chất và vai trò: Tester (Kiểm thử viên) là những nhân sự đóng vai trò trực tiếp tương tác, trải nghiệm, mổ xẻ và đánh giá ứng dụng hoặc hệ thống phần mềm do đội ngũ lập trình viên vừa xây dựng xong. Công việc cốt lõi của một Tester […]

Leave a Reply

Your email address will not be published. Required fields are marked *