การแจ้งเตือน Firebase จะทํางานแตกต่างกันไปตามสถานะเบื้องหน้า/เบื้องหลังของแอปที่รับ หากต้องการให้แอปที่อยู่เบื้องหน้ารับข้อความแจ้งเตือนหรือข้อความข้อมูล คุณจะต้องเขียนโค้ดเพื่อจัดการonMessageReceived
callback
ดูคำอธิบายความแตกต่างระหว่างข้อความแจ้งเตือนกับข้อความข้อมูลได้ที่ประเภทข้อความ
การจัดการข้อความ
หากต้องการรับข้อความ ให้ใช้บริการที่ขยาย
FirebaseMessagingService
บริการของคุณควรลบล้างการเรียกกลับ onMessageReceived
และ onDeletedMessages
onMessageReceived
มีให้ใช้งานสำหรับข้อความส่วนใหญ่ โดยมีข้อยกเว้นต่อไปนี้
-
ข้อความแจ้งเตือนที่ส่งเมื่อแอปทำงานอยู่เบื้องหลัง ในกรณีนี้ ระบบจะส่งการแจ้งเตือนไปยังถาดระบบของอุปกรณ์ เมื่อผู้ใช้แตะการแจ้งเตือน ระบบจะเปิดตัวเปิดแอปโดยค่าเริ่มต้น
-
ข้อความที่มีทั้งเพย์โหลดการแจ้งเตือนและเพย์โหลดข้อมูลเมื่อได้รับในเบื้องหลัง ในกรณีนี้ ระบบจะส่งการแจ้งเตือนไปยังถาดระบบของอุปกรณ์ และส่งเพย์โหลดข้อมูลในส่วนพิเศษของ Intent ของกิจกรรมตัวเรียกใช้งาน
บทสรุปมีดังนี้:
สถานะของแอป | การแจ้งเตือน | ข้อมูล | ทั้งสอง |
---|---|---|---|
พื้นหน้า | onMessageReceived |
onMessageReceived |
onMessageReceived |
ข้อมูลเบื้องต้น | ถาดระบบ | onMessageReceived |
การแจ้งเตือน: ถาดระบบ ข้อมูล: ในส่วนพิเศษของ Intent |
onMessageReceived
การเรียกกลับจะได้รับระยะหมดเวลาที่ช่วยให้คุณโพสต์การแจ้งเตือนได้ง่ายๆ แต่ตัวจับเวลาไม่ได้ออกแบบมาเพื่อให้แอปเข้าถึงเครือข่ายหรือทำงานเพิ่มเติมได้
ดังนั้น หากแอปของคุณทำสิ่งต่างๆ ที่ซับซ้อนกว่านี้ คุณจะต้องดำเนินการเพิ่มเติม
เพื่อให้แน่ใจว่าแอปจะทำงานให้เสร็จสมบูรณ์ได้
หากคาดว่าแอปอาจต้องใช้เวลาเกือบ 10 วินาทีในการจัดการข้อความ คุณควร
กำหนดเวลางาน WorkManager
หรือทำตาม
คำแนะนำเกี่ยวกับ WakeLock ด้านล่าง ในบางกรณี
กรอบเวลาในการจัดการข้อความอาจสั้นกว่า 10 วินาที ทั้งนี้ขึ้นอยู่กับความล่าช้า
ที่เกิดขึ้นก่อนการเรียกใช้ onMessageReceived
ซึ่งรวมถึงความล่าช้าของระบบปฏิบัติการ เวลาเริ่มต้นของแอป
การบล็อกเธรดหลักโดยการดำเนินการอื่นๆ หรือการเรียกใช้ onMessageReceived
ก่อนหน้านี้
ที่ใช้เวลานานเกินไป หลังจากตัวจับเวลาหมดอายุ แอปของคุณอาจ
ต้อง
สิ้นสุดกระบวนการ
หรือ
ขีดจำกัดการทำงานในเบื้องหลัง โปรดทราบว่าเวลาในการตอบสนองสำหรับการทำธุรกรรมในเครือข่ายและการเริ่มต้นแอปอาจนานมาก ดังนั้นหากไม่แน่ใจ ให้วางแผนให้การประมวลผลข้อความทำงานเป็นเวลานานหากมีการขึ้นต่อกันแบบไม่พร้อมกัน เช่น การเข้าถึงเครือข่ายหรือข้อกำหนดในการโหลดข้อมูลจำนวนมาก
แก้ไขไฟล์ Manifest ของแอป
หากต้องการใช้ FirebaseMessagingService
คุณต้องเพิ่มสิ่งต่อไปนี้ในไฟล์ Manifest ของแอป
<service android:name=".java.MyFirebaseMessagingService" android:exported="false"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
นอกจากนี้ เราขอแนะนําให้คุณตั้งค่าเริ่มต้นเพื่อปรับแต่งลักษณะที่ปรากฏของการแจ้งเตือน คุณ ระบุไอคอนเริ่มต้นที่กำหนดเองและสีเริ่มต้นที่กำหนดเองซึ่งจะใช้เมื่อใดก็ตามที่ ไม่ได้ตั้งค่าที่เทียบเท่าไว้ในเพย์โหลดการแจ้งเตือนได้
เพิ่มบรรทัดต่อไปนี้ภายในแท็ก
application
เพื่อตั้งค่าไอคอนเริ่มต้นและสีที่กำหนดเอง
<!-- Set custom default icon. This is used when no icon is set for incoming notification messages. See README(https://goo.gl/l4GJaQ) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_icon" android:resource="@drawable/ic_stat_ic_notification" /> <!-- Set color used with incoming notification messages. This is used when no color is set for the incoming notification message. See README(https://goo.gl/6BKBk7) for more. --> <meta-data android:name="com.google.firebase.messaging.default_notification_color" android:resource="@color/colorAccent" />
Android จะแสดงไอคอนเริ่มต้นที่กำหนดเองสำหรับ
- ข้อความแจ้งเตือนทั้งหมดที่ส่งจาก เครื่องมือแต่งการแจ้งเตือน
- ข้อความแจ้งเตือนที่ไม่ได้ตั้งค่าไอคอนอย่างชัดเจนในเพย์โหลดการแจ้งเตือน
Android ใช้สีเริ่มต้นที่กำหนดเองสำหรับ
- ข้อความแจ้งเตือนทั้งหมดที่ส่งจาก เครื่องมือแต่งการแจ้งเตือน
- ข้อความแจ้งเตือนที่ไม่ได้ตั้งค่าสีอย่างชัดเจนในเพย์โหลดการแจ้งเตือน
หากไม่ได้ตั้งค่าไอคอนเริ่มต้นที่กำหนดเองและไม่ได้ตั้งค่าไอคอนในเพย์โหลดการแจ้งเตือน Android จะแสดงไอคอนแอปพลิเคชันที่แสดงเป็นสีขาว
ลบล้าง onMessageReceived
การลบล้างเมธอด FirebaseMessagingService.onMessageReceived
จะช่วยให้คุณดำเนินการตามออบเจ็กต์ RemoteMessage
ที่ได้รับและรับข้อมูลข้อความได้
Kotlin
override fun onMessageReceived(remoteMessage: RemoteMessage) { // TODO(developer): Handle FCM messages here. // Not getting messages here? See why this may be: https://goo.gl/39bRNJ Log.d(TAG, "From: ${remoteMessage.from}") // Check if message contains a data payload. if (remoteMessage.data.isNotEmpty()) { Log.d(TAG, "Message data payload: ${remoteMessage.data}") // Check if data needs to be processed by long running job if (needsToBeScheduled()) { // For long-running tasks (10 seconds or more) use WorkManager. scheduleJob() } else { // Handle message within 10 seconds handleNow() } } // Check if message contains a notification payload. remoteMessage.notification?.let { Log.d(TAG, "Message Notification Body: ${it.body}") } // Also if you intend on generating your own notifications as a result of a received FCM // message, here is where that should be initiated. See sendNotification method below. }
Java
@Override public void onMessageReceived(RemoteMessage remoteMessage) { // TODO(developer): Handle FCM messages here. // Not getting messages here? See why this may be: https://goo.gl/39bRNJ Log.d(TAG, "From: " + remoteMessage.getFrom()); // Check if message contains a data payload. if (remoteMessage.getData().size() > 0) { Log.d(TAG, "Message data payload: " + remoteMessage.getData()); if (/* Check if data needs to be processed by long running job */ true) { // For long-running tasks (10 seconds or more) use WorkManager. scheduleJob(); } else { // Handle message within 10 seconds handleNow(); } } // Check if message contains a notification payload. if (remoteMessage.getNotification() != null) { Log.d(TAG, "Message Notification Body: " + remoteMessage.getNotification().getBody()); } // Also if you intend on generating your own notifications as a result of a received FCM // message, here is where that should be initiated. See sendNotification method below. }
เปิดหน้าจออุปกรณ์ค้างไว้ขณะจัดการข้อความ FCM
หากแอปต้องทำให้อุปกรณ์ตื่นอยู่ขณะประมวลผลข้อความ FCM แอปจะต้อง
ถือ WakeLock ในช่วงเวลานี้ หรือจะต้องสร้างงาน WorkManager WakeLock ทำงานได้ดี
สำหรับกิจกรรมการประมวลผลสั้นๆ ที่อาจเกินค่าเริ่มต้นonMessageReceived
ของระยะหมดเวลา สำหรับเวิร์กโฟลว์ที่ยาวนาน เช่น การส่ง RPC แบบอนุกรมหลายรายการไปยังเซิร์ฟเวอร์ การใช้
งาน WorkManager จะเหมาะสมกว่า WakeLock ในส่วนนี้ เราจะมุ่งเน้นที่วิธีใช้
WakeLock WakeLock จะป้องกันไม่ให้อุปกรณ์เข้าสู่โหมดสลีประหว่างที่แอปทำงาน ซึ่งอาจ
ส่งผลให้มีการใช้แบตเตอรี่มากขึ้น ดังนั้นจึงควรใช้ WakeLock ในกรณีที่แอป
ไม่ควรหยุดชั่วคราวขณะจัดการข้อความ เช่น
- การแจ้งเตือนที่ต้องดำเนินการทันที
- การโต้ตอบกับสิ่งต่างๆ นอกอุปกรณ์ที่ไม่ควรถูกขัดจังหวะ (เช่น การโอนข้อมูลผ่านเครือข่าย หรือการสื่อสารกับอุปกรณ์อื่น เช่น นาฬิกาที่จับคู่ไว้)
ก่อนอื่น คุณจะต้องตรวจสอบว่าแอปขอสิทธิ์ WakeLock (FCM SDK มีสิทธิ์นี้โดยค่าเริ่มต้น ดังนั้นโดยปกติแล้วจึงไม่จำเป็นต้องเพิ่มอะไร)
<uses-permission android:name="android.permission.WAKE_LOCK" />
จากนั้นแอปจะต้องรับ WakeLock เมื่อเริ่มต้นFirebaseMessagingService.onMessageReceived()
การเรียกกลับและปล่อยเมื่อสิ้นสุดการเรียกกลับ
FirebaseMessagingService
ที่กำหนดเองของแอป
@Override public void onMessageReceived(final RemoteMessage message) { // If this is a message that is time sensitive or shouldn't be interrupted WakeLock wakeLock = getSystemService(PowerManager.class).newWakeLock(PARTIAL_WAKE_LOCK, "myApp:messageReceived"); try { wakeLock.acquire(TIMEOUT_MS); // handle message ... finally { wakeLock.release(); } }
ลบล้าง onDeletedMessages
ในบางกรณี FCM อาจไม่ส่งข้อความ ปัญหานี้เกิดขึ้นเมื่อมีข้อความที่รอดำเนินการสำหรับแอปของคุณในอุปกรณ์หนึ่งๆ มากเกินไป (>100) ในขณะที่เชื่อมต่อ หรือหากอุปกรณ์ไม่ได้เชื่อมต่อกับ FCM นานกว่า 1 เดือน ในกรณีเหล่านี้
คุณอาจได้รับการเรียกกลับไปยัง FirebaseMessagingService.onDeletedMessages()
เมื่ออินสแตนซ์ของแอปได้รับการเรียกกลับนี้
แอปควรทำการซิงค์แบบเต็มกับเซิร์ฟเวอร์ของแอป หากคุณไม่ได้ส่งข้อความไปยังแอปในอุปกรณ์ดังกล่าวภายใน 4 สัปดาห์ที่ผ่านมา FCM จะไม่โทรหา onDeletedMessages()
จัดการข้อความแจ้งเตือนในแอปที่ทำงานเบื้องหลัง
เมื่อแอปทำงานในเบื้องหลัง Android จะส่งข้อความแจ้งเตือนไปยังถาดระบบ เมื่อผู้ใช้แตะการแจ้งเตือน ระบบจะเปิดตัวเปิดแอปโดยค่าเริ่มต้น
ซึ่งรวมถึงข้อความที่มีทั้งเพย์โหลดการแจ้งเตือนและเพย์โหลดข้อมูล (และข้อความทั้งหมดที่ส่งจากคอนโซลการแจ้งเตือน) ในกรณีเหล่านี้ ระบบจะส่งการแจ้งเตือนไปยังถาดระบบของอุปกรณ์ และส่งเพย์โหลดข้อมูลในส่วนพิเศษของ Intent ของกิจกรรมตัวเรียกใช้งาน
ดูข้อมูลเชิงลึกเกี่ยวกับการนำส่งข้อความไปยังแอปได้ที่ FCMแดชบอร์ดการรายงาน ซึ่งบันทึก จำนวนข้อความที่ส่งและเปิดในอุปกรณ์ Apple และ Android พร้อมกับ ข้อมูลสำหรับ "การแสดงผล" (การแจ้งเตือนที่ผู้ใช้เห็น) สำหรับแอป Android
รับข้อความ FCM ในโหมดการบูตโดยตรง
นักพัฒนาแอปที่ต้องการส่งข้อความ FCM ไปยังแอปแม้ก่อนที่อุปกรณ์จะปลดล็อก สามารถเปิดใช้แอป Android เพื่อรับข้อความเมื่ออุปกรณ์อยู่ในโหมด Direct Boot ได้ เช่น คุณอาจต้องการให้ผู้ใช้แอป ได้รับการแจ้งเตือนการปลุกแม้ในอุปกรณ์ที่ล็อกอยู่
เมื่อสร้าง Use Case นี้ ให้สังเกตแนวทางปฏิบัติแนะนำและข้อจำกัดทั่วไปสำหรับโหมดการบูตโดยตรง คุณควรพิจารณาระดับการมองเห็นของข้อความที่เปิดใช้การบูตโดยตรงเป็นพิเศษ เนื่องจากผู้ใช้ที่มีสิทธิ์เข้าถึงอุปกรณ์จะดูข้อความเหล่านี้ได้โดยไม่ต้องป้อนข้อมูลเข้าสู่ระบบของผู้ใช้
ข้อกำหนดเบื้องต้น
- ต้องตั้งค่าอุปกรณ์สำหรับโหมดการบูตโดยตรง
- อุปกรณ์ต้องติดตั้งบริการ Google Play เวอร์ชันล่าสุด (19.0.54 ขึ้นไป)
- แอปต้องใช้ FCM SDK (
com.google.firebase:firebase-messaging
) เพื่อรับข้อความ FCM
เปิดใช้การจัดการข้อความในโหมด Direct Boot ในแอป
ในไฟล์ Gradle ระดับแอป ให้เพิ่มทรัพยากร Dependency ในไลบรารีการรองรับการบูตโดยตรงของ FCM ดังนี้
implementation 'com.google.firebase:firebase-messaging-directboot:20.2.0'
ทำให้แอป
FirebaseMessagingService
รับรู้การบูตโดยตรงด้วยการเพิ่มแอตทริบิวต์android:directBootAware="true"
ในไฟล์ Manifest ของแอป<service android:name=".java.MyFirebaseMessagingService" android:exported="false" android:directBootAware="true"> <intent-filter> <action android:name="com.google.firebase.MESSAGING_EVENT" /> </intent-filter> </service>
คุณต้องตรวจสอบว่า FirebaseMessagingService
สามารถทำงานในโหมดการบูตโดยตรงได้ ตรวจสอบ
ข้อกำหนดต่อไปนี้
- บริการไม่ควรเข้าถึงที่เก็บข้อมูลที่ได้รับการป้องกันด้วยข้อมูลเข้าสู่ระบบขณะทำงานในโหมดการบูตโดยตรง
- บริการไม่ควรพยายามใช้คอมโพเนนต์ เช่น
Activities
,BroadcastReceivers
หรือServices
อื่นๆ ที่ไม่ได้ทำเครื่องหมายว่ารับรู้การบูตโดยตรงขณะทำงานในโหมดการบูตโดยตรง - ไลบรารีใดๆ ที่บริการใช้ต้องไม่เข้าถึงที่เก็บข้อมูลที่ได้รับการปกป้องด้วยข้อมูลเข้าสู่ระบบและไม่เรียกใช้คอมโพเนนต์ที่ไม่ใช่ DirectBootAware ขณะทำงานในโหมดการเปิดเครื่องโดยตรง ซึ่งหมายความว่าไลบรารีใดๆ ที่แอปใช้ซึ่งเรียกจากบริการจะต้องรับรู้การบูตโดยตรง หรือ แอปจะต้องตรวจสอบว่ากำลังทำงานในโหมดการบูตโดยตรงหรือไม่ และไม่เรียกใช้ไลบรารีในโหมดนั้น ตัวอย่างเช่น Firebase SDK จะทํางานกับการบูตโดยตรง (รวมไว้ในแอปได้โดยไม่ทําให้แอปขัดข้องในโหมดการบูตโดยตรง) แต่ Firebase API หลายรายการไม่รองรับการเรียกใช้ในโหมดการบูตโดยตรง
- หากแอปใช้
Application
ที่กำหนดเองApplication
จะต้องเป็นแบบ Direct Boot Aware ด้วย (ไม่มีสิทธิ์เข้าถึงพื้นที่เก็บข้อมูลที่ได้รับการปกป้องด้วยข้อมูลเข้าสู่ระบบในโหมด Direct Boot)
ดูคำแนะนำในการส่งข้อความไปยังอุปกรณ์ในโหมดการบูตโดยตรงได้ที่ส่งข้อความที่เปิดใช้การบูตโดยตรง