Firebase onMessageReceured không được gọi khi ứng dụng chạy nền


233

Tôi đang làm việc với Firebase và thử nghiệm gửi thông báo đến ứng dụng của tôi từ máy chủ của tôi trong khi ứng dụng ở chế độ nền. Thông báo được gửi thành công, nó thậm chí còn xuất hiện trên trung tâm thông báo của thiết bị, nhưng khi thông báo xuất hiện hoặc ngay cả khi tôi nhấp vào nó, phương thức onMessageReceured trong FCMessagingService của tôi sẽ không bao giờ được gọi.

Khi tôi kiểm tra điều này trong khi ứng dụng của tôi ở phía trước, phương thức onMessageReceured đã được gọi và mọi thứ đều hoạt động tốt. Sự cố xảy ra khi ứng dụng đang chạy ẩn.

Đây có phải là hành vi dự định, hoặc có cách nào tôi có thể khắc phục điều này?

Đây là FBMessagingService của tôi:

import android.util.Log;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

public class FBMessagingService extends FirebaseMessagingService {

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.i("PVL", "MESSAGE RECEIVED!!");
        if (remoteMessage.getNotification().getBody() != null) {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getNotification().getBody());
        } else {
            Log.i("PVL", "RECEIVED MESSAGE: " + remoteMessage.getData().get("message"));
        }
    }
}

Ngoài phần thân json, mã onTokenRefresh của bạn ở đâu? Bạn đã hoàn thành thiết lập Android ?
Kato

4
Bạn có ý nghĩa gì cơ thể json của thông báo? Ngoài ra, mã onTokenRefresh của tôi nằm trong dịch vụ FirebaseInstanceID của tôi.
Cyogenos

Bạn có thể gửi tải trọng mẫu bạn đang gửi không?
AL.


Bạn cũng có thể kiểm tra chủ đề này stackoverflow.com/questions/39046270/ từ
Md. Sajedul Karim

Câu trả lời:


144

Điều này hoạt động như dự định, tin nhắn thông báo được gửi đến cuộc gọi lại onMessageReceured của bạn chỉ khi ứng dụng của bạn ở phía trước. Nếu ứng dụng của bạn ở chế độ nền hoặc đóng thì thông báo thông báo sẽ được hiển thị trong trung tâm thông báo và mọi dữ liệu từ tin nhắn đó sẽ được chuyển đến mục đích được đưa ra do người dùng nhấn vào thông báo.

Bạn có thể chỉ định một click_action để cho biết ý định sẽ được đưa ra khi thông báo được gõ bởi người dùng. Hoạt động chính được sử dụng nếu không có click_action được chỉ định.

Khi ý định được đưa ra, bạn có thể sử dụng

getIntent().getExtras();

để truy xuất Tập hợp sẽ bao gồm mọi dữ liệu được gửi cùng với thông báo thông báo.

Để biết thêm về tin nhắn thông báo xem tài liệu .


6
Có cách nào để cài đặt click_actionkhi tôi đang sử dụng Bảng điều khiển thông báo Firebase không?
Nii Laryea

6
ok, nhưng nếu ứng dụng bị giết (không có tiền cảnh hoặc hậu cảnh) thì sao?
michalu

3
Nhưng làm thế nào để vô hiệu hóa thông báo loại bỏ người dùng? Bởi vì nếu người dùng loại bỏ nó, điều đó có nghĩa là tất cả dữ liệu sẽ bị bỏ qua ... Phải không?
Aleksey Timoshchenko

4
Chính xác! Vì vậy, khi gửi tin nhắn thông báo tới Android, dữ liệu đi kèm phải là dữ liệu nâng cao trải nghiệm thông báo. Không nên là dữ liệu quan trọng của ứng dụng, hãy sử dụng thông điệp dữ liệu cho dữ liệu mà ứng dụng cần ngay cả khi người dùng bỏ qua thông báo.
Arthur Thompson

3
Đây không phải là hoàn toàn chính xác. Nếu tin nhắn chỉ chứa dữ liệu và không phải là trọng tải thông báo, tin nhắn sẽ LUÔN được gửi đến onMessageReceive, nếu ứng dụng có ở phía trước hay không.
JacksOnF1re

125

Xóanotification hoàn toàn trường khỏi yêu cầu máy chủ của bạn. Chỉdata gửi và xử lý nó onMessageReceived()nếu không bạn onMessageReceived()sẽ không được kích hoạt khi ứng dụng ở chế độ nền hoặc bị tắt.

Đừng quên bao gồm "priority": "high"trường trong yêu cầu thông báo của bạn. Theo tài liệu: tin nhắn dữ liệu được gửi với mức độ ưu tiên bình thường, do đó chúng sẽ không đến ngay lập tức; nó cũng có thể là vấn đề

Đây là những gì tôi đang gửi từ máy chủ

{
  "data":{
    "id": 1,
    "missedRequests": 5
    "addAnyDataHere": 123
  },
  "to": "fhiT7evmZk8:APA91bFJq7Tkly4BtLRXdYvqHno2vHCRkzpJT8QZy0TlIGs......",
  "priority": "high"
}

Vì vậy, bạn có thể nhận dữ liệu của mình onMessageReceived(RemoteMessage message)như thế này .... giả sử tôi phải lấy id

Object obj = message.getData().get("id");
        if (obj != null) {
            int id = Integer.valueOf(obj.toString());
        }

9
Tôi thấy rằng nếu tôi chỉ gửi tin nhắn dữ liệu, thì Ứng dụng bị xóa khỏi trình quản lý tác vụ sẽ không thể nhận được thông báo. Đây có phải là hành vi dự định không?
Bohhjot Singh

2
Đây là giải pháp để tôi nhận được tin nhắn trong nền!
Ray Hulha

5
Trong Oreo khi ứng dụng bị tắt, onMessageReceured không được gọi. tôi chỉ có tải trọng với dữ liệu mà thôi bạn có bản cập nhật nào không?
Samir Mangroliya

2
Hoạt động như một lá bùa!
ssk

3
Yêu bạn rất nhiều vì câu trả lời này: p
Ahmad Arslan

63

phương thức này handIntent () đã bị khấu hao, do đó việc xử lý thông báo có thể được thực hiện như dưới đây:

  1. Trạng thái tiền cảnh: Nhấp chuột vào thông báo sẽ chuyển đến hoạt động của Ý định đang chờ xử lý mà bạn đang cung cấp trong khi tạo thông báo theo ngữ pháp vì nó thường được tạo với tải trọng dữ liệu của thông báo.

  2. Bối cảnh / Trạng thái bị giết - Tại đây, hệ thống tự tạo thông báo dựa trên tải thông báo và nhấp vào thông báo đó sẽ đưa bạn đến hoạt động của trình khởi chạy ứng dụng nơi bạn có thể dễ dàng tìm nạp dữ liệu Ý định trong bất kỳ phương pháp vòng đời nào.


Cảm ơn bạn!!! Tôi đã mất vài ngày về vấn đề này và điều này đã cứu tôi.
Igor Janković

thực sự là giải pháp hoàn hảo!
EduXavier

4
Tôi đang xử lý logic hiển thị thông báo trong handleIntent (Mục đích ý định), tuy nhiên khi ứng dụng ở chế độ nền, 2 thông báo được hiển thị, một thông báo mà tôi đã tạo và một mặc định chứa toàn bộ tin nhắn từ thông báo.
Joyson

5
Tuyệt vời, nhưng tôi không thấy sử dụng OnMessageReceivedtrong trường hợp này!?
Alaa AbuZarifa

8
Tôi đang gặp com.google.firebase: căn cứ hỏa lực-tin nhắn: 11.6.2 & handleIntent là thức now.Check stackoverflow.com/questions/47308155/...
Ronak Poriya

31

Dưới đây là các khái niệm rõ ràng hơn về thông điệp firebase. Tôi tìm thấy nó từ nhóm hỗ trợ của họ.

Firebase có ba loại thông báo :

Tin nhắn thông báo : Tin nhắn thông báo hoạt động trên nền hoặc tiền cảnh. Khi ứng dụng ở chế độ nền, thông báo Thông báo sẽ được gửi đến khay hệ thống. Nếu ứng dụng ở phía trước, tin nhắn được xử lý bởi onMessageReceived()hoặc didReceiveRemoteNotificationgọi lại. Đây là những gì cơ bản được gọi là hiển thị tin nhắn.

Tin nhắn dữ liệu : Trên nền tảng Android, tin nhắn dữ liệu có thể hoạt động trên nền và tiền cảnh. Thông báo dữ liệu sẽ được xử lý bởi onMessageReceured (). Một lưu ý cụ thể về nền tảng ở đây sẽ là: Trên Android, tải trọng dữ liệu có thể được truy xuất trong Mục đích được sử dụng để khởi chạy hoạt động của bạn. Để xây dựng, nếu bạn có "click_action":"launch_Activity_1", bạn có thể lấy thông qua ý định này getIntent()từ chỉ Activity_1.

Tin nhắn có cả tải thông báo và dữ liệu : Khi ở chế độ nền, ứng dụng sẽ nhận được tải thông báo trong khay thông báo và chỉ xử lý tải trọng dữ liệu khi người dùng chạm vào thông báo. Khi ở phía trước, ứng dụng của bạn sẽ nhận được một đối tượng tin nhắn với cả hai tải trọng có sẵn. Thứ hai, tham số click_action thường được sử dụng trong tải trọng thông báo và không phải trong tải trọng dữ liệu. Nếu được sử dụng bên trong tải trọng dữ liệu, tham số này sẽ được coi là cặp khóa-giá trị tùy chỉnh và do đó bạn sẽ cần triển khai logic tùy chỉnh để nó hoạt động như dự định.

Ngoài ra, tôi khuyên bạn nên sử dụng phương thức onMessageReceured (xem Thông báo dữ liệu) để trích xuất gói dữ liệu. Từ logic của bạn, tôi đã kiểm tra đối tượng gói và không tìm thấy nội dung dữ liệu dự kiến. Dưới đây là một tham chiếu đến một trường hợp tương tự có thể cung cấp rõ ràng hơn.

Từ phía máy chủ, thông báo firebase nên dưới định dạng :

Phía máy chủ nên gửi đối tượng "thông báo" . Thiếu đối tượng "thông báo" trong việc tôi TargetActivitykhông nhận được tin nhắn getIntent().

Định dạng tin nhắn chính xác được đưa ra dưới đây:

{
 "data": {
  "body": "here is body",
  "title": "Title"
 },
"notification": {
  "body": "here is body",
  "title": "Title",
  "click_action": "YOUR_ACTION"
 },
 "to": "ffEseX6vwcM:APA91bF8m7wOF MY FCM ID 07j1aPUb"
}

Dưới đây là các khái niệm rõ ràng hơn về thông điệp firebase. Tôi tìm thấy nó từ nhóm hỗ trợ của họ.

Để biết thêm thông tin truy cập chủ đề này của tôi và chủ đề này


3
đáng nói là "tin nhắn dữ liệu" sẽ không được nhận nếu thiết bị ở chế độ ngủ gật sâu (được giới thiệu trong Android 7.0). hãy cẩn thận với những cái đó
Sameer J

30

Tôi đã từng gặp vấn đề tương tự. Việc sử dụng 'thông điệp dữ liệu' sẽ dễ dàng hơn thay vì 'thông báo'. Thông báo dữ liệu luôn tải lớp onMessageReceured.

Trong lớp đó, bạn có thể tạo thông báo của riêng mình với trình thông báo.

Thí dụ:

 @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        sendNotification(remoteMessage.getData().get("title"),remoteMessage.getData().get("body"));
    }

    private void sendNotification(String messageTitle,String messageBody) {
        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_UPDATE_CURRENT);

        long[] pattern = {500,500,500,500,500};

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

        NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_name)
                .setContentTitle(messageTitle)
                .setContentText(messageBody)
                .setAutoCancel(true)
                .setVibrate(pattern)
                .setLights(Color.BLUE,1,1)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

7
Cảm ơn .. Tôi đã thay đổi mã máy chủ của mình và sử dụng "dữ liệu" thay vì "thông báo" và bây giờ nó hoạt động hoàn hảo,
Mahesh Kavathiya

5
@Koot nó chỉ hoạt động nếu ứng dụng ở nền trước chứ không phải nếu nó ở chế độ nền. bạn có thể giúp tôi kích hoạt sự kiện này trong cả hai trường hợp không ??
Anant Shah

@AnantShah POST của bạn đến máy chủ Firebase trông như thế nào?
Koot

3
Thực tế có ba trường hợp có thể ở đây. 1) Ứng dụng ở tiền cảnh. 2) Ứng dụng trong nền. 3) Ứng dụng không chạy. Như bạn nói, tin nhắn 'dữ liệu' sẽ được nhận trong hai trường hợp đầu tiên, nhưng không phải trong trường hợp thứ ba, khi ứng dụng không chạy. Để phục vụ cho cả ba trường hợp, bạn cần đặt trường 'thông báo' trong tin nhắn. (Cũng là một ý tưởng hay nếu bạn muốn hỗ trợ iOS cũng như máy khách Android)
Steve Moseley

1
Ngay cả trong ứng dụng không chạy, tôi vẫn nhận được một tin nhắn từ máy chủ về chức năng được nhận. Tôi đồng ý với bạn rằng tốt hơn là sử dụng 'thông báo' nếu bạn cũng muốn hỗ trợ ios.
Koot

21

Theo tài liệu Nhắn tin trên đám mây của Firebase - Nếu Hoạt động ở phía trước thì onMessageReceured sẽ được gọi. Nếu Hoạt động ở chế độ nền hoặc đóng thì thông báo thông báo sẽ được hiển thị trong trung tâm thông báo cho hoạt động của trình khởi chạy ứng dụng. Bạn có thể gọi hoạt động tùy chỉnh của mình khi nhấp vào thông báo nếu ứng dụng của bạn ở chế độ nền bằng cách gọi api dịch vụ nghỉ ngơi để nhắn tin cho căn cứ hỏa lực như:

URL- https://fcm.googleapis.com/fcm/send

Kiểu phương thức- POST

Header- Content-Type:application/json
Authorization:key=your api key

Thân / Tải trọng:

{ "notification": {
    "title": "Your Title",
    "text": "Your Text",
     "click_action": "OPEN_ACTIVITY_1" // should match to your intent filter
  },
    "data": {
    "keyname": "any value " //you can get this data as extras in your activity and this data is optional
    },
  "to" : "to_id(firebase refreshedToken)"
} 

Và với điều này trong ứng dụng của bạn, bạn có thể thêm mã bên dưới vào hoạt động của mình để được gọi:

<intent-filter>
                <action android:name="OPEN_ACTIVITY_1" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>

Tôi sẽ tạo ra ý định ở đâu và để nó mở một hoạt động cụ thể? Tôi biết điều này đăng ký ý định OPEN_ACTIVITY_1 trong bảng kê khai, nhưng tôi thực sự gọi nó ở đâu?
Cyogenos


Chúng ta có nên gọi một hoạt động từ các bộ lọc ý định? Hoặc bắt đầu bằng tay trong onMessageReceived?
CoolMind

14

phương thức onMessageReceured (RemoteMessage remoteMessage) được gọi dựa trên các trường hợp sau.

  • Phản hồi FCM Với khối thông báodữ liệu :
{
  
"to": "device token list",
  "notification": {
    "body": "Body of Your Notification",
    "title": "Title of Your Notification"
  },
  "data": {
    "body": "Body of Your Notification in Data",
    "title": "Title of Your Notification in Title",
    "key_1": "Value for key_1",
    "image_url": "www.abc.com/xyz.jpeg",
    "key_2": "Value for key_2"
  }
}
  1. Ứng dụng trong Tiền cảnh:

onMessageReceured (RemoteMessage remoteMessage) được gọi, hiển thị LargeIcon và BigPicture trong thanh thông báo. Chúng tôi có thể đọc nội dung từ cả khối thông báodữ liệu

  1. Ứng dụng trong nền:

onMessageReceured (RemoteMessage remoteMessage) không được gọi, khay hệ thống sẽ nhận thông báo và đọc nội dung và tiêu đề từ khối thông báo và hiển thị thông báo và tiêu đề mặc định trong thanh thông báo.

  • Phản hồi FCM Chỉ với khối dữ liệu :

Trong trường hợp này, xóa các khối thông báo khỏi json

{
  
"to": "device token list",
  "data": {
    "body": "Body of Your Notification in Data",
    "title": "Title of Your Notification in Title",
    "key_1": "Value for key_1",
    "image_url": "www.abc.com/xyz.jpeg",
    "key_2": "Value for key_2"
  }
}

Giải pháp cho việc gọi onMessageReceured ()

  1. Ứng dụng trong Tiền cảnh:

onMessageReceured (RemoteMessage remoteMessage) được gọi, hiển thị LargeIcon và BigPicture trong thanh thông báo. Chúng tôi có thể đọc nội dung từ cả khối thông báodữ liệu

  1. Ứng dụng trong nền:

onMessageReceured (RemoteMessage remoteMessage) được gọi, khay hệ thống sẽ không nhận được thông báo vì khóa thông báo không có trong phản hồi. Hiển thị LargeIcon và BigPicture trên thanh thông báo

 private void sendNotification(Bitmap bitmap,  String title, String 
    message, PendingIntent resultPendingIntent) {

    NotificationCompat.BigPictureStyle style = new NotificationCompat.BigPictureStyle();
    style.bigPicture(bitmap);

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

    NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
    String NOTIFICATION_CHANNEL_ID = mContext.getString(R.string.default_notification_channel_id);

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        NotificationChannel notificationChannel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, "channel_name", NotificationManager.IMPORTANCE_HIGH);

        notificationManager.createNotificationChannel(notificationChannel);
    }
    Bitmap iconLarge = BitmapFactory.decodeResource(mContext.getResources(),
            R.drawable.mdmlogo);
    NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(mContext, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.drawable.mdmlogo)
            .setContentTitle(title)
            .setAutoCancel(true)
            .setSound(defaultSound)
            .setContentText(message)
            .setContentIntent(resultPendingIntent)
            .setStyle(style)
            .setLargeIcon(iconLarge)
            .setWhen(System.currentTimeMillis())
            .setPriority(Notification.PRIORITY_MAX)
            .setChannelId(NOTIFICATION_CHANNEL_ID);


    notificationManager.notify(1, notificationBuilder.build());


}

Liên kết tham khảo:

https://firebase.google.com/docs/cloud-messaging/android/receive


Phần quan trọng nhất đối với những người gặp vấn đề về nền tảng là xóa thuộc tính "thông báo" khỏi JSON được gửi bởi máy chủ. Điều này giải quyết vấn đề. Cảm ơn rất nhiều.
Ramy M. Mousa

13

Tôi đã có cùng một vấn đề. Nếu ứng dụng là tiền cảnh - nó sẽ kích hoạt dịch vụ nền của tôi nơi tôi có thể cập nhật cơ sở dữ liệu của mình dựa trên loại thông báo. Nhưng, ứng dụng đi vào nền - dịch vụ thông báo mặc định sẽ được chăm sóc để hiển thị thông báo cho người dùng.

Đây là giải pháp của tôi để xác định ứng dụng trong nền và kích hoạt dịch vụ nền của bạn,

public class FirebaseBackgroundService extends WakefulBroadcastReceiver {

  private static final String TAG = "FirebaseService";

  @Override
  public void onReceive(Context context, Intent intent) {
    Log.d(TAG, "I'm in!!!");

    if (intent.getExtras() != null) {
      for (String key : intent.getExtras().keySet()) {
        Object value = intent.getExtras().get(key);
        Log.e("FirebaseDataReceiver", "Key: " + key + " Value: " + value);
        if(key.equalsIgnoreCase("gcm.notification.body") && value != null) {
          Bundle bundle = new Bundle();
          Intent backgroundIntent = new Intent(context, BackgroundSyncJobService.class);
          bundle.putString("push_message", value + "");
          backgroundIntent.putExtras(bundle);
          context.startService(backgroundIntent);
        }
      }
    }
  }
}

Trong tệp kê khai

<receiver android:exported="true" android:name=".FirebaseBackgroundService" android:permission="com.google.android.c2dm.permission.SEND">
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </receiver>

Đã thử nghiệm giải pháp này trong phiên bản Android 8.0 mới nhất. Cảm ơn


Ai muốn sử dụng lớp FirebaseBackgroundService này ?? @Nagendra Badiganti

nơi sử dụng mã này lớp công khai FirebaseBackgroundService mở rộng WakefulBroadcastReceiver @Nagendra Badiganti

tạo một lớp dịch vụ trong gói của bạn và đăng ký trong tệp kê khai của bạn. Đảm bảo rằng bạn có bộ lọc cho thông báo của mình. Vì dịch vụ kích hoạt cho mọi thông báo GCM.
Nagendra Badiganti

firebase.google.com/docs/cloud-messaging/android/ Ấn tôi đang theo liên kết này, tôi cần thêm lớp này để nhận thông báo. chỉ gửi tin nhắn từ firebase tin nhắn đầu tiên .. nó nói đã hoàn thành nhưng không nhận được thông báo @Nagendra Badiganti

1
WakefulBroadcastReceiverkhông được chấp nhận kể từ cấp API 26.1.0.
Minoru

12

Nếu ứng dụng ở chế độ nền hoặc không hoạt động (bị tắt) và bạn nhấp vào Thông báo , bạn nên kiểm tra tải trọng trong LaunchScreen (trong trường hợp màn hình khởi chạy của tôi là MainActivity.java).

Vì vậy, trong MainActivity.java trên onCreate hãy kiểm tra Extras :

    if (getIntent().getExtras() != null) {
        for (String key : getIntent().getExtras().keySet()) {
            Object value = getIntent().getExtras().get(key);
            Log.d("MainActivity: ", "Key: " + key + " Value: " + value);
        }
    }

Làm cách nào tôi có thể nhận được tiêu đề thông báo, nội dung và dữ liệu?
Md.Tarikul Hồi giáo

1
Cảm ơn, đây là câu trả lời. @ Md.Tarikul Hồi giáo sử dụng onMessageReceured () như đã đề cập trong câu hỏi này.
felixwcf

7

Ghi đè handleIntentPhương thức FirebaseMessageServicecông việc cho tôi.

đây là mã trong C # (Xamarin)

public override void HandleIntent(Intent intent)
{
    try
    {
        if (intent.Extras != null)
        {
            var builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            foreach (string key in intent.Extras.KeySet())
            {
                builder.AddData(key, intent.Extras.Get(key).ToString());
            }

            this.OnMessageReceived(builder.Build());
        }
        else
        {
            base.HandleIntent(intent);
        }
    }
    catch (Exception)
    {
        base.HandleIntent(intent);
    }
}

và đó là Mã trong Java

public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }

            onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}

xử lýIntent () là cuối cùng
Ettore

@Ettore Làm thế nào tôi có thể gọi hàm handleIntent?
Hiroto

Phương thức được gọi khi bạn nhận được thông báo từ Firebase, nhưng bạn không thể ghi đè vì phương thức được khai báo là cuối cùng. (Firebase 11.6.0)
Ettore

5

Theo mặc định, Hoạt động Trình khởi chạy trong ứng dụng của bạn sẽ được khởi chạy khi ứng dụng của bạn ở chế độ nền và bạn nhấp vào thông báo, nếu bạn có bất kỳ phần dữ liệu nào với thông báo của mình, bạn có thể xử lý nó trong cùng một hoạt động như sau,

if(getIntent().getExtras()! = null){
  //do your stuff
}else{
  //do that you normally do
}

Nếu tôi điều hướng từ mainActivity, làm thế nào điều hướng trở lại Hoạt động cụ thể sẽ hoạt động?
Mac_Play

@Uzair getIntent (). GetExtras () luôn luôn nhận được null, Bạn có giải pháp nào khác không? Khi ứng dụng đang chạy bacground, phương thức này không được gọi
user2025187 28/03/19

3

Nếu ứng dụng ở chế độ nền tảng Fire-base theo thông báo xử lý mặc định Nhưng nếu chúng tôi muốn thông báo tùy chỉnh của mình hơn thì chúng tôi phải thay đổi phía máy chủ, có trách nhiệm gửi dữ liệu tùy chỉnh của chúng tôi (tải trọng dữ liệu)

Xóa hoàn toàn tải thông báo khỏi yêu cầu máy chủ của bạn. Chỉ gửi Dữ liệu và xử lý nó trong onMessageReceured () nếu không, onMessageReceured của bạn sẽ không được kích hoạt khi ứng dụng ở chế độ nền hoặc bị tắt.

Bây giờ, định dạng mã phía máy chủ của bạn trông như thế nào,

{
  "collapse_key": "CHAT_MESSAGE_CONTACT",
  "data": {
    "loc_key": "CHAT_MESSAGE_CONTACT",
    "loc_args": ["John Doe", "Contact Exchange"],
    "text": "John Doe shared a contact in the group Contact Exchange",
    "custom": {
      "chat_id": 241233,
      "msg_id": 123
    },
    "badge": 1,
    "sound": "sound1.mp3",
    "mute": true
  }
}

LƯU Ý : xem dòng này trong mã
"văn bản" ở trên : "John Doe đã chia sẻ một liên hệ trong nhóm Liên hệ trao đổi" trong Tải trọng dữ liệu, bạn nên sử dụng tham số "văn bản" thay vì tham số "nội dung" hoặc "tin nhắn" để mô tả tin nhắn hoặc bất cứ điều gì bạn muốn sử dụng văn bản.

onMessageReceured ()

@Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        Log.e(TAG, "From: " + remoteMessage.getData().toString());

        if (remoteMessage == null)
            return;

        // Check if message contains a data payload.
        if (remoteMessage.getData().size() > 0) {
           /* Log.e(TAG, "Data Payload: " + remoteMessage.getData().toString());*/
            Log.e(TAG, "Data Payload: " + remoteMessage);

            try {

                Map<String, String> params = remoteMessage.getData();
                JSONObject json = new JSONObject(params);
                Log.e("JSON_OBJECT", json.toString());


                Log.e(TAG, "onMessageReceived: " + json.toString());

                handleDataMessage(json);
            } catch (Exception e) {
                Log.e(TAG, "Exception: " + e.getMessage());
            }
        }
    }

2

Chỉ cần gọi điều này trong Phương thức onCreate của MainActivity của bạn:

if (getIntent().getExtras() != null) {
           // Call your NotificationActivity here..
            Intent intent = new Intent(MainActivity.this, NotificationActivity.class);
            startActivity(intent);
        }

Nếu tôi điều hướng từ mainActivity, làm thế nào điều hướng trở lại Hoạt động cụ thể sẽ hoạt động?
Mac_Play

2

theo giải pháp từ t3h Exi tôi muốn đăng mã sạch ở đây. Chỉ cần đặt nó vào MyFirebaseMessagingService và mọi thứ đều hoạt động tốt nếu ứng dụng ở chế độ nền. Bạn cần ít nhất để biên dịch com.google.firebase: firebase-Messaging: 10.2.1

 @Override
public void handleIntent(Intent intent)
{
    try
    {
        if (intent.getExtras() != null)
        {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");

            for (String key : intent.getExtras().keySet())
            {
                builder.addData(key, intent.getExtras().get(key).toString());
            }



           onMessageReceived(builder.build());
        }
        else
        {
            super.handleIntent(intent);
        }
    }
    catch (Exception e)
    {
        super.handleIntent(intent);
    }
}

Tôi đang cố gắng thực hiện giải pháp của bạn, nhưng phương thức handleIntent () là cuối cùng trong phiên bản SDK của tôi (SDK 27), vì vậy tôi không thể ghi đè lên nó trong dịch vụ của mình ...
matdev

Có nhưng đó không phải là lỗi của tôi hoặc bất kỳ lý do nào để đưa ra -1 !!! Rất kiêu ngạo. Nó hoạt động cho đến firebase 11.4.2 sau đó google thay đổi nó (thực hiện phương thức này cuối cùng). Vì vậy, bây giờ bạn phải lập trình giải pháp của riêng bạn với thông báo.
Frank

Tôi đã không cho -1 nhưng là +1!
matdev

Bạn lưu công việc của tôi: P
amitabha2715

2

Thử cái này:

public void handleIntent(Intent intent) {
    try {
        if (intent.getExtras() != null) {
            RemoteMessage.Builder builder = new RemoteMessage.Builder("MyFirebaseMessagingService");
            for (String key : intent.getExtras().keySet()) {
            builder.addData(key, intent.getExtras().get(key).toString());
        }
            onMessageReceived(builder.build());
        } else {
            super.handleIntent(intent);
        }
    } catch (Exception e) {
        super.handleIntent(intent);
    }
}

handleIntent không còn được sử dụng trong firebase: 11.8.0 trở lên.
Shihab Uddin

1

Tôi đã gặp sự cố này (ứng dụng không muốn mở khi nhấp vào thông báo nếu ứng dụng ở chế độ nền hoặc đóng) và sự cố không hợp lệ click_actiontrong phần thông báo, hãy thử xóa hoặc thay đổi thành thông báo hợp lệ.


1

Điểm đáng chú ý là bạn phải sử dụng thông điệp dữ liệu - chỉ khóa dữ liệu - để có được trình xử lý onMessageReceured được gọi ngay cả khi ứng dụng ở chế độ nền. Bạn không nên có bất kỳ khóa thông báo thông báo nào khác trong tải trọng của mình, nếu không trình xử lý sẽ không được kích hoạt nếu ứng dụng ở chế độ nền.

Nó được đề cập (nhưng không quá nhấn mạnh trong tài liệu FCM) ở đây:

https://firebase.google.com/docs/cloud-messaging/concept-options#notifying_and_data_messages

Sử dụng máy chủ ứng dụng và API máy chủ FCM của bạn: Chỉ đặt khóa dữ liệu . Có thể đóng mở hoặc không đóng mở.


1

Phần cuối tôi đang làm việc là sử dụng tin nhắn Thông báo chứ không phải tin nhắn Dữ liệu. Vì vậy, sau khi đọc tất cả các câu trả lời, tôi đã cố gắng lấy các phần bổ sung từ gói ý định đến với hoạt động đã khởi chạy. Nhưng bất kể khóa nào tôi đã cố lấy từ đó getIntent().getExtras();, giá trị luôn luôn là null.

Tuy nhiên, cuối cùng tôi đã tìm được cách gửi dữ liệu bằng tin nhắn Thông báo và lấy nó từ ý định.

Chìa khóa ở đây là thêm tải trọng dữ liệu vào thông báo Thông báo.

Thí dụ:

{
    "data": {
        "message": "message_body",
        "title": "message_title"
    },
    "notification": {
        "body": "test body",
        "title": "test title"
    },
    "to": "E4An.."
}

Sau khi bạn làm điều này, bạn sẽ có thể nhận được thông tin của bạn theo cách này:

intent.getExtras().getString("title") sẽ là message_title

intent.getExtras().getString("message") sẽmessage_body

Tài liệu tham khảo


1

Nếu vấn đề của bạn liên quan đến việc hiển thị Big Image, tức là nếu bạn đang gửi thông báo đẩy với một hình ảnh từ bảng điều khiển firebase và nó chỉ hiển thị hình ảnh nếu ứng dụng ở phía trước. Giải pháp cho vấn đề này là gửi tin nhắn đẩy chỉ với trường dữ liệu. Một cái gì đó như thế này:

{ "data": { "image": "https://static.pexels.com/photos/4825/red-love-romantic-flowers.jpg", "message": "Firebase Push Message Using API" "AnotherActivity": "True" }, "to" : "device id Or Device token" }

bạn bị mất dấu phẩy trước "AnotherActivity". Android của tôi rung nhưng thực sự không có gì hiển thị (không văn bản, không hình ảnh, không đẩy).
jekaby

1

Khi nhận được tin nhắn và ứng dụng của bạn ở chế độ nền, thông báo sẽ được gửi đến mục đích bổ sung của hoạt động chính.

Bạn có thể kiểm tra giá trị bổ sung trong hàm oncreate () hoặc onresume () của hoạt động chính.

Bạn có thể kiểm tra các trường như dữ liệu, bảng, v.v. (trường được chỉ định trong thông báo)

ví dụ tôi đã gửi bằng cách sử dụng dữ liệu làm khóa

public void onResume(){
    super.onResume();
    if (getIntent().getStringExtra("data")!=null){
            fromnotification=true;
            Intent i = new Intent(MainActivity.this, Activity2.class);
            i.putExtra("notification","notification");
            startActivity(i);
        }

}

0

Tôi đã có cùng một vấn đề và đã đào sâu thêm về vấn đề này. Khi ứng dụng ở chế độ nền, một thông báo thông báo sẽ được gửi đến khay hệ thống, NHƯNG một tin nhắn dữ liệu được gửi tới onMessageReceived()
Xem https://firebase.google.com/docs/cloud-messaging/downstream#monitor-token-generation_3
https://github.com/firebase/quickstart-android/blob/master/messaging/app/src/main/java/com/google/firebase/quickstart/fcm/MyFirebaseMessagingService.java

Để đảm bảo rằng thư bạn đang gửi, các tài liệu nói: " Sử dụng API máy chủ ứng dụng và API máy chủ FCM của bạn: Chỉ đặt khóa dữ liệu. Có thể thu gọn hoặc không thu gọn được. "
Xem https://firebase.google.com/ tài liệu / nhắn tin trên đám mây / tùy chọn khái niệm # notify_and_data_messages


0

Có hai loại tin nhắn: tin nhắn thông báo và tin nhắn dữ liệu. Nếu bạn chỉ gửi tin nhắn dữ liệu, đó là không có đối tượng thông báo trong chuỗi tin nhắn của bạn. Nó sẽ được gọi khi ứng dụng của bạn ở chế độ nền.


0

Kiểm tra câu trả lời của @Mahesh Kavathiya. Đối với trường hợp của tôi, trong mã máy chủ chỉ có như thế này:

{
"notification": {
  "body": "here is body",
  "title": "Title",
 },
 "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
}

Bạn cần thay đổi thành:

{
 "data": {
  "body": "here is body",
  "title": "Title",
  "click_action": "YOUR_ACTION"
 },
"notification": {
  "body": "here is body",
  "title": "Title"
 },
 "to": "sdfjsdfonsdofoiewj9230idsjkfmnkdsfm"
}

Sau đó, trong trường hợp ứng dụng trong Nền, mục đích hoạt động mặc định thêm sẽ nhận được "dữ liệu"

Chúc may mắn!


-1

Chỉ cần ghi đè phương thức OnCreate của FirebaseMessagingService. Nó được gọi khi ứng dụng của bạn ở chế độ nền:

public override void OnCreate()
{
    // your code
    base.OnCreate();
}

Câu trả lời này có thể hữu ích hơn nếu bạn có thể thêm một lời giải thích và liên kết đến một số tài liệu. Bạn có thể vui lòng cho chúng tôi biết làm thế nào điều này được cho là để giúp đỡ?
kilokahn

@kilokahn Bạn có thể giải thích cho tôi những gì bạn không hiểu? phương pháp được chỉ định phải được chèn vào mã là một phần của câu hỏi và trả lời đầy đủ câu hỏi. Mã này là dành cho Xamarin, nhưng bạn chỉ cần chuyển đổi trong java.
Renzo Ciot ngày

AFAIK Tài liệu chính thức ( firebase.google.com/docs/cloud-messaging/android/client ) không nói về việc ghi đè OnCreate trong dịch vụ mở rộng FirebaseMessagingService - nếu bạn có quyền truy cập vào tài liệu đó, có lẽ bạn có thể chia sẻ liên kết không? Ngoài ra, từ câu trả lời của bạn, không rõ cách ghi đè onCreate giải quyết vấn đề onMessageReceured không được gọi khi nhấp vào thông báo - do đó yêu cầu thêm thông tin.
kilokahn

Tài liệu này không đề cập đến việc ghi đè phương thức OnCreate, nhưng nó hoạt động vì tôi đang sử dụng nó trong sản xuất. Mã mà bạn muốn chèn vào phương thức onMessageReceured và rõ ràng phục vụ để thực hiện một số thao tác nền có thể được thực hiện trên OnCreate.
Renzo Ciot ngày

Trong trường hợp đó, giải thích về thực tế rằng nó bằng cách nào đó có hiệu quả với bạn có thể chứng minh hữu ích hơn là chỉ liệt kê giải pháp. Ngoài ra, hành vi không có giấy tờ có khả năng tự ý dừng hoạt động với các bản cập nhật và ai đó sử dụng chúng phải được chuẩn bị để làm lại mã của họ khi có.
Tuyên

-1

2 loại của căn cứ hỏa lực đẩy thông báo:

1- Thông báo thông báo (Tin nhắn hiển thị) -> - 1.1 Nếu bạn chọn biến thể này, HĐH sẽ tự tạo thông báo nếu ứng dụng ở chế độ Nền và sẽ truyền dữ liệu trong intent. Sau đó, khách hàng sẽ xử lý dữ liệu này.

- 1.2 Nếu ứng dụng trong Foreground sau đó thông báo nó sẽ được nhận qua callback-functiontrong FirebaseMessagingServicevà nó tùy thuộc vào khách hàng để xử lý nó.

2- Tin nhắn dữ liệu (tối đa 4k dữ liệu) -> Những tin nhắn này được sử dụng để chỉ gửi dữ liệu đến máy khách (âm thầm) và tùy thuộc vào ứng dụng khách để xử lý nó cho cả hai trường hợp nền / tiền cảnh thông qua chức năng gọi lại trong FirebaseMessagingService

Đây là theo tài liệu chính thức: https://firebase.google.com/docs/cloud-messaging/concept-options

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.