Cách xử lý thông báo khi ứng dụng chạy nền trong Firebase


425

Đây là bảng kê khai của tôi

    <service android:name=".fcm.PshycoFirebaseMessagingServices">
        <intent-filter>
            <action android:name="com.google.firebase.MESSAGING_EVENT" />
        </intent-filter>
    </service>

    <service android:name=".fcm.PshycoFirebaseInstanceIDService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

Khi ứng dụng ở chế độ nền và thông báo đến thì thông báo mặc định sẽ đến và không chạy mã của tôi onMessageReceived.

Đây là onMessageReceivedmã của tôi . Điều này gọi nếu ứng dụng của tôi đang chạy trên nền trước, không phải khi ứng dụng ở chế độ nền. Làm thế nào để chạy mã này khi ứng dụng ở chế độ nền?

// [START receive_message]
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    // TODO(developer): Handle FCM messages here.
    // If the application is in the foreground handle both data and notification messages here.
    // 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.
    data = remoteMessage.getData();
    String title = remoteMessage.getNotification().getTitle();
    String message = remoteMessage.getNotification().getBody();
    String imageUrl = (String) data.get("image");
    String action = (String) data.get("action");
    Log.i(TAG, "onMessageReceived: title : "+title);
    Log.i(TAG, "onMessageReceived: message : "+message);
    Log.i(TAG, "onMessageReceived: imageUrl : "+imageUrl);
    Log.i(TAG, "onMessageReceived: action : "+action);

    if (imageUrl == null) {
        sendNotification(title,message,action);
    } else {
        new BigPictureNotification(this,title,message,imageUrl,action);
    }
}
// [END receive_message]

1
Nó được viết trong mẫu ghi đè của onMessageReceured () , dòng bình luận thứ hai nói Not getting messages here? See why this may be: goo.gl/39bRNJ . Giải pháp, giống như các câu trả lời dưới đây, có thể được tìm thấy trong tài liệu trong Tin nhắn có cả tải thông báo và tải dữ liệu
fllo

Nói ngắn gọn, để đánh thức ứng dụng bị giết của bạn, bạn phải luôn gửi thông báo với đối tượng dữ liệu để gọi trình xử lý lớp dịch vụ thông báo của bạn FirebaseMessagingService.onMessageReceured () trong ứng dụng của bạn. Ngoài ra, hãy thử gửi nó không phải từ bảng điều khiển Firebase, nhưng để gửi nó từ một nơi khác (ví dụ: dịch vụ bài kiểm tra trực tuyến).
Zon

1
giải pháp này hiệu quả với tôi stackoverflow.com/a/44150822/6632278 hy vọng có ích. Chúc may mắn
Tony Barajas

cái gì ".fcm." PshycoFirebaseMessagingService có trong bảng kê khai của bạn? Tôi không nhận được lỗi của lớp .. và không tìm thấy ở đâu là phần đầu tiên của tham số này.
Éder Rocha Bezerra

Câu trả lời:


660

1. Tại sao điều này xảy ra?

Có hai loại tin nhắn trong FCM (Firebase Cloud Messaging):

  1. Hiển thị tin nhắn : Những tin nhắn này chỉ kích hoạt cuộc onMessageReceived()gọi lại khi ứng dụng của bạn ở phía trước
  2. Tin nhắn dữ liệu : Tin nhắn luận án kích hoạt cuộc onMessageReceived()gọi lại ngay cả khi ứng dụng của bạn ở nền trước / nền / bị giết

LƯU Ý: Nhóm Firebase chưa phát triển giao diện người dùng để gửi data-messagesđến thiết bị của bạn. Bạn nên sử dụng máy chủ của bạn để gửi loại này!



2. Làm thế nào để?

Để đạt được điều này, bạn phải thực hiện một POSTyêu cầu tới URL sau:

POST https://fcm.googleapis.com/fcm/send

Tiêu đề

  • Khóa : Content-Type , Giá trị: application/json
  • Khóa : Authorization , Giá trị: key=<your-server-key>

Cơ thể sử dụng chủ đề

{
    "to": "/topics/my_topic",
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     }
}

Hoặc nếu bạn muốn gửi nó đến các thiết bị cụ thể

{
    "data": {
        "my_custom_key": "my_custom_value",
        "my_custom_key2": true
     },
    "registration_ids": ["{device-token}","{device2-token}","{device3-token}"]
}


LƯU Ý: Đảm bảo bạn không thêm khóa JSON notification
LƯU Ý: Để lấy khóa máy chủ của bạn, bạn có thể tìm thấy nó trong bảng điều khiển firebase:Your project -> settings -> Project settings -> Cloud messaging -> Server Key

3. Làm thế nào để xử lý tin nhắn thông báo đẩy?

Đây là cách bạn xử lý tin nhắn nhận được:

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String myCustomKey = data.get("my_custom_key");

     // Manage data
}

4
Bạn có thể gửi các khóa "dữ liệu" và "thông báo" trong cùng một thông báo theo các bước này stackoverflow.com/a/42279260/2734021 :)
Daniel S.

15
Firebase team have not developed a UI to send data-messages to your devices, yet.Điều này đã thay đổi trong năm qua?
Hankrecords

2
@Antonio 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

63
Khi ứng dụng chạy nền onMessageReceivedkhông được gọi và đó là một vấn đề nghiêm trọng trong FCM !!! Ngoài ra xin vui lòng cập nhật câu trả lời của bạn.
Muhammad Babar

2
Vâng, đối với tôi, có vẻ như điều này xảy ra trên một số thiết bị Android. Đã dành hàng giờ để nghĩ rằng đó là một vấn đề thực tế, nhưng sau đó hóa ra không có gì. Vì vậy, lời khuyên của tôi là thử nghiệm nó trên các thiết bị khác nhau. Tôi thậm chí đã thử nghiệm nó trên máy ảo và tôi đã nhận được thông báo ngay cả khi ứng dụng bị giết. Tôi chỉ nói điều này để tiết kiệm thời gian của ai đó.
Tarek-Dev

158

Để tạo thư viện firebase, hãy gọi onMessageReceured () của bạn trong các trường hợp sau

  1. Ứng dụng ở phía trước
  2. Ứng dụng trong nền
  3. Ứng dụng đã bị giết

bạn không được đặt khóa JSON 'thông báo' trong yêu cầu của mình vào API firebase mà thay vào đó hãy sử dụng 'dữ liệu', xem bên dưới.

Thông báo sau sẽ không gọi onMessageReceured () của bạn khi ứng dụng của bạn ở chế độ nền hoặc bị giết và bạn không thể tùy chỉnh thông báo của mình.

{
   "to": "/topics/journal",
   "notification": {
   "title" : "title",
   "text": "data!",
   "icon": "ic_notification"
    }
}

nhưng thay vì sử dụng nó sẽ hoạt động

{
  "to": "/topics/dev_journal",
   "data": {
       "text":"text",
       "title":"",
       "line1":"Journal",
       "line2":"刊物"
   }
} 

Về cơ bản, thông báo được gửi trong đối số RemoteMessage cùng với đối tượng dữ liệu của bạn dưới dạng Bản đồ, sau đó bạn có thể quản lý thông báo trong onMessageReceured như trong đoạn trích ở đây

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();

     //you can get your text message here.
     String text= data.get("text");


     NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
        // optional, this is to make beautiful icon
             .setLargeIcon(BitmapFactory.decodeResource(
                                    getResources(), R.mipmap.ic_launcher))  
        .setSmallIcon(smallIcon)  //mandatory
      .......
    /*You can read more on notification here:
    https://developer.android.com/training/notify-user/build-notification.html
    https://www.youtube.com/watch?v=-iog_fmm6mE
    */
}

1
Có thể đạt được điều này từ bảng điều khiển Firebase?
koder

@koder, không may là bảng điều khiển Firebase không hỗ trợ điều này, bạn phải sử dụng công cụ để gửi yêu cầu tin nhắn bài đến firebase như curl hoặc postman (plugin chrome), api nhắn tin firebase vui lòng tham khảo tài liệu tại đây - firebase.google.com/docs / nhắn tin trên đám mây / http-server-ref
Teerakiat Chitawattanarat

1
đây là những gì tôi đã tìm kiếm trong hơn một ngày ..... Cảm ơn bạn rất nhiều nó hoạt động hoàn hảo. và sẽ tốt hơn nếu bạn giải thích làm thế nào các cặp vale chính trong dữ liệu có thể được xử lý trong onMessageReceured () để bắt đầu một hoạt động với các giá trị đó.
Boopathi T

25
Phương pháp của bạn hoạt động tốt khi ứng dụng ở chế độ nền, tuy nhiên khi ứng dụng bị tắt tôi không nhận được dữ liệu
Sanzhar

8
Vấn đề tương tự của Sanzhar. Nếu ứng dụng bị giết tôi không nhận được bất kỳ tin nhắn nào.
Giacomo M

104

Tôi cảm thấy như tất cả các phản hồi không đầy đủ nhưng tất cả chúng đều có thứ bạn cần xử lý thông báo có dữ liệu khi ứng dụng của bạn ở chế độ nền.

Thực hiện theo các bước sau và bạn sẽ có thể xử lý thông báo của mình khi ứng dụng của bạn ở chế độ nền.

1.Thêm một bộ lọc ý định như thế này:

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

đến một hoạt động mà bạn muốn xử lý dữ liệu thông báo.

  1. Gửi thông báo với định dạng tiếp theo:

    { 
     "notification" : {
            "click_action" : ".MainActivity", 
            "body" : "new Symulti update !", 
            "title" : "new Symulti update !", 
            "icon" : "ic_notif_symulti" }, 
     "data": { ... },
     "to" : "c9Vaa3ReGdk:APA91bH-AuXgg3lDN2WMcBrNhJZoFtYF9" }
    

Chìa khóa ở đây là thêm

"click_action" : ".MainActivity"

trong đó .MainActivity là hoạt động với bộ lọc ý định mà bạn đã thêm trong bước 1.

  1. Nhận thông tin "dữ liệu" từ thông báo trong onCreate của ".MainActivity":

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //get notification data info
        Bundle bundle = getIntent().getExtras();
        if (bundle != null) {
           //bundle must contain all info sent in "data" field of the notification
        }
    }
    

Và đó nên là tất cả những gì bạn cần làm. Tôi hi vọng nó sẽ giúp ích cho mọi người :)


5
Đây phải là câu trả lời chính xác. Không có tài liệu nào nói bất cứ điều gì về việc yêu cầu click_action VÀ Bộ lọc ý định để thông báo thậm chí hiển thị trong khay. Cả hai đều được yêu cầu.
airowe

@airowe họ không bắt buộc phải hiển thị thông báo
Luôn luôn được sử dụng vào

Tôi có cả khối dữ liệu và thông báo nhưng tôi không thể nhận dữ liệu trong hoạt động?
Ashwani

3
Tôi chỉ không hiểu làm thế nào đây không phải là câu trả lời được chấp nhận. Không có click_action, nó sẽ không hoạt động. Cứu lấy ngày của tôi
Arun Shankar

4
Cảm ơn sự hỗ trợ của bạn @ArunShankar. Câu trả lời được chấp nhận đã được trả lời 7 tháng trước khi tôi trả lời và đó là một câu trả lời hay. Tôi không thể hiểu tại sao không ai nói về click_action và đó là lý do tại sao tôi đã thêm câu trả lời của mình. Tôi rất vui vì nó rất hữu ích cho nhiều người và đó là điều quan trọng vào cuối ngày :)
Daniel S.

42

Theo tài liệu về căn cứ hỏa lực trong việc gửi xuôi dòng bằng cách sử dụng căn cứ hỏa lực , có 2 loại tải trọng:

  1. dữ liệu

    Tham số này chỉ định các cặp khóa-giá trị tùy chỉnh của tải trọng của thông báo. Ứng dụng khách có trách nhiệm xử lý tin nhắn dữ liệu. Thông điệp dữ liệu chỉ có các cặp khóa-giá trị tùy chỉnh.

  2. thông báo

    Tham số này chỉ định các cặp giá trị khóa-giá trị người dùng có thể nhìn thấy trước của tải trọng thông báo. FCM tự động hiển thị thông báo cho các thiết bị của người dùng cuối thay mặt cho ứng dụng khách. Thông báo thông báo có một bộ các khóa hiển thị được xác định trước.

Khi bạn ở trong nền trước, bạn có thể lấy dữ liệu bên trong FCM bằng cách sử dụng onMessageReceured () , bạn có thể lấy dữ liệu của mình từ tải trọng dữ liệu .

data = remoteMessage.getData();
String customData = (String) data.get("customData");

Khi bạn ở chế độ nền, FCM sẽ hiển thị thông báo trong khay hệ thống dựa trên thông tin từ tải trọng thông báo . Tiêu đề, tin nhắn và biểu tượng được sử dụng cho thông báo trên khay hệ thống được lấy từ tải trọng thông báo .

{
  "notification": {
        "title" : "title",
        "body"  : "body text",
        "icon"  : "ic_notification",
        "click_action" : "OPEN_ACTIVITY_1"
       }
}

Tải trọng thông báo này được sử dụng khi bạn muốn tự động hiển thị thông báo trên khay hệ thống khi ứng dụng của bạn ở chế độ nền. Để nhận dữ liệu thông báo khi ứng dụng của bạn ở chế độ nền, bạn nên thêm click_action bên trong tải trọng thông báo .

Nếu bạn muốn mở ứng dụng của mình và thực hiện một hành động cụ thể [trong khi được nền], hãy đặt click_action trong tải trọng thông báo và ánh xạ nó tới bộ lọc ý định trong Hoạt động bạn muốn khởi chạy. Ví dụ: đặt click_action thành OPEN_ACTIVITY_1 để kích hoạt bộ lọc ý định như sau:

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

Đặt bộ lọc ý định đó vào bảng kê khai của bạn, bên trong một trong các thẻ hoạt động của bạn. Khi bạn nhấp vào thông báo, nó sẽ mở ứng dụng và đi thẳng đến hoạt động mà bạn xác định trong click_action, trong trường hợp này là "OPEN_ACTIVTY_1". Và bên trong hoạt động đó bạn có thể lấy dữ liệu bằng cách:

Bundle b = getIntent().getExtras();
String someData = b.getString("someData");

Tôi đang sử dụng FCM cho ứng dụng Android của mình và sử dụng cả hai trọng tải. Dưới đây là ví dụ JSON tôi đang sử dụng:

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification",
    "click_action" : "OPEN_ACTIVITY_1"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}

"Đặt bộ lọc ý định đó vào bảng kê khai của bạn, bên trong thẻ ứng dụng." bạn không thể đặt bộ lọc ý định bên trong thẻ ứng dụng.
Kyrylo Zapylaiev

các JSON của bạn không hiển thị khóa click_action đi đâu.
Josh

Đây không phải là câu trả lời đúng? nhấp vào hành động n nó đi đâu? một số người nên bỏ phiếu hoặc làm sạch điều này
rana

1
@KyryloZapylaiev Tôi chỉ sửa và cập nhật câu trả lời: "Đặt bộ lọc ý định đó vào bảng kê khai của bạn, bên trong một trong các thẻ hoạt động của bạn".
Dika

1
@Josh cập nhật và định dạng. bạn có thể kiểm tra lại
Dika

32

Theo tài liệu

Xử lý tin nhắn trong ứng dụng chạy nền

Khi ứng dụng của bạn ở chế độ nền, Android sẽ chuyển các thông báo thông báo đến khay hệ thống. Một người dùng chạm 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 có chứa cả thông báo và tải trọng dữ liệu. 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 gửi trong phần bổ sung cho mục đích của Hoạt động trình khởi chạy của bạn.

Nếu bạn muốn mở ứng dụng của mình và thực hiện một hành động cụ thể, hãy đặt click_action trong tải trọng thông báo và ánh xạ nó tới bộ lọc ý định trong Hoạt động bạn muốn khởi chạy. Ví dụ: đặt click_action thành OPEN_ACTIVITY_1 để kích hoạt bộ lọc ý định như sau:

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

Biên tập :

Dựa trên chủ đề này :

Bạn không thể đặt tải trọng click_action bằng Bảng điều khiển Firebase. Bạn có thể thử kiểm tra bằng lệnh curl hoặc máy chủ http tùy chỉnh

curl --header "Authorization: key=<YOUR_KEY_GOES_HERE>" 
     --header Content-Type:"application/json" https://fcm.googleapis.com/fcm/send  
     -d "{\"to\":\"/topics/news\",\"notification\": 
         {\"title\": \"Click Action Message\",\"text\": \"Sample message\",
            \"click_action\":\"OPEN_ACTIVITY_1\"}}"

1
bạn đúng rồi. tôi đã đọc tài liệu Nhưng tôi bối rối không biết nên đặt cái này ở đâu trong bảng kê khai của tôi? Tôi phải chạy mã trên onMessageReceured trên tệp java đó để biết tôi phải làm gì?
Parth Patel

Bạn không thể làm cho ứng dụng tự động gọi onMessageReverated khi nó ở trên nền. Thay vào đó, bạn cần xử lý ý định nhận được và làm cho người xử lý gọi nó. Hoặc có lẽ tốt nhất là thực hiện lớp / phương thức riêng biệt được gọi bởi cả onMessageReverated và xử lý ý định của bạn. Tôi đã thêm trình xử lý vào onNewIntent của hoạt động chính và nó hoạt động tốt với tôi.
diidu

quá muộn để trả lời các câu hỏi của @Parath Patel nhưng có lẽ điều này sẽ giúp người khác có cùng vấn đề, hãy xem câu trả lời của tôi ở đây stackoverflow.com/a/42279260/2734021
Daniel S.

phải đặt hành động này ở đâu? cho hoạt động của tôi hoặc dịch vụ Firebasemessage?
Mahdi

** trên nhiều chuyển hướng thông báo không hoạt động? ví dụ: nếu tôi có ba thông báo từ FCM trên nền sử dụng "click_action" thông báo đầu tiên chuyển hướng thành công và sau đó 2 thông báo nhấp vào chuyển hướng hoạt động không hoạt động
prasanthMurugan

24

Làm việc kể từ tháng 7 năm 2019

Biên dịch AndroidSdkVersion 28, buildToolsVersion 28.0.3 và nhắn tin firebase: 19.0.1

Sau nhiều giờ nghiên cứu qua tất cả các câu hỏi và câu trả lời khác của StackOverflow và thử vô số giải pháp lỗi thời, giải pháp này đã quản lý để hiển thị thông báo trong 3 tình huống sau:

- Ứng dụng nằm ở phía trước:
thông báo được nhận bằng phương thức onMessageReceured tại lớp MyFirebaseMessagingService của tôi

- Ứng dụng đã bị tắt (nó không chạy ở chế độ nền): thông báo được FCM tự động gửi đến khay thông báo. Khi người dùng chạm vào thông báo, ứng dụng sẽ được khởi chạy bằng cách gọi hoạt động có android.intent.c Category.LAUNCHER trong tệp kê khai. Bạn có thể lấy phần dữ liệu của thông báo bằng cách sử dụng getIntent (). GetExtras () tại phương thức onCreate ().

- Ứng dụng ở chế độ nền: thông báo được FCM tự động gửi đến khay thông báo. Khi người dùng chạm vào thông báo, ứng dụng sẽ được đưa lên nền trước bằng cách khởi chạy hoạt động có android.intent.c Category.LAUNCHER trong tệp kê khai. Vì ứng dụng của tôi có launchMode = "singleTop" trong hoạt động đó, phương thức onCreate () không được gọi vì một hoạt động của cùng một lớp đã được tạo, thay vào đó phương thức onNewIntent () của lớp đó được gọi và bạn có được phần dữ liệu của thông báo ở đó bằng cách sử dụng aim.getExtras ().

Các bước: 1- Nếu bạn xác định hoạt động chính của ứng dụng như thế này:

<activity
    android:name=".MainActivity"
    android:label="@string/app_name"
    android:largeHeap="true"
    android:screenOrientation="portrait"
    android:launchMode="singleTop">
    <intent-filter>
        <action android:name=".MainActivity" />
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

2- thêm các dòng này vào phương thức onCreate () của MainActivity. Class của bạn

Intent i = getIntent();
Bundle extras = i.getExtras();
if (extras != null) {
    for (String key : extras.keySet()) {
        Object value = extras.get(key);
        Log.d(Application.APPTAG, "Extras received at onCreate:  Key: " + key + " Value: " + value);
    }
    String title = extras.getString("title");
    String message = extras.getString("body");
    if (message!=null && message.length()>0) {
        getIntent().removeExtra("body");
        showNotificationInADialog(title, message);
    }
}

và các phương thức này cho cùng MainActivity. class:

@Override
public void onNewIntent(Intent intent){
    //called when a new intent for this class is created.
    // The main case is when the app was in background, a notification arrives to the tray, and the user touches the notification

    super.onNewIntent(intent);

    Log.d(Application.APPTAG, "onNewIntent - starting");
    Bundle extras = intent.getExtras();
    if (extras != null) {
        for (String key : extras.keySet()) {
            Object value = extras.get(key);
            Log.d(Application.APPTAG, "Extras received at onNewIntent:  Key: " + key + " Value: " + value);
        }
        String title = extras.getString("title");
        String message = extras.getString("body");
        if (message!=null && message.length()>0) {
            getIntent().removeExtra("body");
            showNotificationInADialog(title, message);
        }
    }
}


private void showNotificationInADialog(String title, String message) {

    // show a dialog with the provided title and message
    AlertDialog.Builder builder = new AlertDialog.Builder(this);
    builder.setTitle(title);
    builder.setMessage(message);
    builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();
}

3- tạo lớp MyFirebase như thế này:

package com.yourcompany.app;

import android.content.Intent;
import android.util.Log;

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

public class MyFirebaseMessagingService extends FirebaseMessagingService {


    public MyFirebaseMessagingService() {
        super();
    }

    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {

        Log.d(Application.APPTAG, "myFirebaseMessagingService - onMessageReceived - message: " + remoteMessage);

        Intent dialogIntent = new Intent(this, NotificationActivity.class);
        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        dialogIntent.putExtra("msg", remoteMessage);
        startActivity(dialogIntent);

    }

}

4- tạo một lớp mới Thông báoActivity. Class như thế này:

package com.yourcompany.app;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.util.Log;

import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.view.ContextThemeWrapper;

import com.google.firebase.messaging.RemoteMessage;

public class NotificationActivity extends AppCompatActivity {

private Activity context;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    context = this;
    Bundle extras = getIntent().getExtras();

    Log.d(Application.APPTAG, "NotificationActivity - onCreate - extras: " + extras);

    if (extras == null) {
        context.finish();
        return;
    }

    RemoteMessage msg = (RemoteMessage) extras.get("msg");

    if (msg == null) {
        context.finish();
        return;
    }

    RemoteMessage.Notification notification = msg.getNotification();

    if (notification == null) {
        context.finish();
        return;
    }

    String dialogMessage;
    try {
        dialogMessage = notification.getBody();
    } catch (Exception e){
        context.finish();
        return;
    }
    String dialogTitle = notification.getTitle();
    if (dialogTitle == null || dialogTitle.length() == 0) {
        dialogTitle = "";
    }

    AlertDialog.Builder builder = new AlertDialog.Builder(new ContextThemeWrapper(context, R.style.myDialog));
    builder.setTitle(dialogTitle);
    builder.setMessage(dialogMessage);
    builder.setPositiveButton(getResources().getString(R.string.accept), new DialogInterface.OnClickListener() {
        public void onClick(DialogInterface dialog, int whichButton) {
            dialog.cancel();
        }
    });
    AlertDialog alert = builder.create();
    alert.show();

}

}

5- Thêm các dòng này vào Ứng dụng của bạn, bên trong các thẻ của bạn

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

    <meta-data android:name="com.google.firebase.messaging.default_notification_channel_id" android:value="@string/default_notification_channel_id"/>

    <activity android:name=".NotificationActivity"
        android:theme="@style/myDialog"> </activity>

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/notification_icon"/>

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/color_accent" />

6- thêm các dòng này trong phương thức Application.java onCreate () hoặc trong phương thức MainActivity. Class onCreate ():

      // notifications channel creation
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
      // Create channel to show notifications.
      String channelId = getResources().getString("default_channel_id");
      String channelName = getResources().getString("General announcements");
      NotificationManager notificationManager = getSystemService(NotificationManager.class);
      notificationManager.createNotificationChannel(new NotificationChannel(channelId,
              channelName, NotificationManager.IMPORTANCE_LOW));
  }

Làm xong.

Bây giờ để điều này hoạt động tốt trong 3 tình huống được đề cập, bạn phải gửi thông báo từ bảng điều khiển web Firebase theo cách sau:

Trong phần Thông báo: Tiêu đề thông báo = Tiêu đề để hiển thị trong hộp thoại thông báo (tùy chọn) Văn bản thông báo = Tin nhắn để hiển thị cho người dùng (bắt buộc) Sau đó, trong phần Mục tiêu: Ứng dụng = ứng dụng Android của bạn và trong phần Tùy chọn bổ sung: Kênh thông báo Android = default_channel_id Khóa dữ liệu tùy chỉnh: giá trị tiêu đề: (cùng văn bản ở đây so với trường Tiêu đề của phần Thông báo): giá trị cơ thể: (cùng văn bản ở đây so với trường Thông báo của phần Thông báo): click_action value: .MainActivity Sound =
Hết hạn sử dụng = 4 tuần

Bạn có thể gỡ lỗi nó trong Trình giả lập với API 28 bằng Google Play.

Chúc mừng mã hóa!


2
Cảm ơn bạn cho câu trả lời tuyệt vời này.
Alex Chengalan

@alvaro, Nếu tôi muốn mở Url khi tôi nhận được Thông báo, Làm thế nào tôi có thể xử lý việc này
engmms

không hoạt động trong điện thoại vivo opp khi ứng dụng bị đóng hoặc bị giết
Nhà phát triển Android

Tôi chưa thử trên điện thoại Vivo nhưng hiện tại nó đang hoạt động ở nhiều điện thoại Android khác. Vui lòng đọc chậm từng bước, kiểm tra tất cả các chi tiết và sau đó bật các điểm dừng gỡ lỗi ở dòng đầu tiên của mỗi phương thức mà tôi đã đề cập ở đây, kết nối điện thoại thực với máy tính phát triển của bạn bằng cáp và gỡ lỗi ứng dụng trong khi gửi một tin nhắn từ FCM. Kiểm tra xem bạn đang gửi tin nhắn FCM với tất cả các tham số và định dạng mà tôi đã đề cập. Chúc may mắn!
alvaro

2
Đây là câu trả lời cập nhật nhất, vì tài liệu Firebase hiện có nội dung: Khi ứng dụng của bạn ở chế độ nền, Android sẽ chuyển các thông báo thông báo đến khay hệ thống. Một người dùng chạm 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 có chứa cả thông báo và tải trọng dữ liệu. 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 gửi trong phần bổ sung cho mục đích của Hoạt động trình khởi chạy của bạn. ( firebase.google.com/docs/cloud-messaging/android/, ) Rất nhiều câu trả lời cũ đã lỗi thời
Riot Goes Wagger

20

display-messagesgiao diện được gửi từ UI Thông báo Firebase chỉ hoạt động nếu ứng dụng của bạn ở phía trước. Đối với data-messages, cần phải thực hiện một cuộc gọi POST đến FCM

Các bước

  1. Cài đặt phần còn lại nâng cao của khách hàng Google Chrome Tiện ích mở rộng nhập mô tả hình ảnh ở đây

  2. Thêm các tiêu đề sau

    Khóa : Loại nội dung, Giá trị : ứng dụng / json

    Khóa : Ủy quyền, Giá trị : key = "khóa máy chủ của bạn" nhập mô tả hình ảnh ở đây

  3. Thêm cơ thể

    • Nếu sử dụng các chủ đề:

      {
          "to" : "/topics/topic_name",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
          }
      }
    • Nếu sử dụng id đăng ký:

      {
          "registration_ids" : "[{"id"},{id1}]",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
           }
      }

Đó là nó!. Bây giờ hãy nghe onMessageReceivedgọi lại như bình thường.

@Override
public void onMessageReceived(RemoteMessage remoteMessage) { 
     Map<String, String> data = remoteMessage.getData();
     String value1 = data.get("key1");
     String value2 = data.get("key2");
}

20

Để chụp tin nhắn ở chế độ nền, bạn cần sử dụng BroadcastReceiver

import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.legacy.content.WakefulBroadcastReceiver
import com.google.firebase.messaging.RemoteMessage

class FirebaseBroadcastReceiver : WakefulBroadcastReceiver() {

    val TAG: String = FirebaseBroadcastReceiver::class.java.simpleName

    override fun onReceive(context: Context, intent: Intent) {

        val dataBundle = intent.extras
        if (dataBundle != null)
            for (key in dataBundle.keySet()) {
                Log.d(TAG, "dataBundle: " + key + " : " + dataBundle.get(key))
            }
        val remoteMessage = RemoteMessage(dataBundle)
        }
    }

và thêm nó vào bảng kê khai của bạn:

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

7
Điều này thực sự nhận được thông báo thông báo, khi ứng dụng ở chế độ nền. Nhưng nó không ngăn người nhận Firebase mặc định xử lý nó, vì vậy thông báo vẫn được hiển thị dưới dạng cảnh báo thông báo.
Galya

Hiện tại không hoạt động, vì vậy đó là lý do tại sao tôi đề xuất giải pháp này. Có một lỗi nộp trên google bugbase. Bạn có thể muốn kiểm tra xem.
Romulano

Bạn có thể vui lòng gửi một liên kết đến lỗi ở đây không
Galya

Làm thế nào để có được dữ liệu từ thông báo?
Ravi Vaghela

Điều này rõ ràng là không hoạt động khi ứng dụng bị giết. Tôi đã thử giải pháp này trong nhiều giờ. vì một số lý do, người nhận đang làm việc trong khi ứng dụng ở chế độ nền và không hoạt động khi ứng dụng bị tắt
XcodeNOOB

16
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}

không được gọi mỗi lần nó chỉ được gọi khi ứng dụng nằm trong khu vực

Có một phương thức ghi đè phương thức này được gọi mỗi lần, bất kể ứng dụng nào ở nền trước hoặc nền hoặc bị giết nhưng phương thức này có sẵn với phiên bản api firebase này

đây là phiên bản bạn phải nhập từ gradle

compile 'com.google.firebase:firebase-messaging:10.2.1'

đây là phương pháp

@Override
public void handleIntent(Intent intent) {
    super.handleIntent(intent);

    // you can get ur data here 
    //intent.getExtras().get("your_data_key") 


}

với api firebase trước đây, phương pháp này không có ở đó nên trong trường hợp đó, cơ sở fire tự xử lý khi ứng dụng ở chế độ nền .... bây giờ bạn có phương thức này bất cứ khi nào bạn muốn làm ... bạn có thể thực hiện ở đây trong phương thức này .. ...

nếu bạn đang sử dụng phiên bản trước hơn hoạt động mặc định sẽ bắt đầu trong trường hợp đó bạn có thể nhận dữ liệu theo cách tương tự

if(getIntent().getExtras() != null && getIntent().getExtras().get("your_data_key") != null) {
String strNotificaiton = getIntent().getExtras().get("your_data_key").toString();

// làm những gì bạn muốn ....}

nói chung đây là cấu trúc từ máy chủ mà chúng tôi nhận được trong thông báo

{
    "notification": {
        "body": "Cool offers. Get them before expiring!",
        "title": "Flat 80% discount",
        "icon": "appicon",
        "click_action": "activity name" //optional if required.....
    },
    "data": {
        "product_id": 11,
        "product_details": "details.....",
        "other_info": "......."
    }
}

tùy thuộc vào cách bạn muốn cung cấp khóa dữ liệu đó hoặc bạn muốn thông báo bất cứ điều gì bạn có thể cung cấp ....... những gì bạn sẽ cung cấp ở đây với cùng khóa bạn sẽ nhận được dữ liệu đó ........ .

Có vài trường hợp nếu bạn không gửi hành động nhấp trong trường hợp đó khi bạn nhấp vào thông báo thì hoạt động mặc định sẽ mở, nhưng nếu bạn muốn mở hoạt động cụ thể của mình khi ứng dụng ở chế độ nền, bạn có thể gọi hoạt động của mình từ phương thức này trên phương thức handleIntent vì điều này được gọi mỗi lần


Tôi đã cập nhật tin nhắn firebase lên 10.2.1, Đã thêm Dữ liệu vào tin nhắn thông báo và nó đã hoạt động. Tiền cảnh, Bối cảnh và Giết chóc. Cảm ơn
Firas Shrourou

trong Kotlin, tôi nhận được Lỗi này: (44, 5) 'xử lý' trong 'FirebaseMessagingService' là cuối cùng và không thể bị ghi đè
ugali mềm

Nó không hoạt động trên các phiên bản của căn cứ hỏa lực 11
venu46

14

Theo các tài liệu: ngày 17 tháng 5 năm 2017

Khi ứng dụng của bạn ở chế độ nền , Android sẽ chuyển các thông báo thông báo đến khay hệ thống. Một người dùng chạm 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ả thông báo và tải trọng 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 gửi trong phần bổ sung cho mục đích của Hoạt động trình khởi chạy của bạn.

Vì vậy, bạn nên sử dụng cả dữ liệu + thông báo tải trọng:

{
  "to": "FCM registration ID",
  "notification": {
    "title" : "title",
    "body"  : "body text",
    "icon"  : "ic_notification"
   },
   "data": {
     "someData"  : "This is some data",
     "someData2" : "etc"
   }
}

Không cần sử dụng click_action. Bạn chỉ nên lấy ý định từ hoạt động LAUNCHER

<activity android:name=".MainActivity">
        <intent-filter>
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>

Mã Java phải là phương thức onCreate trên MainActivity:

Intent intent = getIntent();
if (intent != null && intent.getExtras() != null) {
    Bundle extras = intent.getExtras();
    String someData= extras.getString("someData");
    String someData2 = extras.getString("someData2");
}

Bạn có thể kiểm tra cả thông báo tải trọng + dữ liệu từ Bảng điều khiển thông báo Firebase . Đừng quên điền các trường dữ liệu tùy chỉnh vào phần Tùy chọn nâng cao


13

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à tải 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, click_actiontham số 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 onMessageReceivedphương thức (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.

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



8

Tóm tắt đơn giản như thế này

  • nếu ứng dụng của bạn đang chạy;

    onMessageReceived()

là tác nhân.

  • nếu ứng dụng của bạn không chạy (bị giết bằng cách vuốt);

    onMessageReceived()

không được kích hoạt và phân phối bởi direclty. Nếu bạn có bất kỳ cặp khóa-giá trị đặc biệt. Họ không làm việc với beacuse của onMessageReceured () không hoạt động.

Tôi đã tìm thấy cách này;

Trong hoạt động launcher của bạn, đặt logic này,

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState, R.layout.activity_splash);

    if (getIntent().getExtras() != null && getIntent().getExtras().containsKey("PACKAGE_NAME")) {

        // do what you want

        // and this for killing app if we dont want to start
        android.os.Process.killProcess(android.os.Process.myPid());

    } else {

        //continue to app
    }
}

trong khối if này, tìm kiếm các khóa của bạn theo UI firebase.

Trong ví dụ này, khóa và giá trị của tôi như trên; (xin lỗi vì ngôn ngữ =)) nhập mô tả hình ảnh ở đây

Khi mã của tôi hoạt động, tôi nhận được "com.rda.note".

android.os.Process.killProcess(android.os.Process.myPid());

với dòng mã này, tôi đã đóng ứng dụng của mình và mở Google Play Market

mã hóa hạnh phúc =)


6

Tôi đã tìm ra các kịch bản,

Khi ứng dụng ở chế độ nền trước , phương thức onMessageReceured () được gọi từ FirebaseService . Vì vậy, chờ đợi được xác định trong lớp dịch vụ sẽ được gọi.

Và khi ứng dụng ở chế độ nền , hoạt động đầu tiên được gọi.

Bây giờ, nếu bạn sử dụng một hoạt động giật gân , thì phải nhớ rằng tính năng giật gân sẽ được gọi, nếu không thì không có hoạt động giật gân , thì bất kể hoạt động đầu tiên là gì, sẽ được gọi.

Sau đó, bạn cần kiểm tra getIntent () của FirstActivity để xem nó có gói nào không . Nếu mọi thứ đều ổn, bạn sẽ thấy gói có ở đó với các giá trị được điền vào. Nếu giá trị trong thẻ dữ liệu được gửi từ máy chủ trông như thế này,

"data": {
    "user_name": "arefin sajib",
    "value": "user name notification"
  }

Sau đó, trong hoạt động đầu tiên, bạn sẽ thấy, có một mục đích hợp lệ ( getIntent () không phải là null ), gói hợp lệ và bên trong gói, sẽ có toàn bộ JSON được đề cập ở trên với dữ liệukhóa .

Đối với kịch bản này, mã trích xuất giá trị sẽ trông như thế này,

    if(getIntent()!=null){
            Bundle bundle = getIntent().getExtras();
            if (bundle != null) {
                try {
                   JSONObject object = new JSONObject(bundle.getStringExtra("data"));
String user_name = object.optString("user_name");

                } catch (JSONException e) {
                    e.printStackTrace();
                }


            }
        }

3

Cảm ơn tất cả các bạn đã trả lời. Nhưng tôi đã giải quyết điều này bằng cách gửi tin nhắn dữ liệu thay vì gửi Thông báo . Mã máy chủ

<?php
$url = "https://fcm.googleapis.com/fcm/send";
$token = "C-l6T_a7HouUK****";
$serverKey = "AAAAaOcKS00:********";
define( 'API_ACCESS_KEY', $serverKey );
$registrationIds = array($token);
// prep the bundle

$msg = array

(
 'message'  => 'here is a message. message',
 'title'        => 'This is a title. title',
 'subtitle' => 'This is a subtitle. subtitle',
 'tickerText'   => 'Ticker text here...Ticker text here...Ticker text 
 here',
 'vibrate'  => 1,
 'sound'        => 1,
 'largeIcon'    => 'large_icon',
 'smallIcon'    => 'small_icon'

);

$fields = array

(
  'registration_ids'    => $registrationIds,
  'data'            => $msg

);
$headers = array

(
  'Authorization: key=' . API_ACCESS_KEY,
 'Content-Type: application/json'

);


$ch = curl_init();

curl_setopt( $ch,CURLOPT_URL, 'https://android.googleapis.com/gcm/send' 
);

curl_setopt( $ch,CURLOPT_POST, true );

curl_setopt( $ch,CURLOPT_HTTPHEADER, $headers );

curl_setopt( $ch,CURLOPT_RETURNTRANSFER, true );

curl_setopt( $ch,CURLOPT_SSL_VERIFYPEER, false );

curl_setopt( $ch,CURLOPT_POSTFIELDS, json_encode( $fields ) );

$result = curl_exec($ch );

curl_close( $ch );

echo $result;

?>

Và bắt được Dữ liệu trong onMessageReceured

public class MyFirebaseMessagingService extends FirebaseMessagingService     {

  private static final String TAG = "MyFirebaseMsgService";

@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
    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());

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


}
   private void sendNotification(String messageBody) {
    Intent intent = new Intent(this, Notify.class).putExtra("msg",messageBody);
    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
            PendingIntent.FLAG_ONE_SHOT);

    String channelId = "idddd";
    Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
    NotificationCompat.Builder notificationBuilder =
            new NotificationCompat.Builder(MyFirebaseMessagingService.this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle("FCM Message")
                    .setContentText(messageBody)
                    .setAutoCancel(true)
                    .setSound(defaultSoundUri)
                    .setContentIntent(pendingIntent);

    NotificationManager notificationManager =
            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

    notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
}

1
nó cũng làm việc với một nền tảng?
Tabish khan

@Tabishkhan Có anh em nó đang hoạt động nếu bạn có bất kỳ vấn đề nào, vui lòng hỏi tôi .. cảm ơn
Android Sanaullah

1
xin chào @AndroidSanaullah, bạn có thể giải thích phần đầu tiên về mã máy chủ không, bạn thực sự đặt nó ở đâu, tôi đang đối mặt với cùng một vấn đề nhưng tôi không hiểu lắm về phần máy chủ, bạn có đang sử dụng người đưa thư không?
Shid

curl được sử dụng cho yêu cầu và tất cả các tham số được truyền cho nó. @ Shid
Android Sanaullah

2

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ó onMessageReceived(), nếu không, onMessageReceivedứng dụng của bạn sẽ không được kích hoạt khi ứng dụng ở chế độ nền hoặc bị tắt.

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

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

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

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

Và tương tự, bạn có thể nhận được bất kỳ dữ liệu nào bạn đã gửi từ máy chủ bên trong onMessageReceived().


2

Cách dễ dàng để gửi tin nhắn ngay cả khi ứng dụng ở chế độ nền và tiền cảnh như sau: - Để gửi tin nhắn bằng API, bạn có thể sử dụng công cụ có tên AdvancedREST Client, tiện ích mở rộng chrome và gửi tin nhắn với các tham số sau.

Phần còn lại của công cụ khách hàng Liên kết: https://chrome.google.com/webstore/detail/advified-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

sử dụng url này: - https://fcm.googleapis.com/fcm/send Loại nội dung: application / json Ủy quyền: key = Khóa máy chủ của bạn Từ hoặc khóa Authoization (xem bên dưới ref)

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

Có thể lấy khóa ủy quyền bằng cách truy cập bảng điều khiển dành cho nhà phát triển của Google và nhấp vào nút Thông tin xác thực ở menu bên trái cho dự án của bạn. Trong số các khóa API được liệt kê, khóa máy chủ sẽ là khóa ủy quyền của bạn.

Và bạn cần đặt mã thông báo của người nhận trong phần Rô-lô-lô của yêu cầu POST của bạn được gửi bằng API.


2

bạn muốn làm việc trênMessageReceured (RemoteMessage remoteMessage) trong nền chỉ gửi phần thông báo phần dữ liệu này:

"data":    "image": "",    "message": "Firebase Push Message Using API", 

"AnotherActivity": "True", "to": "id thiết bị hoặc mã thông báo thiết bị"

Bằng cách này, onMessageRecivied là nền cuộc gọi và tiền cảnh không cần xử lý thông báo bằng khay thông báo trên hoạt động trình khởi chạy của bạn. Xử lý tải trọng dữ liệu trong việc sử dụng này:

  public void onMessageReceived(RemoteMessage remoteMessage)
    if (remoteMessage.getData().size() > 0) 
    Log.d(TAG, "Message data payload: " + remoteMessage.getData());      

1

Trả lời tháng 6 năm 2018 -

Bạn phải chắc chắn rằng không có từ khóa "thông báo" ở bất cứ đâu trong tin nhắn. Chỉ bao gồm "dữ liệu" và ứng dụng sẽ có thể xử lý tin nhắn trong onMessageReceured, ngay cả khi ở chế độ nền hoặc bị giết.

Sử dụng các chức năng đám mây:

const message = {
    token: token_id,   // obtain device token id by querying data in firebase
    data: {
       title: "my_custom_title",
       body:  "my_custom_body_message"
       }
    }


return admin.messaging().send(message).then(response => {
    // handle response
});

Sau đó, trong onMessageReceured (), trong lớp của bạn mở rộng com.google.firebase.messaging.FirebaseMessagingService:

if (data != null) {
  Log.d(TAG, "data title is: " + data.get("title");
  Log.d(TAG, "data body is: " + data.get("body");
}

// build notification using the body, title, and whatever else you want.

bạn có nguồn nào không, có an toàn không?
Yogesh Rathi

Nó an toàn, tôi sử dụng nó trong các ứng dụng của mình. Tuy nhiên, 6 tháng kể từ khi đăng, tôi không thể nhớ nguồn - tôi tưởng tượng đó là tài liệu về căn cứ hỏa lực.
Jeff Padgett

1

Theo OAUTH 2.0:

Sẽ có vấn đề Auth cho trường hợp này beacuse FCM hiện đang sử dụng OAUTH 2

Vì vậy, tôi đọc tài liệu firebase và theo tài liệu cách mới để gửi thông điệp dữ liệu là;

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

Tiêu đề

Key: Content-Type, Value: application/json

Xác thực

Bearer YOUR_TOKEN 

Thân ví dụ

{
   "message":{
    "topic" : "xxx",
    "data" : {
         "body" : "This is a Firebase Cloud Messaging Topic Message!",
         "title" : "FCM Message"
          }
      }
 }

Trong url có Id cơ sở dữ liệu mà bạn có thể tìm thấy nó trên bảng điều khiển firebase. (Đi định cư dự án)

Và bây giờ, hãy lấy mã thông báo của chúng tôi (Nó sẽ chỉ có hiệu lực trong 1 giờ):

Đầu tiên trong bảng điều khiển Firebase, mở Cài đặt> Tài khoản dịch vụ . Nhấp vào Tạo khóa riêng mới , lưu trữ an toàn tệp JSON chứa khóa. Tôi cần tệp JSON này để ủy quyền các yêu cầu máy chủ theo cách thủ công. Tôi đã tải nó.

Sau đó, tôi tạo một dự án node.js và sử dụng chức năng này để nhận mã thông báo của mình;

var PROJECT_ID = 'YOUR_PROJECT_ID';
var HOST = 'fcm.googleapis.com';
var PATH = '/v1/projects/' + PROJECT_ID + '/messages:send';
var MESSAGING_SCOPE = 'https://www.googleapis.com/auth/firebase.messaging';
var SCOPES = [MESSAGING_SCOPE];

  router.get('/', function(req, res, next) {
      res.render('index', { title: 'Express' });
      getAccessToken().then(function(accessToken) {
        console.log("TOKEN: "+accessToken)
      })

    });

function getAccessToken() {
return new Promise(function(resolve, reject) {
    var key = require('./YOUR_DOWNLOADED_JSON_FILE.json');
    var jwtClient = new google.auth.JWT(
        key.client_email,
        null,
        key.private_key,
        SCOPES,
        null
    );
    jwtClient.authorize(function(err, tokens) {
        if (err) {
            reject(err);
            return;
        }
        resolve(tokens.access_token);
    });
});
}

Bây giờ tôi có thể sử dụng mã thông báo này trong yêu cầu bài viết của mình. Sau đó, tôi đăng thông báo dữ liệu của mình và hiện tại nó được xử lý bởi các ứng dụng của tôi trên chức năng onMessageReceured.


Câu trả lời được chấp nhận đang làm việc, barer auth thẻ không phải là đường đi, bạn cần phải đọc để thử nó với Postman: stackoverflow.com/questions/45309674/...
Carlos Chúa Giêsu Arancibia Taborga

1

Kể từ năm 2019, Google Firebase có một thay đổi lớn trong API của họ, ý tôi là: 'com.google.firebase:firebase-messaging:18.0.0'

trong 18.0.0 họ đã xóa MyFirebaseInstanceIDServicevà bạn cần nhận mã thông báo MyFirebaseMessagingServiceđể bạn chỉ cần viết:

@Override
public void onNewToken(String token) {
    Log.d(TAG, "Refreshed token: " + token);

}

và cũng trong AndroidManifest.xml của bạn, bạn phải xóa:

<service android:name=".service.MyFirebaseInstanceIDService">
        <intent-filter>
            <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
        </intent-filter>
    </service>

Ngoài ra, bạn nên đặt giá trị mặc định để tùy chỉnh sự xuất hiệ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 giá trị tương đương không được đặt trong tải trọng thông báo.

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

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_icon"
        android:resource="@drawable/ic_notification" />

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_color"
        android:resource="@color/colorAccent" />

    <meta-data
        android:name="com.google.firebase.messaging.default_notification_channel_id"
        android:value="@string/push_channel" />

ngay bây giờ để xử lý tin nhắn thông báo trong ứng dụng chạy nền, bạn nên xác định Ý định trong Hoạt động đầu tiên ngay cả khi đó là SplashScreen, Khi ứng dụng của bạn ở chế độ nền, Android sẽ chuyển các thông báo thông báo đến khay hệ thống. Một người dùng chạm vào thông báo sẽ mở trình khởi chạy ứng dụng theo mặc định.

ví dụ: nếu Json của bạn giống như thế này:

 "data": {
"message": "2",
"title": "1",
"pushType" : "banner",
"bannerLink": "http://www.google.com",
"image" : "https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png"}

bạn chỉ cần viết một ý định đơn giản để có được các giá trị đó:

        Bundle extras = intent.getExtras();
        String bannerLink = extras.getString("bannerLink");
        ...
        String channelId = extras.getString("channelId");

0

Ngoài các câu trả lời ở trên, Nếu bạn đang kiểm tra thông báo đẩy bằng bảng điều khiển FCM , khóa và đối tượng 'dữ liệu' sẽ không được thêm vào gói Thông báo đẩy. Vì vậy, bạn sẽ không nhận được thông báo đẩy chi tiết khi Ứng dụng chạy nền hoặc bị tắt.

Trong trường hợp này, bạn phải chọn cho bảng điều khiển quản trị viên phía sau để kiểm tra kịch bản nền Ứng dụng.

Tại đây, bạn sẽ thêm khóa 'dữ liệu' vào gói đẩy của mình. vì vậy, đẩy chi tiết sẽ được hiển thị như mong đợi. Hy vọng điều này sẽ giúp ít.


0

Sử dụng mã này, bạn có thể nhận được thông báo ở chế độ nền / tiền cảnh và cũng có thể thực hiện hành động:

//Data should come in this format from the notification
{
  "to": "/xyz/Notifications",
  "data": {
      "key1": "title notification",
      "key2": "description notification"
  }
}

Trong ứng dụng sử dụng mã này:

  @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        super.onMessageReceived(remoteMessage);
      String key1Data = remoteMessage.getData().get("key1");
      // use key1Data to according to your need
    }

// Dữ liệu phải có định dạng này từ thông báo {"đến": "/ xyz / Thông báo", "dữ liệu": {"key1": "thông báo tiêu đề", "key2": "thông báo mô tả"}} Cách viết mã này trong dịch vụ php?
Tabish khan

-3

Sẽ có hai loại thông báo

  1. Thông báo hiển thị - Chỉ hiển thị thông báo, sẽ chỉ hiển thị ứng dụng không mở và ứng dụng này trong ngăn xếp ứng dụng.
  2. Thông báo dữ liệu - gọi lại sẽ đi vào phương thức onMessageReceured của firebasemessagingservice và nó hoạt động khi ứng dụng ở chế độ nền, tiền cảnh hoặc trạng thái bị giết.

Bạn phải sử dụng Thông báo dữ liệu để xử lý thông báo khi ứng dụng ở chế độ nền.


-5

Tôi đã gặp vấn đề tương tự và biên dịch lại thư viện firebase và ngăn nó gửi thông báo khi ứng dụng ở chế độ nền

* thư viện https://github.com/erdalceylan/com-google-firebase-messaging

 dependencies {
        compile 'com.google.firebase:firebase-core:11.2.0'
        compile 'com.github.erdalceylan:com-google-firebase-messaging:v1-11.2.0'
    }

*

@WorkerThread
public void onMessageReceived(RemoteMessage var1) {
  //your app is in background or foreground all time calling
}

Hy vọng giúp. Chúc may mắn


2
Câu trả lời không hữu ích
Ankit Patidar 26/03/18

2
Đây là một đề nghị khủng khiếp.
vsecades
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.