Google Cloud Messaging for Your Android App 2016

Google Cloud Messaging for Your Android App 2016

Google Cloud Messaging for Your Android App

This article helps you to integrate Google Cloud Messaging inside your android app. Using this article you are able to send Push notification from your PHP Server to register android device.

How Google Cloud Messaging Work ?

Below image show's how GCM work for sending push notification

 

Google Cloud Messaging for Android

 

 

 

 

As shown in above image

  1. When your application start it share application id and sender id with GCM.
  2. GCM register the application and provide a registration id for your device.
  3. Mobile receive the registration id and share it with the web server.
  4. Web Server Store the registration id in the databases or any other storage medium.
  5. Now whenever we not send a notification to register mobile device, first we retrieve the stored registration id from our database.Send all registration ids (max 1000 at a time) and with message to deliver to GCM.
  6. Finally GCM deliver notification to all the registrations ids

How to implement it with your Android App ?

  • First we need to create a project on Google Developer Console. Get the required config files.
  • Modify our Android Project.
  • Get ready our Server to save register ids
  • Finally send notifications from server to all register devices.

Below is the demo video shows the working implementation of GCM.

 

Lets start by creating project in developer console 

1. Visit this link. Click on Create Project Button to create a project.

Open Developer Console

2. Create a new project with appropriate name and click on create button.

Create New Project

3. Once your project is create visit this link to create a configuration file. Click on button Generate Configuration File under the section Get a configuration file.

Get Config File

4. Create or choose app wizard select your project which is created in step 3. Provide appropriate Android package name (Remember this package name we need to use the same name at the time creating our android project if you are going to create a new project) and Finally Country and click on Choose and configure services button.

Create new server key for your android projet

5. In Choose and configure services windows click on ENABLE GOOGLE CLOUD MESSAGING button. It is going to enable GOOGLE CLOUD MESSAGING and create a Server Key for you

Enable Google Cloud Messaging

6. Copy the generated server key and Sender ID and finally click on Generate Configuration Files button.

7. Last click on Download google-services.json file save it in appropriate location. we need copy the same in our android project.

Download google services json

Finally our task for developer console is done. Next thing let's create our android project or use existing one(Assuming the package name for existing project is same as mentioned in the step no 4)

1. Open Android Studio. Create a new project or open existing one. I am creating a new android project so you can skip steps which are not applicable for you.

2. Select appropriate Min and Max SDK you want to support

3. Select the Layout for your application

4. Finally click on finish to create your project.

5. Once your project is created we need to modify our gradle-wrapper.properties for this you need to click on Project Files -> GCMBlogTutor -> gradle/wrapper -> gradle-wrapper.properties

Change below line

Code

distributionUrl=https://services.gradle.org/distributions/gradle-2.8-all.zip

into

distributionUrl=https://services.gradle.org/distributions/gradle-2.10-all.zip

6. Now we need to modify our build.gradle for project and build.gradle for mobile.

7. Open build.gradle for project file and made below changes.

look for classpath 'com.android.tools.build:gradle:1.5.0'

Modify it 

classpath 'com.android.tools.build:gradle:2.0.0-alpha6'
classpath 'com.google.gms:google-services:2.0.0-alpha6'

8. Next open build.gradle for mobile file and made below changes.

Add below line in defaultConfig

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

In dependecies Add below lines

compile 'com.android.support:support-v4:23.1.1'
compile 'com.google.android.gms:play-services-gcm:8.4.0'

// Testing dependencies
androidTestCompile 'com.android.support.test.espresso:espresso-core:2.1'
androidTestCompile 'com.android.support.test:runner:0.2'
androidTestCompile 'com.android.support:support-annotations:23.1.1'

In the last of file add below line

apply plugin: 'com.google.gms.google-services'

9. Finally right click on app and select show in explorer

Open in new Explorer

10. Open app folder and past google-services.json file

11. Finally click on Syn button to syn your grable. It will take some time to refresh. If it is failed then ensure you copied the correct google-services.json file. Package name is matching in your project and google-services.json file. Check the version of dependencies need to modify.

12. I am assuming grable build sync is successfull. Not it time to implement GCM in our App. Open Android Manifest and add below lines. I know some lines are in red but we are going to add some more required files in next step.

<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<uses-permission android:name="android.permission.WAKE_LOCK" /><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="gcm.play.android.samples.com.gcmquickstart" />
    </intent-filter>
</receiver>
<!-- [END gcm_receiver] -->
<!-- [START gcm_listener] -->
<service
    android:name=".MyGcmListenerService"
    android:exported="false" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>
<!-- [END gcm_listener] -->
<!-- [START instanceId_listener] -->
<service
    android:name=".MyInstanceIDListenerService"
    android:exported="false">
    <intent-filter>
        <action android:name="com.google.android.gms.iid.InstanceID"/>
    </intent-filter>
</service>
<!-- [END instanceId_listener] -->
<service
    android:name=".RegistrationIntentService"
    android:exported="false">
</service>

13. Now add MyGcmListenerService.java file with below code.

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().
     */
    // [START receive_message]
    @Override
    public void onMessageReceived(String from, Bundle data) {
        String message = data.getString("message");
        String myURL = data.getString("url");
        Log.d(TAG, "Mayank From: "   from);
        Log.d(TAG, "Mayank Message: "   message);
        Log.d(TAG, "Mayank URL: "   myURL);

        if (from.startsWith("/topics/")) {
            // message received from some topic.
        } else {
            // normal downstream message.
        }

        // [START_EXCLUDE]
        /**
         * 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,myURL);
        // [END_EXCLUDE]
    }
    // [END receive_message]

    /**
     * Create and show a simple notification containing the received GCM message.
     *
     * @param message GCM message received.
     */
    private void sendNotification(String message,String myURL) {
        Log.d(TAG, "Mayank message is: "   message);

        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        intent.putExtra("url",myURL);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,PendingIntent.FLAG_CANCEL_CURRENT);

        Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.mipmap.ic_launcher)
                .setContentTitle("GCM Message")
                .setContentText(message)
                .setContentTitle("GCM Demo")  // <--- add this
                .setContentText(message)

                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

        NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);

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

14. Now add MyInstanceIDListenerService.java file with below code.

public class MyInstanceIDListenerService extends InstanceIDListenerService {

    private static final String TAG = "MyInstanceIDLS";

   // [START refresh_token]
    @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);
    }
    // [END refresh_token]
}

15. Now add QuickstartPreferences.java file with below code.

public class QuickstartPreferences  {
    public static final String SENT_TOKEN_TO_SERVER = "sentTokenToServer";
    public static final String REGISTRATION_COMPLETE = "registrationComplete";

}

16. Now add RegistrationIntentService.java file with below code.

public class RegistrationIntentService extends IntentService {

    private static final String TAG = "RegIntentService";
    private static final String[] TOPICS = {"global"};

    public RegistrationIntentService() {
        super(TAG);
}

    @Override
    protected void onHandleIntent(Intent intent) {
        SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

        try {
            
InstanceID instanceID = InstanceID.getInstance(this);
String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
            // [END get_token]
Log.i(TAG, "Mayank GCM Registration Token: "   token);

            // TODO: Implement this method to send any registration to your app's servers.
sendRegistrationToServer(token);

            // Subscribe to topic channels
subscribeTopics(token);


sharedPreferences.edit().putBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, true).apply();
            // [END register_for_gcm]
} catch (Exception e) {
            Log.d(TAG, "Mayank Failed to complete token refresh", e);

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);
}

    
    private void sendRegistrationToServer(String token) {
        PackageInfo pInfo = null;
try {
            pInfo = getPackageManager().getPackageInfo(getPackageName(),0);
} catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
}

ServerManager serverManager = new ServerManager();
String sURL = "http://192.168.56.1:8085/mobileapi/API_Register.php";

        serverManager.execute(sURL, "Register","GCM Demo",token,pInfo.versionCode "");
}

 
 // [START subscribe_topics]
 private void subscribeTopics(String token) throws IOException {
 GcmPubSub pubSub = GcmPubSub.getInstance(this);
 for (String topic : TOPICS) {
 pubSub.subscribe(token, "/topics/"   topic, null);
}
 }
 // [END subscribe_topics]

}

17. Now add ServerManager.java file with below code.

public class ServerManager extends AsyncTask<String, String, String> {

    public boolean executionStatus=false;
    public ServerManager() {}
    @Override
    protected String doInBackground(String... params) {
        executionStatus=true;
        String responseBody = null;
        URL url;
        HttpURLConnection connection = null;
        try {
            url = new URL(params[0]);

            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("POST");
            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            DataOutputStream wr =
                    new DataOutputStream(connection.getOutputStream());
            String urlParameters=null;
            urlParameters = "Action="   URLEncoder.encode(params[1].toString(), "UTF-8")
                      "&AppID="   URLEncoder.encode(params[2].toString(), "UTF-8")
                      "&Token="   URLEncoder.encode(params[3].toString(), "UTF-8")
                      "&Version="   URLEncoder.encode(params[4].toString(), "UTF-8");
            wr.writeBytes(urlParameters);
            wr.flush();
            wr.close();
            InputStream is = connection.getInputStream();
            BufferedReader rd = new BufferedReader(new InputStreamReader(is));
            String line;
            StringBuffer response = new StringBuffer();
            while ((line = rd.readLine()) != null) {
                response.append(line);
                response.append('r');
            }
            rd.close();
            responseBody = response.toString();
        } catch (Exception e) {
            //Log.i("Mayank SM Err", e.toString());
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return responseBody;
    }
    @Override
    protected void onPostExecute(String s) {    }

}

18. Finally modify MainActivity.java file with below code.

public class MainActivity extends AppCompatActivity
        implements NavigationView.OnNavigationItemSelectedListener {

    private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
    private static final String TAG = "MainActivity";
    private BroadcastReceiver mRegistrationBroadcastReceiver;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();
        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
        mRegistrationBroadcastReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                SharedPreferences sharedPreferences =
                        PreferenceManager.getDefaultSharedPreferences(context);
                boolean sentToken = sharedPreferences
                        .getBoolean(QuickstartPreferences.SENT_TOKEN_TO_SERVER, false);
            }
        };
        if (checkPlayServices()) {
            // Start IntentService to register this application with GCM.
            Intent intent = new Intent(this, RegistrationIntentService.class);
            startService(intent);
        }
    }
    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }
    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (id == R.id.nav_camera) {
            // Handle the camera action
        } else if (id == R.id.nav_gallery) {
        } else if (id == R.id.nav_slideshow) {
        } else if (id == R.id.nav_manage) {
        } else if (id == R.id.nav_share) {
        } else if (id == R.id.nav_send) {
        }
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }
    @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();
    }
    private boolean checkPlayServices() {
        GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
        int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
        if (resultCode != ConnectionResult.SUCCESS) {
            if (apiAvailability.isUserResolvableError(resultCode)) {
                apiAvailability.getErrorDialog(this, resultCode, PLAY_SERVICES_RESOLUTION_REQUEST)
                        .show();
            } else {
                Log.i(TAG, "Mayank This device is not supported.");
                finish();
            }
            return false;
        }
        return true;
    }
}

In Last we need to create scripts for our server.

Create a database in MySQL Let's Say GCM and execute below script

CREATE TABLE IF NOT EXISTS `gcmregusers` (
  `ID` bigint(20) NOT NULL AUTO_INCREMENT,
  `AppID` varchar(20) NOT NULL,
  `RegToken` varchar(200) NOT NULL,
  `RegDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `Status` tinyint(4) NOT NULL,
  `IsDelete` tinyint(1) NOT NULL,
  `AppVersion` bigint(20) NOT NULL,
  PRIMARY KEY (`ID`),
  UNIQUE KEY `AppID` (`AppID`,`RegToken`),
  UNIQUE KEY `AppID_2` (`AppID`,`RegToken`)
)

Create a API_Register.php file

 

<?php
$_uv_ScriptResult=-1;

if(isset($_POST["Action"])&&isset($_POST["AppID"])&&isset($_POST["Token"])&&isset($_POST["Version"])){
   $_uv_Action=$_POST["Action"];
   $_uv_AppID=$_POST["AppID"];
   $_uv_Token=$_POST["Token"];
   $_uv_AppVersion=intval($_POST["Version"]);
   $mysqli =  new mysqli("localhost","root","","gcm");
   if(!$mysqli->connect_errno)
        {
           $q="INSERT INTO gcmregusers ( AppID, RegToken, RegDate, Status, IsDelete,AppVersion) VALUES ( ?, ?, CURRENT_TIMESTAMP, 1, 0,?)"
              ." ON DUPLICATE KEY UPDATE Status = 1, IsDelete = 0, AppVersion=?;";
                if ($stmt = $mysqli->prepare($q))
               {
                   $stmt->bind_param("ssii", $_uv_AppID,$_uv_Token,$_uv_AppVersion,$_uv_AppVersion);
                   /* execute query */
                   $stmt->execute();
                   /* close statement */
                   $stmt->close();
                   $_uv_ScriptResult=1;
               }
               else
                  $_uv_ScriptResult=-3;
        }
        else
           $_uv_ScriptResult="-2".$mysqli->connect_error;
        $mysqli->close();
}

echo $_uv_ScriptResult;
?>

 

Final Send_Notification.php. I did not automate it but you can modify and use it to send Notifications. Do not forgot to add your server api key and Device Register ID in the below PHP script.

<?php

function sendPushNotificationToGCM($registatoin_ids, $message) {
      //Google cloud messaging GCM-API url
        $url = 'https://android.googleapis.com/gcm/send';
        $fields = array(
            'registration_ids' => $registatoin_ids,
            'data' => $message,
        );
      // Google Cloud Messaging GCM API Key
      define("GOOGLE_API_KEY", "Your_Server_API_Key");      
        $headers = array(
            'Authorization: key=' . GOOGLE_API_KEY,
            'Content-Type: application/json'
        );
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt ($ch, CURLOPT_SSL_VERIFYHOST, 0);  
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
        $result = curl_exec($ch);           
        if ($result === FALSE) {
            die('Curl failed: ' . curl_error($ch));
        }
        curl_close($ch);
        return $result;
    }

?>

<?php
$gcmRegID=array("Your_Register_Device_ID");
$pushMessage = "This is a Test Message";
/*Replace URL which you need to open*/
$message = array("message" => $pushMessage,"url"=>"https://vlemonn.com/Blog/All/All/");          
$pushStatus = sendPushNotificationToGCM($gcmRegID, $message);
echo "Status is Here".$pushStatus;
?>

Congratulation, your are successfully able to send push notification to all your register device.

And before leaving this blog page don't forgot to share your valuable feedback, subscribe, like and share.

0 Comments
Leave A Comment

Please login to post your valuable comments.

Join the newsletter

Get the latest vLemonn news first

share