วิธีจัดการกับการแจ้งเตือนเมื่อแอปในพื้นหลังใน Firebase


426

นี่คือรายการของฉัน

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

onMessageReceivedเมื่อแอปที่อยู่ในพื้นหลังและการแจ้งเตือนมาถึงแล้วแจ้งเตือนเริ่มต้นมาและไม่ได้เรียกใช้รหัสของฉัน

นี่คือonMessageReceivedรหัสของฉัน สิ่งนี้จะเรียกใช้หากแอพของฉันทำงานบนพื้นหน้าไม่ใช่เมื่อแอปอยู่ในพื้นหลัง จะรันรหัสนี้ได้อย่างไรเมื่อแอปอยู่ในพื้นหลังด้วย?

// [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
มันเขียนในตัวอย่างของการแทนที่ onMessageReceived ()Not getting messages here? See why this may be: goo.gl/39bRNJ บรรทัดที่สองกล่าวว่าการแสดงความคิดเห็น การแก้ปัญหาเช่นคำตอบด้านล่างสามารถพบได้ในเอกสารในข้อความที่มีทั้งการแจ้งเตือนและข้อมูลที่บรรจุข้อมูล
fllo

พูดสั้น ๆ เพื่อปลุกแอพที่ถูกฆ่าคุณควรส่งการแจ้งเตือนด้วยออบเจ็กต์ข้อมูลเพื่อเรียกใช้ตัวจัดการคลาสการแจ้งเตือนของคุณ FirebaseMessagingService.onMessageReceived () ในแอปพลิเคชันของคุณ ลองส่งมันไม่ได้จากคอนโซล Firebase แต่ลองโพสต์มันจากที่อื่น (เช่นบริการทดสอบโพสต์ออนไลน์)
Zon

1
โซลูชันนี้ใช้งานได้สำหรับฉันstackoverflow.com/a/44150822/6632278หวังว่าจะช่วยได้ ขอให้โชคดี
Tony Barajas

อะไร ".fcm." PshycoFirebaseMessagingServices อยู่ในรายการของคุณหรือไม่ ฉันพบข้อผิดพลาดของการเรียนไม่พบและไม่พบที่ใดในส่วนแรกของพารามิเตอร์
Éder Rocha Bezerra

คำตอบ:


660

1. ทำไมสิ่งนี้จึงเกิดขึ้น

มีข้อความสองประเภทใน FCM (Firebase Cloud Messaging):

  1. ข้อความที่แสดง : ข้อความเหล่านี้เรียกการonMessageReceived()เรียกกลับเฉพาะเมื่อแอปของคุณอยู่เบื้องหน้า
  2. ข้อความข้อมูล : ข้อความเหล่านี้ทำให้เกิดการonMessageReceived()โทรกลับแม้ว่าแอพของคุณจะทำงานเบื้องหน้า / พื้นหลัง / ถูกฆ่า

หมายเหตุ:ทีม Firebase ยังไม่ได้พัฒนา UI เพื่อส่งdata-messagesไปยังอุปกรณ์ของคุณ คุณควรใช้เซิร์ฟเวอร์ของคุณเพื่อส่งประเภทนี้!



2. ทำอย่างไร

เพื่อให้บรรลุสิ่งนี้คุณต้องดำเนินการPOSTตามคำขอไปยัง URL ต่อไปนี้:

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

ส่วนหัว

  • รหัส: Content-Type , ค่า: application/json
  • รหัส: Authorization , ค่า: key=<your-server-key>

ร่างกายใช้หัวข้อ

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

หรือถ้าคุณต้องการที่จะส่งไปยังอุปกรณ์เฉพาะ

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


หมายเหตุ:ตรวจสอบให้แน่ใจว่าคุณไม่ได้เพิ่มคีย์ JSON notification
หมายเหตุ:ในการรับรหัสเซิร์ฟเวอร์ของคุณคุณสามารถค้นหาได้ในคอนโซล firebase:Your project -> settings -> Project settings -> Cloud messaging -> Server Key

3. วิธีจัดการข้อความแจ้งเตือนแบบพุช

นี่คือวิธีที่คุณจัดการกับข้อความที่ได้รับ:

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

     // Manage data
}

4
คุณสามารถส่งคีย์ "data" และ "การแจ้งเตือน" ในการแจ้งเตือนเดียวกันโดยทำตามขั้นตอนเหล่านี้stackoverflow.com/a/42279260/2734021 :)
Daniel S.

15
Firebase team have not developed a UI to send data-messages to your devices, yet.สิ่งนี้มีการเปลี่ยนแปลงในปีที่ผ่านมาหรือไม่?
Hankrecords

2
@Antonio ใน oreo เมื่อแอพถูกฆ่า onMessageReceived จะไม่ถูกเรียก ฉันเพิ่งมีน้ำหนักบรรทุกพร้อมข้อมูลเท่านั้น คุณมีอัพเดตอะไรบ้าง?
Samir Mangroliya

63
เมื่อแอปที่อยู่ในพื้นหลังonMessageReceivedไม่ได้รับการโทรและมันเป็นปัญหาร้ายแรงใน FCM !!! นอกจากนี้โปรดอัปเดตคำตอบของคุณ
Muhammad Babar

2
สำหรับฉันมันดูเหมือนว่าเกิดขึ้นกับอุปกรณ์ Android บางรุ่น เวลาที่ใช้ไปคิดว่าเป็นปัญหาจริง แต่กลับกลายเป็นว่าไม่มีอะไรเลย ดังนั้นคำแนะนำของฉันคือทดสอบบนอุปกรณ์ต่าง ๆ ฉันได้ทดสอบบน VM และฉันได้รับการแจ้งเตือนแม้ในขณะที่แอปถูกฆ่า ฉันแค่พูดแบบนี้เพื่อประหยัดเวลาของใครบางคน
Tarek-Dev

158

ในการสร้างไลบรารี firebase ให้เรียกใช้onMessageReceived ()ในกรณีต่อไปนี้

  1. แอปเบื้องหน้า
  2. แอปในพื้นหลัง
  3. แอปถูกฆ่าตาย

คุณต้องไม่ใส่คีย์ JSON 'การแจ้งเตือน' ในคำขอของคุณไปยัง firebase API แต่ให้ใช้ 'data' แทนดูด้านล่าง

ข้อความต่อไปนี้จะไม่เรียกonMessageReceived ()เมื่อแอปของคุณอยู่ในพื้นหลังหรือถูกฆ่าและคุณไม่สามารถปรับแต่งการแจ้งเตือนของคุณได้

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

แต่แทนที่จะใช้สิ่งนี้จะได้ผล

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

โดยพื้นฐานแล้วข้อความจะถูกส่งในอาร์กิวเมนต์ RemoteMessage พร้อมกับวัตถุข้อมูลของคุณเป็นแผนที่จากนั้นคุณสามารถจัดการการแจ้งเตือนใน onMessageReceived เช่นเดียวกับในตัวอย่างที่นี่

@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
เป็นไปได้ไหมที่จะได้สิ่งนี้จากคอนโซล Firebase?
koder

@koder โชคไม่ดีที่คอนโซล Firebase ไม่สนับสนุนสิ่งนี้คุณต้องใช้เครื่องมือในการส่งคำขอข้อความไปยัง firebase เช่น curl หรือบุรุษไปรษณีย์ (ปลั๊กอิน chrome), firebase ข้อความ API กรุณาอ้างอิงเอกสารที่นี่ - firebase.google.com/docs / cloud-messaging / http-server-ref
Teerakiat Chitawattanarat

1
นี่คือสิ่งที่ฉันค้นหามานานกว่าหนึ่งวัน ..... ขอบคุณมากมันทำงานได้อย่างสมบูรณ์แบบ และมันจะดีกว่าถ้าคุณอธิบายวิธีจัดการคู่คีย์ vale ในข้อมูลใน onMessageReceived () เพื่อเริ่มกิจกรรมด้วยค่าเหล่านั้น
Boopathi T

25
วิธีการของคุณทำงานได้ดีเมื่อแอปอยู่ในพื้นหลัง แต่เมื่อแอพถูกฆ่าฉันไม่ได้รับข้อมูล
Sanzhar

8
ปัญหาเดียวกันของ Sanzhar หากแอพถูกฆ่าฉันจะไม่ได้รับข้อความใด ๆ
Giacomo M

104

ฉันรู้สึกว่าคำตอบทั้งหมดไม่สมบูรณ์ แต่ทุกคนมีสิ่งที่คุณต้องการในการประมวลผลการแจ้งเตือนที่มีข้อมูลเมื่อแอปของคุณอยู่ในพื้นหลัง

ทำตามขั้นตอนเหล่านี้และคุณจะสามารถประมวลผลการแจ้งเตือนของคุณเมื่อแอปของคุณอยู่ในพื้นหลัง

1. เพิ่มตัวกรองเจตนาเช่นนี้:

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

ไปยังกิจกรรมที่คุณต้องการประมวลผลข้อมูลการแจ้งเตือน

  1. ส่งการแจ้งเตือนด้วยรูปแบบถัดไป:

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

กุญแจสำคัญที่นี่คือการเพิ่ม

"click_action" : ".MainActivity"

โดยที่ MainActivity เป็นกิจกรรมที่มีตัวกรองเจตนาที่คุณเพิ่มไว้ในขั้นตอนที่ 1

  1. รับข้อมูล "data" จากการแจ้งเตือนใน onCreate ของ ".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
        }
    }

และนั่นคือทั้งหมดที่คุณต้องทำ ฉันหวังว่านี่จะช่วยใครซักคน :)


5
นี่ควรเป็นคำตอบที่ถูกต้อง ไม่มีเอกสารใดที่พูดถึงการเรียกใช้ click_action และตัวกรองเจตนาเพื่อให้การแจ้งเตือนปรากฏแม้แต่ในถาด พวกเขาทั้งสองต้องการ
arowrow

@airowe พวกเขาไม่ต้องการให้การแจ้งเตือนปรากฏขึ้น
AlwaysConfused

ฉันมีทั้งข้อมูลและบล็อคการแจ้งเตือน แต่ฉันไม่สามารถรับข้อมูลในกิจกรรมได้หรือไม่
Ashwani

3
ฉันแค่ไม่เข้าใจว่านี่ไม่ใช่คำตอบที่ยอมรับได้ หากไม่มี click_action มันจะไม่ทำงาน บันทึกวันของฉัน
Arun Shankar

4
ขอบคุณสำหรับการสนับสนุน @ArunShankar คำตอบที่ยอมรับนั้นได้รับการตอบเมื่อ 7 เดือนก่อนหน้านี้และเป็นคำตอบที่ดี ฉันไม่สามารถเข้าใจได้ว่าทำไมไม่มีใครพูดถึง click_action และนั่นคือสาเหตุที่ฉันได้เพิ่มคำตอบของฉัน ผมมีความสุขมากที่มันจะเป็นประโยชน์มากสำหรับผู้คนจำนวนมากและนั่นคือสิ่งที่สำคัญในตอนท้ายของวัน :)
แดเนียลเอ

42

ตามเอกสารของ firebase ในการส่งดาวน์สตรีมโดยใช้ firebaseมี payload 2 ประเภท:

  1. ข้อมูล

    พารามิเตอร์นี้ระบุคู่ของคีย์ - ค่าที่กำหนดเองของเพย์โหลดของข้อความ แอปไคลเอ็นต์รับผิดชอบการประมวลผลข้อความข้อมูล ข้อความข้อมูลมีคู่ค่าคีย์ที่กำหนดเองเท่านั้น

  2. การแจ้งเตือน

    พารามิเตอร์นี้ระบุคู่คีย์ - ค่าที่กำหนดไว้ล่วงหน้าซึ่งผู้ใช้มองเห็นได้ของเพย์โหลดการแจ้งเตือน FCM จะแสดงข้อความไปยังอุปกรณ์ของผู้ใช้โดยอัตโนมัติในนามของแอพไคลเอ็นต์ ข้อความแจ้งเตือนมีชุดปุ่มที่ผู้ใช้เห็นได้ล่วงหน้า

เมื่อคุณอยู่ในเบื้องหน้าคุณจะได้รับข้อมูลที่อยู่ภายใน FCM ใช้onMessageReceived ()คุณจะได้รับข้อมูลของคุณจากข้อมูลน้ำหนักบรรทุก

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

เมื่อคุณอยู่ในพื้นหลัง FCM จะแสดงการแจ้งเตือนในถาดระบบบนพื้นฐานของข้อมูลจากการแจ้งเตือนน้ำหนักบรรทุก ชื่อข้อความและไอคอนที่ใช้สำหรับการแจ้งเตือนบนซิสเต็มเทรย์จะได้รับจากเพย์โหลดการแจ้งเตือน

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

เพย์โหลดการแจ้งเตือนนี้จะใช้เมื่อคุณต้องการแสดงการแจ้งเตือนบนถาดระบบโดยอัตโนมัติเมื่อแอปของคุณอยู่ในพื้นหลัง เพื่อให้ได้ข้อมูลการแจ้งเตือนเมื่อแอปของคุณในพื้นหลังคุณควรเพิ่ม click_action ภายในแจ้งเตือนน้ำหนักบรรทุก

หากคุณต้องการเปิดแอปและดำเนินการบางอย่าง [ขณะที่แบ็กกราวน์] ให้ตั้งค่า click_action ในส่วนของการแจ้งเตือนและแมปกับตัวกรองเจตนาในกิจกรรมที่คุณต้องการเปิดใช้ ตัวอย่างเช่นตั้งค่า click_action เป็น OPEN_ACTIVITY_1 เพื่อทริกเกอร์ตัวกรองเจตนาดังต่อไปนี้:

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

ใส่ตัวกรองเจตนาลงในรายการของคุณในแท็กกิจกรรมหนึ่งของคุณ เมื่อคุณคลิกการแจ้งเตือนก็จะเปิดแอปและตรงไปที่กิจกรรมที่คุณกำหนดใน click_action ในกรณีนี้ "OPEN_ACTIVTY_1" และภายในกิจกรรมนั้นคุณสามารถรับข้อมูลได้โดย:

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

ฉันใช้ FCM สำหรับแอพ Android ของฉันและใช้น้ำหนักบรรทุกทั้งสองอย่าง นี่คือตัวอย่าง JSON ที่ฉันใช้:

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

"ใส่ตัวกรองความตั้งใจนั้นไว้ในไฟล์ Manifest ของคุณภายในแท็กแอปพลิเคชัน" คุณไม่สามารถใส่ตัวกรองเจตนาในแท็กแอปพลิเคชัน
Kyrylo Zapylaiev

JSON ของคุณไม่แสดงตำแหน่งที่คีย์ click_action จะไป
Josh

นี่ไม่ใช่คำตอบที่ถูก? การดำเนินการคลิกคืออะไรมันไปที่ไหน บางคนควรจะลงลงคะแนนหรือทำความสะอาดนี้
rana

1
@KyryloZapylaiev ฉันเพิ่งแก้ไขและอัปเดตคำตอบ: "ใส่ตัวกรองเจตนาในรายการของคุณภายในแท็กกิจกรรมหนึ่งของคุณ"
Dika

1
@ Josh ปรับปรุงและจัดรูปแบบแล้ว คุณสามารถตรวจสอบได้อีกครั้ง
Dika

32

ตามเอกสาร

จัดการข้อความในแอปที่มีพื้นหลัง

เมื่อแอปของคุณอยู่ในพื้นหลัง Android จะส่งข้อความแจ้งเตือนไปยังถาดระบบ ผู้ใช้แตะที่การแจ้งเตือนจะเปิดตัวเรียกใช้งานแอปตามค่าเริ่มต้น

ซึ่งรวมถึงข้อความที่มีทั้งการแจ้งเตือนและข้อมูลที่บรรจุ ในกรณีเหล่านี้การแจ้งเตือนจะถูกส่งไปที่ซิสเต็มเทรย์ของอุปกรณ์และมีการส่งข้อมูลไปยังส่วนเสริมของเจตนาของตัวเรียกใช้งานของคุณ

หากคุณต้องการเปิดแอปและดำเนินการบางอย่างให้ตั้งค่า click_action ในส่วนของการแจ้งเตือนและแมปกับตัวกรองเจตนาในกิจกรรมที่คุณต้องการเปิด ตัวอย่างเช่นตั้งค่า click_action เป็น OPEN_ACTIVITY_1 เพื่อทริกเกอร์ตัวกรองเจตนาดังต่อไปนี้:

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

แก้ไข:

ตามหัวข้อนี้:

คุณไม่สามารถตั้งค่า click_action payload โดยใช้ Firebase Console คุณสามารถลองทดสอบด้วยคำสั่ง curl หรือเซิร์ฟเวอร์ http ที่กำหนดเอง

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
คุณพูดถูก ฉันอ่านเอกสารแล้ว แต่ฉันสับสนที่จะนำสิ่งนี้ไว้ในรายการของฉัน? ฉันต้องเรียกใช้รหัสบน onMessageReceived บนไฟล์ java นั้นดังนั้นสิ่งที่ฉันควรทำอย่างไร
Parth Patel

คุณไม่สามารถทำให้แอปเรียกใช้ข้อความแจ้งเตือนโดยอัตโนมัติเมื่ออยู่ในพื้นหลัง แต่คุณต้องจัดการกับเจตนาที่ได้รับและดำเนินการเรียกมัน หรืออาจเป็นการดีที่สุดที่จะใช้คลาส / วิธีการแยกต่างหากที่ถูกเรียกใช้โดย onMessageReveiced และการจัดการความตั้งใจของคุณ ฉันได้เพิ่มตัวจัดการไปที่ onNewent ของกิจกรรมหลักและใช้งานได้ดีสำหรับฉัน
diidu

สายเกินไปที่จะตอบคำถาม @Parath Patel แต่อาจช่วยคนอื่นที่มีปัญหาเดียวกันลองดูคำตอบของฉันที่นี่stackoverflow.com/a/42279260/2734021
Daniel S.

จะต้องดำเนินการนี้ที่ไหน สำหรับกิจกรรมหรือบริการ Firebasemessage ของฉัน
มาห์ดี

** การเปลี่ยนเส้นทางการแจ้งเตือนหลายรายการไม่ทำงาน เช่น: หากฉันมีการแจ้งเตือนสามรายการจาก fcm บนพื้นหลังโดยใช้ "click_action" การแจ้งเตือนครั้งแรกเปลี่ยนเส้นทางสำเร็จแล้ว 2 การแจ้งเตือนการคลิกการเปลี่ยนเส้นทางกิจกรรมไม่ทำงาน
prasanthMurugan

24

ทำงานตั้งแต่กรกฎาคม 2562

Android compileSdkVersion 28, buildToolsVersion 28.0.3 และ firebase-messaging: 19.0.1

หลังจากการค้นคว้าหลายชั่วโมงผ่านคำถามและคำตอบ StackOverflow อื่น ๆ ทั้งหมดและลองใช้โซลูชันที่ล้าสมัยนับไม่ถ้วนโซลูชันนี้มีการจัดการเพื่อแสดงการแจ้งเตือนใน 3 สถานการณ์เหล่านี้:

- แอพอยู่ด้านหน้า:
ได้รับการแจ้งเตือนโดยวิธี onMessageReceived ที่คลาส MyFirebaseMessagingService ของฉัน

- แอปถูกฆ่า (มันไม่ได้ทำงานในพื้นหลัง): การแจ้งเตือนจะถูกส่งไปยังถาดการแจ้งเตือนโดยอัตโนมัติโดย FCM เมื่อผู้ใช้สัมผัสกับการแจ้งเตือนแอพจะเปิดตัวโดยเรียกกิจกรรมที่มี android.intent.category.LAUNCHER ในรายการ คุณสามารถรับส่วนข้อมูลของการแจ้งเตือนโดยใช้ getIntent (). getExtras () ที่เมธอด onCreate ()

- แอปอยู่ในพื้นหลัง: การแจ้งเตือนจะถูกส่งไปยังถาดการแจ้งเตือนโดยอัตโนมัติจาก FCM เมื่อผู้ใช้แตะที่การแจ้งเตือนแอปจะถูกนำไปยังส่วนหน้าโดยเรียกใช้กิจกรรมที่มี android.intent.category.LAUNCHER ในรายการ เนื่องจากแอพของฉันมี launchMode = "singleTop" ในกิจกรรมนั้นเมธอด onCreate () ไม่ได้ถูกเรียกเนื่องจากกิจกรรมหนึ่งของคลาสเดียวกันถูกสร้างขึ้นแล้วแทนที่จะเรียกใช้เมธอด onNewIntent () ของคลาสนั้นและคุณจะได้รับส่วนข้อมูลของ การแจ้งเตือนที่นั่นโดยใช้ intent.getExtras ()

ขั้นตอน: 1- หากคุณกำหนดกิจกรรมหลักของแอพเช่นนี้:

<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- เพิ่มบรรทัดเหล่านี้ที่เมธอด onCreate () ของ MainActivity.class ของคุณ

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

และวิธีการเหล่านี้เป็น 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- สร้างคลาส MyFirebase ดังนี้:

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- สร้างคลาสใหม่ NotificationActivity.class ดังนี้:

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- เพิ่มบรรทัดเหล่านี้ในแอป Manifest ภายในแท็กของคุณ

    <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- เพิ่มบรรทัดเหล่านี้ใน Application.java onCreate () วิธีการของคุณหรือใน 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));
  }

เสร็จสิ้น

ตอนนี้สิ่งนี้จะทำงานได้ดีใน 3 สถานการณ์ที่กล่าวถึงคุณต้องส่งการแจ้งเตือนจากเว็บคอนโซล Firebase ด้วยวิธีต่อไปนี้:

ในส่วนการแจ้งเตือน: หัวข้อการแจ้งเตือน = ชื่อที่จะแสดงในกล่องโต้ตอบการแจ้งเตือน (ตัวเลือก) ข้อความการแจ้งเตือน = ข้อความที่จะแสดงให้ผู้ใช้ (จำเป็น) จากนั้นในส่วนเป้าหมาย: แอป = แอป Android ของคุณและในส่วนตัวเลือกเพิ่มเติม: ช่องการแจ้งเตือน Android = default_channel_id คีย์ข้อมูลที่กำหนดเอง: ค่าชื่อ: (ข้อความเดียวกันที่นี่ในฟิลด์ชื่อของส่วนการแจ้งเตือน) คีย์: ค่าตัว: (ข้อความเดียวกันที่นี่มากกว่าในฟิลด์ข้อความของส่วนการแจ้งเตือน): ค่า click_action: เสียงหลัก = ปิดการใช้งาน
หมดอายุ = 4 สัปดาห์

คุณสามารถดีบักได้ใน Emulator ด้วย API 28 ด้วย Google Play

การเข้ารหัสที่มีความสุข!


2
ขอบคุณสำหรับคำตอบที่ยอดเยี่ยมนี้
Alex Chengalan

@alvaro, หากฉันต้องการเปิด Url เมื่อฉันได้รับการแจ้งเตือน, ฉันจะจัดการสิ่งนี้ได้อย่างไร
engmms

ไม่ทำงานในโทรศัพท์มือถือ vivo เมื่อแอปปิดหรือถูกฆ่า
นักพัฒนา Android

ฉันไม่ได้ลองใช้โทรศัพท์ Vivo แต่ขณะนี้ใช้งานได้กับโทรศัพท์ Android อื่น ๆ อีกมากมาย โปรดอ่านช้าทุกขั้นตอนตรวจสอบรายละเอียดทั้งหมดแล้วเปิดจุดบกพร่องจุดบกพร่องที่บรรทัดแรกของแต่ละวิธีที่ฉันได้กล่าวถึงที่นี่เชื่อมต่อโทรศัพท์จริงกับคอมพิวเตอร์พัฒนาของคุณด้วยสายเคเบิลและดีบักแอปในขณะที่ส่ง ข้อความจาก FCM ตรวจสอบว่าคุณกำลังส่งข้อความ FCM พร้อมพารามิเตอร์ทั้งหมดและรูปแบบที่ฉันกล่าวถึง โชคดี!
alvaro

2
นี่เป็นคำตอบที่ทันสมัยที่สุดเนื่องจากขณะนี้เอกสารประกอบของ Firebase อ่าน: เมื่อแอปของคุณอยู่ในพื้นหลัง Android จะส่งข้อความแจ้งเตือนไปยังถาดระบบ ผู้ใช้แตะที่การแจ้งเตือนจะเปิดตัวเรียกใช้งานแอปตามค่าเริ่มต้น ซึ่งรวมถึงข้อความที่มีทั้งการแจ้งเตือนและข้อมูลที่บรรจุ ในกรณีเหล่านี้การแจ้งเตือนจะถูกส่งไปที่ซิสเต็มเทรย์ของอุปกรณ์และมีการส่งข้อมูลไปยังส่วนเสริมของเจตนาของตัวเรียกใช้งานของคุณ ( firebase.google.com/docs/cloud-messaging/android/… ) คำตอบเก่า ๆ มากมายล้าสมัย
Riot Goes Woof

20

เนื่องจากสิ่งdisplay-messagesที่ส่งมาจาก Firebase Notification UI ใช้งานได้เฉพาะเมื่อแอปของคุณอยู่เบื้องหน้า สำหรับdata-messagesมีความจำเป็นต้องทำการโทร POST ไปที่FCM

ขั้นตอน

  1. ติดตั้งไคลเอ็นต์ขั้นสูงที่เหลือสำหรับส่วนขยายของ Google Chrome ป้อนคำอธิบายรูปภาพที่นี่

  2. เพิ่มส่วนหัวต่อไปนี้

    คีย์ : ประเภทเนื้อหา, ค่า : application / json

    รหัส : การอนุญาต, ค่า : key = "คีย์เซิร์ฟเวอร์ของคุณ" ป้อนคำอธิบายรูปภาพที่นี่

  3. เพิ่มร่างกาย

    • หากใช้หัวข้อ:

      {
          "to" : "/topics/topic_name",
          "data": {
          "key1" : "value1",
          "key2" : "value2",
          }
      }
    • หากใช้รหัสการลงทะเบียน:

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

แค่นั้นแหละ!. ตอนนี้ฟังการonMessageReceivedโทรกลับตามปกติ

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

20

ในการจับภาพข้อความในพื้นหลังคุณจำเป็นต้องใช้ 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)
        }
    }

และเพิ่มสิ่งนี้ในรายการของคุณ:

<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
นี่จะได้รับข้อความแจ้งเตือนเมื่อแอปอยู่ในพื้นหลัง แต่มันไม่ได้หยุดตัวรับ Firebase เริ่มต้นจากการจัดการมันดังนั้นข้อความยังคงปรากฏขึ้นเป็นการแจ้งเตือนการแจ้งเตือน
Galya

ในขณะนี้ใช้งานไม่ได้ดังนั้นฉันจึงเสนอวิธีแก้ปัญหานี้ มีข้อผิดพลาดที่ยื่นใน google bugbase คุณอาจต้องการตรวจสอบว่า
Romulano

คุณช่วยกรุณาโพสต์ลิงก์ไปยังข้อผิดพลาดได้ที่นี่หรือ
เปล่า

วิธีรับข้อมูลจากการแจ้งเตือน
Ravi Vaghela

เห็นได้ชัดว่าไม่ได้ทำงานเมื่อแอพถูกฆ่า ฉันลองวิธีนี้มาหลายชั่วโมงแล้ว ด้วยเหตุผลบางอย่างตัวรับสัญญาณทำงานในขณะที่แอปอยู่ในพื้นหลังและไม่ทำงานเมื่อแอพถูกฆ่า
XcodeNOOB

16
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {

}

ไม่ได้ถูกเรียกทุกครั้งที่มีการเรียกเฉพาะเมื่อแอปอยู่ใน Forground

มีวิธีการหนึ่งแทนที่วิธีนี้เรียกว่าทุกครั้งไม่ว่าแอพใดจะอยู่ด้านหน้าหรือเบื้องหลังหรือถูกฆ่า แต่วิธีนี้ใช้ได้กับ firebase api รุ่นนี้

นี่เป็นเวอร์ชั่นที่คุณต้องนำเข้าจาก gradle

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

นี่คือวิธีการ

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

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


}

กับ firebase api ก่อนหน้านี้วิธีการนี้ไม่ได้มีดังนั้นในกรณีนั้น fire base จัดการตัวเองเมื่อ app อยู่ในพื้นหลัง .... ตอนนี้คุณมีวิธีนี้สิ่งที่คุณอยากจะทำ ... คุณสามารถทำได้ที่นี่ในวิธีนี้ .. ...

หากคุณใช้เวอร์ชันก่อนหน้านี้มากกว่ากิจกรรมเริ่มต้นจะเริ่มในกรณีนั้นคุณสามารถรับข้อมูลได้ในลักษณะเดียวกัน

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

// ทำในสิ่งที่คุณต้องการ .... }

โดยทั่วไปนี่คือโครงสร้างจากเซิร์ฟเวอร์ที่เราได้รับการแจ้งเตือน

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

มันขึ้นอยู่กับคุณว่าคุณต้องการให้คีย์ข้อมูลนั้นหรือคุณต้องการให้การแจ้งเตือนสิ่งที่คุณสามารถให้ ....... สิ่งที่คุณจะให้ที่นี่ด้วยคีย์เดียวกันคุณจะได้รับข้อมูล ........ .

มีบางกรณีหากคุณไม่ได้ส่งการคลิกในกรณีนี้เมื่อคุณจะคลิกที่กิจกรรมเริ่มต้นการแจ้งเตือนจะเปิดขึ้น แต่ถ้าคุณต้องการเปิดกิจกรรมเฉพาะของคุณเมื่อแอปอยู่ในพื้นหลังคุณสามารถเรียกกิจกรรมของคุณได้จากวิธีการจัดการ ถูกเรียกทุกครั้ง


ฉันอัปเดต firebase-messaging เป็น 10.2.1 เพิ่มข้อมูลไปยังข้อความแจ้งเตือนและใช้งานได้ เบื้องหน้าเบื้องหลังและฆ่า ขอบคุณ
Firas Shrourou

ใน Kotlin ฉันได้รับข้อผิดพลาดนี้: (44, 5) 'handleIntent' ใน 'FirebaseMessagingService' ถือเป็นที่สิ้นสุดและไม่สามารถแทนที่ได้
ugali soft

มันไม่ทำงานเหนือเวอร์ชั่นของ
firebase

14

อ้างอิงจากเอกสาร: 17 พฤษภาคม 2017

เมื่อแอปของคุณอยู่ในพื้นหลัง Android จะส่งข้อความแจ้งเตือนไปยังถาดระบบ แตะของผู้ใช้ในการแจ้งเตือนเปิดlauncher app โดยค่าเริ่มต้น

ซึ่งรวมถึงข้อความที่มีทั้งการแจ้งเตือนและข้อมูลที่บรรจุ (และข้อความทั้งหมดที่ส่งจากคอนโซลการแจ้งเตือน) ในกรณีเหล่านี้การแจ้งเตือนจะถูกส่งไปที่ซิสเต็มเทรย์ของอุปกรณ์และมีการส่งข้อมูลไปยังส่วนเสริมของเจตนาของตัวเรียกใช้งานของคุณ

ดังนั้นคุณควรใช้การแจ้งเตือน payload + data ทั้งสอง:

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

ไม่จำเป็นต้องใช้ click_action คุณควรได้รับความพิเศษจากเจตนาต่อกิจกรรมของ LAUNCHER

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

รหัส Java ควรเป็น onCreate วิธีการใน MainActivity:

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

คุณสามารถทดสอบทั้งสองของการแจ้งเตือนอัตรา + ข้อมูลจากFirebase การแจ้งเตือนคอนโซล อย่าลืมเติมฟิลด์ข้อมูลที่กำหนดเองในส่วนตัวเลือกขั้นสูง


13

นี่คือแนวคิดที่ชัดเจนมากขึ้นเกี่ยวกับข้อความ firebase ฉันพบมันจากทีมสนับสนุนของพวกเขา

Firebase มีข้อความสามประเภท :

ข้อความแจ้งเตือน : ข้อความแจ้งเตือนทำงานบนพื้นหลังหรือเบื้องหน้า เมื่อแอปอยู่ในพื้นหลังข้อความแจ้งเตือนจะถูกส่งไปที่ซิสเต็มเทรย์ หากแอปอยู่เบื้องหน้าข้อความจะถูกจัดการonMessageReceived()หรือdidReceiveRemoteNotificationโทรกลับ สิ่งเหล่านี้เป็นสิ่งที่เรียกว่าข้อความการแสดงผล

ข้อความข้อมูล : บนแพลตฟอร์ม Android ข้อความข้อมูลสามารถทำงานบนพื้นหลังและเบื้องหน้า ข้อความข้อมูลจะถูกจัดการโดย onMessageReceived () หมายเหตุเฉพาะแพลตฟอร์มที่นี่จะเป็น: บน Android สามารถโหลดข้อมูลได้ใน Intent ที่ใช้เพื่อเริ่มกิจกรรมของคุณ ทำอย่างละเอียดถ้าคุณมี"click_action":"launch_Activity_1"คุณสามารถดึงนี้ผ่านความตั้งใจที่จะเริ่มต้นเพียงgetIntent()Activity_1

ข้อความที่มีทั้งการแจ้งเตือนและข้อมูลที่รับส่งข้อมูล : เมื่ออยู่ในพื้นหลังแอปจะได้รับการแจ้งข้อมูลในถาดการแจ้งเตือนและจัดการเฉพาะข้อมูลที่รับส่งข้อมูลเมื่อผู้ใช้แตะที่การแจ้งเตือน เมื่ออยู่เบื้องหน้าแอปของคุณจะได้รับออบเจกต์ข้อความพร้อมเพย์โหลดทั้งสองที่มีอยู่ ประการที่สองclick_actionพารามิเตอร์นี้มักใช้ในเพย์โหลดการแจ้งเตือนไม่ใช่ในเพย์โหลดข้อมูล หากใช้ภายใน data payload พารามิเตอร์นี้จะถือว่าเป็นคู่ของคีย์ - ค่าที่กำหนดเองดังนั้นคุณจะต้องใช้ตรรกะที่กำหนดเองเพื่อให้มันทำงานตามที่ต้องการ

นอกจากนี้ฉันขอแนะนำให้คุณใช้onMessageReceivedวิธีการ (ดูที่ Data data) เพื่อแยกบันเดิลข้อมูล จากตรรกะของคุณฉันตรวจสอบวัตถุบันเดิลและไม่พบเนื้อหาข้อมูลที่คาดหวัง นี่คือการอ้างอิงถึงกรณีที่คล้ายกันซึ่งอาจให้ความชัดเจนมากขึ้น

สำหรับข้อมูลเพิ่มเติมโปรดเยี่ยมชมหัวข้อของฉันนี้



8

สรุปง่าย ๆ เช่นนี้

  • หากแอปของคุณกำลังทำงาน

    onMessageReceived()

เป็นตัวกระตุ้น

  • หากแอปของคุณไม่ทำงาน (ถูกฆ่าโดยการปัดนิ้ว)

    onMessageReceived()

จะไม่ถูกเรียกและส่งมอบโดย direclty หากคุณมีคู่คีย์ - ค่าพิเศษใด ๆ พวกเขาไม่ได้ทำงานเพราะ onMessageReceived () ไม่ทำงาน

ฉันพบวิธีนี้แล้ว

ในกิจกรรมตัวเรียกใช้ของคุณให้วางตรรกะนี้

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

ในนี้ถ้าบล็อกค้นหากุญแจของคุณตาม firebase UI

ในตัวอย่างนี้คีย์และค่าของฉันเหมือนด้านบน (ขออภัยภาษา =) ป้อนคำอธิบายรูปภาพที่นี่

เมื่อรหัสของฉันทำงานฉันจะได้รับ "com.rda.note"

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

ด้วยรหัสบรรทัดนี้ฉันปิดแอปพลิเคชันของฉันและเปิด Google Play Market

การเข้ารหัสที่มีความสุข =)


6

ฉันหาสถานการณ์

เมื่อ app อยู่ในเบื้องหน้า , onMessageReceived ()วิธีการที่เรียกว่าจากFirebaseServiceดังนั้นpendingIntentกำหนดไว้ในระดับบริการจะถูกเรียกว่า

และเมื่อ app อยู่ในพื้นหลัง , กิจกรรมแรกที่เรียกว่า

ทีนี้ถ้าคุณใช้กิจกรรมสแปลชคุณต้องจำไว้ว่าสแปลชจะถูกเรียกมิฉะนั้นถ้าไม่มีกิจกรรมสแปลชกิจกรรมใดก็ตามที่ถูกเรียก

จากนั้นคุณต้องตรวจสอบgetIntent ()ของfirstActivityเพื่อดูว่ามีบันเดิลใด ๆ หรือไม่หากทุกอย่างไม่เป็นไรคุณจะเห็นบันเดิลนั้นมีค่าที่กรอกหากค่าในแท็กข้อมูลที่ส่งจากเซิร์ฟเวอร์มีลักษณะเช่นนี้

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

จากนั้นในกิจกรรมแรกคุณจะดูมีความตั้งใจที่ถูกต้อง ( getIntent () ไม่ null ) มัดที่ถูกต้องและมัดภายในมีทั้ง JSON จะกล่าวถึงข้างต้นด้วยข้อมูลที่ เป็นกุญแจสำคัญ

สำหรับสถานการณ์นี้รหัสสำหรับการแยกค่าจะมีลักษณะเช่นนี้

    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

ขอบคุณทุกคนสำหรับคำตอบของคุณ แต่ฉันจะแก้ไขนี้โดยการส่งข้อความข้อมูลแทนการส่งการแจ้งเตือน รหัสเซิร์ฟเวอร์

<?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;

?>

และจับข้อมูลใน onMessageReceived

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
มันทำงานกับพื้นหลังด้วยหรือไม่
Tabish khan

@ Tabishkhan ใช่พี่ชายมันทำงานถ้าคุณมีปัญหาใด ๆ โปรดถามฉัน .. ขอบคุณ
Android Sanaullah

1
สวัสดี @AndroidSanaullah คุณช่วยอธิบายส่วนแรกของรหัสเซิร์ฟเวอร์ที่คุณใส่ไว้จริงฉันกำลังเผชิญปัญหาเดียวกัน แต่ฉันไม่เข้าใจส่วนเซิร์ฟเวอร์คุณใช้บุรุษไปรษณีย์หรือไม่
Shid

curlใช้สำหรับการร้องขอและพารามิเตอร์ทั้งหมดจะถูกส่งผ่านไปยัง @ Shid
Android Sanaullah

2

ลบเพย์โหลดการแจ้งเตือนออกจากคำขอเซิร์ฟเวอร์ของคุณโดยสมบูรณ์ ส่งข้อมูลเท่านั้นและจัดการกับมันonMessageReceived()มิฉะนั้นคุณonMessageReceivedจะไม่ถูกเรียกใช้เมื่อแอปอยู่ในพื้นหลังหรือถูกฆ่า

นี่คือสิ่งที่ฉันกำลังส่งจากเซิร์ฟเวอร์:

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

ดังนั้นคุณสามารถรับข้อมูลของคุณในonMessageReceived(RemoteMessage message)ลักษณะนี้: (สมมติว่าฉันต้องได้รับ id)

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

และในทำนองเดียวกันคุณสามารถรับข้อมูลใด ๆ ที่คุณส่งจากเซิร์ฟเวอร์ภายใน onMessageReceived()ที่คุณได้ส่งจากเซิร์ฟเวอร์ภายใน


2

วิธีง่ายๆในการส่งข้อความแม้ว่าแอปจะอยู่ในพื้นหลังและพื้นหน้าดังต่อไปนี้: - ในการส่งข้อความโดยใช้ API คุณสามารถใช้เครื่องมือที่ชื่อว่า AdvancedREST Client ซึ่งเป็นส่วนขยายของ Chrome และส่งข้อความด้วยพารามิเตอร์ต่อไปนี้

ส่วนที่เหลือเชื่อมโยงเครื่องมือลูกค้า: https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo

ใช้ URL นี้: - https://fcm.googleapis.com/fcm/send Content-Type: application / json การอนุญาต: key = คีย์เซิร์ฟเวอร์ของคุณจากหรือคีย์ Authoization (ดูด้านล่างอ้างอิง)

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

คุณสามารถรับรหัสอนุญาตได้โดยไปที่คอนโซลนักพัฒนาซอฟต์แวร์ของ Google และคลิกที่ปุ่มข้อมูลรับรองที่เมนูด้านซ้ายสำหรับโครงการของคุณ ในบรรดาคีย์ API ที่ระบุไว้รหัสเซิร์ฟเวอร์จะเป็นรหัสอนุญาตของคุณ

และคุณต้องใส่โทเค็น ID ของผู้รับในส่วน“ ถึง” ของคำขอ POST ของคุณที่ส่งโดยใช้ API


2

คุณต้องการที่จะทำงานกับ MessageReceived (RemoteMessage remoteMessage) ในพื้นหลังส่งเพียงส่วนหนึ่งของการแจ้งเตือนข้อมูลนี้:

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

"AnotherActivity": "True", "ถึง": "รหัสอุปกรณ์หรือโทเค็นอุปกรณ์"

โดย onMessageRecivied นี้เป็นพื้นหลังการโทรและเบื้องหน้าไม่จำเป็นต้องจัดการการแจ้งเตือนโดยใช้ถาดการแจ้งเตือนในกิจกรรมตัวเปิดใช้ของคุณ จัดการ data payload ในการใช้สิ่งนี้:

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

1

มิถุนายน 2561 คำตอบ -

คุณต้องแน่ใจว่าไม่มีคำว่า "การแจ้งเตือน" ที่ใด ๆ ในข้อความ รวมเฉพาะ "ข้อมูล" เท่านั้นและแอปจะสามารถจัดการข้อความใน onMessageReceived ได้แม้ว่าจะอยู่ในพื้นหลังหรือถูกฆ่า

การใช้ฟังก์ชั่นคลาวด์:

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

จากนั้นใน onMessageReceived () ของคุณในชั้นเรียนของคุณขยาย 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.

คุณมีแหล่งข้อมูลใด ๆ ปลอดภัยหรือไม่
Yogesh Rathi

มันปลอดภัยฉันใช้มันในแอพของฉัน อย่างไรก็ตามการโพสต์ 6 เดือนฉันจำแหล่งที่มาไม่ได้ - ฉันคิดว่ามันเป็นเอกสารของ firebase
Jeff Padgett

1

อ้างอิงจาก OAUTH 2.0:

จะมีปัญหาการตรวจสอบสิทธิ์สำหรับกรณีนี้เนื่องจาก FCM ใช้ OAUTH 2 ในขณะนี้

ดังนั้นฉันอ่านเอกสาร firebase และตามเอกสารวิธีใหม่ในการโพสต์ข้อมูลเป็น;

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

ส่วนหัว

Key: Content-Type, Value: application/json

รับรองความถูกต้อง

Bearer YOUR_TOKEN 

ตัวอย่างร่างกาย

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

ใน url มีรหัสฐานข้อมูลซึ่งคุณสามารถค้นหาได้บนคอนโซล firebase ของคุณ (ไปตั้งโครงการ)

และตอนนี้ให้ใช้โทเค็นของเรา (จะใช้ได้เพียง 1 ชั่วโมง):

เป็นครั้งแรกใน Firebase คอนโซลเปิดการตั้งค่า> บริการบัญชี คลิกสร้างคีย์ส่วนตัวใหม่จัดเก็บไฟล์ JSON ที่มีรหัสอย่างปลอดภัย ฉันต้องการไฟล์ JSON นี้เพื่อให้สิทธิ์คำขอเซิร์ฟเวอร์ด้วยตนเอง ฉันดาวน์โหลดมัน

จากนั้นฉันสร้างโปรเจค node.js และใช้ฟังก์ชันนี้เพื่อรับโทเค็นของฉัน

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

ตอนนี้ฉันสามารถใช้โทเค็นนี้ในคำขอโพสต์ของฉัน จากนั้นฉันโพสต์ข้อความข้อมูลของฉันและตอนนี้แอพของฉันจัดการกับฟังก์ชั่น Messenger ที่ได้รับ


คำตอบที่ยอมรับใช้งานได้ Barer token auth ไม่ใช่วิธีที่คุณต้องอ่านเพื่อลองใช้กับ Postman: stackoverflow.com/questions/45309674/…
Carlos Jesus Arancibia Taborga

1

ตั้งแต่ปี 2019 Google Firebase มีการเปลี่ยนแปลงครั้งใหญ่ใน API ของพวกเขาฉันหมายถึง: 'com.google.firebase:firebase-messaging:18.0.0'

ใน 18.0.0 พวกเขาถูกลบออกMyFirebaseInstanceIDServiceและคุณต้องรับโทเค็นMyFirebaseMessagingServiceดังนั้นคุณต้องเขียน:

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

}

และใน AndroidManifest.xml คุณต้องลบ:

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

นอกจากนี้คุณขอแนะนำให้ตั้งค่าเริ่มต้นเพื่อปรับแต่งลักษณะที่ปรากฏของการแจ้งเตือน คุณสามารถระบุไอคอนเริ่มต้นที่กำหนดเองและสีเริ่มต้นที่กำหนดเองที่ใช้เมื่อใดก็ตามที่ค่าที่เทียบเท่าไม่ได้ตั้งค่าไว้ในเพย์โหลดการแจ้งเตือน

เพิ่มบรรทัดเหล่านี้ภายในแท็กของแอปพลิเคชันเพื่อตั้งค่าไอคอนเริ่มต้นที่กำหนดเองและสีที่กำหนดเอง:

    <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" />

ตอนนี้เพื่อจัดการข้อความแจ้งเตือนในแอปที่มีพื้นหลังคุณควรกำหนดเจตนาในกิจกรรมแรกของคุณแม้ว่าจะเป็น SplashScreen เมื่อแอปของคุณอยู่ในพื้นหลัง Android จะส่งข้อความแจ้งเตือนไปยังถาดระบบ ผู้ใช้แตะที่การแจ้งเตือนจะเปิดตัวเรียกใช้งานแอปตามค่าเริ่มต้น

ตัวอย่างเช่นหาก Json ของคุณเป็นเช่นนี้:

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

คุณเพียงแค่ต้องเขียนเจตนาง่าย ๆ เพื่อรับค่าเหล่านั้น:

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

0

นอกเหนือจากคำตอบข้างต้นหากคุณกำลังทดสอบการแจ้งเตือนแบบพุชโดยใช้คอนโซล FCMคีย์และวัตถุ 'ข้อมูล' ไม่ใช่ถูกเพิ่มลงในชุดการแจ้งเตือนแบบพุช ดังนั้นคุณจะไม่ได้รับการแจ้งเตือนแบบละเอียดเมื่อแอปเป็นพื้นหลังหรือถูกฆ่า

ในกรณีนี้คุณต้องเลือกใช้คอนโซลผู้ดูแลระบบด้านหลังเพื่อทดสอบสถานการณ์พื้นหลังของแอป

ที่นี่คุณจะได้เพิ่มคีย์ 'data' ลงในชุดพุชของคุณ ดังนั้นรายละเอียดการพุชจะแสดงตามที่คาดไว้ หวังว่าจะช่วยได้ไม่กี่


0

ใช้รหัสนี้คุณสามารถรับการแจ้งเตือนในพื้นหลัง / เบื้องหน้าและดำเนินการ:

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

In-App ใช้รหัสนี้:

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

// ข้อมูลควรอยู่ในรูปแบบนี้จากการแจ้งเตือน {"ถึง": "/ xyz / การแจ้งเตือน", "ข้อมูล": {"key1": "การแจ้งเตือนชื่อ", "key2": "การแจ้งเตือนคำอธิบาย"}} วิธีเขียน รหัสนี้ในบริการ php?
Tabish khan

-3

การแจ้งเตือนจะมีสองประเภท

  1. แสดงการแจ้งเตือน - เฉพาะการแจ้งเตือนการแสดงผลที่จะแสดงเฉพาะแอปที่ไม่ได้เปิดอยู่และในแอปสแต็ก
  2. การแจ้งข้อมูล - การโทรกลับจะเข้าสู่ onMessageReceived วิธีการดับเพลิงการบริการการแจ้งเตือนและจะทำงานเมื่อแอปอยู่ในพื้นหลังเบื้องหน้าหรือสถานะที่ถูกฆ่า

คุณต้องใช้การแจ้งเตือนข้อมูลเพื่อจัดการการแจ้งเตือนเมื่อแอปอยู่ในพื้นหลัง


-5

ฉันประสบปัญหาเดียวกันและคอมไพล์ไลบรารี firebase อีกครั้งและป้องกันไม่ให้ส่งการแจ้งเตือนเมื่อแอปพลิเคชันอยู่ในพื้นหลัง

* ห้องสมุด 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
}

หวังว่าจะช่วย โชคดี


2
ไม่ใช่คำตอบที่มีประโยชน์
Ankit Patidar

2
นี่เป็นคำแนะนำที่น่ากลัว
vsecades
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.