Google Cloud Messaging allows you send lightweight messages from the backend server to all the devices whenever there is new data available. This saves lot of user’s battery by avoiding poll request to server for new data. Using GCM you can build powerful multi platform (iOS, Android & Web) apps like real time chat, news feed, cloud storage and lot more. On top of everything, GCM is completely free and there are no limitations.
As parse.com announced their shutdown recently, GCM is the only best option even though it won’t comes with an admin interface. But don’t worry, we’ll build a simple admin panel in this article.
As this article is pretty lengthy, I have divided it into 3 parts. Each part covers a unique part in building the final realtime chat app.
Part 1: Covers building the REST API for chat app including the GCM server app.
Part 2: Explains integrating GCM into your android app including a test message.
Part 3: Building Simple Realtime Chat App.
1. Google Cloud Messaging
Typically GCM implementation involves three components. Google cloud messaging server, the app server and the client app. We should take care of writing the app server and the client app. In order to make calls from the app server to GCM server, you can follow HTTP or XMPP protocol. HTTP supports downstream (gcm to client) messages only. XMPP supports both downstream and upstream (device to gcm, then from gcm to server) messages.
Below is the pictorial representation of the overall architecture.
1. First the app connects to GCM server and register itself.
2. Upon successful registration, GCM issues gcm registration token to device. This registration token uniquely identifies each device.
3. The device sends the registration token to our server to store it in MySQL.
4. Whenever app server wants to send push notification, it sends a request to GCM server sending the push message along with the registration token.
5. GCM server identifies the device using the registration token and initiates the push message.
6. The device receives the push messages and further action takes place.
2. Obtaining Google API Key
Google API key is necessary to interact with GCM server. GCM uses this key to identify your server app. Follow the below steps to obtain your API key. Note that the developer console interface is changing more frequently. So, the below steps may vary in future.
1. Goto Google developers console and create a new app. If you have already created one, select the app.
2. Give a name to your new project. Once the project is created, goto project’s dashboard and click on Use Google APIs
3. Under Mobile APIs, click on Cloud Messaging for Android and enable the API by clicking on top enable API button.
4. Once enabled, click on Credentials on the left. You will be asked to create new credentials by showing multiple options. Choose API Key and then Server Key.
5. After choosing Server Key, your API key will be displayed on the dashboard. Note down the API key as we need to use it in our PHP project.
3. Building Simple Realtime Chat App
In this article, we are going to learn how to create a simple realtime chat app by using Android, GCM, PHP, MySQL, HTML & CSS. We use HTML & CSS to build the admin panel for the server app.
Below are the screens of the android app.
And the server app comes with the option of choosing the user(s) / topic and send the push notification.
This part of the article involves building the server app including designing the MySQL database, REST API for mobile app and an admin panel to send push notifications. I am using Netbeans IDE to develop the PHP code and WAMP / MAMP server to create the php, mysql environment.
Now let’s start designing the database first.
4. Designing MySQL Database
For this app we need only three tables. users, chat rooms and messages.
users – This table holds the user information like name, email and other profile information along with gcm registration id.
chat_rooms – Contains the chat room information.
messages – Contains the messages sent in the chat rooms.
Open phpmyadmin and execute the below sql query to create the required database and tables.
CREATE DATABASE gcm_chat; CREATE TABLE `chat_rooms` ( `chat_room_id` int(11) NOT NULL, `name` varchar(100) NOT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; CREATE TABLE `messages` ( `message_id` int(11) NOT NULL, `chat_room_id` int(11) NOT NULL, `user_id` int(11) NOT NULL, `message` text NOT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1; CREATE TABLE `users` ( `user_id` int(11) NOT NULL, `name` varchar(255) NOT NULL, `email` varchar(255) NOT NULL, `gcm_registration_id` text NOT NULL, `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=latin1; ALTER TABLE `chat_rooms` ADD PRIMARY KEY (`chat_room_id`); ALTER TABLE `messages` ADD PRIMARY KEY (`message_id`), ADD KEY `chat_room_id` (`chat_room_id`), ADD KEY `user_id` (`user_id`), ADD KEY `chat_room_id_2` (`chat_room_id`); ALTER TABLE `users` ADD PRIMARY KEY (`user_id`), ADD UNIQUE KEY `email` (`email`); ALTER TABLE `messages` ADD CONSTRAINT `messages_ibfk_3` FOREIGN KEY (`chat_room_id`) REFERENCES `chat_rooms` (`chat_room_id`), ADD CONSTRAINT `messages_ibfk_2` FOREIGN KEY (`user_id`) REFERENCES `users` (`user_id`) ON DELETE CASCADE ON UPDATE CASCADE;
5. Creating PHP REST API
I am using Slim framework to create the REST endpoints. If you are not aware of PHP Slim, refer my previous tutorial REST API for Android app using PHP, Slim and MySQL to understand how easily you can create the REST API endpoints for your android app.
Below is the project structure of the PHP app. You have to make sure that you are following same structure while following the further steps.
include – Contains the database classes to perform CRUD operations on the database.
libs – Contains the libraries needed for the app (slim, gcm)
v1 – Root directory of the REST API
index.php, demo.php, styles.css – Required to create the admin interface.
1. Goto your WAMP/MAMP installation location and open the web directory. On windows, it will be c:/wamp/www directory. On Mac, the path will be /Applications/MAMP/htdocs.
2. Inside the web directory (www or htdocs), create a directory named gcm_chat. This will be the root directory of our project.
3. Inside gcm_chat folder, create the remaining directories as shown in the above image. Create folders named include, libs and v1. Inside libs, create another folder named gcm.
4. Download Slim framework and paste it inside libs folder.
5. Create a file named config.php in include. This file contains the app configuration like database credentials, google API Key and other information.
Replace GOOGLE_API_KEY with your API Key which you obtained in 2nd section. Also keep the correct database credentials.
<?php /** * Database configuration */ define('DB_USERNAME', 'root'); define('DB_PASSWORD', 'root'); define('DB_HOST', 'localhost'); define('DB_NAME', 'gcm_chat'); define("GOOGLE_API_KEY", "AIzaSyDKk_Ew7Vi4FZnMzu6GCY5PLb4xZG8muvX"); // push notification flags define('PUSH_FLAG_CHATROOM', 1); define('PUSH_FLAG_USER', 2); ?>
6. Create a file named db_connect.php inside include folder. This class takes care of database connection.
<?php /** * Handling database connection * */ class DbConnect { private $conn; function __construct() { } /** * Establishing database connection * @return database connection handler */ function connect() { include_once dirname(__FILE__) . '/config.php'; // Connecting to mysql database $this->conn = new mysqli(DB_HOST, DB_USERNAME, DB_PASSWORD, DB_NAME); // Check for database connection error if (mysqli_connect_errno()) { echo "Failed to connect to MySQL: " . mysqli_connect_error(); } // returing connection resource return $this->conn; } } ?>
7. Create another file named db_handler.php inside include folder. This file contains all the necessary functions to interact with database tables.
<?php /** * Class to handle all db operations * This class will have CRUD methods for database tables * * @author Ravi Tamada */ class DbHandler { private $conn; function __construct() { require_once dirname(__FILE__) . '/db_connect.php'; // opening db connection $db = new DbConnect(); $this->conn = $db->connect(); } // creating new user if not existed public function createUser($name, $email) { $response = array(); // First check if user already existed in db if (!$this->isUserExists($email)) { // insert query $stmt = $this->conn->prepare("INSERT INTO users(name, email) values(?, ?)"); $stmt->bind_param("ss", $name, $email); $result = $stmt->execute(); $stmt->close(); // Check for successful insertion if ($result) { // User successfully inserted $response["error"] = false; $response["user"] = $this->getUserByEmail($email); } else { // Failed to create user $response["error"] = true; $response["message"] = "Oops! An error occurred while registereing"; } } else { // User with same email already existed in the db $response["error"] = false; $response["user"] = $this->getUserByEmail($email); } return $response; } // updating user GCM registration ID public function updateGcmID($user_id, $gcm_registration_id) { $response = array(); $stmt = $this->conn->prepare("UPDATE users SET gcm_registration_id = ? WHERE user_id = ?"); $stmt->bind_param("si", $gcm_registration_id, $user_id); if ($stmt->execute()) { // User successfully updated $response["error"] = false; $response["message"] = 'GCM registration ID updated successfully'; } else { // Failed to update user $response["error"] = true; $response["message"] = "Failed to update GCM registration ID"; $stmt->error; } $stmt->close(); return $response; } // fetching single user by id public function getUser($user_id) { $stmt = $this->conn->prepare("SELECT user_id, name, email, gcm_registration_id, created_at FROM users WHERE user_id = ?"); $stmt->bind_param("s", $user_id); if ($stmt->execute()) { // $user = $stmt->get_result()->fetch_assoc(); $stmt->bind_result($user_id, $name, $email, $gcm_registration_id, $created_at); $stmt->fetch(); $user = array(); $user["user_id"] = $user_id; $user["name"] = $name; $user["email"] = $email; $user["gcm_registration_id"] = $gcm_registration_id; $user["created_at"] = $created_at; $stmt->close(); return $user; } else { return NULL; } } // fetching multiple users by ids public function getUsers($user_ids) { $users = array(); if (sizeof($user_ids) > 0) { $query = "SELECT user_id, name, email, gcm_registration_id, created_at FROM users WHERE user_id IN ("; foreach ($user_ids as $user_id) { $query .= $user_id . ','; } $query = substr($query, 0, strlen($query) - 1); $query .= ')'; $stmt = $this->conn->prepare($query); $stmt->execute(); $result = $stmt->get_result(); while ($user = $result->fetch_assoc()) { $tmp = array(); $tmp["user_id"] = $user['user_id']; $tmp["name"] = $user['name']; $tmp["email"] = $user['email']; $tmp["gcm_registration_id"] = $user['gcm_registration_id']; $tmp["created_at"] = $user['created_at']; array_push($users, $tmp); } } return $users; } // messaging in a chat room / to persional message public function addMessage($user_id, $chat_room_id, $message) { $response = array(); $stmt = $this->conn->prepare("INSERT INTO messages (chat_room_id, user_id, message) values(?, ?, ?)"); $stmt->bind_param("iis", $chat_room_id, $user_id, $message); $result = $stmt->execute(); if ($result) { $response['error'] = false; // get the message $message_id = $this->conn->insert_id; $stmt = $this->conn->prepare("SELECT message_id, user_id, chat_room_id, message, created_at FROM messages WHERE message_id = ?"); $stmt->bind_param("i", $message_id); if ($stmt->execute()) { $stmt->bind_result($message_id, $user_id, $chat_room_id, $message, $created_at); $stmt->fetch(); $tmp = array(); $tmp['message_id'] = $message_id; $tmp['chat_room_id'] = $chat_room_id; $tmp['message'] = $message; $tmp['created_at'] = $created_at; $response['message'] = $tmp; } } else { $response['error'] = true; $response['message'] = 'Failed send message'; } return $response; } // fetching all chat rooms public function getAllChatrooms() { $stmt = $this->conn->prepare("SELECT * FROM chat_rooms"); $stmt->execute(); $tasks = $stmt->get_result(); $stmt->close(); return $tasks; } // fetching single chat room by id function getChatRoom($chat_room_id) { $stmt = $this->conn->prepare("SELECT cr.chat_room_id, cr.name, cr.created_at as chat_room_created_at, u.name as username, c.* FROM chat_rooms cr LEFT JOIN messages c ON c.chat_room_id = cr.chat_room_id LEFT JOIN users u ON u.user_id = c.user_id WHERE cr.chat_room_id = ?"); $stmt->bind_param("i", $chat_room_id); $stmt->execute(); $tasks = $stmt->get_result(); $stmt->close(); return $tasks; } /** * Checking for duplicate user by email address * @param String $email email to check in db * @return boolean */ private function isUserExists($email) { $stmt = $this->conn->prepare("SELECT user_id from users WHERE email = ?"); $stmt->bind_param("s", $email); $stmt->execute(); $stmt->store_result(); $num_rows = $stmt->num_rows; $stmt->close(); return $num_rows > 0; } /** * Fetching user by email * @param String $email User email id */ public function getUserByEmail($email) { $stmt = $this->conn->prepare("SELECT user_id, name, email, created_at FROM users WHERE email = ?"); $stmt->bind_param("s", $email); if ($stmt->execute()) { // $user = $stmt->get_result()->fetch_assoc(); $stmt->bind_result($user_id, $name, $email, $created_at); $stmt->fetch(); $user = array(); $user["user_id"] = $user_id; $user["name"] = $name; $user["email"] = $email; $user["created_at"] = $created_at; $stmt->close(); return $user; } else { return NULL; } } } ?>
8. Now let’s start creating the files required for GCM. Create a file named gcm.php inside libs ⇒ gcm folder. This file contains necessary functions required to interact with GCM server. These functions basically makes a CURL request to GCM server by passing required parameters in order to invoke a push notification.
send() – Function sends push notification to a single user
sendToTopic() – Sends push notification to a topic
sendToMultiple() – Send push notification to multiple users
<?php class GCM { // constructor function __construct() { } // sending push message to single user by gcm registration id public function send($to, $message) { $fields = array( 'to' => $to, 'data' => $message, ); return $this->sendPushNotification($fields); } // Sending message to a topic by topic id public function sendToTopic($to, $message) { $fields = array( 'to' => '/topics/' . $to, 'data' => $message, ); return $this->sendPushNotification($fields); } // sending push message to multiple users by gcm registration ids public function sendMultiple($registration_ids, $message) { $fields = array( 'registration_ids' => $registration_ids, 'data' => $message, ); return $this->sendPushNotification($fields); } // function makes curl request to gcm servers private function sendPushNotification($fields) { // include config include_once __DIR__ . '/../../include/config.php'; // Set POST variables $url = 'https://gcm-http.googleapis.com/gcm/send'; $headers = array( 'Authorization: key=' . GOOGLE_API_KEY, 'Content-Type: application/json' ); // Open connection $ch = curl_init(); // Set the url, number of POST vars, POST data curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // Disabling SSL Certificate support temporarly curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields)); // Execute post $result = curl_exec($ch); if ($result === FALSE) { die('Curl failed: ' . curl_error($ch)); } // Close connection curl_close($ch); return $result; } } ?>
9. Under libs ⇒ gcm, create another file named push.php. This class prepares the required json format that is transferred as a push message to device. If you want to add additional fields to json, you need to add them in this class.
<?php /** * @author Ravi Tamada * @link URL Tutorial link */ class Push{ // push message title private $title; // push message payload private $data; // flag indicating background task on push received private $is_background; // flag to indicate the type of notification private $flag; function __construct() { } public function setTitle($title){ $this->title = $title; } public function setData($data){ $this->data = $data; } public function setIsBackground($is_background){ $this->is_background = $is_background; } public function setFlag($flag){ $this->flag = $flag; } public function getPush(){ $res = array(); $res['title'] = $this->title; $res['is_background'] = $this->is_background; $res['flag'] = $this->flag; $res['data'] = $this->data; return $res; } }
10. At this stage, we have all the necessary functions ready. Let’s start preparing the REST API endpoints for the android app. Create a file named .htaccess inside v1 folder and add below rules.
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^(.*)$ %{ENV:BASE}index.php [QSA,L]
11. Create index.php inside v1 folder. All the rest api requests will be handled by this file only.
<?php error_reporting(-1); ini_set('display_errors', 'On'); require_once '../include/db_handler.php'; require '.././libs/Slim/Slim.php'; \Slim\Slim::registerAutoloader(); $app = new \Slim\Slim(); // User login $app->post('/user/login', function() use ($app) { // check for required params verifyRequiredParams(array('name', 'email')); // reading post params $name = $app->request->post('name'); $email = $app->request->post('email'); // validating email address validateEmail($email); $db = new DbHandler(); $response = $db->createUser($name, $email); // echo json response echoRespnse(200, $response); }); /* * * * Updating user * we use this url to update user's gcm registration id */ $app->put('/user/:id', function($user_id) use ($app) { global $app; verifyRequiredParams(array('gcm_registration_id')); $gcm_registration_id = $app->request->put('gcm_registration_id'); $db = new DbHandler(); $response = $db->updateGcmID($user_id, $gcm_registration_id); echoRespnse(200, $response); }); /* * * * fetching all chat rooms */ $app->get('/chat_rooms', function() { $response = array(); $db = new DbHandler(); // fetching all user tasks $result = $db->getAllChatrooms(); $response["error"] = false; $response["chat_rooms"] = array(); // pushing single chat room into array while ($chat_room = $result->fetch_assoc()) { $tmp = array(); $tmp["chat_room_id"] = $chat_room["chat_room_id"]; $tmp["name"] = $chat_room["name"]; $tmp["created_at"] = $chat_room["created_at"]; array_push($response["chat_rooms"], $tmp); } echoRespnse(200, $response); }); /** * Messaging in a chat room * Will send push notification using Topic Messaging * */ $app->post('/chat_rooms/:id/message', function($chat_room_id) { global $app; $db = new DbHandler(); verifyRequiredParams(array('user_id', 'message')); $user_id = $app->request->post('user_id'); $message = $app->request->post('message'); $response = $db->addMessage($user_id, $chat_room_id, $message); if ($response['error'] == false) { require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $gcm = new GCM(); $push = new Push(); // get the user using userid $user = $db->getUser($user_id); $data = array(); $data['user'] = $user; $data['message'] = $response['message']; $data['chat_room_id'] = $chat_room_id; $push->setTitle("Google Cloud Messaging"); $push->setIsBackground(FALSE); $push->setFlag(PUSH_FLAG_CHATROOM); $push->setData($data); // echo json_encode($push->getPush());exit; // sending push message to a topic $gcm->sendToTopic('topic_' . $chat_room_id, $push->getPush()); $response['user'] = $user; $response['error'] = false; } echoRespnse(200, $response); }); /** * Sending push notification to a single user * We use user's gcm registration id to send the message * * */ $app->post('/users/:id/message', function($to_user_id) { global $app; $db = new DbHandler(); verifyRequiredParams(array('message')); $from_user_id = $app->request->post('user_id'); $message = $app->request->post('message'); $response = $db->addMessage($from_user_id, $to_user_id, $message); if ($response['error'] == false) { require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $gcm = new GCM(); $push = new Push(); $user = $db->getUser($to_user_id); $data = array(); $data['user'] = $user; $data['message'] = $response['message']; $data['image'] = ''; $push->setTitle("Google Cloud Messaging"); $push->setIsBackground(FALSE); $push->setFlag(PUSH_FLAG_USER); $push->setData($data); // sending push message to single user $gcm->send($user['gcm_registration_id'], $push->getPush()); $response['user'] = $user; $response['error'] = false; } echoRespnse(200, $response); }); /** * Sending push notification to multiple users * We use gcm registration ids to send notification message * At max you can send message to 1000 recipients * * */ $app->post('/users/message', function() use ($app) { $response = array(); verifyRequiredParams(array('user_id', 'to', 'message')); require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $db = new DbHandler(); $user_id = $app->request->post('user_id'); $to_user_ids = array_filter(explode(',', $app->request->post('to'))); $message = $app->request->post('message'); $user = $db->getUser($user_id); $users = $db->getUsers($to_user_ids); $registration_ids = array(); // preparing gcm registration ids array foreach ($users as $u) { array_push($registration_ids, $u['gcm_registration_id']); } // insert messages in db // send push to multiple users $gcm = new GCM(); $push = new Push(); // creating tmp message, skipping database insertion $msg = array(); $msg['message'] = $message; $msg['message_id'] = ''; $msg['chat_room_id'] = ''; $msg['created_at'] = date('Y-m-d G:i:s'); $data = array(); $data['user'] = $user; $data['message'] = $msg; $data['image'] = ''; $push->setTitle("Google Cloud Messaging"); $push->setIsBackground(FALSE); $push->setFlag(PUSH_FLAG_USER); $push->setData($data); // sending push message to multiple users $gcm->sendMultiple($registration_ids, $push->getPush()); $response['error'] = false; echoRespnse(200, $response); }); $app->post('/users/send_to_all', function() use ($app) { $response = array(); verifyRequiredParams(array('user_id', 'message')); require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $db = new DbHandler(); $user_id = $app->request->post('user_id'); $message = $app->request->post('message'); require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $gcm = new GCM(); $push = new Push(); // get the user using userid $user = $db->getUser($user_id); // creating tmp message, skipping database insertion $msg = array(); $msg['message'] = $message; $msg['message_id'] = ''; $msg['chat_room_id'] = ''; $msg['created_at'] = date('Y-m-d G:i:s'); $data = array(); $data['user'] = $user; $data['message'] = $msg; $data['image'] = 'https://www.androidhive.info/wp-content/uploads/2016/01/Air-1.png'; $push->setTitle("Google Cloud Messaging"); $push->setIsBackground(FALSE); $push->setFlag(PUSH_FLAG_USER); $push->setData($data); // sending message to topic `global` // On the device every user should subscribe to `global` topic $gcm->sendToTopic('global', $push->getPush()); $response['user'] = $user; $response['error'] = false; echoRespnse(200, $response); }); /** * Fetching single chat room including all the chat messages * */ $app->get('/chat_rooms/:id', function($chat_room_id) { global $app; $db = new DbHandler(); $result = $db->getChatRoom($chat_room_id); $response["error"] = false; $response["messages"] = array(); $response['chat_room'] = array(); $i = 0; // looping through result and preparing tasks array while ($chat_room = $result->fetch_assoc()) { // adding chat room node if ($i == 0) { $tmp = array(); $tmp["chat_room_id"] = $chat_room["chat_room_id"]; $tmp["name"] = $chat_room["name"]; $tmp["created_at"] = $chat_room["chat_room_created_at"]; $response['chat_room'] = $tmp; } if ($chat_room['user_id'] != NULL) { // message node $cmt = array(); $cmt["message"] = $chat_room["message"]; $cmt["message_id"] = $chat_room["message_id"]; $cmt["created_at"] = $chat_room["created_at"]; // user node $user = array(); $user['user_id'] = $chat_room['user_id']; $user['username'] = $chat_room['username']; $cmt['user'] = $user; array_push($response["messages"], $cmt); } } echoRespnse(200, $response); }); /** * Verifying required params posted or not */ function verifyRequiredParams($required_fields) { $error = false; $error_fields = ""; $request_params = array(); $request_params = $_REQUEST; // Handling PUT request params if ($_SERVER['REQUEST_METHOD'] == 'PUT') { $app = \Slim\Slim::getInstance(); parse_str($app->request()->getBody(), $request_params); } foreach ($required_fields as $field) { if (!isset($request_params[$field]) || strlen(trim($request_params[$field])) <= 0) { $error = true; $error_fields .= $field . ', '; } } if ($error) { // Required field(s) are missing or empty // echo error json and stop the app $response = array(); $app = \Slim\Slim::getInstance(); $response["error"] = true; $response["message"] = 'Required field(s) ' . substr($error_fields, 0, -2) . ' is missing or empty'; echoRespnse(400, $response); $app->stop(); } } /** * Validating email address */ function validateEmail($email) { $app = \Slim\Slim::getInstance(); if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $response["error"] = true; $response["message"] = 'Email address is not valid'; echoRespnse(400, $response); $app->stop(); } } function IsNullOrEmptyString($str) { return (!isset($str) || trim($str) === ''); } /** * Echoing json response to client * @param String $status_code Http response code * @param Int $response Json response */ function echoRespnse($status_code, $response) { $app = \Slim\Slim::getInstance(); // Http response code $app->status($status_code); // setting response content type to json $app->contentType('application/json'); echo json_encode($response); } $app->run(); ?>
The index.php inside v1 folder providers the below endpoints.
Base URL: http://localhost/gcm_chat/v1
Endpoint | Params | Method | Description |
/user/login | name, email | POST | User login or registration |
/user/:id | gcm_registration_id | PUT | Updates user’s gcm registration id in database |
/chat_rooms | – | GET | Fetches all chat rooms |
/chat_rooms/:id | replace :id with actual chat room id | GET | Fetches single chat room messages |
/chat_rooms/:id/message | replace :id with actual chat room id | POST | Posting a message in a chat room |
/users/:id/message | replace :id with actual user id | POST | Sending a message to user |
/users/message | user_id, to, message `to` – param is user ids separated by comma (,) |
POST | Sending a message to multiple users |
/users/send_to_all | user_id, message | POST | Sending a message to all the users subscribed to `global` topic |
6. Testing the REST API
Before starting the android project, make sure that the php project is running without any errors. Follow the below steps to test the API.
1. Enable apache mod_rewrite module (link)
2. Enable curl extension. This allows php to make http requests from the backend (link).
3. Install Postman Chrome REST API extension. You can use any other rest api clients too.
The below video takes you through testing the API using Postman.
7. Building the Admin Panel
I created very simple admin panel using PHP, HTML, CSS & jQuery. This admin panel might not be used in production stage, but gives you necessary functions to build a better one.
1. Create a file named demo.php in the root directory of gcm_chat. This class contains function for the admin panel.
<?php /** * Class to handle all db operations * This class will have CRUD methods for database tables * * @author Ravi Tamada */ class Demo { private $conn; function __construct() { require_once dirname(__FILE__) . '/include/db_connect.php'; // opening db connection $db = new DbConnect(); $this->conn = $db->connect(); } public function getAllChatRooms() { $stmt = $this->conn->prepare("SELECT * FROM chat_rooms"); $stmt->execute(); $tasks = $stmt->get_result(); $stmt->close(); return $tasks; } public function getAllUsers() { $stmt = $this->conn->prepare("SELECT * FROM users"); $stmt->execute(); $tasks = $stmt->get_result(); $stmt->close(); return $tasks; } public function getDemoUser() { $name = 'AndroidHive'; $email = 'admin@androidhive.info'; $stmt = $this->conn->prepare("SELECT user_id from users WHERE email = ?"); $stmt->bind_param("s", $email); $stmt->execute(); $stmt->store_result(); $num_rows = $stmt->num_rows; if ($num_rows > 0) { $stmt->bind_result($user_id); $stmt->fetch(); return $user_id; } else { $stmt = $this->conn->prepare("INSERT INTO users(name, email) values(?, ?)"); $stmt->bind_param("ss", $name, $email); $result = $stmt->execute(); $user_id = $stmt->insert_id; $stmt->close(); return $user_id; } } } ?>
2. Create a style sheet named style.css in the root directory.
/* Created on : 22 Jan, 2016, 10:12:06 PM Author : Ravi Tamada */ body{ width: 100%; margin: 0; padding: 0; font-family: 'Raleway', sans-serif; } .container_body{ width: 1000px; margin: 0 auto; } .header{ padding: 100px 0; text-align: center; color: #fff; background: -moz-radial-gradient(center, ellipse cover, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* ff3.6+ */ background: -webkit-gradient(radial, center center, 0px, center center, 100%, color-stop(0%, rgba(227,71,73,1)), color-stop(100%, rgba(186,27,31,1))); /* safari4+,chrome */ background:-webkit-radial-gradient(center, ellipse cover, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* safari5.1+,chrome10+ */ background: -o-radial-gradient(center, ellipse cover, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* opera 11.10+ */ background: -ms-radial-gradient(center, ellipse cover, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* ie10+ */ background:radial-gradient(ellipse at center, rgba(227,71,73,1) 0%, rgba(186,27,31,1) 100%); /* w3c */ filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#e34749', endColorstr='#ba1b1f',GradientType=1 ); /* ie6-9 */ } .header .logo{ font-weight: bold; font-size: 30px; display: block; margin: 10px 0; letter-spacing: 3px; } .header h2{ display: block; font-size: 50px; font-weight: 100; line-height: 10px; } .header h2.small{ font-size: 25px; font-weight: 300; padding-top: 20px; letter-spacing: 1px; } .topics{ text-align: center; padding-top: 50px; } .topics h2.heading{ font-size: 30px; color: #666; font-weight: 400; display: block; } .box{ width: 900px; margin: 40px auto; border: 1px solid #dedede; background: #f2f4f8; position: relative; } .box .usr_container, .box .msg_container{ float: left; height: 600px; overflow-x: hidden; overflow-y: auto; } .box .usr_container{ width: 350px; border-right: 1px solid #dedede; background: #fff; } .box .msg_container{ width: 548px; position: relative; } .box ul{ margin: 0; padding: 0; } .box ul li{ margin: 0; padding: 0; list-style: none; text-align: left; cursor: pointer; } .box .usr_container ul li{ padding: 20px 10px; background: #fff; border-bottom: 1px solid #dedede; } .box .usr_container ul li label{ display: block; width: 100%; font-family: arial; font-weight: 400; color: #333; font-size: 18px; margin-bottom: 5px; } .box .usr_container ul li label:hover{ cursor: pointer; } .box .usr_container ul li span{ color: #777; font-family: arial; font-size: 14px; font-style: italic; } .box .usr_container ul li.selected{ background: #f2f4f8; } .box .usr_container ul li.selected label{ color: #e34749; } .box .usr_container ul li.selected span{ color: #000; } .box .usr_container ul li:hover{ background: #dedede; cursor: pointer; } .box .msg_container ul{ padding: 10px 0; margin-bottom: 75px; } .box .msg_container li{ padding: 10px 0; } .box .msg_container li.others{ cursor: auto; text-align: left; padding-left: 20px; } .box .msg_container li.self{ text-align: right; cursor: auto; padding-right: 20px; } .box .msg_container li.self label{ float: right; } .box .msg_container li .message{ background: #fff; border-radius: 3px; padding: 15px; max-width: 400px; font-size: 15px; font-family: arial; float: left; line-height: 20px; margin: 5px 0 10px 0; } .box .msg_container li label{ float: left; display: block; width: 100%; font-size: 12px; color: #777; font-family: arial; } .box .msg_container li.others .message{ } .box .msg_container li.self .message{ background: #dee2ef; float: right; display: inline-block; } .clear{ clear:both; } .send_container{ border-top: 1px solid #dedede; background: #f7f9fd; position: absolute; bottom: 0; height:75px; right: 0; } .send_container textarea{ background: #f7f9fd; height: 30px; width: 550px; font-size: 15px; text-align: left; padding: 20px; border: none; resize: none; outline: none; } .send_container input[type="button"]{ position: absolute; top: 20px; right: 20px; padding: 10px; background: #e34749; outline: none; border: none; cursor: pointer; color: #fff; font-weight: bold; font-size: 15px; } .btn_send{ padding: 10px; background: #e34749; outline: none; border: none; cursor: pointer; color: #fff; font-weight: bold; font-size: 15px; } .box .msg_container li label.name{ display: block; } div.container{ width: 900px; margin: 0 auto; } select.select_single{ padding: 10px; font-size: 16px; width: 400px; } select.select_single option{ font-size: 19px; } select.select_multiple{ font-size: 15px; width: 400px; height: 200px; } select.select_multiple option{ padding: 5px; } textarea.textarea_msg{ width: 400px; height: 120px; resize: none; margin:20px auto; padding: 15px; background: #f7f9fd; font-size: 15px; } .loader{ display: none; } pre{ width: 800px; text-align: left !important; font-size: 16px; font-family: monospace; margin: 0 auto; line-height: 20px; } .separator{ width: 100%; height: 1px; background: #cdcdcd; margin: 50px 0; }
3. Paste the loader.gif image in the same directory.
4. Create index.php in the root directory. Here I have written necessary php, html and jQuery code to build the admin UI.
<?php error_reporting(-1); ini_set('display_errors', 'On'); ?> <?php require_once __DIR__ . '/demo.php'; $demo = new Demo(); $admin_id = $demo->getDemoUser(); ?> <html> <head> <title>Google Cloud Messaging 3.0 | AndroidHive</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <link href='https://fonts.googleapis.com/css?family=Raleway:400,800,100' rel='stylesheet' type='text/css'> <link href='style.css' rel='stylesheet' type='text/css'> <link href='https://api.androidhive.info/gcm/styles/default.css' rel='stylesheet' type='text/css'> <script type="text/javascript" src="https://code.jquery.com/jquery-2.2.0.min.js"></script> <script type="text/javascript"> var user_id = '<?= $admin_id ?>'; $(document).ready(function () { getChatroomMessages($('#topics li:first').attr('id')); $('ul#topics li').on('click', function () { $('ul#topics li').removeClass('selected'); $(this).addClass('selected'); getChatroomMessages($(this).prop('id')) }); function getChatroomMessages(id) { $.getJSON("v1/chat_rooms/" + id, function (data) { var li = ''; $.each(data.messages, function (i, message) { li += '<li class="others"><label class="name">' + message.user.username + '</label><div class="message">' + message.message + '</div><div class="clear"></div></li>'; }); $('ul#topic_messages').html(li); if (data.messages.length > 0) { scrollToBottom('msg_container_topic'); } }).done(function () { }).fail(function () { alert('Sorry! Unable to fetch topic messages'); }).always(function () { }); // attaching the chatroom id to send button $('#send_to_topic').attr('chat_room', id); } $('#send_to_topic').on('click', function () { var msg = $('#send_to_topic_message').val(); if (msg.trim().length === 0) { alert('Enter a message'); return; } $('#send_to_topic_message').val(''); $('#loader_topic').show(); $.post("v1/chat_rooms/" + $(this).attr('chat_room') + '/message', {user_id: user_id, message: msg}, function (data) { if (data.error === false) { var li = '<li class="self" tabindex="1"><label class="name">' + data.user.name + '</label><div class="message">' + data.message.message + '</div><div class="clear"></div></li>'; $('ul#topic_messages').append(li); scrollToBottom('msg_container_topic'); } else { alert('Sorry! Unable to send message'); } }).done(function () { }).fail(function () { alert('Sorry! Unable to send message'); }).always(function () { $('#loader_topic').hide(); }); }); $('input#send_to_single_user').on('click', function () { var msg = $('#send_to_single').val(); var to = $('.select_single').val(); if (msg.trim().length === 0) { alert('Enter a message'); return; } $('#send_to_single').val(''); $('#loader_single').show(); $.post("v1/users/" + to + '/message', {user_id: user_id, message: msg}, function (data) { if (data.error === false) { $('#loader_single').hide(); alert('Push notification sent successfully! You should see a Toast message on device.'); } else { alert('Sorry! Unable to post message'); } }).done(function () { }).fail(function () { alert('Sorry! Unable to send message'); }).always(function () { $('#loader_single').hide(); }); }); $('input#send_to_multiple_users').on('click', function () { var msg = $('#send_to_multiple').val(); var to = $('.select_multiple').val(); if (to === null) { alert("Please select the users!"); return; } if (msg.trim().length === 0) { alert('Enter a message'); return; } $('#send_to_multiple').val(''); $('#loader_multiple').show(); var selMulti = $.map($(".select_multiple option:selected"), function (el, i) { return $(el).val(); }); to = selMulti.join(","); $.post("v1/users/message", {user_id: user_id, to: to, message: msg}, function (data) { if (data.error === false) { $('#loader_multiple').hide(); alert('Push notification sent successfully to multiple users'); } else { alert('Sorry! Unable to send message'); } }).done(function () { }).fail(function () { alert('Sorry! Unable to send message'); }).always(function () { $('#loader_multiple').hide(); }); }); $('input#send_to_multiple_users_with_image').on('click', function () { var msg = $('#send_to_multiple_with_image').val(); if (msg.trim().length === 0) { alert('Enter a message'); return; } $('#send_to_multiple_with_image').val(''); $('#loader_multiple_with_image').show(); $.post("v1/users/send_to_all", {user_id: user_id, message: msg}, function (data) { if (data.error === false) { $('#loader_multiple_with_image').hide(); alert('Push notification sent successfully to multiple users'); } else { alert('Sorry! Unable to send message'); } }).done(function () { }).fail(function () { alert('Sorry! Unable to send message'); }).always(function () { $('#loader_topic_with_image').hide(); }); }); function scrollToBottom(cls) { $('.' + cls).scrollTop($('.' + cls + ' ul li').last().position().top + $('.' + cls + ' ul li').last().height()); } }); </script> </head> <body> <div class="header"> <label class="logo">ANDROIDHIVE</label> <h2>Google Cloud Messaging</h2> <h2 class="small">Sending push notifications using Android, PHP & MySQL</h2> </div> <div class="container_body"> <div class="topics"> <h2 class="heading">Download & Install the GCM apk</h2> Download & Install the Google Cloud Messaging <a href="#">apk</a> before trying the demos. <br/><br/>Once installed, refresh this page to see your name, email in the recipients list. </div> <div class="topics"> <div class="separator"></div> <h2 class="heading">Sending message to a `topic`</h2> Select any of the topics below and send a message.<br/><br/> <div class="box"> <div class="usr_container"> <ul id="topics"> <?php $chatrooms = $demo->getAllChatRooms(); foreach ($chatrooms as $key => $chatroom) { $cls = $key == 0 ? 'selected' : ''; ?> <li id="<?= $chatroom['chat_room_id'] ?>" class="<?= $cls ?>"> <label><?= $chatroom['name'] ?></label> <span>topic_<?= $chatroom['chat_room_id'] ?></span> </li> <?php } ?> </ul> </div> <div class="msg_container msg_container_topic"> <ul id="topic_messages"></ul> </div> <div class="send_container"> <textarea placeholder="Type a message here" id="send_to_topic_message"></textarea> <input id="send_to_topic" type="button" value="Send to Topic"/> <img src="loader.gif" id="loader_topic" class="loader"/> </div> <div class="clear"></div> </div> <br/> <div class="separator"></div> <h2 class="heading">Sending message to `Single User`</h2> Select your name from the below recipients and send a message<br/><br/> <div class="container"> <select class="select_single"> <?php $users = $demo->getAllUsers(); foreach ($users as $key => $user) { ?> <option value="<?= $user['user_id'] ?>"><?= $user['name'] ?> (<?= $user['email'] ?>)</option> <?php } ?> </select><br/> <textarea id="send_to_single" class="textarea_msg" placeholder="Type a message"></textarea><br/> <input id="send_to_single_user" type="button" value="Send to single user" class="btn_send"/> <img src="loader.gif" id="loader_single" class="loader"/> </div> <br/> <div class="separator"></div> <h2 class="heading">Sending message to `Multiple Users`</h2> Select multiple recipients and send a message. You can use ctrl or shift to select multiple users<br/><br/><br/> <div class="container"> <select multiple class="select_multiple"> <?php foreach ($users as $key => $user) { ?> <option value="<?= $user['user_id'] ?>"><?= $user['name'] ?> (<?= $user['email'] ?>)</option> <?php } ?> </select> <br/> <textarea id="send_to_multiple" class="textarea_msg" placeholder="Type a message"></textarea><br/> <input id="send_to_multiple_users" type="button" value="Send to multiple users" class="btn_send"/> <img src="loader.gif" id="loader_multiple" class="loader"/> </div> <br/> <div class="separator"></div> <h2 class="heading">Sending push notification with an `Image`</h2> A message with an image attachment will be sent to every user. You have to minimize or close the app in order to see it in action.<br/><br/> <div class="container"> <textarea id="send_to_multiple_with_image" class="textarea_msg" placeholder="Type a message"></textarea><br/> <input id="send_to_multiple_users_with_image" type="button" value="Send with image" class="btn_send"/> <img src="loader.gif" id="loader_multiple_with_image" class="loader"/> </div> </div> <br/><br/> <br/><br/> <br/><br/> </div> </body> </html>
5. Finally access the admin panel by going to http://localhost/gcm_chat/ (If your apache is running under a port, add the port number to localhost)
You should able to see the below admin panel which provides options to send the messages to devices from admin panel. Here the Live Demo of the admin app.
With this we have completed 1s part of the article, but before moving to 2nd Part, quickly go through below code snippets which are very useful if you want to extend the server app functionality.
7. Quick Code Snippets
Sending Push To Single User
require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $gcm = new GCM(); $push = new Push(); $data = array(); // user node $data['user'] = $user; // message node $data['message'] = $response['message']; $data['image'] = ''; $push->setTitle("Google Cloud Messaging"); $push->setIsBackground(FALSE); $push->setFlag(PUSH_FLAG_USER); $push->setData($data); // Pass the receiver gcm registration token $gcm_registration_id = 'fnFAQ_BA7pY:APA91bFOwrCw9LHhJKatfvMx-2XA7-NdUMUMF5c9RS0....'; // sending push message to single user $gcm->send($user['gcm_registration_id'], $push->getPush());
Sending Push To Multiple Users
require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $gcm = new GCM(); $push = new Push(); $msg = array(); $msg['message'] = $message; $msg['message_id'] = ''; $msg['chat_room_id'] = ''; $msg['created_at'] = date('Y-m-d G:i:s'); $data = array(); $data['user'] = $user; $data['message'] = $msg; $data['image'] = ''; $push->setTitle("Google Cloud Messaging"); $push->setIsBackground(FALSE); $push->setFlag(PUSH_FLAG_USER); $push->setData($data); // Keep all the recipients gcm tokens in an array $registration_ids = array('fnFAQ_BA7pY:APA91bFOwrCw9LHhJKatfvMx-2XA7-NdUMUMF5c9RS0....', 'fnFAQ_BA7pY:APA91bFOwrCw9LHhJKatfvMx-2XA7-NdUMUMF5c9RS0....'); // sending push message to multiple users $gcm->sendMultiple($registration_ids, $push->getPush());
Sending Push To a Topic
require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $gcm = new GCM(); $push = new Push(); $data = array(); $data['user'] = $user; $data['message'] = $response['message']; $data['chat_room_id'] = $chat_room_id; $push->setTitle("Google Cloud Messaging"); $push->setIsBackground(FALSE); $push->setFlag(PUSH_FLAG_CHATROOM); $push->setData($data); // the topic you want to send notification $topic = 'your_topic_name'; // sending push message to a topic $gcm->sendToTopic($topic, $push->getPush());
Sending Push with an Image
require_once __DIR__ . '/../libs/gcm/gcm.php'; require_once __DIR__ . '/../libs/gcm/push.php'; $gcm = new GCM(); $push = new Push(); // keep the notification image url here $image = 'https://api.androidhive.info/gcm/panda.jpg'; $data = array(); $data['user'] = $user; $data['message'] = $response['message']; $data['image'] = $image; $push->setTitle("Google Cloud Messaging"); $push->setIsBackground(FALSE); $push->setFlag(PUSH_FLAG_USER); $push->setData($data); $gcm_registration_id = 'fnFAQ_BA7pY:APA91bFOwrCw9LHhJKatfvMx-2XA7-NdUMUMF5c9RS0....'; // sending push message to single user $gcm->send($user['gcm_registration_id'], $push->getPush());
By far we have successfully built the proper REST API client and a simple admin panel. Now let’s start building the android app in 2nd Part. If you are facing any issue in this part, please comment in below discussions.
Hi there! I am Founder at androidhive and programming enthusiast. My skills includes Android, iOS, PHP, Ruby on Rails and lot more. If you have any idea that you would want me to develop? Let’s talk: ravi@androidhive.info
Thank you for new tutorial bro..can you post a tutorial with beacons
I guess I need to buy a Beacon right?
yes..any app using beacons..how to detect beacon and etc..
by impleming first part this is what i am getting can you please check what is wrong in it.
http://booksasap.in/gcm_chat ca
Install mysqlnd drivers on your server.
How to do that
?
Its not possible on most of the shared hosting servers. But if you have VPS, you can install on your own.
http://stackoverflow.com/questions/23158943/install-both-mysql-and-mysqlnd-on-ubuntu-12-04
http://stackoverflow.com/questions/13159518/how-to-enable-mysqlnd-for-php
Hi. He could solve the problem? I have the same error.
Your database credentials are wrong. Keep correct username, password, database name.
hello
how can we send as push msg with GCM for free?
Hi Oussama, GCM is already free.
Hi Ravi!
I don’t want to use local development environment (MAMP) instead I want to use Hostgator. Should I follow the exact steps or there are something different need to be done?
Yeah you can. But make sure that hostgator is supporting musqlnd. Just download the code, upload it to hostgator and verify.
what if it does not ?
Master Piece.. great you have illustrated it in it’s easiest level..!
Yeah I spent lot time writing it.
nice tutorial…
Oh my god….This Tutorial is great!I almost certainly love u!
Thank You.
Thansk again Ravi, your tutorials are very self explanatory. Am always greatful.
You are welcome:)
thanks for your great tutorials
Hello Ravi,
I setup and install api. Thank you the tutorial.
But I have one problem. If I write the messages I don’t see the phone real time… If I open the room i can see after loading the room. What do I do wrong? Thank you your answers.
After login check whether gcm registration token is printing in LogCat or not.
I did everything as explained but i am getting error 404 Page Not Found.. I have enabled apache rewrite mod and curl extension. index.php is working fine but when i am adding localhost/gcm_chat/v1 its show page not found. I am using xampp.. Please guide.. Thanks
localhost/gcm_chat/v1 always gives 404. You need to access the final endpoint with the correct http method
localhost/gcm_chat/v1/user/login with POST method.
replace ‘localhost’ to your IPAdress. For example
public static final String BASE_URL = “http://192.168.82.10/gcm_chat/v1”;
use url /gcm_chat/v1/index.php/user/login and it will work
Hi Ravi. tks for awesome tut. But I have an error: when I test rest api by postman , I input name and email, the server always respone :{
“error”: true,
“message”: “Oops! An error occurred while registereing”
}
I have the same problem 🙁
Make sure you have created the mysql tables correctly and gave the correct database credentials in config file.
thank for your reply, I fixed it by coppy all code MySQL from folder db (downloaded) without copy code from web.
Okay. Let me check the website SQL code again. Thanks.
SQL codes from this page does not include adding auto_increment in user_id.
That’s why people can not make a new user because there is always 0 in user_id (primary key, unique as default).
so how can we fix this?
I am getting the same error. Can you explain, how did you fix it?
I have still the same issue, even though I’ve try the solution provided here 🙁 any ideas?
hi Ravi
i get error
Volley error:null
i use locall sever(wamp)
hello…. how can i delete the chat msgs ..like we do in whatsapp…. & to include touch & select feature for msgs for forwarding it
& how to change the notification ringtone
Awesome tutorial. Working perfect 🙂
Cheers!
Hi Ravi
I use http: //localhost/gcm_chat/push_test.php
when pressed send push notification messages are then sorry! unable to send message.
I am getting an error please help. Thanks
Fatal error: Call to a member function bind_param() on a non-object in /home/wawawebfep/www/gcm_chat/demo.php on line 42
Hi!! Thanks a lot for this tut!!
i am getting this erro:
~
Type: ErrorException
Code: 8
Message: Use of undefined constant PUSH_FLAG_CHATROOM – assumed ‘PUSH_FLAG_CHATROOM’
File: C:xampphtdocslocalhosthivegcm_chatv1index.php
Line: 106
Trace
#0 C:xampphtdocslocalhosthivegcm_chatv1index.php(106): SlimSlim::handleErrors(8, ‘Use of undefine…’, ‘C:xampphtdocs…’, 106, Array)
#1 [internal function]: {closure}(‘2’)
#2 C:xampphtdocslocalhosthivegcm_chatlibsSlimRoute.php(436): call_user_func_array(Object(Closure), Array)
#3 C:xampphtdocslocalhosthivegcm_chatlibsSlimSlim.php(1307): SlimRoute->dispatch()
#4 C:xampphtdocslocalhosthivegcm_chatlibsSlimMiddlewareFlash.php(85): SlimSlim->call()
#5 C:xampphtdocslocalhosthivegcm_chatlibsSlimMiddlewareMethodOverride.php(92): SlimMiddlewareFlash->call()
#6 C:xampphtdocslocalhosthivegcm_chatlibsSlimMiddlewarePrettyExceptions.php(67): SlimMiddlewareMethodOverride->call()
#7 C:xampphtdocslocalhosthivegcm_chatlibsSlimSlim.php(1254): SlimMiddlewarePrettyExceptions->call()
#8 C:xampphtdocslocalhosthivegcm_chatv1index.php(453): SlimSlim->run()
#9 {main}
I just solve… it was my mistake…
Thankssss
OK
Hi Ravi, this tutorial is incredible. Thank you for your effort in writing it!
I was testing my REST API with Postman like in your video and everything works fine except for the PUT request.
I made sure to type in the parameter name very carefully “gcm_registration_id” but it refuses to work and I keep getting this message:
“error”: true,
“message”: “Required field(s) gcm_registration_id is missing or empty”
Do you know why this might be happening?
Yeah, in Postman for PUT request choose x-www-form-urlencoded instead of form-data (see there is a radio button)
You are THE MAN! Thank you 🙂
You are welcome 🙂
Hi ravi I have an error
Fatal error: Call to undefined method mysqli_stmt::get_result() in /localhost/www/gcm_chat/include/db_handler.php on line 164
json parsing error: <br of type java.lang.String cannot be converted to JSONObject
seconded.
I fixed this by installing mysqlnd:
sudo apt-get install php5-mysqlnd
sudo service apache2 restart
how to install it?
Hi Ravi, How can I get the gcm_registration_id I am new to Android can you please Elobarate
Check the part 2 of the article. You can see that I logged the gcm token in Main Activity.
Thanks Ravi,
Okay where I can place Project Number (or) sender Id in this..
We don’t use project number or sender id anymore like we did for older GCM. Instead we add google-services.json file where all these things will be configured. Check part 2 of this article.
Thanks,
Now I got voelly error
Log cat is
params: {email=mymailid@gmail.com, name=Mahesh}
02-21 12:15:24.497 19582-19963/info.androidhive.gcm E/Volley﹕ [162] BasicNetwork.performRequest: Unexpected response code 500 for http://192.168.1.3/cloud_chat/v1/user/login
02-21 12:15:24.513 19582-19582/info.androidhive.gcm E/LoginActivity﹕ Volley error: null, code: com.android.volley.NetworkResponse@4111964
02-21 12:15:24.667 19582-19611/info.androidhive.gcm W/EGL_emulation﹕ eglSurfaceAttrib not implemented
Can you please how can I login into app
public void addToRequestQueue(Request req) {
req.setTag(TAG);
getRequestQueue().add(req);
} and I debug the param req = I
[ ] http://192.168.1.3/cloud_chat/v1/user/login 0x355f917 NORMAL null… What I can get instead of 0x355f917
Thanks for the long awaited tutorial.
I want to implement this in a web app not an android app. Pls what will be the next step after this first part of the tutorial, Since I probably don’t need the second and third part.
Hi Ravi,
When I clicked on login button I got the following errors,
What will be the reason???
02-17 01:16:32.970 12507-12507/info.androidhive.googlecloudmessagingexample E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
02-17 01:16:32.970 12507-12507/info.androidhive.googlecloudmessagingexample E/SpannableStringBuilder: SPAN_EXCLUSIVE_EXCLUSIVE spans cannot have a zero length
02-17 01:16:47.441 12507-12821/info.androidhive.googlecloudmessagingexample E/LoginActivity: params: {email=lagadpankaj@gmail.com, name=Pankaj Lagad}
02-17 01:16:47.480 12507-12821/info.androidhive.googlecloudmessagingexample E/Volley: [1260] BasicNetwork.performRequest: Unexpected response code 403 for http://192.168.42.125:80/gcm_chat/v1/user/login
02-17 01:16:47.481 12507-12821/info.androidhive.googlecloudmessagingexample E/LoginActivity: params: {email=lagadpankaj@gmail.com, name=Pankaj Lagad}
02-17 01:16:47.495 12507-12821/info.androidhive.googlecloudmessagingexample E/Volley: [1260] BasicNetwork.performRequest: Unexpected response code 403 for http://192.168.42.125:80/gcm_chat/v1/user/login
02-17 01:16:47.502 12507-12507/info.androidhive.googlecloudmessagingexample E/LoginActivity: Volley error: null, code: com.android.volley.NetworkResponse@42d8b0f0
Hey Ravi,
Your demo at http://demo.androidhive.info/gcm_chat/ has been hacked. Displays porn now… Might want to fix that. This is why we can’t have nice things.
I’m hitting a 404 and am out of ideas. I have ensured that mod_rewrite and curl are enabled. My site can be hit at gcm_chat/ (although i get “Sorry! Unable to fetch topic messages”). When I use postman to GET http://ec2-XX-XXX-XXX-XXX.compute-1.amazonaws.com/gcm_chat/v1/chat_rooms I get
404 Not Found
Not Found
The requested URL /gcm_chat/v1/chat_rooms was not found on this server.
Apache/2.4.7 (Ubuntu) Server at ec2-XX-XXX-XXX-XXX.compute-1.amazonaws.com Port 80
I have tried changing permissions of my virtual host… My full dir to the project is /var/www/html/gcm_chat. I am using a default install of apache2. I haven’t been able to observe any php errors.
Help?
use url /gcm_chat/v1/index.php/user/login and it will work
hey ravi i used hostinger to host the server side and i made sure it has mysqlnd enabled but i still get Call to undefined method mysqli_stmt::get_result() ? any ideas?
Hi ravi I got the following errors,
//when sent the message from our device to chat room(Material Design)
02-20 14:02:04.216 26053-26053/? E/ChatRoomActivity: endpoint: http://192.168.42.102/gcm_chat/v1/chat_rooms/1/message
02-20 14:02:04.261 682-682/? E/RemoteViews: ANR Warning,RemoteViews can only be used once ,if not ,it may cause ANR in hosts such as Laucher,SystemUI. keys for search
02-20 14:02:04.264 26053-26287/? E/ChatRoomActivity: Params: {message=haha, user_id=20}
02-20 14:02:04.266 682-682/? E/RemoteViews: ANR Warning,RemoteViews can only be used once ,if not ,it may cause ANR in hosts such as Laucher,SystemUI. keys for search
02-20 14:02:04.333 26053-26053/? E/ChatRoomActivity: response: {“error”:true,”message”:”Failed send message”}
whats going wrong… I also can’t sent the massage to single user
reply soon..
thank you, you does a great job
You are welcome. Follow the other two parts too.
brother Ravi Tamada
thanks aloot
i need your help to upload php files to 00webhost….
waiting you brother
Hi Yaqoub
This app won’t work on 000webhost because of the limitations. 000webhost won’t support mysqlnd.
thank you Ravi
is there any way to use web server ?
Please try to host the services on to 000webhost. Once done you can see the errors in the log when accessing the urls. Then I can tell you what to do exactly.
now i face this :-
Fatal error: Call to undefined method mysqli_stmt::get_result() in /home/a1657826/public_html/gcm3/demo.php on line 24
Your webhosting is not supporting mysqlnd. You have to convert all the mysqli statements to PDO.
thanks Ravi
I have no idea in php…
Instead of get_result(), you could use this method :
function get_result( $Statement ) {
$RESULT = array();
$Statement->store_result();
for ( $i = 0; $i num_rows; $i++ ) {
$Metadata = $Statement->result_metadata();
$PARAMS = array();
while ( $Field = $Metadata->fetch_field() ) {
$PARAMS[] = &$RESULT[ $i ][ $Field->name ];
}
call_user_func_array( array( $Statement, ‘bind_result’ ), $PARAMS );
$Statement->fetch();
}
return $RESULT;
}
And to process the result, instead of $result->fetch_assoc()
use – array_shift( $RESULT )
thanks Alankrita
i did what you said but i get this
Warning: Invalid argument supplied for foreach() in /home/a1657826/public_html/gcm3/index.php on line 212
could i contact by your email??
You have to edit three files : demo.php, v1/index.php and db_handler.php
In demo.php :
public function getAllChatRooms() {
$stmt = $this->conn->prepare(“SELECT * FROM chat_rooms”);
$stmt->execute();
//$stmt->store_result();
$RESULT = get_result( $stmt );
$stmt->close();
return $RESULT;
}
public function getAllUsers() {
$stmt = $this->conn->prepare(“SELECT * FROM users”);
$stmt->execute();
$RESULT = get_result( $stmt );
//$tasks = $stmt->fetch();
$stmt->close();
return $RESULT;
}
In db_handler.php
// fetching all chat rooms
public function getAllChatrooms() {
$stmt = $this->conn->prepare(“SELECT * FROM chat_rooms”);
$stmt->execute();
// $tasks = $stmt->get_result();
$tasks = get_result( $stmt );
$stmt->close();
return $tasks;
}
// fetching single chat room by id
function getChatRoom($chat_room_id) {
$stmt = $this->conn->prepare(“SELECT cr.chat_room_id, cr.name, cr.created_at as chat_room_created_at, u.name as username, c.* FROM chat_rooms cr LEFT JOIN messages c ON c.chat_room_id = cr.chat_room_id LEFT JOIN users u ON u.user_id = c.user_id WHERE cr.chat_room_id = ?”);
$stmt->bind_param(“i”, $chat_room_id);
$stmt->execute();
// $tasks = $stmt->get_result();
$tasks = get_result( $stmt );
$stmt->close();
return $tasks;
}
// fetching multiple users by ids
public function getUsers($user_ids) {
$users = array();
if (sizeof($user_ids) > 0) {
$query = “SELECT user_id, name, email, gcm_registration_id, created_at FROM users WHERE user_id IN (“;
foreach ($user_ids as $user_id) {
$query .= $user_id . ‘,’;
}
$query = substr($query, 0, strlen($query) – 1);
$query .= ‘)’;
$stmt = $this->conn->prepare($query);
$stmt->execute();
// $result = $stmt->get_result();
$result = get_result( $stmt );
while ($user = array_shift( $result )) {
$tmp = array();
$tmp[“user_id”] = $user[‘user_id’];
$tmp[“name”] = $user[‘name’];
$tmp[“email”] = $user[’email’];
$tmp[“gcm_registration_id”] = $user[‘gcm_registration_id’];
$tmp[“created_at”] = $user[‘created_at’];
array_push($users, $tmp);
}
}
return $users;
}
In v1/index.php
/* * *
* fetching all chat rooms
*/
$app->get(‘/chat_rooms’, function() {
$response = array();
$db = new DbHandler();
// fetching all user tasks
$result = $db->getAllChatrooms();
$response[“error”] = false;
$response[“chat_rooms”] = array();
// pushing single chat room into array
while ($chat_room = array_shift( $result )) {
$tmp = array();
$tmp[“chat_room_id”] = $chat_room[“chat_room_id”];
$tmp[“name”] = $chat_room[“name”];
$tmp[“created_at”] = $chat_room[“created_at”];
array_push($response[“chat_rooms”], $tmp);
}
echoRespnse(200, $response);
});
/**
* Fetching single chat room including all the chat messages
* */
$app->get(‘/chat_rooms/:id’, function($chat_room_id) {
global $app;
$db = new DbHandler();
$result = $db->getChatRoom($chat_room_id);
$response[“error”] = false;
$response[“messages”] = array();
$response[‘chat_room’] = array();
$i = 0;
// looping through result and preparing tasks array
while ($chat_room = array_shift( $result )) {
// adding chat room node
if ($i == 0) {
$tmp = array();
$tmp[“chat_room_id”] = $chat_room[“chat_room_id”];
$tmp[“name”] = $chat_room[“name”];
$tmp[“created_at”] = $chat_room[“chat_room_created_at”];
$response[‘chat_room’] = $tmp;
}
if ($chat_room[‘user_id’] != NULL) {
// message node
$cmt = array();
$cmt[“message”] = $chat_room[“message”];
$cmt[“message_id”] = $chat_room[“message_id”];
$cmt[“created_at”] = $chat_room[“created_at”];
// user node
$user = array();
$user[‘user_id’] = $chat_room[‘user_id’];
$user[‘username’] = $chat_room[‘username’];
$cmt[‘user’] = $user;
array_push($response[“messages”], $cmt);
}
}
echoRespnse(200, $response);
});
I can not understand this , you can help me what are the changes in demo.php file
which mysqli statements should i convert to PDO?
Have you tried digitalocean to host the services.
http://www.androidhive.info/2015/03/android-hosting-php-mysql-restful-services-to-digitalocean/
Hi Ravi,
Chinese mobile phones don’t support google play. What else do you recommend except GCM?
Hi Brook
I haven’t used any of the services for china. Have look at the below answer.
http://stackoverflow.com/questions/17825121/android-push-notifications-in-china
Hi Ravi,
What Sofware did you use to model your database tables?It really looks presentable.
It’s photoshop.
Hi Ravi,
There is some issue in Live Demo link, please have a look.
http://demo.androidhive.info/gcm_chat/
Hi Sandeep
What is the issue?. If you are getting some random alert messages, HACKERS … playing with the site. I’ll upload a fresh copy now.
it is showing some alert messages and a porn image in background.
Shit.. 🙁 Is it ok now? I guess It should be resolved.
Why not get msg notification when use vmware android image? But on Android Studio works fine, if I use 2 devices on Android Studio then I get only on first device msg notification… can you explain me why?
maybe google play services are not installed
Yes, it is resolved now. Thanks.
Okay.
hey thanks but the api can work for me getting 404
come on please still getting 404 error after adding ../v1/index.php/user/login
Use postman or not?
yeah but i wanna use it on my browser it working so well with postman
Ravi says “localhost/gcm_chat/v1 always gives 404. You need to access the final endpoint with the correct http method”
Browser can make http call only.
Hi Tavi Please i noticed you always use Slim version 2.3.5 I hope its safe to use it also considering that slim is now in version 3.2.1 ? please let me know because i need to built a RESTFUL app and i need to use Version 2.3.5 just like you. How is Srinivas Its been a while…
I need to check the latest Slim and verify the code once as there might be lot of function deprecated. Thanks for letting me know.
Ok Ravi please check so i would know which way to go because i notice that to instantiate the slim is now $app = new SlimApp(); instead of $app = new SlimSlim(); in version 2.3.5 So Please Ravi Cross check so that we can know if its safe to continue with the old one or the new one.
are this source codes implement xmpp conncetion ? (for upstream purpose also ? ) i want to build app which sends data from android app to chrome extension is this possible by making some changes in this codes ?
hi ravi your tutorials are really helpful.i dont know how to code but with your code i made one good app. can u provide the codes for app invites via facebook,whatsapp etc would be very helpful for me i am struggling with it
Ravi..thanks for this tutorial. I am having an error if I type localhost/gcm_chat.. Warning: require_once(../include/db_handler.php): failed to open stream: No such file or directory in /var/www/html/gcm_chat/index.php on line 6
Fatal error: require_once(): Failed opening required ‘../include/db_handler.php’ (include_path=’.:/usr/share/php:/usr/share/pear’) in /var/www/html/gcm_chat/index.php on line 6. I am using LAMP on ubuntu. Any take?
I have seen my error and have corrected the mistake..I mistakently thought v1/index.php is the same as index.php in the folder
Thank you for this work! 🙂
I’m trying to start app on Debian8 server, but web page don’t show me messages (Sorry! Unable to fetch topic messages), while the rest shows. Can you attach php modules that which are necessary for operation of the application?
I’m facing the same problem ” Unable to fech topic messages ” and I’m using Ubuntu. Could you tell me please if you resolved the issue ?
Hi Ravi, awesome tutorial, im still on this 1st part because when i’m trying to test it on postman the only thing that doesnt seem to be working properly is when i try to register a new user and i’ve make sure that i have the right credentials for the db, also i notice in the video when you first create the db theres a user already, it didnt happen with mine, any ideas?
I have solve the issue now but I dont know if this is going to affect the project works later on, what i did is modify on db_handler.php on line 28 to the following:
$stmt = $this->conn->prepare(” INSERT INTO users (name, email, gcm_registration_id,created_at) values(?, ?,”,CURRENT_TIMESTAMP)”);
let me know if that is going to give me an error, even thoug gcm_registration_id is going to be updated i assume
How Did you solve your error? Please?
I get this error while using this tutorial
404 Not Found
Not Found
The requested URL /gcm_chat/v1/user/login was not found on this server.
Apache/2.4.7 (Ubuntu) Server at localhost Port 80
Hi Ravi, Thanks for the Great tutorial.
I need a little help regarding ‘demo.php’ file.
I am getting an error :
Fatal error: Call to undefined method mysqli_stmt::get_result() in /home/a7612275/public_html/chattesting/demo.php on line 18.
Can u please help me with it ?
you have to setup mysqlnd on your server
how do i setup mysqlnd driver on live server. I am using hostinger??
Dear
If you are using Go daddy Hosting service,Than Follow this steps:
Goto Control Panel > Software > Select PHP Version
Select Version 5 >
1. Uncheck mysqli
2. Check mark nd_mysqli
This helped me man.. 🙂
after adding 1 message , i get this error trying to add another message from same user
{
“error”: true,
“message”: “Failed send message Duplicate entry ‘0’ for key ‘PRIMARY'”
}
just make all of the ID of database Primer key Auto Increment
Thanks mohamed , that’s just what i did to solve it , but note that u can’t do that to the chat_rooms table primary key (chat_room_id) nor the users table (user_id) since they are both used in foreign key constraint with the messages table
Delete all the users chatroom and the message after that make the id of each table auto increment and creat Again the chatroom and it wel be ok
can you help me please? iam facing problem
Have a way around “oops error while registering?”
Hai Ravi,
I implemented as you said above all working good . . .
but i received the notification from who all r installing your application.i have to stop it,can you help me to do this . . .
i have changed my own API key but still i received notification from all.
Thank You 🙂
Hi Ravi thanku for the tutorial , I am getting some issue while connecting to MY SQL kindly help me out,
Error is as follows:
Warning: mysqli::mysqli(): (HY000/1045): Access denied for user ‘gcm’@’localhost’ (using password: YES) in C:xampphtdocsgcm_chatincludedb_connect.php on line 24
Failed to connect to MySQL: Access denied for user ‘gcm’@’localhost’ (using password: YES)
Warning: mysqli::prepare(): Couldn’t fetch mysqli in C:xampphtdocsgcm_chatdemo.php on line 41
Fatal error: Call to a member function bind_param() on null in C:xampphtdocsgcm_chatdemo.php on line 42
hi! your database name and password is not same i think. check againg. you have to control database to php way
check the password in your config file for the db connection. then the problem solved!!
hey ravi! thanks for everything this tutorial is my best. gread and educational. i have there is question. yesterday work is great but today i have error: sorry ! unable to send message.what is that ? thank for help.
hi guys! i am working on this tutorial. i have error : sorry unable to send mesagge. but my first mesagge work perfectly bur secont mesagge i have error. why it say error i dont understand please help me. i am working only web.
please help me!. my first sending message is work perfectly but secont sending is not working. i have error sorry unable to send mesagge!!
Guys!!!!
Please recommend me IDE for PHP which is FREE and actually SUPPORTS code completition…
I have tried NET beans and Eclipse but they don’t. I only managed to use visual studio with php tools but it’s a trial….
Use NetBeans
Thanks for quick answear but it does not complite my code… Like I said only php tools for VS done the job right. Eclipse and NetBeans works fine with java code but I have non suggestions when for example typing ‘db_handler.php’ and trying to close db connection… http://imgur.com/s40MkZZ
It is not working properly…
http://imgur.com/a/uILgU
Here is example: http://imgur.com/s40MkZZ
hi there! i am working in this case but i have an error. i sent firt message perfectly but i again sent later web page says: sorry unable yo send message. what is that ?
me2 i face the same problem