Android Push Notifications using Firebase Cloud Messaging (FCM), PHP and MySQL

Sending Push Notification By PHP

Creating MySQL Database

1. Open phpmyadmin panel by going to http://localhost/phpmyadmin and create a database called fcm. (if your localhost is running on port number add port number to url)
2. After creating the database, select the database and execute following query in SQL tab to create users table.

CREATE TABLE IF NOT EXISTS `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`fcm_registered_id` text,
`name` varchar(50) NOT NULL,
`email` varchar(255) NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Check the following video to know about creating database and php project.

Creating & Running the PHP Project

When we are making request to FCM server using PHP i used curl to make post request. Before creating php project enable curl module in your php extensions.
Left Click on the WAMP icon the system try -> PHP -> PHP Extensions -> Enable php_curl
1. Goto your WAMP folder and inside www folder create a folder called fcm_server. (In my case i installed wamp in D:\WAMP)
2. Create a file called config.php

<?php
$username = "root";
$password = "root";
$host = "localhost";
$dbname = "fcm";
$options = array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8');
try
{
$db = new PDO("mysql:host={$host};dbname={$dbname};charset=utf8", $username, $password, $options);
}
catch(PDOException $ex)
{
die("Failed to connect to the database: " . $ex->getMessage());
}
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
if(function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc())
{
function undo_magic_quotes_gpc(&$array)
{
foreach($array as &$value)
{
if(is_array($value))
{
undo_magic_quotes_gpc($value);
}
else
{
$value = stripslashes($value);
}
}
}
undo_magic_quotes_gpc($_POST);
undo_magic_quotes_gpc($_GET);
undo_magic_quotes_gpc($_COOKIE);
}
header('Content-Type: text/html; charset=utf-8');
session_start();
?>

3. Now create registration file register.php

<?php
require("config.inc.php");
if (!empty($_POST)) {
   $response = array("error" => FALSE);
    $query = " SELECT * FROM users WHERE email = :email";
    //now lets update what :user should be
    $query_params = array(
        ':email' => $_POST['email']
    );
    try {
        $stmt   = $db->prepare($query);
        $result = $stmt->execute($query_params);
    }
    catch (PDOException $ex) {
        $response["error"] = TRUE;
        $response["error_msg"] = "Database Error1. Please Try Again!";
        die(json_encode($response));
    }
    $row = $stmt->fetch();
    if ($row) {
      $response["error"] = TRUE;
        $response["error_msg"] = "I'm sorry, this email is already in use";
        die(json_encode($response));
   } else {
      $query = "INSERT INTO users ( name, email, fcm_registered_id, created_at ) VALUES ( :name, :email, :fcm_id, NOW() ) ";
      $query_params = array(
         ':name' => $_POST['name'],
         ':email' => $_POST['email'],
         ':fcm_id' => $_POST['fcm_id']
      );
      try {
         $stmt   = $db->prepare($query);
         $result = $stmt->execute($query_params);
      }
      catch (PDOException $ex) {
         $response["error"] = TRUE;
         $response["error_msg"] = "Database Error2. Please Try Again!";
         die(json_encode($response));
      }
      $response["error"] = FALSE;
      $response["error_msg"] = "Register successful!";
      echo json_encode($response);
   }
} else {
?>
   <h1>Register</h1>
   <form action="register.php" method="post">
       name:<br />
       <input type="text" name="name" value="" />
       <br /><br />
      email:<br />
       <input type="text" name="email" value="" />
       <br /><br />
      fcm_id:<br />
       <input type="text" name="fcm_id" value="" />
       <br /><br />
       <input type="submit" value="Register" />
   </form>
   <?php
}
?>

4. Create another file called admin.php

<?php
require("config.inc.php");
$query = "SELECT * FROM users";
$stmt = $db->query($query);
$target_path = 'uploads/';
if (!empty($_POST)) {
    $response = array("error" => FALSE);
    function send_gcm_notify($reg_id, $message, $img_url, $tag) {
        define("GOOGLE_API_KEY", "AIzaSyBsGSPuDKtN5KNmxK1zSqonaMMHUmAfeFQ");
        define("GOOGLE_GCM_URL", "https://fcm.googleapis.com/fcm/send");
        $fields = array(
            'to'                  => $reg_id ,
            'priority'             => "high",
            'data'                => array("title" => "Android Learning", "message" => $message, "image"=> $img_url, "tag" => $tag)
        );
        $headers = array(
            GOOGLE_GCM_URL,
            'Content-Type: application/json',
            'Authorization: key=' . GOOGLE_API_KEY
        );
        echo "<br>";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, GOOGLE_GCM_URL);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
        $result = curl_exec($ch);
        if ($result === FALSE) {
            die('Problem occurred: ' . curl_error($ch));
        }
        curl_close($ch);
        echo $result;
    }
    $reg_id = $_POST['fcm_id'];
    $msg = $_POST['msg'];
    $img_url = '';
    $tag = 'text';
    if ($_FILES['image']['name'] != '') {
        $tag = 'image';
        $target_file = $target_path . basename($_FILES['image']['name']);
        $img_url = 'http://192.168.225.83:8080/fcm_server/'.$target_file;
        try {
            // Throws exception incase file is not being moved
            if (!move_uploaded_file($_FILES['image']['tmp_name'], $target_file)) {
                // make error flag true
                echo json_encode(array('status'=>'fail', 'message'=>'could not move file'));
            }
            // File successfully uploaded
            echo json_encode(array('status'=>'success', 'message'=> $img_url));
        } catch (Exception $e) {
            // Exception occurred. Make error flag true
            echo json_encode(array('status'=>'fail', 'message'=>$e->getMessage()));
        }
        send_gcm_notify($reg_id, $msg, $img_url, $tag);
    } else {
        send_gcm_notify($reg_id, $msg, $img_url, $tag);
    }
}
?>
<!Doctype html>
<html>
<head>
    <meta charset="utf-8">
    <!--Import Google Icon Font-->
    <link href="http://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
    <!--Import materialize.css-->
    <link type="text/css" rel="stylesheet" href="../script/css/materialize.min.css"  media="screen,projection"/>
    <!--Let browser know website is optimized for mobile-->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <title>Admin | FCM Server</title>
    <style>body, .row{ text-align: center;}</style>
    <script>
        $(function(){
            $("textarea").val("");
        });
        function checkTextAreaLen(){
            var msgLength = $.trim($("textarea").val()).length;
            if(msgLength == 0){
                alert("Please enter message before hitting submit button");
                return false;
            }else{
                return true;
            }
        }
    </script>
</head>
<body>
<h1>Admin Panel</h1>
<div class="row">
    <div class="col s12 m12 l2"><p></p></div>
    <form class="col s12 m12 l8" action="admin.php" method="post" enctype="multipart/form-data" onsubmit="return checkTextAreaLen()">
        <div class="row">
            <div class="input-field col s12">
                <select name="fcm_id" required>
                    <option value="" disabled selected>Select User</option>
                    <?php while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
                        echo "<option value='".$row['fcm_registered_id']."'>".$row['name']." &lt;".$row['email']."&gt;</option>";
                    } ?>
                </select><br><br>
                <div class="file-field input-field">
                    <div class="btn">
                        <span>File</span>
                        <input type="file" name="image">
                    </div>
                    <div class="file-path-wrapper">
                        <input class="file-path validate" type="text">
                    </div>
                </div>
                <textarea id="msg" name="msg" class="materialize-textarea" placeholder="Type your message"></textarea>
                <br><br>
                <button class="btn waves-effect waves-light" type="submit" name="action">Send</button>
            </div>
        </div>
    </form>
    <div class="col s12 m12 l2"><p></p></div>
</div>
<!--Import jQuery before materialize.js-->
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script type="text/javascript" src="../script/js/materialize.min.js"></script>
<script>
    $('select').material_select();
</script>
</body>
</html>

5. Now update your MyFirebaseMessagingService.java file :-

package akraj.snow.fcm;

import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.NotificationCompat;

import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by Akshay Raj on on 1/17/2019.
 * [email protected]
 * www.snowcorp.org
 */

public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private static final String TAG = "MyFirebaseMsgService";
    NotificationCompat.Builder notificationBuilder;
    Bitmap image;
    /**
     * Called when message is received.
     *
     * @param remoteMessage Object representing the message received from Firebase Cloud Messaging.
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(RemoteMessage remoteMessage) {
        // TODO(developer): Handle FCM messages here.
        // If the application is in the foreground handle both data and notification messages here.
        // Also if you intend on generating your own notifications as a result of a received FCM
        // message, here is where that should be initiated. See sendNotification method below.
        String tag = remoteMessage.getData().get("tag");
        String msg = remoteMessage.getData().get("message");
        String img = remoteMessage.getData().get("image");
        image = getBitmapFromURL(img);
        sendNotification(tag, msg, image);
    }
    // [END receive_message]



    /**
     * Create and show a simple notification containing the received FCM message.
     *
     * @param messageBody FCM message body received.
     */
    private void sendNotification(String tag, String messageBody, Bitmap img) {
        Intent intent = new Intent(this, HomeActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                PendingIntent.FLAG_ONE_SHOT);
        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);

        String channelID = getString(R.string.channel_id);

        if (tag.equalsIgnoreCase("image")) {
            notificationBuilder = new NotificationCompat.Builder(this, channelID)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle("Android Learning")
                    .setContentText(messageBody)
                    .setStyle(new NotificationCompat.BigPictureStyle()
                            .bigPicture(img))
                    .setAutoCancel(true)
                    .setSound(defaultSoundUri)
                    .setContentIntent(pendingIntent);
        } else {
            notificationBuilder = new NotificationCompat.Builder(this, channelID)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle("Android Learning")
                    .setContentText(messageBody)
                    .setAutoCancel(true)
                    .setSound(defaultSoundUri)
                    .setContentIntent(pendingIntent);
        }
        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

        // Since android Oreo notification channel is needed.
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(channelID,
                    "Channel human readable title",
                    NotificationManager.IMPORTANCE_DEFAULT);
            notificationManager.createNotificationChannel(channel);
        }

        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    }

    private static Bitmap getBitmapFromURL(String src) {
        try {
            URL url = new URL(src);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.connect();
            InputStream input = connection.getInputStream();
            Bitmap myBitmap = BitmapFactory.decodeStream(input);
            return myBitmap;
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
}

6. Now run your app
FCM
FCM
FCM

Source Code Download

About the author

Akshay Raj

View all posts

162 Comments