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 / nền của ứng dụng nhận. Nếu bạn muốn cận cảnh ứng dụng để nhận tin nhắn thông báo hoặc thông điệp dữ liệu, bạn sẽ cần phải viết mã để xử lý các onMessageReceived gọi lại. Để giải thích về sự khác biệt giữa thông báo và dữ liệu bài viết, thấy tin nhắn loại .

Xử lý tin nhắn

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

  • Thư thông báo giao khi ứng dụng của bạn ở chế độ nền. Trong trường hợp này, thông báo được chuyển đến khay hệ thống của thiết bị. 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.

  • Tin nhắn với cả hai thông báo và tải trọng dữ liệu, khi nhận được ở 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ị và tải trọng dữ liệu được phân phối ngoài mục đích của 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
Tiểu sử 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, xem Thông báo và dữ liệu thông điệp .

Chỉnh sửa tệp kê khai ứng dụng

Để sử dụng FirebaseMessagingService , bạn cần phải thêm những điều sau đây trong manifest ứng dụng của bạn:

<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 các dòng bên trong application thẻ để thiết lập các biểu tượng mặc định tùy chỉnh và màu sắc 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ừ các nhà soạn nhạc Notifications .
  • 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ừ các nhà soạn nhạc Notifications .
  • Bất kỳ thông báo 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 thông báo, thì Android sẽ hiển thị biểu tượng ứng dụng được hiển thị bằng màu trắng.

override onMessageReceived

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

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

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}")

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

override 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 tin nhắn (> 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 nó 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 một callback để FirebaseMessagingService.onDeletedMessages() Khi dụ ứng dụng nhận callback này, cần thực hiện đồng bộ đầy đủ với máy chủ ứng dụng của bạn. Nếu bạn chưa gửi một thông điệp tới các ứ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 một ứ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 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 được gửi đến khay hệ thống của thiết bị và tải trọng dữ liệu được phân phối ngoài mục đích của Hoạt động trình khởi chạy của bạn.

Đối với cái nhìn sâu sắc vào giao thông điệp tới ứng dụng của bạn, vui lòng xem bảng điều khiển báo cáo FCM , trong đó ghi rõ số lượng tin nhắn đã gửi và mở trên các thiết bị của Apple và Android, cùng với dữ liệu cho "ấn tượng" (thông báo nhìn thấy bởi người sử dụng) cho các ứng dụng Android.

Ứng dụng bị hạn chế trong nền (Android P hoặc mới hơn)

FCM có thể không mang lại thông điệp cho các ứng dụng đã được đưa vào hạn chế nền bởi người sử dụng (ví dụ như thông qua: Setting -> Ứng dụng và Thông báo -> [appname] -> Pin). Sau khi ứng dụng của bạn được xóa khỏi giới hạn nền, các tin nhắn mới đến ứng dụng sẽ được gửi như trước. Để ngăn chặn thư đã bị mất và các tác động hạn chế nền khác, hãy chắc chắn để tránh những hành vi xấu được liệt kê bởi vitals Android nỗ lực. Những hành vi này có thể dẫn đến việc thiết bị Android đề xuất với người dùng rằng ứng dụng của bạn bị hạn chế trong nền. Ứng dụng của bạn có thể kiểm tra nếu nó là nền hạn chế sử dụng: isBackgroundRestricted () .

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 các ứng dụng ngay cả trước khi thiết bị được mở khóa có thể cho phép ứng dụng Android nhận tin nhắn khi thiết bị ở chế độ khởi động trực tiếp. Ví dụ: bạn có thể muốn người dùng ứng dụng của mình nhận được thông báo báo thức ngay cả trên một thiết bị bị khóa.

Khi xây dựng ra trường hợp sử dụng này, quan sát chung thực hành tốt nhất và hạn chế đối với chế độ khởi động trực tiếp . Đó là đặc biệt quan trọng để xem xét khả năng hiển thị các thông điệp khởi động kích hoạt 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 thông báo 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 cho chế độ khởi động trực tiếp.
  • Thiết bị phải được cài đặt phiên bản gần đây của dịch vụ Google Play (19.0.54 trở lên).
  • Các ứng dụng phải được sử dụng FCM SDK ( com.google.firebase:firebase-messaging ) để nhận tin nhắn FCM.

Bật 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. Tận dụng của ứng dụng FirebaseMessagingService khởi động trực tiếp nhận thức được bằng cách thêm android:directBootAware="true" thuộc tính trong biểu hiện ứ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 đây FirebaseMessagingService có thể chạy trong 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 vào bộ nhớ đượ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ụ này không nên cố gắng để các thành phần sử dụng, chẳng hạn như Activities , BroadcastReceivers , hoặc khác Services không được đánh dấu là khởi động trực tiếp nhận thức được khi 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 vào bộ nhớ đượ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 non-directBootAware khi đang chạy ở chế độ khởi động trực tiếp. Điều này có nghĩa là bất kỳ thư viện nào 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 nó 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 tính năng khởi động trực tiếp (chúng có thể được đưa vào ứng dụng mà không làm ứng dụng gặp sự cố ở 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 một tùy chỉnh Application , các Application cũng sẽ cần phải được khởi động trực tiếp nhận thức được (không truy cập để lưu trữ được bảo vệ chứng chỉ trong chế độ khởi động trực tiếp).

Để có hướng dẫn về việc gửi thư đến các thiết bị trong chế độ khởi động trực tiếp, xem Gửi thông điệp khởi động cho phép trực tiếp .