25 March 2017

[Android Code] ลองเล่น Notification Channels ของเล่นใหม่จาก Android O



        Notification Channels นั้นเรียกได้ว่าเป็นหนึ่งในฟีเจอร์หลักที่เพิ่มเข้ามาใน Android O (API 26) เลยก็ว่าได้ ซึ่งเป็นฟีเจอร์ที่ช่วยให้ผู้ใช้งานสามารถจัดการกับ Notification ได้ละเอียดขึ้นกว่าเดิม ซึ่งก็ต้องแลกด้วยหยาดเหงื่อของนักพัฒนาที่ต้องเขียนโค้ด ฮาๆ

การทำงานของ Notification Channels ในมุมมองของ User

        ในแอนดรอยด์เวอร์ชันก่อนๆ ถ้าผู้ใช้อยากจะปิด Notification ของแอปฯซักตัว ก็แค่ไปกดปิดใน App Info ของแอปฯตัวนั้นๆหรือในเมนู Notification ของ Settings

         แต่ปัญหาที่เจอคือมันเป็นการปิด Notification ทั้งหมดของแอปฯตัวนั้นเลย ถ้าแอปฯมีการเรียกแสดง Notification ใดๆก็ตาม มันจะถูกบล็อคไม่แสดงให้ผู้ใช้งานเห็น

        ซึ่งแอปฯบางตัวที่มีการแสดง Notification หลายๆแบบ ก็อาจจะต้องทำหน้าตั้งค่า Notification ในแอปฯเองว่าจะให้เแจ้งเตือนแบบไหนบ้าง เพื่อไม่ให้ผู้ใช้รู้สึกรำคาญกับ Notification ที่ไม่ต้องการ และได้แต่ Notification ที่สนใจจริงๆ (ก็ดีกว่าผู้ใช้กดปิด Notification ทั้งหมดนะ)


        ยกตัวอย่างเช่น Facebook ที่ให้ผู้ใช้สามารถกำหนดได้ว่าจะให้ตัวแอปฯแจ้งเตือนแบบไหนบ้าง จึงทำให้ผู้ใช้งานสามารถกำหนดได้ตามใจชอบว่าจะให้เตือนเมื่อไร

        แต่มุมมองของฝั่งนักพัฒนาบอกเลยว่าแค่หน้านี้หน้าเดียวเนี่ย นับว่าเป็นหนึ่งฟีเจอร์ได้เลยนะ เพราะว่ามันต้องมีการเขียนโค้ดเพื่อเข้าไปกำหนดการทำงานของ Notification

        Android O จึงทำการตั้งค่า Notification แบบนี้ขึ้นมาให้เพื่อให้ผู้ใช้สามารถใช้งานได้สะดวกมากขึ้น และนักพัฒนาก็สามารถจัดการกับโค้ดได้ง่ายขึ้นด้วยเช่นกัน และนั่นก็คือที่มาของ Notification Channels ครับ


        โดยผู้ใช้สามารถเข้าไปจัดการกับ Notification Channels ในทั้งหมด 3 วิธี

        • Settings > App & notifications > Notifications > แอปฯที่ต้องการ
        • กดค้างที่ Notification ของแอปฯนั้นๆ
        • เข้าไปที่ App Info ของแอปฯนั้นๆ แล้วกดเลือก Notifications

สิ่งที่นักพัฒนาต้องทำเพื่อรองรับ Notification Channels

        • จัดประเภท Notification ในแอปฯทั้งหมด
        • สร้าง Channel และ Channel Group เพื่อแบ่งกลุ่ม Notification ตามที่กำหนดไว้
        • เมื่อแสดง Notification ก็ให้กำหนด Channel ให้ตรงกับที่สร้างไว้

จัดประเภท Notification ในแอปฯทั้งหมด

        การจัดประเภทในที่นี้จะหมายถึง การวางแผนว่า Notification ในแอปฯทั้งหมดนั้นมีอะไรบ้าง และสามารถจัดกลุ่มแบบไหนได้บ้าง จะแยกตาม Business หรือจะแยกตามหน้าที่ของ Notification แต่ละตัวก็ได้ (ขึ้นอยู่กับความเหมาะสม) เพื่อที่จะได้เอาไปกำหนดเป็น Channel และ Channel Group อีกทีหนึ่ง

สร้าง Channel และ Channel Group เพื่อแบ่งกลุ่ม Notification ตามที่กำหนดไว้

        เป็นขั้นตอนที่จะต้องเพิ่มคำสั่งเข้าไปในโค้ด โดยที่ Channel แบบมีและไม่มี Channel Group จะต่างกันดังนี้

        ถ้าสร้าง Channel แบบไม่มี Channel Group จะทำให้ Channel ที่สร้างขึ้นมาถูกรวมอยู่กับ Miscellaneous และถูกจัดเป็น Group ที่ชื่อว่า Categories



        แต่ถ้ามีการสร้าง Channel ที่มี Channel Group ขึ้นมาด้วย ก็จะมีการแยก Group ออกมาต่างหากให้ ส่วน Channel ที่ไม่มี Group ก็จะรวมอยู่กับ Miscelaneous เหมือนเดิม แต่ Group จะถูกเปลี่ยนเป็น Other แทน


        ซึ่งการสร้าง Channel และ Channel Group จะเป็นการสร้างเตรียมไว้ ดังนั้นคำสั่งนี้เรียกใช้งานแค่ตอนแรกเมื่อแอปฯถูกเปิดขึ้นมาครั้งแรกก็ได้เช่นกัน (อยากจะอัพเดท Channel และ Channel Group ก็แก้ไขผ่านคำสั่งทีหลังได้เช่นกัน)

        ถ้าต้องการสร้างแค่ Channel ให้ใช้คำสั่งแบบนี้

int importance = NotificationManager.IMPORTANCE_DEFAULT;
String channelId = "comment_notification";
String channelName = "Comment";
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);

NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannel(channel);

        สิ่งที่ต้องกำหนดจะมี 3 อย่างด้วยกันคือ

        • ระดับความสำคัญของ Channel
        • ID ของ Channel
        • ชื่อของ Channel ที่ใช้ในการแสดงในเมนูให้ผู้ใช้เห็น

        จากนั้นก็สร้าง NotificationManager แล้วใช้คำสั่ง createNotificationChannel เพื่อสร้าง Channel ตามที่กำหนดไว้ได้เลย และในกรณีที่มี Channel หลายตัว สามารถใช้คำสั่ง createNotificationChannels เพื่อสร้างพร้อมกันหลายๆตัวได้เลย แต่ให้โยน Parameter เป็น List<NotificationChannel> แทน

        หมายเหตุ : ผู้ใช้สามารถลบ Notification Channels ได้ด้วยการสั่ง Clear Data หรือลบแอปฯออกจากเครื่อง (จึงเป็นที่มาว่าทำไมต้องกำหนด Channel กับ Channel Group ทุกครั้งที่แอปฯถูกเปิดใช้งานครั้งแรก)


        ถ้าต้องการสร้าง Channel Group ให้ใช้คำสั่งแบบนี้

String groupId = "timeline_group";
String groupName = "Timeline";
NotificationChannelGroup group = new NotificationChannelGroup(groupId, groupName);

int importance = NotificationManager.IMPORTANCE_DEFAULT;
String channelId = "comment_notification";
String channelName = "Comment";
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
channel.setGroup(groupId);

NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
manager.createNotificationChannelGroup(group);
manager.createNotificationChannel(channel);

        มีเงื่อนไขสำคัญว่าจะต้องสร้าง Channel Group ก่อน แล้วถึงจะค่อยสร้าง Channel เพราะการกำหนด Group ให้กับ Channel จะต้องใช้คำสั่ง setGroup(String groupId)

        ถ้าสร้าง Channel แล้วเพิ่ม Channel Group ที่ไม่ได้สร้างเตรียมไว้ จะทำให้เกิด Exception ตอนที่เรียกใช้คำสั่ง createNotificationChannel หรือ createNotificationChannels ดังนี้

java.lang.IllegalArgumentException: NotificationChannelGroup doesn't exist

เมื่อแสดง Notification ก็ให้กำหนด Channel ให้ตรงกับที่สร้างไว้

        คำสั่งในส่วนของ Notification ก็ใช้คำสั่งเหมือนเดิมนั่นแหละ แต่เพิ่มเติมคือกำหนด Channel ID ให้ตรงกับที่กำหนดไว้

String channelId = "comment_notification";

...

int notificationId = 0;
String contentTitle = "Sleeping For Less just comments to your post";
String contentText = "Wow! This is greater article than ever read before!";
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new NotificationCompat.Builder(getContext())
        .setSmallIcon(R.mipmap.ic_launcher_round)
        .setContentTitle(contentTitle)
        .setContentText(contentText)
        .setChannel(channelId)
        .build();
manager.notify(notificationId, notification);

        เพียงเท่านี้ Notification ก็จะทำงานตามที่ผู้ใช้กำหนดไว้เองโดยอัตโนมัติ

        เพิ่มเติม - สำหรับ Notification ที่ไม่มีการกำหนด Channel ID ไว้ จะถูกจัดเป็น Miscellaneous ทั้งหมด

ผู้ใช้ตั้งค่าอะไรใน Notification Channel ได้บ้าง

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


        ที่น่าสนใจก็คือ Show Badge ซึ่งสามารถกำหนดได้ว่าจะให้จำนวน Notification ขึ้นบอกที่ไอคอนแอปฯหรือป่าว


        เพราะว่าเดิมทีนั้นตัวแอนดรอยด์ไม่ได้รองรับการแสดง Notification Badge โดยตรงอยู่แล้ว ที่ทำกันได้นั้นก็เป็นเพราะว่า Launcher เจ้าอื่นๆต่างหากที่รองรับฟีเจอร์นี้ อย่างเช่น TouchWiz ของ Samsung หรือ APEX Launcher ที่ผู้ใช้สามารถดาวน์โหลดมาติดตั้งใช้งานแทนได้ (และทุกวันนี้นักพัฒนาก็ต้องไปใช้ 3rd-Party Library เพื่อให้แอปฯรองรับ Notification Badge ของทุกๆ Launcher)

        ซึ่งตัว Android O ที่ให้ทดลองใช้งานในตอนนี้อาจจะยังไม่มี Notification Badge ให้ใช้งาน และยังไม่ได้พูดถึงรายละเอียดของฟีเจอร์นี้มากนัก แต่จากที่เห็นในหน้าตั้งค่าของแต่ละ Notification Channel ก็เป็นตัวบอกใบ้ได้ดีมากๆว่า แอนดรอยด์กำลังจะรองรับ Notification Badge โดยตรงแล้ว

การสร้าง Notification Channel กำหนดค่าอะไรได้บ้าง

        Notification Channel ที่สร้างขึ้นในโค้ดจะมี Setter หลายๆอย่างที่นักพัฒนาสามารถกำหนดได้ (แต่ผู้ใช้ก็สามารถไปตั้งค่าตามใจชอบเองได้นะ)

        • enableLights กำหนดว่าจะให้แสดงไฟแจ้งเตือนหรือไม่ (อุปกรณ์แอนดรอยด์หลายๆรุ่นจะมีไฟแจ้งเตือน)
        • enableVibration กำหนดว่าจะให้เครื่องสั่นเมื่อแจ้งเตือนหรือไม่
        • setBypassDnd กำหนดได้ว่าจะให้ Notification สามารถทำงานได้อยู่ ถึงแม้ว่าผู้ใช้เปิด Do not disturb หรือไม่
         • setGroup กำหนด Channel Group (ต้องสร้าง Channel Group ขึ้นมาก่อน)
         • setImportance กำหนดความสำคัญของ Channel ซึ่งจะทำให้การแจ้งเตือนแสดงผลแตกต่างไปตามที่กำหนดไว้
        • setLightColor นอกจากจะมีไฟแจ้งเตือนแล้ว อุปกรณ์แอนดรอยด์บางรุ่นสามารถกำหนดสีของไฟแจ้งเตือนได้ด้วยนะ (กำหนดเป็น ARGB)
        • setLockscreenVisibility กำหนดว่าจะให้แสดงให้เห็นในหน้า Lockscreen ด้วยหรือไม่
        • setShowBadge กำหนดว่าจะให้แสดงเป็น Badge ในหน้า Home ด้วยหรือไม่
        • setSound สามารถกำหนดเสียงแจ้งเตือนได้
        • setVibrationPattern กำหนดรูปแบบจังหวะการสั่นแจ้งเตือน (ถ้ามีการเปิดสั่นเพื่อแจ้งเตือนด้วย)

        ซึ่งเจ้าของบล็อกหยิบมาแค่ Setter Method เท่านั้น ถ้าอยากดูรายละเอียดของคำสั่งทั้งหมดสามารถเข้าไปดูได้ที่ Notification Channel - API Reference [Android Developers]

Importance ที่มาแทนที่ Priority

        ใน Notification แบบเดิมๆนั้น สามารถกำหนดได้ว่า Notification อันไหนสำคัญมากน้อยเพียงใด ด้วยการกำหนดจากค่า Priority แต่สำหรับ Android O นั้นได้ประกาศ Deprecated คำสั่งดังกล่าว แล้วเปลี่ยนมาใช้ Importance แทน

        ซึ่ง Importance เป็นการกำหนดความสำคัญในแต่ละ Notification Channel แทนที่จะกำหนดที่ Notification แต่ละตัวแบบเดิมๆ ซึ่งการกำหนดแบบนี้จะช่วยให้จัดกลุ่มของ Notification ตามลำดับความสำคัญได้ง่ายขึ้น โดยสามารถกำหนดค่าได้ทั้งหมดดังนี้

        • NotificationManager.IMPORTANCE_NONE
        • NotificationManager.IMPORTANCE_MIN
        • NotificationManager.IMPORTANCE_LOW
        • NotificationManager.IMPORTANCE_DEFAULT
        • NotificationManager.IMPORTANCE_HIGH

        ซึ่งก็มีบางตัวเพิ่มเข้ามาด้วยนะ แต่ใน API Reference บอกว่าไม่ได้ใช้งาน

        • NotificationManager.IMPORTANCE_MAX
        • NotificationManager.IMPORTANCE_UNSPECIFIED

        เมื่อสร้าง Notification Channel ขึ้นมา ก็จะต้องกำหนดค่า Importance ด้วยทุกครั้ง

int importance = NotificationManager.IMPORTANCE_MAX;
String channelId = "warning_notification";
String channelName = "Warning";
NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);

        เพียงเท่านี้ Notification ที่อยู่ในแต่ละ Channel ก็จะมีรูปแบบการแจ้งเตือนตามค่า Importance ที่กำหนดไว้

การแก้ไข/ลบ Notification Channel

        เมื่อต้องการเปลี่ยนแปลง Notification Channel และ Group สามารถดึง Notification Channel โดยใช้ Channel ID ที่เคยกำหนดไว้ได้เลย

NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = "comment_notification";
NotificationChannel channel = manager.getNotificationChannel(channelId);

        ในกรณีที่ต้องการลบ Channel ที่ไม่ต้องการ ก็ให้ใช้คำสั่งที่อยู่ใน Notification Manager ได้เลย โดยให้ระบุ Channel ID ที่ต้องการลบ

NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
String channelId = "comment_notification";
manager.deleteNotificationChannel(channelId);

การเปิดหน้าตั้งค่า Notification Channel ผ่านโค้ด

        เพราะการเข้าไปตั้งค่า Notification Channel ในหน้า Settings เป็นอะไรที่ทำให้ผู้ใช้สับสนบ้างเป็นบางครั้ง เพราะว่ากว่าจะเข้าไปถึงหน้าตั้งค่าได้ ต้องกดหลายเมนูมาก ดังนั้นเพื่อให้ผู้ใช้สามารถเข้าไปตั้งค่าได้สะดวกสบาย นักพัฒนาสามารถทำปุ่มให้ผู้ใช้สามารถกดเข้าหน้าตั้งค่า Notification Channel จากในแอปฯได้เลย

Intent intent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);
intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId);
intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName());
startActivity(intent);

สรุป

        ถึงแม้ว่า Notification Channel อาจจะไม่ใช่ฟีเจอร์ที่สำคัญอะไรมากนักในมุมมองของนักพัฒนาส่วนใหญ่ เพราะไม่ใช่หลายๆแอปฯก็ไม่ได้มี Notification เยอะขนาดนั้น แต่เมื่อลองมองดูแอปฯยอดนิยมหลายๆตัวแล้ว ก็ต้องบอกเลยว่า Notification เป็นสิ่งสำคัญมาก เพราะมันทำให้เกิด User Retention ได้มากที่สุด ทำให้ผู้ใช้กลับเข้ามาใช้งานแอปฯบ่อยๆได้ 

        สำหรับแอปฯที่มี Notification ที่จะใช้แจ้งเตือนผู้ใช้หลายประเภท ต้องทำให้ผู้ใช้สามารถกำหนดรูปแบบการแจ้งเตือนในแต่ละแบบได้ ซึ่งเดิมทีแอนดรอยด์นั้นไม่ได้รองรับการใช้งานถึงขนาดนี้ ดังนั้นนักพัฒนาก็ต้องไปทำเองเพื่อให้ตอบโจทย์ความต้องการของผู้ใช้ แต่เมื่อ Notification Channel ถูกเพิ่มเข้ามาใน Android O ก็จะช่วยให้นักพัฒนาสามารถจัดการเรื่องนี้ได้ง่ายขึ้น โดยที่เขียนโค้ดน้อยลง ที่เหลือก็ปล่อยให้เป็นหน้าที่ของตัวระบบแอนดรอยด์เอง (แต่ก็ต้องรอซักสองสามปี กว่าที่ Android O จะแพร่หลายอยู่ในกลุ่มผู้ใช้งานจริงๆ)

        และที่สำคัญคือรองรับ Native Notification Badge แล้วววววว ดีใจจนอยากจะร้องไห้เลยยยยยย

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

        • Exploring Android O: Notification Channels [Medium]
        • Notification Channels [Android Developers]




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium