Catch up on highlights from Firebase at Google I/O 2023. Learn more

Nhận tin nhắn trong ứng dụng Android

Thông báo Firebase hoạt động khác nhau tùy thuộc vào trạng thái nền trước/nền của ứng dụng nhận. Nếu muốn ứng dụng nền trước nhận tin nhắn thông báo hoặc tin nhắn dữ liệu, bạn sẽ cần viết mã để xử lý cuộc gọi lại onMessageReceived . Để biết giải thích về sự khác biệt giữa thông báo và thông báo dữ liệu, hãy xem Các loại thông báo .

Xử lý tin nhắn

Để nhận tin nhắn, hãy sử dụng dịch vụ mở rộng FirebaseMessagingService . Dịch vụ của bạn nên ghi đè các lệnh gọi lại onMessageReceivedonDeletedMessages . Nó sẽ xử lý bất kỳ tin nhắn nào trong vòng 20 giây sau khi nhận (10 giây trên Android Marshmallow). Cửa sổ thời gian có thể ngắn hơn tùy thuộc vào độ trễ của hệ điều hành phát sinh trước khi gọi onMessageReceived . Sau thời gian đó, các hành vi khác nhau của hệ điều hành chẳng hạn như giới hạn thực thi nền của Android O có thể cản trở khả năng hoàn thành công việc của bạn. Để biết thêm thông tin, hãy xem tổng quan của chúng tôi về mức độ ưu tiên của tin nhắn .

onMessageReceived được cung cấp cho hầu hết các loại tin nhắn, với các ngoại lệ sau:

  • Tin nhắn thông báo được gửi khi ứng dụng của bạn ở chế độ nền . Trong trường hợp này, thông báo được gửi đến khay hệ thống của thiết bị. Theo mặc định, người dùng nhấn vào thông báo sẽ mở trình khởi chạy ứng dụng.

  • Tin nhắn có cả tải trọng thông báo và dữ liệu, khi nhận được ở chế độ nền . Trong trường hợp này, thông báo được gửi tới khay hệ thống của thiết bị và tải trọng dữ liệu được gửi trong phần bổ sung của mục đích Hoạt động trình khởi chạy của bạn.

Tóm tắt:

trạng thái ứng dụng Thông báo Dữ liệu Cả hai
Vấn đề xung quanh onMessageReceived onMessageReceived onMessageReceived
Lý lịch Khay hệ thống onMessageReceived Thông báo: khay hệ thống
Dữ liệu: trong phần bổ sung của mục đích.
Để biết thêm thông tin về các loại tin nhắn, hãy xem Thông báo và tin nhắn dữ liệu .

Chỉnh sửa bảng kê khai ứng dụng

Để sử dụng FirebaseMessagingService , bạn cần thêm phần sau vào bảng kê khai ứng dụng của mình:

<service
    android:name=".java.MyFirebaseMessagingService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.firebase.MESSAGING_EVENT" />
    </intent-filter>
</service>

Ngoài ra, bạn nên đặt các giá trị mặc định để tùy chỉnh giao diện của thông báo. Bạn có thể chỉ định biểu tượng mặc định tùy chỉnh và màu mặc định tùy chỉnh được áp dụng bất cứ khi nào các giá trị tương đương không được đặt trong tải trọng thông báo.

Thêm những dòng này bên trong thẻ application để đặt biểu tượng mặc định tùy chỉnh và màu tùy chỉnh:

<!-- Set custom default icon. This is used when no icon is set for incoming notification messages.
     See README(https://goo.gl/l4GJaQ) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_icon"
    android:resource="@drawable/ic_stat_ic_notification" />
<!-- Set color used with incoming notification messages. This is used when no color is set for the incoming
     notification message. See README(https://goo.gl/6BKBk7) for more. -->
<meta-data
    android:name="com.google.firebase.messaging.default_notification_color"
    android:resource="@color/colorAccent" />

Android hiển thị biểu tượng mặc định tùy chỉnh cho

  • Tất cả các tin nhắn thông báo được gửi từ trình tổng hợp Thông báo .
  • Bất kỳ tin nhắn thông báo nào không đặt biểu tượng một cách rõ ràng trong tải trọng thông báo.

Android sử dụng màu mặc định tùy chỉnh cho

  • Tất cả các tin nhắn thông báo được gửi từ trình tổng hợp Thông báo .
  • Bất kỳ tin nhắn thông báo nào không đặt màu rõ ràng trong tải trọng thông báo.

Nếu không có biểu tượng mặc định tùy chỉnh nào được đặt và không có biểu tượng nào được đặt trong tải trọng thông báo, Android sẽ hiển thị biểu tượng ứng dụng được hiển thị bằng màu trắng.

Ghi đè onMessageReceived

Bằng cách ghi đè phương thức FirebaseMessagingService.onMessageReceived , bạn có thể thực hiện các hành động dựa trên đối tượng RemoteMessage đã nhận và nhận dữ liệu tin nhắn:

Kotlin+KTX

override fun onMessageReceived(remoteMessage: RemoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: ${remoteMessage.from}")

    // Check if message contains a data payload.
    if (remoteMessage.data.isNotEmpty()) {
        Log.d(TAG, "Message data payload: ${remoteMessage.data}")

        // Check if data needs to be processed by long running job
        if (needsToBeScheduled()) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob()
        } else {
            // Handle message within 10 seconds
            handleNow()
        }
    }

    // Check if message contains a notification payload.
    remoteMessage.notification?.let {
        Log.d(TAG, "Message Notification Body: ${it.body}")
    }

    // 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.
}

Java

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // Not getting messages here? See why this may be: https://goo.gl/39bRNJ
    Log.d(TAG, "From: " + remoteMessage.getFrom());

    // Check if message contains a data payload.
    if (remoteMessage.getData().size() > 0) {
        Log.d(TAG, "Message data payload: " + remoteMessage.getData());

        if (/* Check if data needs to be processed by long running job */ true) {
            // For long-running tasks (10 seconds or more) use WorkManager.
            scheduleJob();
        } else {
            // Handle message within 10 seconds
            handleNow();
        }

    }

    // Check if message contains a notification payload.
    if (remoteMessage.getNotification() != null) {
        Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody());
    }

    // 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.
}

Ghi đè onDeletedMessages

Trong một số trường hợp, FCM có thể không gửi tin nhắn. Điều này xảy ra khi có quá nhiều thư (>100) đang chờ xử lý cho ứng dụng của bạn trên một thiết bị cụ thể tại thời điểm ứng dụng kết nối hoặc nếu thiết bị không kết nối với FCM trong hơn một tháng. Trong những trường hợp này, bạn có thể nhận được lệnh gọi lại tới FirebaseMessagingService.onDeletedMessages() Khi phiên bản ứng dụng nhận được lệnh gọi lại này, phiên bản ứng dụng sẽ thực hiện đồng bộ hóa hoàn toàn với máy chủ ứng dụng của bạn. Nếu bạn chưa gửi tin nhắn đến ứng dụng trên thiết bị đó trong vòng 4 tuần qua, FCM sẽ không gọi onDeletedMessages() .

Xử lý tin nhắn thông báo trong ứng dụng nền

Khi ứng dụng của bạn ở chế độ nền, Android sẽ chuyển các tin nhắn thông báo đến khay hệ thống. Người dùng nhấn vào thông báo sẽ mở trình khởi chạy ứng dụng theo mặc định.

Điều này bao gồm các tin nhắn chứa cả tải trọng thông báo và dữ liệu (và tất cả các tin nhắn được gửi từ bảng điều khiển Thông báo). Trong những trường hợp này, thông báo sẽ được gửi tới khay hệ thống của thiết bị và tải trọng dữ liệu được gửi trong mục đích bổ sung của Hoạt động trình khởi chạy của bạn.

Để biết thông tin chi tiết về việc gửi tin nhắn đến ứng dụng của bạn, hãy xem bảng điều khiển báo cáo FCM , ghi lại số lượng tin nhắn được gửi và mở trên thiết bị Apple và Android, cùng với dữ liệu về "số lần hiển thị" (thông báo mà người dùng nhìn thấy) cho ứng dụng Android.

Nhận tin nhắn FCM ở chế độ khởi động trực tiếp

Các nhà phát triển muốn gửi tin nhắn FCM tới ứng dụng ngay cả trước khi thiết bị được mở khóa có thể bật ứng dụng Android để nhận tin nhắn khi thiết bị ở chế độ khởi động trực tiếp. Chẳng hạn, bạn có thể muốn người dùng ứng dụng của mình nhận thông báo cảnh báo ngay cả trên thiết bị bị khóa.

Khi xây dựng trường hợp sử dụng này, hãy tuân thủ các biện pháp hạn chế và thực hành tốt nhất chung đối với chế độ khởi động trực tiếp . Điều đặc biệt quan trọng là phải xem xét khả năng hiển thị của các thông báo kích hoạt khởi động trực tiếp; bất kỳ người dùng nào có quyền truy cập vào thiết bị đều có thể xem các tin nhắn này mà không cần nhập thông tin đăng nhập của người dùng.

điều kiện tiên quyết

  • Thiết bị phải được thiết lập ở chế độ khởi động trực tiếp.
  • Thiết bị phải được cài đặt phiên bản dịch vụ Google Play gần đây (19.0.54 trở lên).
  • Ứng dụng phải đang sử dụng FCM SDK ( com.google.firebase:firebase-messaging ) để nhận tin nhắn FCM.

Cho phép xử lý thông báo ở chế độ khởi động trực tiếp trong ứng dụng của bạn

  1. Trong tệp Gradle cấp ứng dụng, hãy thêm phần phụ thuộc vào thư viện hỗ trợ khởi động trực tiếp FCM:

    implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
    
  2. Làm cho FirebaseMessagingService nhận biết khả năng khởi động trực tiếp của ứng dụng bằng cách thêm thuộc tính android:directBootAware="true" trong tệp kê khai ứng dụng:

    <service
        android:name=".java.MyFirebaseMessagingService"
        android:exported="false"
        android:directBootAware="true">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>
    

Điều quan trọng là đảm bảo rằng FirebaseMessagingService này có thể chạy ở chế độ khởi động trực tiếp. Kiểm tra các yêu cầu sau:

  • Dịch vụ không được truy cập bộ lưu trữ được bảo vệ bằng thông tin xác thực khi đang chạy ở chế độ khởi động trực tiếp.
  • Dịch vụ không được cố gắng sử dụng các thành phần, chẳng hạn như Activities , BroadcastReceivers hoặc Services khác không được đánh dấu là nhận biết khởi động trực tiếp khi đang chạy ở chế độ khởi động trực tiếp.
  • Bất kỳ thư viện nào mà dịch vụ sử dụng cũng không được truy cập bộ lưu trữ được bảo vệ bằng thông tin xác thực cũng như không được gọi các thành phần không phải directBootAware khi đang chạy ở chế độ khởi động trực tiếp. Điều này có nghĩa là mọi thư viện mà ứng dụng sử dụng được gọi từ dịch vụ sẽ cần phải nhận biết khởi động trực tiếp hoặc ứng dụng sẽ cần kiểm tra xem ứng dụng có đang chạy ở chế độ khởi động trực tiếp hay không và không gọi chúng ở chế độ đó. Ví dụ: SDK Firebase hoạt động với khởi động trực tiếp (chúng có thể được đưa vào ứng dụng mà không làm hỏng ứng dụng ở chế độ khởi động trực tiếp), nhưng nhiều API Firebase không hỗ trợ được gọi ở chế độ khởi động trực tiếp.
  • Nếu ứng dụng đang sử dụng Application tùy chỉnh, Application cũng sẽ cần được nhận biết khởi động trực tiếp (không có quyền truy cập vào bộ lưu trữ được bảo vệ bằng thông tin xác thực ở chế độ khởi động trực tiếp).

Để biết hướng dẫn về cách gửi tin nhắn đến thiết bị ở chế độ khởi động trực tiếp, hãy xem Gửi tin nhắn hỗ trợ khởi động trực tiếp .