เขียนเป็น Short Note ไว้เป็น Best Practices สำหรับการทำ Push Notifications บน Android นะครับ เวลาเขียนมีไม่มาก ดังนั้นขอเขียนไม่ยาวมาก เป็นแนวทางและให้ไปศึกษาเพิ่มเอาเองเน้อ
ทำไม Push Notifications ถึงสำคัญ
การดึงคนให้โหลดแอพฯนั้นเป็นเรื่องไม่ยาก เอาเงินลงทำ Marketing สักพักนึงก็ได้ยอดโหลดมาเป็นแสนแล้ว
ปัญหาจึงไม่ได้อยู่ที่จะทำยังไงให้คนโหลดแอพฯ เพราะคนโหลดไม่ได้แปลว่าจะใช้ คนส่วนใหญ่โหลดแอพฯมาแล้วก็ลืม ทิ้งไว้อย่างงั้น สิ่งที่ยากทึ่สุดคือจะทำยังไงให้คนเปิดแอพฯขึ้นมาเรื่อยๆ
Push Notifications นี่แหละที่ตอบโจทย์ตรงนี้ ด้วยการ Push ให้คนเห็นว่ามีอะไรใหม่ คนส่วนใหญ่ก็จะกดเข้าแอพฯไปผ่าน Push เหล่านั้น
เป็นการเพิ่ม Return Rate ของแอพฯที่ดีมากๆ ถือเป็น Advantage ใหญ่ๆของการทำ Mobile App เลย
หากท่านทำแอพฯ แนะนำให้ใส่ Push Notifications ไว้เสมอ ไม่ว่าจะอยู่บนแพลตฟอร์มไหนและไม่ว่าแอพฯจะเล็กใหญ่แค่ไหนก็ตาม สังเกตได้ว่าแอพฯระดับโลกเกือบทุกแอพฯมี Push หมด แม้จะ Push แบบไร้สาระก็จะ Push เพื่อให้คนไม่ลืมนั่นเอง
Flow Push Notifications บน Android
Push บน Android เราเรียกว่า Google Cloud Messaging (GCM) การจะให้มันทำงานได้สมบูรณ์ จะต้องมีองค์ประกอบ 3 ส่วนด้วยกัน ได้แก่
1) Client App - แอพฯบนแอนดรอยด์ ไม่มีแอพฯก็จะไม่มีตัวรองรับการ Push เคยมีคนถามอยู่เหมือนกันว่าจะ Push โดยไม่ต้องลงแอพฯอะไรได้มั้ย ตอบว่าไม่ได้นะครับ
2) GCM Connection Servers - Server ของกูเกิ้ลที่เอาไว้จัดการ Push Key รวมถึงการส่งข้อมูลไปยัง Client App เวลาเราจะ Push เราก็จะยิงไปที่เจ้า Server ตัวนี้ แล้ว Message จะ Deliver ไปยังมือถืออีกต่อนึง
3) 3rd-Party App Server - Server ของเราที่เอาไว้ยิง Push ไปยัง GCM Connection Servers ตรงนี้ถ้าจะทดสอบก็ใช้เครื่อง Local ทดสอบก็ได้ครับ ไม่ต้องไปเปิด Server จริงจังอะไร
สำหรับการจะทำให้มันใช้งานได้ จะมี Flow การทำงาน 5 ส่วนด้วยกัน ดังนี้
1. Enable GCM ก่อน
ตามธรรมเนียม ถ้าจะทำอะไรกับ API ของ Google ก็ต้องไป Enable ที่หน้า Google Developers Console ก่อน
วิธีตามนี้เลยจ๊ะ Google Cloud Messaging: Getting Started ง่ายมากจนไม่ต้องเขียนอะไรเพิ่ม ไม่เกิน 3 นาทีทำเสร็จ
2. Register: ขอ Push Key จาก GCM Server
เป็นการส่งคำร้องขอ Push Key มาจาก GCM Server ผ่านทาง Client App โดย 1 แอพฯบนเครื่อง 1 เครื่องจะได้คืนมา 1 Key นั่นแปลว่าถึงคุณจะใช้ Google Account เดียวกัน แต่ใช้บนเครื่องอื่น ก็จะได้ Key มาอีก 1 ตัว และ Key นี่เองที่เราจะใช้ยิง Push ไปยังเครื่องปลายทาง 1 Key จะยิงเข้าได้ 1 เครื่อง
ชุดคำสั่งไม่มีอะไรซับซ้อน หน้าตาประมาณนี้
String regId = GoogleCloudMessaging.getInstance(context).register(SENDER_ID);
หลังจากนั้นถ้าจะทำเป็นระบบ เราก็มักจะส่ง Key นี้ไปเก็บบน Server ของเรา (ซึ่งก็คือ 3rd-Party App Server) เพื่อใช้ยิง Push ในโอกาสต่อไป
ทั้งนี้ Best Practices และข้อควรระวังของส่วนนี้มีดังต่อไปนี้
- Key ไม่ค่อยเปลี่ยน ไม่ต้องขอใหม่ทุกครั้งที่เปิดแอพฯ : เมื่อได้ Push Key มาแล้ว เก็บไว้ใน SharedPreference ไว้ได้เลย เปิดแอพฯครั้งต่อไปถ้ามี Key อยู่แล้ว ก็ไม่ต้องทำอะไร แต่ถ้ายังไม่มีก็ค่อยขอใหม่และส่งไปเก็บที่ Server อีกที จะช่วยประหยัดการทำงานลงไปได้เยอะมาก อันนี้ในตัวอย่างโค้ดก็ทำไว้แบบนี้ ลอกตามได้เลย
- Key เปลี่ยนได้ถ้ามีการอัพเดตเวอร์ชั่นของแอพฯ : เมื่อมีการอัพเดตเวอร์ชั่น มีโอกาสบ้างที่ Push Key จะถูกเปลี่ยน ดังนั้นเวลาเก็บ Push Key ลง SharedPreference ก็ควรเก็บ App Version ตอนขอ Push Key ไว้ด้วย ถ้าเกิดเปิดแอพฯมาอีกครั้งแล้วตัวเลขเวอร์ชั่นไม่ตรงกับปัจจุบัน ขอใหม่ทันที มีอยู่ในโค้ดตัวอย่างเช่นกัน กูเกิ้ลทำไว้ดีละ
- Key มีโอกาสเปลี่ยนได้โดยเราไม่รู้ตัว : ถึงแม้ในเอกสารจะบอกว่า 1 Key ต่อ 1 เครื่อง/1 แอพฯเท่านั้น แต่จากการใช้จริง กลับพบว่ามีโอกาสจะเกิด Key "เพิ่ม" ได้ แปลว่าขอสองครั้งแต่ได้ 2 Keys (จริงๆควรจะได้ Key เดิม) และทั้ง Key เก่าและ Key ใหม่ก็ใช้ได้ทั้งคู่ ผลคือเวลา Push ไปทั้งสอง Key นี้ เครื่องเดียวกันก็จะได้ข้อความซ้ำ 2 ครั้ง
- เวลาส่งไปเก็บที่ Server ให้ส่ง Device Unique ID ไปด้วย : ด้วยเหตุผลข้างต้น จึงขอแนะนำให้ส่ง Device Unique ID ไปเก็บไว้บน Server ด้วย เวลาจะอัพเดต Key บน Server ก็ให้เช็คว่า Device Unique ID ซ้ำมั้ย ถ้าซ้ำก็เก็บเอาตัวล่าสุดไว้ตัวเดียวพอ จะได้ไม่เกิดการซ้ำขึ้น สำหรับโค้ดของ Device Unique ID คือ
String deviceId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
ทั้งนี้ Device Unique ID ตรงนี้จะเปลี่ยนเมื่อมีการ Factory Reset ด้วย
3. Send Message: ส่ง Push ไปยัง Client App
เมื่อได้ Push Key ไปเก็บไว้บน 3rd-Party App Server แล้ว เวลาจะส่ง Push ไปหาเครื่องต่างๆ ก็แค่ยิง HTTP Request ไปยัง GCM Server พร้อมแนบ Key เครื่องปลายทางที่เราต้องการ จากนั้นข้อความจะถูกส่งเข้าไปยังแอพฯในเวลาอันสั้น ส่วนใหญ่ก็คือได้ทันที ยกเว้นบางกรณี (ไว้บอกด้านล่าง)
ทั้งนี้เราสามารถแนบข้อมูลเพิ่มเติมเข้าไปได้เพื่อให้ปลายทางเอาไปใช้ต่อ (เรียกว่า Payload) เช่น ชื่อของสติกเกอร์ตัวใหม่ ชื่อ Blog ใหม่ บลาๆๆๆ รูปแบบการส่งจะเป็น json format ประมาณนี้
Content-Type:application/jsonAuthorization:key=AIzaSyB-1uEai2WiUapxCs2Q0GZYzPu7Udno5aA{ "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx..."], "data" : { ... },}
Best Practices ตรงนี้มีข้อนึงคือ เราแนะนำให้แนบ Unique Device ID ที่เก็บไว้ในตอน Register ไปใน Payload ด้วย เพื่อให้เครื่องปลายทางเอาไปเปรียบเทียบว่า Device ID ตรงกันหรือเปล่า ถ้าตรงกันถึงจะเอาไปแสดงผล ถ้าไม่ตรงกัน Ignore ไป
4. Receive Message: รอรับ Push Message แล้วนำไปแสดงผล
ข้อความที่ถูก Push มา จะไม่ได้แสดงผลทันทีเหมือนกับ iOS แต่จะถูกยิงเข้า BroadcastReceiver ให้เราไปพิจารณาก่อนว่าจะทำอะไรกับมันต่อ (ซึ่ง Basically คือสร้างเป็น Notifications ไว้บนแถบด้านบน)
ทั้งนี้ทั้งนั้น เนื่องจาก BroadcastReceiver ทำงานบน Main Thread จึงอาจเกิด ANR ได้ Best Practices ตรงนี้คือให้ส่งข้อมูลที่ได้รับมาไปทำงานต่อที่ IntentService ซึ่งทำงานเป็น Background จะดีกว่า ตรงนี้โค้ดตัวอย่างก็ทำไว้ดีแล้วเช่นกัน (ถือเป็นการอธิบายว่าทำไมเค้าทำอย่างงั้นละกันนะ)
ตามปกติแล้ว Push Notification จะมีส่งไปได้หลายแบบเช่น (1) มีเวอร์ชั่นใหม่ (2) มี Content ใหม่ ... ซึ่งแต่ละตัวจะสร้างเป็น Notification รูปแบบที่แตกต่างกันไป จากประสบการณ์ โอกาสที่ประเภทของ Push จะเพิ่มขึ้นเรื่อยๆนั้นมีอยู่เสมอ และถ้าส่ง Push ใหม่ไปยังแอพฯตัวเก่าแล้วไม่มีการ Handle อย่างเหมาะสม ... แอพฯ Crash แน่นอน
ตรงนี้แนะนำให้ฝั่ง Server แนบ notification_type มากับ Payload ด้วย ฝั่ง Client ตอนได้รับ Push มา ก็เช็คว่ารู้จัก notification_type ที่ส่งมามั้ย ถ้ารู้จักก็เอาไปทำงานต่อ ถ้าไม่รู้จักก็ ignore ทิ้งทันที
สำหรับการกำหนดรูปแบบของ Notification ก็มีผลต่อการล่อให้คนกดด้วย หรือบางทีการสร้างปุ่มให้โต้ตอบได้เลยบน Notification ก็จะสร้าง Activity ให้กับแอพฯได้อย่างดี ไปดูข้อมูลเพิ่มเติมเรื่องของการทำ Notification แบบต่างๆได้ที่ Notifications (หมายเหตุ: เวลาจะทำดูด้วยว่าแบบไหนใช้กับแอนดรอยด์เวอร์ชั่นไหนได้ ไม่งั้น Crash เอา)
การ Notify ผู้ใช้ไม่ได้มีแค่การสร้าง Notification บนจอ แต่ยังทำท่าอื่นเพิ่มได้ด้วย เช่น สั่นตรืดดดดด หรือมีเสียงขึ้นมา ติดิ๊งงงง ตรงนี้ต้องจัดการทำเองเช่นกันครับ ใส่เพิ่มได้ตามอัธยาศัย
5. ลบ Notification ที่อ่านแล้วทิ้ง
สุดท้าย หลังจากที่มีการกด Notification แล้ว ตัว Notification จะไม่หายไปโดยอัตโนมัติ ต้องสั่งเคลียร์ทิ้งด้วย NotificationManager ด้วย ตรงนี้อย่าพลาดๆ ไม่งั้น User จะเกิดความรำคาญทันที
ทั้งนี้การลบ Notification นั้นๆทิ้ง ไม่จำเป็นต้องเกิดจากการกด Notification เท่านั้น บางทีแค่กดเข้าไปหน้านั้นด้วยตัวเอง ก็ลบ Notification ที่เกี่ยวข้องทิ้งได้ทันที ยกตัวอย่างเช่น Facebook ถ้ามี Notification ว่ามีคนคอมเม้นท์โพสต์เข้ามา แล้วเราไปกดเข้า Tab Notifications ด้วยตัวเราเอง ตัว Notification ที่บอกว่ามีคอมเม้นต์ใหม่ก็จะโดนลบทิ้งอัตโนมัติ
Best Practices ตรงนี้คือคิดให้รอบสำหรับทุกๆ Notification ที่ถูกสร้างขึ้นมาว่าจะถูกทำลายได้ตอนไหนบ้าง สำคัญมากๆ
สำหรับส่วน Register และ Receive Message สามารถดูโค้ดตัวอย่างได้จาก Implementing GCM Client ส่วน Send Message ไปดูจาก Implementing GCM Server: HTTP ได้ครับ ตัว HTTP ทดสอบง่ายดี แค่ curl ผ่าน Command Line ก็ได้ละ โค้ดตัวอย่างที่กูเกิ้ลทำมาถือว่าทำมาดีมาก สามารถลอกตามได้หมดเลย แค่เพิ่มส่วนที่แนะนำเข้าไปตามที่บอกข้างต้นครับ
Push แต่เนื้อหาที่คนอยากอ่าน
การ Push นั้น ถึงจะขึ้นเป็นข้อมูลบนเครื่องปลายทางก็จริง แต่ไม่ได้แปลว่าคนจะกด ดังนั้นอย่าเอะอะก็ Push มั่วๆ ควรจะมีศิลปะด้วย ใส่ข้อความที่คนชอบ เห็นแล้วต้องกด และข้อความไม่ควรยาวไป ควรจะว้าวตั้งแต่ประโยคแรก เพราะโอกาสที่ Notification จะขึ้นแค่ประโยคสั้นๆนั้นมีเยอะ ถึงจะขยายข้อความออกมาดูได้ แต่คนส่วนใหญ่ทำไม่เป็น แนะนำว่าอย่าให้ข้อความ Push นั้นยาวเกิน 2 บรรทัดครับ
Handle Push Event อย่างเหมาะสม สอดคล้องกับข้อความ
บนแอพฯบางตัว ยกตัวอย่างเช่น True Wallet มีข้อมูล Push เข้ามาว่า "โปรโมชั่น บลาๆๆๆๆ" แต่พอกดเข้าไปกลับเข้าหน้าอะไรไม่รู้และไม่สามารถเข้าถึงข้อมูลได้
นอกจากจะเสียโอกาสที่ผู้ใช้จะสร้างยอดขายแล้ว ยังสร้างความหงุดหงุดให้กับผู้ใช้จนไม่คิดจะกดอีกต่อไป
ดังนั้นแนะนำว่าควรจะ Handle Push Notification อย่างเหมาะสม ถ้าเป็นข้อความชวนให้อ่านต่อ พอกดแล้วก็ต้องเข้า Activity สำหรับอ่านเลย หรือถ้าเป็นข้อความบอกว่ามีเวอร์ชั่นใหม่ ก็ควรจะเข้า Play Store หน้าแอพฯนั้นๆเลย
Push แต่พอเหมาะ วันละครั้งก็พอ และอย่าเกินวันละสองครั้ง ยกเว้นแอพฯที่มี Interaction Rate สูง
สำหรับคนที่ทำแอพฯประเภท Content ที่ต้องใช้เวลาอ่าน เช่น ข่าว, Blog จริงอยู่ที่ Push เป็นการเพิ่ม Return Rate ให้กับแอพฯได้เป็นอย่างดี แต่การ Push กระหน่ำก็สร้างผลเสียได้ไม่น้อย เพราะมันคือ Spam ดีๆนี่เอง ผู้ใช้ไม่ชอบหรอก ตัวเลขที่เหมาะสมคือวันละครั้ง หรือมากสุดเลยคืออย่าเกินวันละ 2 ครั้ง ไม่งั้นเกิดเป็นผลลบมากกว่าผลบวกแน่นอนครับ
แต่กับแอพฯประเภทที่ใช้เวลาเข้าไปดูน้อยและผู้ใช้รู้สึกดีทุกครั้งที่มีคน Interact เช่น มีคน Like มาใน Instagram พวกนี้ยิงมาเรื่อยๆได้เลยครับ แต่ฝั่ง Server ควรทิ้งระยะห่างไว้ด้วยว่าถ้ามีการยิง Push ถี่ๆ แต่ผู้ใช้ยังไม่กดเข้ามาดู ก็ให้ยิงช้าลงไปแบบ Regressive จนกระทั่งผู้ใช้กดเข้ามาดูแอพฯ ก็ส่งไปบอก Server ให้เริ่มยิงถี่ๆได้ ตรงนี้ใช้สกิล Server กันได้เต็มที่จ๊ะ
แต่พวกนี้อย่าลืมใส่ Options ในการตั้งเสียงและสั่นไว้ด้วย ไม่งั้นจะน่ารำคาญมาก
ใส่ Options เปิด/ปิด Push ไว้ในแอพฯด้วย
ไม่ใช่ทุกคนที่ชอบ Push Notifications ดังนั้นอย่าลืมใส่ Options ให้เปิด/ปิดไว้ด้วย
วิธีการทำมีอยู่สองแบบ
1) ส่งไปหา 3rd-Party Server ว่า Key นี้ไม่ต้องส่ง Push มา
2) ส่ง Push มาเถอะ ไม่ถือ แต่ตอน Receive Message ให้เช็คแบบ Local ว่าปิดการรับ Push ไว้หรือไม่ ถ้าปิดก็ให้ Ignore ข้อความไป แต่ถ้าเปิดไว้ก็ Render ออกมาเป็น Notification ซะ
แบบหลังจะ Handle ง่ายกว่าครับ
เทคนิค Push ตาม Demographic เพิ่ม Conversion Rate
สำหรับคนที่ทำแอพฯแบบ Global เทคนิค Push ตาม Demographic เช่น เพศ/อายุ/ประเทศ เป็นสิ่งที่สำคัญพอสมควร เพราะ Message จะ Deliver ไปได้ถูก Target และถูกเวลา (บ่ายสองของไทยหมายถึงตีสองของเมกา ถ้าคนเมกาลงแอพฯเราแล้ว Push ไปพร้อมกัน คงโดนคนเมกาด่าแหงม คงไม่มีใครชอบให้ Push ไปตอนตีสองใช่ม้า)
ตรงนี้ก็ต้องเก็บข้อมูล Demographic ไว้ด้วย วางแผนไว้ให้ดีตั้งแต่ต้นเน้อ
ต่อ WiFi นานๆจะเริ่มไม่ได้ Push
อาจจะมีบางทีที่ปล่อยทิ้งไว้นานๆแล้วไม่ได้รับ Push ทั้งนี้ก็เพราะว่า Push บนแอนดรอยด์มันมาทาง Google Talk ผ่านทาง Keep Alive Connection และโดยปกติ WiFi Router จะตัด Keep Alive Connection เหล่านี้ทิ้งหลังจากต่อ WiFi ไปสักพัก ถ้าเกิดเทสต์แล้วไม่ได้รับ Push ทั้งๆที่ฝั่ง GCM Server ก็บอกว่าส่งไปแล้วเรียบร้อย ให้ลอง Disconnect WiFi แล้วต่อใหม่ดู น่าจะได้ครับ
ก็ทิ้งไว้เท่านี้ ลองเล่น Push กันดูนะคร้าบ =)