Envoyer des notifications avec Google Cloud Messaging ( GCM )

CODE SOURCE

Bonjour les amis, aujourd’hui nous allons apprendre comment faire pour envoyer des notifications pushs à nos utilisateurs grâce au GCM, d’abord :

Qu’est-ce que le GCM ?

Google Cloud Messaging (GCM) est un service gratuit qui aide les développeurs à envoyer des messages à partir de différentes plate-formes : Android, iOS et Chrome, bien évidement dans notre cas nous nous intéresserons à Android 😀

Pourquoi cela vaut le coup ?

  • Ne pas se fatiguer à faire son propre système de notifications, et surtout ménager notre serveur.
  • Vous pouvez notifier d’un coup 1000 utilisateurs en une seule requête.
  • Vous pouvez créer une application de chat…etc.
  • Inciter les utilisateurs a revenir sur votre application.

Qu’est-ce qu’on va faire exactement ?

Bref on va commencer d’abord par aller dans la console de Google et de créer un nouveau projet, par exemple dans notre cas nous mettrons comme nom androidpourtous.

image3004
Puis quand la création du projet se termine, nous allons nous rendre sur Google Developers.

Dans App name vous choisissez le projet que nous avons créé, c’est à dire androidpourtous, et pour Android package name vous mettez “com.androidpourtous.gcm”, puis vous cliquer sur le bouton bleu.

image3021

Ici vous aller sélectionner Cloud Messaging et cliquer sur ENABLE GOOGLE CLOUD MESSAGING

rzezr

Et bien sûr vous cliquer sur Generate configuration files.

mage3055

Normalement à cette étape vous devriez avoir cela, c’est à dire la Server API key et Sender ID que je vous conseille de garder bien chaudement chez vous 😀

image3072

Maintenant nous allons nous occupé de notre application côté serveur, le but de l’application c’est d’enregistrer le token ( vous verrez plus tard ) utilisateur dans notre DB, mais aussi faire des requêtes vers le serveur de gcm de google pour notifier tous les utilisateur enregistrés chez nous.

    1. D’abord commencer par ouvrir PhpMyAdmin et créer une database sous le nom de androidpourtous.
    2. Puis exécuter cette requête SQL
CREATE TABLE IF NOT EXISTS `gcm_ids` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`gcm_token` text NOT NULL,
`date_creation` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;

Coté serveur ( PHP )

    1. Dans le dossier WWW, créer un dossier sous le nom gcm.
    2. Créer un fichier db_config.php et n’oubliez pas de mettre votre API KEY
      db_config.php
      
      /**
       * Configuration pour votre DB
       */
      define("DB_HOST", "localhost");
      define("DB_USER", "root");
      define("DB_PASSWORD", "");
      define("DB_DATABASE", "androidpourtous");
      
      /*
       * Votre API KEY ici
       */
      define("GOOGLE_API_KEY", "AIzaSyBR0OD8oNc5EroehGxnItAOorKTq5cpcyY");
      ?>
    3. On créer un fichier qui va s’occuper de la connexion vers la DB, nommez le db_connect.php
      db_connect.php
      
      class DB_Connect {
      
       public function connect() {
       require_once 'config.php';
       // Connexion à MySQL
      
       $con = new mysqli(DB_HOST, DB_USER, DB_PASSWORD, DB_DATABASE);
      
       return $con;
       }
      
       public function close() {
       mysql_close();
       }
      
      }
      ?>
    4. Puis créer un fichier db_functions.php qui aura pour fonction d’insérer un utilisateur…etc
      db_functions.php
      
      class DB_Functions {
      
          private $db;
      
          private $mysqli;
      
          function __construct() {
              include_once 'db_connect.php';
              // connecting to database
              $this->db = new DB_Connect();
              $this->mysqli = $this->db->connect();
          }
      
          /**
           * On ajoute un nouvel utilisateur
           */
          public function addUser($gcm_token) {
              // insert user into database
              $result = $this->mysqli->query("INSERT INTO gcm_ids (gcm_token, date_creation) VALUES('$gcm_token', NOW())");
      
              if ($result)
              {
                  return true;
              }
              else
              {
                  return false;
              }
          }
      
          /**
           * Pour obtenir tous les utilisateurs
           */
          public function getDevices() {
              $result = $this->mysqli->query("select gcm_token FROM gcm_ids");
              return $result;
          }
      
      }
      
      ?>
    5. Créer un fichier nommé register.php qui aura pour but d’enregistrer l’utilisateur, c’est ce script qui recevra la requête d’Android.
      register.php
      
      if (isset($_POST["gcm_token"])) {
      
          $gcm_token = $_POST["gcm_token"];
          // Store user details in db
          include_once 'db_functions.php';
      
          $db = new DB_Functions();
      
          $res = $db->addUser($gcm_token);
      
          if ($res)
          {
              $response['message'] = 'Utilisateur enregistré !';
              $response['success'] = 1;
          }
          else
          {
              $response['message'] = 'Utilisateur non enregistré !';
              $response['success'] = 0;
          }
      
      } else {
          $response['message'] = "Je crois que tu t'es planté mon gars...";
          $response['success'] = 0;
      }
      
      echo json_encode($response);    
      
      ?>
    6. Maintenant nous allons créer un script qui s’occupe des requêtes vers Google, je l’ai trouvé sur Github et je l’ai un poil modifié 😛 , donc créer un fichier GCMPushMessage.php et copier le code suivant
      GCMPushMessage.php
      
      /*
      	Class to send push notifications using Google Cloud Messaging for Android
      
      	Example usage
      	-----------------------
      	$an = new GCMPushMessage($apiKey);
      	$an->setDevices($devices);
      	$response = $an->send($message);
      	-----------------------
      
      	$apiKey Your GCM api key
      	$devices An array or string of registered device tokens
      	$message The mesasge you want to push out
      
      	@author Matt Grundy
      
      	Adapted from the code available at:
      	http://stackoverflow.com/questions/11242743/gcm-with-php-google-cloud-messaging
      
      */
      class GCMPushMessage {
      
      	private $url = 'https://gcm-http.googleapis.com/gcm/send';
      	private $serverApiKey;
      	private $devices = array();
      
      	/*
      		Constructor
      		@param $apiKeyIn the server API key
      	*/
      	function __construct($apiKeyIn){
      		$this->serverApiKey = $apiKeyIn;
      	}
      	/*
      		Set the devices to send to
      		@param $deviceIds array of device tokens to send to
      	*/
      	function setDevices($deviceIds){
      
      		if(is_array($deviceIds)){
      			$this->devices = $deviceIds;
      		} else {
      			$this->devices = array($deviceIds);
      		}
      
      	}
      
      	/*
      		Send the message to the device
      		@param $message The message to send
      		@param $data Array of data to accompany the message
      	*/
      	function send($message, $data = false, $collapse_key = null, $time_to_live = null){
      
      		if(!is_array($this->devices) || count($this->devices) == 0){
      			$this->error("No devices set");
      		}
      
      		if(strlen($this->serverApiKey) < 8){ $this->error("Server API Key not set");
      		}
      
      		$fields = array(
      			'registration_ids'  => $this->devices,
      			'data'              => array( "message" => $message ),
      		);
      
      		if ($time_to_live != null) {
      			$fields['time_to_live'] = $time_to_live;
      		}
      
      		if ($collapse_key != null) {
      			//$fields['delay_while_idle'] = true;
      			$fields['collapse_key'] = $collapse_key;
      		}
      
      		if(is_array($data)){
      			foreach ($data as $key => $value) {
      				$fields['data'][$key] = $value;
      			}
      		}
      
      		$headers = array(
      			'Authorization: key=' . $this->serverApiKey,
      			'Content-Type: application/json'
      		);
      
      		// Open connection
      		$ch = curl_init();
      
      		// Set the url, number of POST vars, POST data
      		curl_setopt( $ch, CURLOPT_URL, $this->url );
      
      		curl_setopt( $ch, CURLOPT_POST, true );
      		curl_setopt( $ch, CURLOPT_HTTPHEADER, $headers);
      		curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
      
      		curl_setopt( $ch, CURLOPT_POSTFIELDS, json_encode( $fields ) );
      
      		// Avoids problem with https certificate
      		curl_setopt( $ch, CURLOPT_SSL_VERIFYHOST, false);
      		curl_setopt( $ch, CURLOPT_SSL_VERIFYPEER, false);
      
      		// Execute post
      		$result = curl_exec($ch);
      
      		// Close connection
      		curl_close($ch);
      
      		return $result;
      	}
      
      	function error($msg){
      		echo "Android send notification failed with error:";
      		echo "\t" . $msg;
      		exit(1);
      	}
      }
    7. Et bien évidemment le script qu’on appellera pour notifier tous les utilisateurs, nommez le send_message.php 
      send_message.php
      
      if (isset($_POST["title"]) && isset($_POST["message"])) {
      
      	$title = $_POST["title"];
          $message = $_POST["message"];
      
          include_once 'GCMPushMessage.php';
          include_once 'db_functions.php';
          include_once 'config.php';
      
          $gcm = new GCMPushMessage(GOOGLE_API_KEY);
          $db = new DB_Functions();
      
          $result = $db->getDevices();
      
          // Notre tableau de token des utilisateurs
          $registatoin_ids = array();
      
          while($row = $result->fetch_array())
          {
              array_push($registatoin_ids, $row['gcm_token']);
          }
      
          // listre des utilisateurs à notifier
          $gcm->setDevices($registatoin_ids);
      
          // Le titre de la notification
          $data['title'] = $title;
      
          // On notifie nos utilisateurs
          $result = $gcm->send($message, $data);
      
          echo $result;
      }
      
      ?>
    8. Et ajouter un fichier index.php qui nous servira d’interface pour envoyer notre message
      <!DOCTYPE html>
      <html>
       <head>
       <title>Google Cloud Messaging</title>
       <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      
       <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
       <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap-theme.min.css">
       <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
      
       </head>
      
       <body>
      
      
      <form role="form" method="post" action="send_message.php" >
      
      <div class="form-group">
       <label >Titre</label>
       <input type="text" class="form-control" name="title">
       </div>
      
      
      <div class="form-group">
       <label >Message</label>
       <input type="text" class="form-control" name="message">
       </div>
      
      
       <button type="submit" class="btn btn-default center-block">Envoyer</button>
       </form>
      
      
       </body>
      </html>
      

Côté client ( Android )

  1. Sous Android studio faîtes file->New->New Project
  2. Dans Application name mettez “GCM” et Company name “androidpourtous.com”, puis Next et laisser par défaut jusqu’à ce que vous arriviez à Finish.
  3. Maintenant dans le fichier build.gradle ( Module : app ), dans dependencies ajoutez les lignes suivantes et synchronisez le tout :
    compile 'com.google.android.gms:play-services-gcm:7.5.+'
    compile 'com.squareup.okhttp:okhttp:2.4.0'
  4. Copiez ces ressources strings dans res->values->strings et mettez l’id du projet que vous avez créer plus haut, j’espère que vous n’avez pas égarer ce nombre ! 😛
    1020617849953
    Token généré et envoyé au serveur, vous pouvez maintenant envoyer des messages
    à cette application
    Génération du token...
    Une erreur s\'est produite, veuillez réessayer !
  5. Dans res->layout->activity_main copiez le code suivant
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" android:background="@android:color/white" android:orientation="vertical" tools:context=".MainActivity">
    
        <TextView android:text="@string/registering_message" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/informationTextView" android:textAppearance="?android:attr/textAppearanceMedium" />
    
        <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/registrationProgressBar" />
    
    </LinearLayout>
  6. La suite est basé sur l’exemple de google, nous allons bêtement suivre les étapes 😀 , donc dans le package com.androidpourtous.gcm créer la class MyGcmListenerService, c’est elle qui nous permet de recevoir les messages.
    public class MyGcmListenerService extends GcmListenerService {
    
        private static final String TAG = "MyGcmListenerService";
    
        /**
         * Called when message is received.
         *
         * @param from SenderID of the sender.
         * @param data Data bundle containing message data as key/value pairs.
         *             For Set of keys use data.keySet().
         */
        @Override
        public void onMessageReceived(String from, Bundle data) {
    
            String message = data.getString("message");
            String title = data.getString("title");
    
            Log.d(TAG, "From: " + from);
            Log.d(TAG, "Message: " + message);
    
            /**
             * Production applications would usually process the message here.
             * Eg: - Syncing with server.
             *     - Store message in local database.
             *     - Update UI.
             */
    
            /**
             * In some cases it may be useful to show a notification indicating to the user
             * that a message was received.
             */
            sendNotification(message, title);
        }
    
        /**
         * Create and show a simple notification containing the received GCM message.
         *
         * @param message GCM message received.
         */
        private void sendNotification(String message, String title) {
            Intent intent = new Intent(this, MainActivity.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);
            NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                    .setSmallIcon(R.mipmap.ic_launcher)
                    .setContentTitle(title)
                    .setContentText(message)
                    .setAutoCancel(true)
                    .setSound(defaultSoundUri)
                    .setContentIntent(pendingIntent);
    
            NotificationManager notificationManager =
                    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
            // On génère un nombre aléatoire pour pouvoir afficher plusieurs notifications
            notificationManager.notify(new Random().nextInt(9999), notificationBuilder.build());
        }
    }
  7. Créer la class MyInstanceIDListenerService
    public class MyInstanceIDListenerService extends InstanceIDListenerService {
    
        private static final String TAG = "MyInstanceIDLS";
    
        /**
         * Called if InstanceID token is updated. This may occur if the security of
         * the previous token had been compromised. This call is initiated by the
         * InstanceID provider.
         */
        @Override
        public void onTokenRefresh() {
            // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).
            Intent intent = new Intent(this, RegistrationIntentService.class);
            startService(intent);
        }
    }
  8. Créer la class QuickstartPreferences
    public class QuickstartPreferences {
    
        public static final String SENT_TOKEN_TO_SERVER = "sentTokenToServer";
        public static final String REGISTRATION_COMPLETE = "registrationComplete";
    
    }
  9. Créer la class RegistrationIntentService, c’est la class qui va s’occuper de générer le token et de l’envoyer à notre serveur
    public class RegistrationIntentService extends IntentService {
    
        private static final String TAG = "RegIntentService";
    
        private static final String REGISTER_URL = "http://192.168.1.9/gcm/register.php";
    
        private static final String KEY_TOKEN = "gcm_token";
    
        public RegistrationIntentService() {
            super(TAG);
        }
    
        @Override
        protected void onHandleIntent(Intent intent) {
            SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
    
            try {
                // In the (unlikely) event that multiple refresh operations occur simultaneously,
                // ensure that they are processed sequentially.
                synchronized (TAG) {
                    // [START register_for_gcm]
                    // Initially this call goes out to the network to retrieve the token, subsequent calls
                    // are local.
                    InstanceID instanceID = InstanceID.getInstance(this);
    
                    String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
                            GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
    
                    Log.i(TAG, "GCM Registration Token: " + token);
    
                    // Si le token a déjà été engistre pas la peine de le renvoyer
                    if (!sharedPreferences.getBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false))
                        sendRegistrationToServer(token);
    
                    // You should store a boolean that indicates whether the generated token has been
                    // sent to your server. If the boolean is false, send the token to your server,
                    // otherwise your server should have already received the token.
                    sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, true).apply();
                }
            } catch (Exception e) {
                Log.d(TAG, "Failed to complete token refresh", e);
                // If an exception happens while fetching the new token or updating our registration data
                // on a third-party server, this ensures that we'll attempt the update at a later time.
                sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false).apply();
            }
            // Notify UI that registration has completed, so the progress indicator can be hidden.
            Intent registrationComplete = new Intent(QuickstartPreferences.REGISTRATION_COMPLETE);
            LocalBroadcastManager.getInstance(this).sendBroadcast(registrationComplete);
        }
    
        /**
         *  Ici nous allons envoyer le token de l'utilisateur au serveur
         *
         * @param token Le token
         */
        private void sendRegistrationToServer(String token) {
    
            OkHttpClient client = new OkHttpClient();
    
            RequestBody requestBody = new FormEncodingBuilder()
                    .add(KEY_TOKEN, token)
                    .build();
    
            Request request = new Request.Builder()
                    .url(REGISTER_URL)
                    .post(requestBody)
                    .build();
    
            try {
                Response response = client.newCall(request).execute();
    
            } catch (IOException e) {
                e.printStackTrace();
            }
    
        }
    
    }
  10. Dans MainActivity copiez le code ci-dessous
    public class MainActivity extends AppCompatActivity {
    
        private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
        private static final String TAG = "MainActivity";
    
        private BroadcastReceiver mRegistrationBroadcastReceiver;
        private ProgressBar mRegistrationProgressBar;
        private TextView mInformationTextView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mRegistrationProgressBar = (ProgressBar) findViewById(R.id.registrationProgressBar);
            mRegistrationBroadcastReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    mRegistrationProgressBar.setVisibility(ProgressBar.GONE);
                    SharedPreferences sharedPreferences =
                            PreferenceManager.getDefaultSharedPreferences(context);
                    boolean sentToken = sharedPreferences
                            .getBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false);
                    if (sentToken) {
                        mInformationTextView.setText(getString(R.string.gcm_send_message));
                    } else {
                        mInformationTextView.setText(getString(R.string.token_error_message));
                    }
                }
            };
            mInformationTextView = (TextView) findViewById(R.id.informationTextView);
    
            if (checkPlayServices()) {
                // Start IntentService to register this application with GCM.
                Intent intent = new Intent(this, RegistrationIntentService.class);
                startService(intent);
            }
        }
    
        @Override
        protected void onResume() {
            super.onResume();
            LocalBroadcastManager.getInstance(this).registerReceiver(mRegistrationBroadcastReceiver,
                    new IntentFilter(QuickstartPreferences.REGISTRATION_COMPLETE));
        }
    
        @Override
        protected void onPause() {
            LocalBroadcastManager.getInstance(this).unregisterReceiver(mRegistrationBroadcastReceiver);
            super.onPause();
        }
    
        /**
         * Vérifier si notre utilisateur a l'application Google Play Service
         */
        private boolean checkPlayServices() {
            int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
            if (resultCode != ConnectionResult.SUCCESS) {
                if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
                    GooglePlayServicesUtil.getErrorDialog(resultCode, this,
                            PLAY_SERVICES_RESOLUTION_REQUEST).show();
                } else {
                    Log.i(TAG, "This device is not supported.");
                    finish();
                }
                return false;
            }
            return true;
        }
    
    }
  11. Et pour finir ajouter le code suivant dans votre AndroidManifest.xml, cela contient les autorisations nécessaire pour le fonctionnement de l’application.
    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.androidpourtous.gcm" >
    
        <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
        <uses-permission android:name="android.permission.WAKE_LOCK" />
    
        <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" >
    
            <activity android:name="com.androidpourtous.gcm.MainActivity" android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
    
            <receiver android:name="com.google.android.gms.gcm.GcmReceiver" android:exported="true" android:permission="com.google.android.c2dm.permission.SEND" >
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                    <category android:name="com.androidpourtous.gcm" />
                </intent-filter>
            </receiver>
    
            <service android:name="com.androidpourtous.gcm.MyGcmListenerService" android:exported="false" >
                <intent-filter>
                    <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                </intent-filter>
            </service>
    
            <service android:name="com.androidpourtous.gcm.MyInstanceIDListenerService" android:exported="false">
                <intent-filter>
                    <action android:name="com.google.android.gms.iid.InstanceID"/>
                </intent-filter>
            </service>
    
            <service android:name="com.androidpourtous.gcm.RegistrationIntentService" android:exported="false">
            </service>
    
        </application>
    
    </manifest>

Voilà ! maintenant vous pouvez lancer l’application et aller sur index.php pour commencer à vous auto-spammer 😛

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *