จากเนื้อหาในตอนที่แล้ว เราได้เตรียมความพร้อมในเบื้องต้นสำหรับใช้งาน Push
Notification ไปแล้ว
เตรียมพร้อม ใช้งาน Push Notification ใน ionic material app
https://www.ninenik.com/content.php?arti_id=748 via @ninenik
โดยเฉพาะค่าที่จำเป็นสำหรับต่อเนื่องในบทความนี้คือ Sender ID และ
Firebase Cloud Messaging token (FCM token) ซึ่งจะได้จากบทความที่แล้วตามรูป
เนื้อหาในตอนนี้เราจะทำความเข้าใจรูปแบบการทำงาน และการใช้งานระบบ Push Notification
ของระบบของเรา
โดยรูปแบบการทำงานคือ เมื่อเปิด app เข้ามาครั้งแรกเราจะให้ app ทำการส่ง UUID กับ
registrationId ไปทำการบันทึกไว้ยัง database บน Server ในที่นี้เราจะทดสอบใน lcoalhost
ใช้งานผ่านระบบ Lan คือเชื่อมโยง wifi เดียวกัน หรือใครจะสะดวกใช้รวมกับ Server เลยก็
สามารถทำได้ตามสะดวก
UUID รหัสเฉพาะของเครื่องมือถือนั้นๆ
registrationId รหัสสำหรับลงทะเบียนเพื่อรับข้อความ Push
หลังจากข้อมูลถูกส่งไปบันทึกบันฝั่ง Server เรียบร้อยแล้ว app ก็จะมีคำสั่งตรวจจับข้อความ Push
ทำงานตลอดเวลา แม้ปิด app ไปแล้ว และเมื่อเราทำการส่งข้อมูลจากฝั่ง Server มายังเครื่องที่
ลงทะเบียนไว้ app ก็จะแสดง Push Notification แจ้งเตือน เมื่อผู้ใช้กดไปที่แจ้งเตือน ก็จะเปิด app
และไปยังหน้าที่เรากำหนด นี่คือรายละเอียดการทำงานของระบบเบื้องต้นที่เราจะทำ
เริ่มต้นใช้งาน Push Notification plugin
1. ติดตั้ง Push Notification plugin และ Device plugin
ก่อนอื่นเราจะติดตั้ง Device plugin ซึ่งตัวนี้จะเป็นตัวที่เราใช้ดึงข้อมูล UUID หรือรหัสเฉพาะของ
เครื่องมือถือนั้นๆ ดูเพิ่มเติมได้ที่ http://ngcordova.com/docs/plugins/device/
ใช้คำสั่ง
C:\phonegap\learn004>cordova plugin add cordova-plugin-device
ตามด้วย Push Notification plugin
ดูเพิ่มเติมได้ที่ http://ngcordova.com/docs/plugins/pushNotificationsV5/
ใช้คำสั่ง
C:\phonegap\learn004>cordova plugin add phonegap-plugin-push --variable SENDER_ID="XXXXX"
สังเกตว่าเรามีการส่งตัวแปรเข้าใปในขั้นตอนการติดตั้ง plugin ด้วย คือ SENDER_ID ค่าตรงนี้
ให้เราเปลี่ยน XXXXX เป็น SENDER_ID ที่เราได้จากบทความที่แล้ว *ส่วนนี้สำคัญ
2. สร้างตาราง tbl_notify ใน database บน Server
ในที่นี้เราจะทดสอบบน localhost จะทำผ่าน phpmyadmin โดยสร้างตาราง tbl_notify
มีโครงสร้างโดยประมาณดังนี้ (โครงสร้างเบื้องต้นเท่านั้น สามารถไปประยุกต์เพิ่มเติมได้)
-- -- Table structure for table `tbl_notify` -- CREATE TABLE IF NOT EXISTS `tbl_notify` ( `notify_id` int(11) NOT NULL, `notify_uid` varchar(255) NOT NULL, `notify_regid` varchar(255) NOT NULL, `notify_status` tinyint(1) NOT NULL, `notify_dateadd` datetime NOT NULL, `notify_updateadd` datetime NOT NULL ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -- -- Indexes for dumped tables -- -- -- Indexes for table `tbl_notify` -- ALTER TABLE `tbl_notify` ADD PRIMARY KEY (`notify_id`); -- -- AUTO_INCREMENT for dumped tables -- -- -- AUTO_INCREMENT for table `tbl_notify` -- ALTER TABLE `tbl_notify` MODIFY `notify_id` int(11) NOT NULL AUTO_INCREMENT;
ตามโครงสร้างตาราง tbl_notify ข้างต้น
จะอธิบายคร่าวๆ ว่าเราจะเก็บอะไร
notify_uid เก็บรหัสเฉพาะของเครื่องมือถือนั้นๆ
notify_regid เก็บรหัสลงทะเบียนรับข้อความ Push
notify_status เก็บสถานะการรับข้อความ Push เช่น รับเป็น 1 ยกเลิกเป็น 0
notify_dateadd เก็บวันเวลาที่เพิ่ม
notify_updateadd เก็บวันเวลาที่อัพเดท
เนื่องจาก registrationId นั้นไม่ได้เป็นค่าที่ตายตัวหรือค่าเดียวเสมอไป อาจมีการเปลี่ยนแปลงในบาง
กรณี เช่น มือถือนั้นๆ ติดตั้ง app ใหม่ ดังนั้นเราจึงมีการเก็บวันที่ update ข้อมูลด้วย เผื่อได้ประยุกต์ใช้งาน
โดยการอัพเดท ก็จะอิงจาก UUID ที่เป็นค่าเดียวเฉพาะของเครื่องนั้นๆ
3. สร้าง Service สำหรับส่งข้อมูลบันทึกฝั่ง Server
ให้เราเปิดไฟล์ services.js ในโฟลเดอร์ js เพื่อทำการเพิ่ม service สำหรับ
ทำงานในการส่งข้อมูลไปบันทึกบน server จะได้ไฟล์ทั้งหมดเป็น
'use strict'; angular.module('starter.services', []) .service('ArticleService',function($http, $q) { // สร้าง service // url ไฟล์ json var url="https://www.ninenik.com/demo/article_new_api.php?callback=JSON_CALLBACK"; return { // ในที่นี้เราจะใช้การส่งค่าแบบ post getArticle: function() { var deferred = $q.defer(); $http.jsonp(url) .success(deferred.resolve) .error(deferred.reject); return deferred.promise; } }; }) .service('notifyService',function($http, $q){ // สร้าง service // กำหนด url ของ ไฟล์ api ของเรา var url = "http://192.168.8.102/app/api/notify_api.php"; return { // ในที่นี้เราจะใช้การส่งค่าแบบ post setNotify: function(dataSend) { var deferred = $q.defer(); $http.post(url,dataSend) .success(deferred.resolve) .error(deferred.reject); return deferred.promise; } }; }) .service('ShareService',function(){ });
โดย service ที่เราสร้างเพิ่มเข้ามาก็คือ notifyService ส่งไปที่ server url ในที่นี้
ใช้การทดสอบบนเครื่องโดยระบุเป็น IP ในระบบ LAN
notifyService จะมีฟังก์ชั่นชื่อ setNotify สำหรับส่งค่าไปบันทึกฝั่ง server
4. สร้างไฟล์ notify_api.php เพื่อรับค่ามาบันทึกบน Sever
โค้ดไฟล์ dbconnect.php
<?php $mysqli = new mysqli("localhost", "root","","app"); /* check connection */ if ($mysqli->connect_errno) { printf("Connect failed: %s\n", $mysqli->connect_error); exit(); } if(!$mysqli->set_charset("utf8")) { printf("Error loading character set utf8: %s\n", $mysqli->error); exit(); }
โค้ดไฟล์ notify_api.php
<?php header("Content-type:application/json; charset=UTF-8"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); if(isset($_SERVER['HTTP_ORIGIN'])) { header("Access-Control-Allow-Origin: {$_SERVER['HTTP_ORIGIN']}"); header('Access-Control-Allow-Credentials: true'); // header('Access-Control-Max-Age: 86400'); // cache for 1 day } // Access-Control headers are received during OPTIONS requests if($_SERVER['REQUEST_METHOD'] == 'OPTIONS') { if(isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_METHOD'])) header("Access-Control-Allow-Methods: GET, POST, OPTIONS"); if(isset($_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS'])) header("Access-Control-Allow-Headers: {$_SERVER['HTTP_ACCESS_CONTROL_REQUEST_HEADERS']}"); exit(0); } // ส่วนการกำหนด header ให้กำหนดตามด้านบน ไม่เช่นนั้น app จะไม่สามารถส่งค่ามาได้ require_once("dbconnect.php"); $postdata = file_get_contents("php://input"); // ค่าที่ส่งมาจะถูกเก็บที่ไฟล์ if(isset($postdata)) { // ถ้ามีคาที่ส่งมา $_POST = json_decode($postdata,true); // แปลงค่าที่ส่งมาเป็นตัวแปร array $_POST } $_error_msg = null; $_success_msg = null; if( isset($_POST['regid']) && $_POST['regid']!="" && isset($_POST['uid']) && $_POST['uid']!="" ){ // $_res_regID = $mysqli->real_escape_string(trim($_POST['regid'])); $_res_UID = $mysqli->real_escape_string(trim($_POST['uid'])); if(isset($_error_msg) && $_error_msg!=""){ $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); }else{ // เช็คในตารางก่อนว่า เครื่องมือถือนั้นๆ ได้เคยบันทึกข้อมูลมาก่อนแล้วหรือไม่ อิงจาก UUID $sql=" SELECT notify_regid,notify_uid,notify_status FROM tbl_notify WHERE notify_uid = '".$_res_UID."' "; $result = $mysqli->query($sql); if($result && $result->num_rows>0){ // ถ้าเคยบันทึกแล้ว $row = $result->fetch_assoc(); // ดึงค่ามาตรวจสอบ $_success_msg=1; if($row['notify_regid'] != $_res_regID){ // ถ้าค่าเดิม กับค่าหใม่ไม่เหมือนกัน ให้อัพเดทค่าใหม่ $sql2 = " UPDATE tbl_notify SET notify_regid = '".$_res_regID."' , notify_status = '1' , notify_updateadd = '".date('Y-m-d H:i:s')."' WHERE notify_uid = '".$_res_UID."' "; $result2 = $mysqli->query($sql2); if($result2 && $mysqli->affected_rows>0){ // ถ้าอัพเดทสำเร็จ $_success_msg=1; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg, "regid" => $_res_regID, "uid"=> $_res_UID, "status"=> 1 ); }else{ // ถ้าอัพเดทไม่สำเร็จ $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); } }else{ // ถ้าค่าใหม่ เท่ากับค่าเดิม ใช้ค่าเดิม $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg, "regid" => $row['notify_regid'], "uid" => $row['notify_uid'], "status" => $row['notify_status'] ); } }else{ // ถ้ายังไม่มีข้อมูล ให้บันทีกข้อมูลใหม่ $sql2 = " INSERT INTO tbl_notify SET notify_uid = '".$_res_UID."' , notify_regid = '".$_res_regID."' , notify_status = '1' , notify_dateadd = '".date('Y-m-d H:i:s')."' "; $result2 = $mysqli->query($sql2); if($result2 && $mysqli->affected_rows>0){ // ถ้าบันทึกขอ้มูลสำเร็จ $_success_msg=1; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg, "regid" => $_res_regID, "uid"=> $_res_UID, "status"=> 1 ); }else{ // ถ้าบันทึกข้อมูลล้มเหลว $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); } } } // }else{ // ไม่มีการส่งข้อมูลใดๆ เข้ามา $_error_msg = "เกิดข้อผิดพลาด ไม่มีค่าส่งมา"; $json_data[]=array( "success" => $_success_msg, "error" => $_error_msg ); } // แปลง array เป็นรูปแบบ json string if(isset($json_data)){ $json= json_encode($json_data); if(isset($_GET['callback']) && $_GET['callback']!=""){ echo $_GET['callback']."(".$json.");"; }else{ echo $json; } } ?>
5. เพิ่มคำสั่งใช้งาน Push Notification
ต่อมาเป็นส่วนสำคัญของการใช้งาน Push Notification คือคำสั่งในการจัดการการใช้งาน
เกี่ยวกับข้อความ Push ให้เราเปิดไฟล์ app.js ในโฟลเดอร์ js และดูในส่วนของ
การตั้งค่าการทำงานเริ่มต้มของ module ด้วย method run() โดยโค้ดเริ่มต้นเดิมของเราในส่วนนี้จะเป็นดังนี้
.run(function($ionicPlatform,$ionicPopup,$cordovaDialogs) { $ionicPlatform.ready(function() { if (window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); } if (window.StatusBar) { StatusBar.styleDefault(); } }); })
เราจะปรับเพิ่มเติม เป็นดังนี้
.run(function($ionicPlatform,$ionicPopup,$cordovaDialogs, $cordovaPushV5, $rootScope, $cordovaDevice, notifyService, $state) { $ionicPlatform.ready(function() { if (window.cordova && window.cordova.plugins.Keyboard) { cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true); } if (window.StatusBar) { StatusBar.styleDefault(); } }); // กำหนด senderID สำหรับ android var options = { android: { senderID: "XXXXXX" } }; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตั้งค่าเริ่มต้น $cordovaPushV5.initialize(options).then(function() { // เรียกฟังก์ชั่นตรวจจับข้อความ push กรณีได้รับข้อความ $cordovaPushV5.onNotification(); // เรียกฟังก์ชั่นตรวจจับข้อความ push กรณีเกิดข้อผิดพลาด $cordovaPushV5.onError(); // ลงทะเบียนรับ registrationId $cordovaPushV5.register().then(function(registrationId) { alert('RegID: '+registrationId); alert('UUID: '+$cordovaDevice.getUUID()); // เตรียมข้อมูลสำหรับส่งไปบันทึกบน server var dataSend = { uid:$cordovaDevice.getUUID(), regid:registrationId }; // service เรียกใช้ฟังก์ชั่น notifyService ส่งค่าไปยัง server notifyService.setNotify(dataSend) .then(function(response) { // ทดสอบแสดงค่าว่าบันทึกสำเร็จหรือไม่ alert(JSON.stringify(response)); }); }); }); // รอรับทำงานเมื่อ มีข้อความ push เข้ามา $rootScope.$on('$cordovaPushV5:notificationReceived', function(event, data){ alert('OK Received:'+JSON.stringify(data)); $state.go('app.article'); // เมื่อเปิดที่ข้อความ push ให้ไปหน้าที่ต้องการ // ชุดข้อมูลที่เราจะได้จากข้อความ push สามารถกำหนดค่าเองเพิ่มเติมได้ // ด้านล่างนี้คือค่าพื้นฐาน // data.message, // ข้อความแจ้ง // data.title, // หัวข้อ // data.count, // จำนวนเลขระบุ กรณีมีการแจ้งจำนวนใดๆ // data.sound, // เสียง // data.image, // รูปภาพที่แสดงใน push ใช้เป็น url ได้ // data.additionalData // ข้อมูลเพิ่ม // ค่าข้างต้นเหล่านี้เป็นค่าที่เรา ต้องกำหนดในไฟล์ส่งข้อความ push }); // รอรับทำงานเมื่อ เกิดข้อผิดพลาด ปกติเราจะไม่ให้ทำงานใดๆ $rootScope.$on('$cordovaPushV5:errorOcurred', function(event, e){ alert('ERR Received:'+JSON.stringify(e)); // e.message // ข้อความ error }); }); })
คำอธิบายแสดงในโค้ด สังเกตว่าเรามีการ inject ค่าเข้ามาเพิ่มเติม ได้แก่
$cordovaPushV5 สำหรับใช้งาน Push Notification plugin
$rootScope เป็น root สำหรับใช้งานรอรับการทำงานหรือ event ตรวจสอบข้อความ push
$cordovaDevice สำหรับใช้งาน Device plugin ในที่นี้เราใช้สำหรับดึงค่า UUID
notifyService เป็น service ที่เราสร้างขึ้นมาเพื่อส่งค่าไปบันทึกบน server
$state เป็นส่วนจัดการการลิ้งค์หรือเปลี่ยนหน้า app ไปหน้าที่ต้องการ
โค้ดตัวอย่างข้างต้น เราใช้ คำสั่ง alert() เพื่อแสดงข้อมูลการทำงาน เวลานำไปใช้จริงสามารถลบออกได้
หรือเปลี่ยนเป็นคำสั่งอื่นๆ ตามความเหมาะสม
ตอนนี้เราได้ app ที่พร้อมสำหรับรับข้อความ push แล้ว โดยเมื่อเราเปิดเครื่องเข้า app ก็จะทำงานในส่วน
ของ run() เพียงครั้งแรกครั้งเดียว เมื่อได้ลงทะเบียนรับข้อความ push แล้วเครื่องมือถือของเราก็พร้อม
ที่จะรับข้อความแม้ไม่ได้เปิด app ทิ้งไว้
6. ส่งข้อความ push จาก server
เมื่อเราเตรียมมือถือ และ app สำหรับรับข้อความ push แล้ว ต่อมาก็คือ การส่งข้อความ
ไปยังเครื่องที่ลงทะเบียนไว้ ซึ่งจะเป็นการทำงานฝั่ง server
โดยให้โหลดไฟล์ pusher.php สำหรับใช้ร่วมกับการส่งข้อความได้ที่
ดาวน์โหลดไฟล์ pusher.php ได้ที่ https://goo.gl/kbojIU
จากนั้นให้เราสร้างไฟล์ทดสอบ สมมติชื่อ test_push.php ดังนี้
<?php header("Content-type:text/html; charset=UTF-8"); header("Cache-Control: no-store, no-cache, must-revalidate"); header("Cache-Control: post-check=0, pre-check=0", false); // เชื่อมต่อกับฐานข้อมูล require_once("dbconnect.php"); // ส่วนตั้งค่าการใช้งาน push require_once("pusher.php"); $fcmToken = "your_fcm_token"; // ค่าา FCM token $pusher = new Pusher($fcmToken); $regId=array(); $sql=" SELECT * FROM tbl_notify "; $result = $mysqli->query($sql); if($result){ while($row = $result->fetch_assoc()){ $regId[]=$row['notify_regid']; } } $msg = array ( 'message' => 'ทดสอบข้อความภาษาไทย', 'title' => 'ทดสอบหัวข้อหลัก', 'subtitle' => 'ทดสอบหัวข้อย่อย', 'tickerText' => 'Ticker text here...Ticker text here...Ticker text here', 'vibrate' => 1, 'sound' => 1, 'count' => 2, 'image' => 'https://www.ninenik.com/images/banner_ninenik.gif', 'largeIcon' => 'large_icon', 'smallIcon' => 'small_icon' ); $pusher->notify($regId, $msg); echo "<pre>"; print_r($pusher->getOutputAsArray()); echo "</pre>"; ?>
เปลี่ยนค่า your_fcm_token ใน
$fcmToken = "your_fcm_token"; // ค่าา FCM token
เป็นค่าที่เราได้จากเนื้อหาตอนที่แล้ว
https://www.ninenik.com/content.php?arti_id=748 via @ninenik
มาดูตัวอย่างไฟล์ที่รันทดสอบส่งข้อความ push
7. ทำการ build apk ไฟล์แล้วนำไปทดสอบติดตั้งบนมือถือ
ด้วยคำสั่ง
C:\phonegap\learn004>phonegap build android
ให้ทำการทดสอบติดตั้งในมือถือ android ของเรา จะได้หน้าตา app และลำดับการทำงาน
ประมาณนี้
เมื่อเข้ามา app ครั้งแรก และลงทะเบียนขอ registrationId | แจ้ง UUID | แจ้งเมื่อส่งข้อมูลบันทึกบน server สำเร็จ | ||
เมื่อกลับหน้า app ปกติ | เมื่อปิด app แล้วและมีข้อความ push เข้ามา | เมื่อเลื่อนดูรายละเอียด แสดงข้อมูลที่เราทดสอบส่ง | ||
พอแตะที่แจ้งเตือนเพื่อเข้ามาใน app | app ไปหน้าตามที่เรากำหนด | |||
การทำงานตัวอย่างข้าง เราใช้คำัส่ง alert() เพื่อแสดงค่าให้เห็นรูปแบบการทำงานเท่านั้น เวลานำไปใช้
สามารถปิดหรือใช้เป็นรูปแบบอื่นๆได้
สามารถปิดหรือใช้เป็นรูปแบบอื่นๆได้