มาเปลี่ยน Push Notification บน Android จาก GCM ไปเป็น FCM กัน

Akexorcist
Firebase Thailand
Published in
5 min readOct 1, 2018
เดี๋ยว GCM ก็จะหยุดให้บริการแล้ว เปลี่ยนมาใช้ FCM ก่อนจะสายเกินไปดีกว่า

ลาก่อน GCM, สวัสดี FCM

ย้อนไปเมื่อหลายก่อน ถ้าคุณอยากจะทำ Push Notification ในแอพแอนดรอยด์ ก็คงไม่พ้น Google Cloud Messaging (GCM) ที่เป็นบริการส่งข้อความอยาก Web Server ของเราไปให้ผู้ใช้ได้อย่างง่ายดาย

จนกระทั่งวันที่ Google ได้เปิดตัว Firebase ขึ้นมาซึ่งในนั้นมี Firebase Cloud Messaging (FCM) อยู่ด้วยอีกทั้งยังแนะนำให้นักพัฒนาเปลี่ยนจาก GCM ไปใช้เป็น FCM เพื่ออนาคตที่ดีกว่า

มาถึงวันนี้ GCM ใกล้จะหมดอายุขัยในอีกไม่นาน (ประกาศ Deprecated ในวันที่ 4 ตุลาคม 2018 และปิดให้บริการในวันที่ 11 เมษายน 2019) แต่ก็ยังมีนักพัฒนาอีกมากมายที่ยังคงใช้ GCM กันอยู่

ลาก่อยยยยย

ดังนั้นใครที่ยังใช้ GCM อยู่ก็จะต้อง Migrate ระบบไปใช้เป็น FCM ให้เรียบร้อยซะ ก่อนที่ GCM จะปิดให้บริการอย่างถาวร

อะไรนะ ยังไม่รู้ว่าจะ Migrate ยังไง? ถ้างั้นก็อ่านบทความนี้ต่อได้เลย

สิ่งที่นักพัฒนาควรรู้ก่อนจะย้าย Push Notification จาก GCM ไปใช้ FCM

ฝั่ง Android

  • Device Token ที่ใช้บน GCM สามารถเอาใช้งานบน FCM ได้ทันที และ Device Token ก็ยังคงมีโอกาสเปลี่ยนได้ตลอดเวลาเหมือนเดิม
  • Topic Subscription บน GCM สามารถทำงานบน FCM ได้ทันที ไม่จำเป็นต้อง Subscribe ใหม่

ฝั่ง Web Server

  • FCM รองรับการใช้งานผ่าน HTTP และ XMPP เหมือนกับ GCM ดังนั้นแทบจะไม่ต้องทำอะไรเพิ่มเติมนอกจากเปลี่ยน Endpoint มาใช้ของ FCM เท่านั้นเอง

ขั้นตอนการ Migrate จาก GCM ไปเป็น FCM (ฝั่ง Android)

เพิ่มโปรเจคเก่าเข้าไปใน Firebase Console

การเพิ่มโปรเจคบน Google API Console ให้ไปอยู่ใน Firebase Console นั้นทำได้ง่ายมาก เพราะแค่กดสร้างโปรเจคขึ้นมาใหม่ใน Firebase Console ก็จะมีรายชื่อโปรเจคเก่าๆที่อยู่ใน Google API Console ให้เลือกด้วย

อยาก Import ตัวไหนก็จิ้มเลือกได้เลย

ถ้าเลือกโปรเจคเก่าๆที่อยู่บน Google API Console ก็จะเป้นการ Import ตัวโปรเจคเข้าสู่ Firebase Console โดยที่ API บางส่วนบน Google API ก็ยังสามารถใช้งานควบคู่กันได้ตามปกติ ยกตัวอย่างเช่นโปรเจคของผมที่มีบริการต่างๆของ Google API และ Firebase ดังนี้

  • Google API Console : Google Maps API และ Google Direction API
  • Firebase Console : Firebase Analytics และ Firebase Cloud Messaging

ซึ่งทั้งหมดนี้อยู่ในโปรเจคตัวเดียวกันล่ะ ดังนั้นผมจึงสามารถใช้บริการของทั้งสองฝั่งโดยอยู่ในโปรเจคตัวเดียวกันได้เลย เย้

เตรียม google-services.json ให้พร้อม

จากนั้นก็ให้เข้าไปที่ Project settings ของโปรเจคตัวนั้นต่อ เพราะว่าเราจะต้องไปดาวน์โหลดไฟล์ google-services.json เพื่อเอาไปใช้ในฝั่ง Android แทนไฟล์ของเก่าที่ได้มาจาก GCM

กดที่ปุ่มรูปเฟืองแล้วเลือก Project settings

เมื่อเข้าหน้า Project settings แล้ว ในแถบ General จะมีรายละเอียดของโปรเจคอยู่ รวมไปถึง Web API Key เพื่อให้ฝั่ง Web Server เอาไปใช้แทน API Key ตัวเก่าที่ได้จาก GCM (ที่ต้องแนบไปใน Header ที่ชื่อว่า Authorization)

และเมื่อเลื่อนลงมาข้างล่างอีกนิดก็จะเป็นส่วนที่เราจะต้องเพิ่มรายละเอียดแอพของเราเข้าไปเพื่อให้ Firebase Console สร้างไฟล์​ google-service.json ขึ้นมา

โดยกดที่ปุ่ม Add app แล้วเลือกเป็น Android ซะ จากนั้นจะมีหน้าต่างที่แบ่งออกเป็น 4 ตอน

โดยขั้นตอนที่ 1 จะต้องกรอกข้อมูลของแอพให้เรียบร้อยซะ มีดังนี้

  • Package Name
  • SHA-1 Certificate Fingerprint

จากนั้นในขั้นตอนที่ 2 จะให้เราดาวน์โหลดไฟล์ google-services.json ไปใช้งาน

และขั้นตอนที่ 3 ก็จะเป็นวิธีการเพิ่ม Firebase SDK เข้าไปในโปรเจค ซึ่งข้ามไปได้เลย

ส่วนขั้นตอนที่ 4 จะเป็นการเช็คว่าสามารถใช้งาน Firebase ได้ปกติหรือป่าว เราสามารถข้ามขั้นตอนนี้ได้ จะมีปุ่มให้กดข้ามอยู่

เพิ่มเติม — ส่วนใหญ่จะแบ่งโปรเจคเป็น 2 โปรเจค ตัวนึงสำหรับ Develop และอีกตัวสำหรับ Production ดังนั้นอย่าลืมเตรียม google-services.json แยกกันด้วยนะ โดยที่

  • โปรเจคที่เป็น Develop ก็ให้ใช้ SHA-1 ของ Debug Keystore
  • โปรเจคที่เป็น Production ก็ให้ใช้ SHA-1 ของ Signed Keystore แทน

เพราะว่า Firebase SDK นั้นรองรับ Build Variant อยู่แล้ว เราจึงสามารถใส่ google-services.json แยกตาม Variant ได้ด้วย ตัวที่เป็น debug ก็ให้ใช้ของโปรเจคที่เป็น Develop ซะ ส่วนตัว release ก็ให้ใช้ของตัวโปรเจคที่เป็น Production แทน

ถ้าไม่แยกไว้ตั้งแต่แรก เดี๋ยวก็ลืมทำในตอนหลังอยู่ดี เพราะงั้นทำๆให้มันเสร็จๆไปเถอะ ดีกว่าลืม

แต่ถ้าคุณมีโปรเจคอยู่ตัวเดียวที่พร้อมจะใช้งานเป็นทั้ง Debug และ Release ก็ให้ใส่ google-services.json ไว้ใน /src/main ได้เลย

เปลี่ยนไปใช้ Dependency ของ FCM

สำหรับ Classpath ใน Gradle ยังใช้ของตัวเดิมเหมือน GCM อยู่นะ

แต่ให้เปลี่ยน Dependency จาก GCM เป็น FCM ซะ

ส่วน apply plugin: "com.google.gms.google-services" ก็ใส่ไว้ที่บรรทัดสุดท้ายของ build.gradle (Module) เหมือนเดิมนะ ไม่ต้องเปลี่ยนอะไร และไม่ต้องลบออก

เปลี่ยนโค้ดในแอพให้รองรับ FCM

ทีนี้ก็เป็นส่วนของโค้ดที่เขียนไว้ใน Android ที่ต้องปรับเล็กน้อยเพื่อให้เป็นของ FCM แทน

สมัยที่ใช้ GCM เราจะต้องสร้างคลาสขึ้นมา 3 ตัวด้วยกันดังนี้

  • GcmListenerService — เพื่อรับ Push Notification ที่ส่งเข้ามา
  • InstanceIDListenerService — เพื่อดักว่า Token มีการอัพเดทใหม่
  • IntentService — เพื่อส่ง Token ตัวใหม่ขึ้น Web Server จะได้ใช้ Token ตัวใหม่แทนตัวเก่า

แต่เมื่อใช้ FCM จะยุบรวมเหลือเพียงตัวเดียวที่มีชื่อว่า FirebaseMessagingService

ถ้ายังนึกภาพไม่ออกว่าโค้ดจะเปลี่ยนไปยังไงบ้าง ให้ดูตามภาพข้างล่างนี้ได้เลย

จะเห็นว่าโค้ดหายไปเยอะมาก เหลือแค่โค้ดที่เราจำเป็นต้องเขียนเองเท่านั้น ซึ่งก็คือคำสั่งอัปโหลด Token ขึ้น Web Server และคำสั่งเมื่อมี Message จาก Push Notification ส่งเข้ามา

ไม่ต้องประกาศคำสั่งเรียก IntentService ไว้ที่ Activity ตัวแรกสุดของแอพแล้ว

ตอนที่ใช้ GCM จะต้องใส่คำสั่งเพื่อเรียกให้ IntentService ทำงานครั้งหนึ่งก่อน เพื่อให้ Token สร้างขึ้นมาใหม่

ไม่จำเป็นต้องสร้าง setupGcm() แล้ว ลาก่อยยยยยย

แต่พอมาใช้ FCM ก็ไม่จำเป็นอีกต่อไป เพราะว่า Firebase SDK จัดการให้หมดแล้ว ลบคำสั่งตรงนั้นทิ้งได้เลย

เมื่อ Token มีการอัปเดต

เมื่อไม่ต้องประกาศคำสั่งในหน้าแรกของ Activity เพื่อให้ GCM สร้าง Token ขึ้นมาใหม่ ดังนั้น Event จาก Token จะมี Behavior แตกต่างกันอยู่นิดหน่อย

GCM — AppRegistrationIntentService ถูกเรียกทุกครั้งเมื่อเปิดแอพขึ้นมาใหม่ และเมื่อ Token มีการ Refresh ดังนั้นต้องมีการเขียนเช็คว่าเคยอัปโหลด Token ตัวนั้นขึ้น Web Server แล้วหรือยัง เพื่อป้องกันการอัปโหลด Token ซ้ำ

FCM — onNewToken() ใน AppFirebaseMessagingService จะถูกเรียกก็ต่อเมื่อ Token มีการอัปเดตใหม่เท่านั้น ดังนั้นเขียนคำสั่งอัปโหลด Token ขึ้น Web Server ก็พอ และคำสั่งเผื่อกรณีที่ส่งไม่สำเร็จด้วย (เผื่ออินเตอร์เนตมีปัญหา)

เมื่อได้รับ Message จาก Push Notification

ลักษณะของข้อมูลที่ส่งเข้าในเครื่องของผู้ใช้จะมีความแตกต่างกันระหว่าง GCM กับ FCM ดังนี้

GCM — Message จะถูกส่งเข้ามาใน onMessageReceived(from: String?, data: Bundle?) โดยเช็คว่าส่งมาจากใครได้จากตัวแปร from และข้อมูลที่ส่งมาจะอยู่ในรูปของ Bundle ที่ชื่อว่า data

FCM — Message จะถูกส่งเข้ามาใน onMessageReceived(remoteMessage: RemoteMessage?) ซึ่งข้างใน RemoteMessage จะมีให้ดังนี้

ถ้าอยากได้เหมือนเดิมแบบที่เคยเขียนไว้ใน GCM ก็ดึงแค่ from และ data มาใช้ก็พอ

แต่สังเกตดีๆจะเห็นว่า data ที่ได้นั้นอยู่ในรูปของ Map<String, String> นะ ไม่ได้เป็น Bundle เหมือน GCM ดังนั้นตรงนี้ก็ต้องเปลี่ยนโค้ดกันนิดหน่อย

อย่าลืมลบ Permission, Service และ Broadcast Receiver ใน Android Manifest ด้วยนะ

จากของเดิมที่จะต้องประกาศ Wake Lock Permission, Receiver ของ GCM Receiver และ Service ทั้ง 3 ตัวที่สร้างขึ้นมาสำหรับ GCM

เมื่อเปลี่ยนเป็น FCM ซึ่งไม่จำเป็นต้องประกาศ Service และ Broadcast Receiver ให้เยอะแยะอีกต่อไป และไม่จำเป็นต้องขอ Wake Lock Permission แล้วด้วย ดังนั้นจะเหลือแค่นี้แทน

สบายตาขึ้นเยอะเลยเนอะ

ยังไม่พอ FCM ยังมี Meta-data สำหรับกำหนดการทำงานของ Notification ด้วยนะ ทำให้ไม่ต้องไปนั่งประกาศผ่านโค้ด Java/Kotlin แค่ประกาศไว้ใน Android Manifest ก็พอ

โดยที่

  • com.google.firebase.messaging.default_notification_icon — เอาไว้กำหนด Default Icon เวลามี Notification Payload ส่งเข้ามา (สามารถกำหนดเป็น Icon ต่างๆได้ใน Payload)
  • com.google.firebase.messaging.default_notification_color — เอาไว้กำหนดสีของ Icon ที่ถูกสร้างจาก Notification Payload
  • com.google.firebase.messaging.default_notification_channel_id — เอาไว้กำหนด Default Channel ID ของ Notification (Channel ID เป็นฟีเจอร์ของ Android 8.0 Oreo ที่จะต้องกำหนดให้กับ Notification ทุกตัว)

เพียงเท่านี้ฝั่ง Android ก็พร้อมใช้งาน FCM แล้ว

ขั้นตอนการ Migrate จาก GCM ไปเป็น FCM (ฝั่ง Web Server)

สำหรับฝั่ง Web Server แทบจะไม่ต้องทำอะไรนอกจากเปลี่ยน Endpoint

ถ้าคุณใช้ HTTP แบบที่เคยใช้ใน GCM (Legacy)

จากเดิม

https://gcm-http.googleapis.com/gcm/send

ก็ให้เปลี่ยนเป็น

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

ส่วนรูปแบบของข้อมูลก็เหมือนเดิมเป๊ะๆ และอย่าลืมอัปเดต Web API Key เป็นตัวใหม่ที่ได้มาจาก Firebase Console ด้วยนะ

ซึ่งวิธีการส่งข้อมูลผ่าน HTTP แบบที่เคยทำใน GCM นั้น ใน FCM จะเรียกว่า Legacy HTTP แต่ถ้าคุณอยากลองของใหม่บน FCM ก็ลองเปลี่ยนไปใช้ HTTP v1 API ดูก็ได้นะ เผื่อจะชอบ

เสร็จแล้ว ยินดีต้อนรับสู่ FCM

เห็นมั้ยล่ะ ย้ายจาก GCM ไปใช้ FCM ง่ายนิดเดียว แถมโค้ดก็น้อยกว่า แต่ฟีเจอร์ทำอะไรได้เยอะกว่า เพราะ FCM สามารถทำงานร่วมกับบริการอื่นๆใน Firebase ได้ด้วย ซึ่งต่างจาก GCM ที่ทำจะเอาไปทำงานร่วมกับอะไรก็ไม่ได้เลย ต้องมานั่ง Implement เพิ่มเองทั้งหมด

แหล่งข้อมูลอ้างอิง

--

--

Akexorcist
Firebase Thailand

Lovely android developer who enjoys learning in android technology, habitual article writer about Android development for Android community in Thailand.