Google cloud messaging cho android (Bài 6)

Google cloud messaging cho android (Bài 6)

google-cloud-messaging-cho-android-1
Phát triển app android

Google cloud messaging cho android (Bài 6)

Google Cloud Messaging cho Android (GCM) là một dịch vụ cho phép gửi dữ liệu từ những máy chủ đến ứng dụng android. Sử dụng dịch vụ này, bạn có thể gửi dữ liệu cho ứng dụng của bạn bất cứ khi nào có dữ liệu mới một cách tự động thay vì phải gửi yêu cầu đến máy chủ.

Sơ đồ dưới đây là minh họa tổng quan về mục đích của mỗi thực thể tham gia trong hướng dẫn google cloud messaging cho android.

google cloud messaging cho android
  1. Đầu tiên thiết bị android gửi sender idapplication id đến máy chủ GCM để đăng ký
  2. Sau khi đăng ký thành công máy chủ GCM sẽ phát sinh một registration id cho thiết bị android
  1. Sau khi nhận registration id, thiết bị sẽ gửi registration id đến server
  2. Server sẽ lưu registration id vào cơ sở dữ liệu
  3. Bất cứ khi nào có thông báo, server sẽ gửi một thông điệp tới máy chủ GCM cùng với registration id củathiết bị
  4. Máy chủ GCM sẽ chuyển thông điệp này đến thiết bị di động registration id củathiết bị

Google Cloud Messaging cho AndroidCác bước thực hiện

Một số hình ảnh của ứng dụng cài đặt google cloud messaging cho android

Trước khi nhập thông tin và đăng ký

google cloud messaging cho android 41

Nhập thông tin và chạm vào “REGISTER

google cloud messaging cho android 44

Sau khi đăng ký thành công

google cloud messaging cho android 43

Nhập thông tin tại trang web và click vào nút “Send“, dữ liệu sẽ được gửi đến ứng dụng android

google cloud messaging cho android 46

Bước 1: Đăng ký với Google Cloud Messaging

Truy cập trang Google APIs Console page và tạo một project mới

Chọn Create project

google cloud messaging cho android 2

Nhập tên project và chọn Create

google cloud messaging cho android 3

Kết quả sau khi tạo xong project bạn sẽ nhận được SENDER ID

google cloud messaging cho android 4

Đăng ký API Key

Chọn Credentials -> chọn API key

google cloud messaging cho android 5

Chọn Android key

google cloud messaging cho android

Chọn Create

google cloud messaging cho android

API key sau khi tạo thành công

google cloud messaging cho android

Kích hoạt dịch vụ Cloud Messaging for Android

Chọn Google APIs -> chọn Cloud Messaging for Android

google cloud messaging cho android 29

Chọn Enable API

google cloud messaging cho android 30

Bước 2: Tạo MySQL Database (Tham khảo bài viết hướng dẫn kết android với mysql)

Truy cập trang http://localhost/phpmyadmin và tạo một database tên gcm (Nếu localhost của bạn đang chạy trên port khác 80 thì bạn phải thêm port vào url theo định dạng http://localhost:port/phpmyadmin)

Sau khi tạo xong database, bạn chọn gcm và thực thi đoạn script sau để tạo bảng gcm_users

CREATE TABLE IF NOT EXISTS gcm_users (
  id int(11) NOT NULL AUTO_INCREMENT,
  gcm_regid 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 ;

Bước 3: Tạo PHP Project

Tạo thư mục tên gcm_server_php trong thư mục htdocs

Giải nén tập tin gcm_server_php.jar vào thư mục gcm_server_php

Lưu ý thay đổi thông tin kết nối đến MySQL và API Key tại config.php

google cloud messaging cho android 35

Bước 4: Cài đặt Google Cloud Messaging for Android Library

Tại Android Studio -> chọn SDK Manager

google cloud messaging cho android 22

Chọn SDK Tools -> chọn Show Package Details -> chọn Google Cloud Messaging for Android Library -> chọn OK

google cloud messaging cho android 21

Bước 5: Tạo Android Project

5.1. Sử dụng Android Studio và tạo mới một project tên GCMDemo, tải và copy các file đặt vào thư mục drawable

5.2. Vào sdk\extras\google\gcm\samples\gcm-demo-client\libs và copy gcm.jar -> sau đópaste vào thư mục \app\libs

Kết quả sau khi paste thành công

google cloud messaging cho android 34

5.3. Trong Android Studio -> mở file build.gradle (Module:app) và thêm vào đoạn code

compile files('libs/gcm.jar')
google cloud messaging cho android 23

5.4. Tạo tập tin CommonUtilities.java

Chuột phải package -> chọn New -> chọn Java Class

Nội dung tập tin

import android.content.Context;
import android.content.Intent;
/**
 * Created by giasutinhoc.vn
 */
public class CommonUtilities {
    // give your server registration url here
    static final String SERVER_URL = "http://10.0.2.2:7777/gcm_server_php/register.php";
    // Google project id
    static final String SENDER_ID = "508241416041";
    /**
     * Tag used on log messages.
     */
    static final String TAG = "GCM Demo";
    static final String DISPLAY_MESSAGE_ACTION = "android.gcmdemo.DISPLAY_MESSAGE";
    static final String EXTRA_MESSAGE = "message";
    /**
     * Notifies UI to display a message.
     * <p>
     * This method is defined in the common helper because it's used both by
     * the UI and the background service.
     *
     * @param context application's context.
     * @param message message to be displayed.
     */
    static void displayMessage(Context context, String message) {
        Intent intent = new Intent(DISPLAY_MESSAGE_ACTION);
        intent.putExtra(EXTRA_MESSAGE, message);
        context.sendBroadcast(intent);
    }
}

Lưu ý thay đổi các thông sau cho phù hợp với máy của bạn

google cloud messaging cho android 36

5.5. Tạo tập tin ServerUtilities.java

import android.content.Context;
import android.util.Log;
import com.google.android.gcm.GCMRegistrar;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Random;
/**
 * Created by giasutinhoc.vn
 */
public class ServerUtilities {
    private static final int MAX_ATTEMPTS = 5;
    private static final int BACKOFF_MILLI_SECONDS = 2000;
    private static final Random random = new Random();
    /**
     * Register this account/device pair within the server.
     *
     */
    static void register(final Context context, String name, String email, final String regId) {
        Log.i(CommonUtilities.TAG, "registering device (regId = " + regId + ")");
        String serverUrl = CommonUtilities.SERVER_URL;
        Map<String, String> params = new HashMap<String, String>();
        params.put("regId", regId);
        params.put("name", name);
        params.put("email", email);
        long backoff = BACKOFF_MILLI_SECONDS + random.nextInt(1000);
        // Once GCM returns a registration id, we need to register on our server
        // As the server might be down, we will retry it a couple
        // times.
        for (int i = 1; i <= MAX_ATTEMPTS; i++) {
            Log.d(CommonUtilities.TAG, "Attempt #" + i + " to register");
            try {
                CommonUtilities.displayMessage(context, context.getString(
                        R.string.server_registering, i, MAX_ATTEMPTS));
                post(serverUrl, params);
                GCMRegistrar.setRegisteredOnServer(context, true);
                String message = context.getString(R.string.server_registered);
                CommonUtilities.displayMessage(context, message);
                return;
            } catch (IOException e) {
                // Here we are simplifying and retrying on any error; in a real
                // application, it should retry only on unrecoverable errors
                // (like HTTP error code 503).
                Log.e(CommonUtilities.TAG, "Failed to register on attempt " + i + ":" + e);
                if (i == MAX_ATTEMPTS) {
                    break;
                }
                try {
                    Log.d(CommonUtilities.TAG, "Sleeping for " + backoff + " ms before retry");
                    Thread.sleep(backoff);
                } catch (InterruptedException e1) {
                    // Activity finished before we complete - exit.
                    Log.d(CommonUtilities.TAG, "Thread interrupted: abort remaining retries!");
                    Thread.currentThread().interrupt();
                    return;
                }
                // increase backoff exponentially
                backoff *= 2;
            }
        }
        String message = context.getString(R.string.server_register_error,
                MAX_ATTEMPTS);
        CommonUtilities.displayMessage(context, message);
    }
    /**
     * Unregister this account/device pair within the server.
     */
    static void unregister(final Context context, final String regId) {
        Log.i(CommonUtilities.TAG, "unregistering device (regId = " + regId + ")");
        String serverUrl = CommonUtilities.SERVER_URL + "/unregister";
        Map<String, String> params = new HashMap<String, String>();
        params.put("regId", regId);
        try {
            post(serverUrl, params);
            GCMRegistrar.setRegisteredOnServer(context, false);
            String message = context.getString(R.string.server_unregistered);
            CommonUtilities.displayMessage(context, message);
        } catch (IOException e) {
            // At this point the device is unregistered from GCM, but still
            // registered in the server.
            // We could try to unregister again, but it is not necessary:
            // if the server tries to send a message to the device, it will get
            // a "NotRegistered" error message and should unregister the device.
            String message = context.getString(R.string.server_unregister_error,
                    e.getMessage());
            CommonUtilities.displayMessage(context, message);
        }
    }
    /**
     * Issue a POST request to the server.
     *
     * @param endpoint POST address.
     * @param params request parameters.
     *
     * @throws IOException propagated from POST.
     */
    private static void post(String endpoint, Map<String, String> params)
            throws IOException {
        URL url;
        try {
            url = new URL(endpoint);
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("invalid url: " + endpoint);
        }
        StringBuilder bodyBuilder = new StringBuilder();
        Iterator<Entry<String, String>> iterator = params.entrySet().iterator();
        // constructs the POST body using the parameters
        while (iterator.hasNext()) {
            Entry<String, String> param = iterator.next();
            bodyBuilder.append(param.getKey()).append('=')
                    .append(param.getValue());
            if (iterator.hasNext()) {
                bodyBuilder.append('&');
            }
        }
        String body = bodyBuilder.toString();
        Log.v(CommonUtilities.TAG, "Posting '" + body + "' to " + url);
        byte[] bytes = body.getBytes();
        HttpURLConnection conn = null;
        try {
            Log.e("URL", "> " + url);
            conn = (HttpURLConnection) url.openConnection();
            conn.setDoOutput(true);
            conn.setUseCaches(false);
            conn.setFixedLengthStreamingMode(bytes.length);
            conn.setRequestMethod("POST");
            conn.setRequestProperty("Content-Type",
                    "application/x-www-form-urlencoded;charset=UTF-8");
            // post the request
            OutputStream out = conn.getOutputStream();
            out.write(bytes);
            out.close();
            // handle the response
            int status = conn.getResponseCode();
            if (status != 200) {
                throw new IOException("Post failed with error code " + status);
            }
        } finally {
            if (conn != null) {
                conn.disconnect();
            }
        }
    }
}

5.6. Tạo tập tin GCMIntentService.java

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.google.android.gcm.GCMBaseIntentService;
/**
 * Created by giasutinhoc.vn
 */
public class GCMIntentService extends GCMBaseIntentService {
    private static final String TAG = "GCMIntentService";
    public GCMIntentService() {
        super(CommonUtilities.SENDER_ID);
    }
    /**
     * Method called on device registered
     **/
    @Override
    protected void onRegistered(Context context, String registrationId) {
        Log.i(TAG, "Device registered: regId = " + registrationId);
        CommonUtilities.displayMessage(context, "Your device registred with GCM");
        Log.d("NAME", MainActivity.name);
        ServerUtilities.register(context, MainActivity.name, MainActivity.email, registrationId);
    }
    /**
     * Method called on device un registred
     * */
    @Override
    protected void onUnregistered(Context context, String registrationId) {
        Log.i(TAG, "Device unregistered");
        CommonUtilities.displayMessage(context, getString(R.string.gcm_unregistered));
        ServerUtilities.unregister(context, registrationId);
    }
    /**
     * Method called on Receiving a new message
     * */
    @Override
    protected void onMessage(Context context, Intent intent) {
        Log.i(TAG, "Received message");
        String message = intent.getExtras().getString("msg");
        CommonUtilities.displayMessage(context, message);
        // notifies user
        generateNotification(context, message);
    }
    /**
     * Method called on receiving a deleted message
     * */
    @Override
    protected void onDeletedMessages(Context context, int total) {
        Log.i(TAG, "Received deleted messages notification");
        String message = getString(R.string.gcm_deleted, total);
        CommonUtilities.displayMessage(context, message);
        // notifies user
        generateNotification(context, message);
    }
    /**
     * Method called on Error
     * */
    @Override
    public void onError(Context context, String errorId) {
        Log.i(TAG, "Received error: " + errorId);
        CommonUtilities.displayMessage(context, getString(R.string.gcm_error, errorId));
    }
    @Override
    protected boolean onRecoverableError(Context context, String errorId) {
        // log message
        Log.i(TAG, "Received recoverable error: " + errorId);
        CommonUtilities.displayMessage(context, getString(R.string.gcm_recoverable_error,
                errorId));
        return super.onRecoverableError(context, errorId);
    }
    /**
     * Issues a notification to inform the user that server has sent a message.
     */
    private static void generateNotification(Context context, String message) {
        long when = System.currentTimeMillis();
        NotificationManager notificationManager = (NotificationManager)
                context.getSystemService(Context.NOTIFICATION_SERVICE);
        String title = context.getString(R.string.app_name);
        Intent notificationIntent = new Intent(context, MainActivity.class);
        notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
        // set intent so it does not start a new activity
        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, 0);
        Notification.Builder builder = new Notification.Builder(context);
        builder.setAutoCancel(false);
        builder.setContentTitle(title);
        builder.setContentText(message);
        builder.setSmallIcon(R.mipmap.ic_launcher);
        builder.setContentIntent(pendingIntent);
        Notification notification = builder.getNotification();
        notificationManager.notify(0, notification);
    }
}

5.7. Tạo tập tin AlertDialogManager.java

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
/**
 * Created by giasutinhoc.vn
 */
public class AlertDialogManager {
    /**
     * Function to display simple Alert Dialog
     * @param context - application context
     * @param title - alert dialog title
     * @param message - alert message
     * @param status - success/failure (used to set icon)
     *               - pass null if you don't want icon
     * */
    public void showAlertDialog(Context context, String title, String message,
                                Boolean status) {
        AlertDialog alertDialog = new AlertDialog.Builder(context).create();
        // Setting Dialog Title
        alertDialog.setTitle(title);
        // Setting Dialog Message
        alertDialog.setMessage(message);
        if(status != null)
            // Setting alert dialog icon
            alertDialog.setIcon((status) ? R.drawable.success : R.drawable.fail);
        // Setting OK Button
        alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
            public void onClick(DialogInterface dialog, int which) {
            }
        });
        // Showing Alert Message
        alertDialog.show();
    }
}

5.8. Tạo tập tin ConnectionDetector.java

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
/**
 * Created by giasutinhoc.vn
 */
public class ConnectionDetector {
    private Context _context;
    public ConnectionDetector(Context context){
        this._context = context;
    }
    /**
     * Checking for all possible internet providers
     * **/
    public boolean isConnectingToInternet(){
        ConnectivityManager connectivity = (ConnectivityManager) _context.getSystemService(Context.CONNECTIVITY_SERVICE);
        if (connectivity != null)
        {
            NetworkInfo[] info = connectivity.getAllNetworkInfo();
            if (info != null)
                for (int i = 0; i < info.length; i++)
                    if (info[i].getState() == NetworkInfo.State.CONNECTED)
                    {
                        return true;
                    }
        }
        return false;
    }
}

5.9. Tạo tập tin WakeLocker.java

import android.content.Context;
import android.os.PowerManager;
public abstract class WakeLocker {
    private static PowerManager.WakeLock wakeLock;
    public static void acquire(Context context) {
        if (wakeLock != null) wakeLock.release();
        PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
        wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK |
                PowerManager.ACQUIRE_CAUSES_WAKEUP |
                PowerManager.ON_AFTER_RELEASE, "WakeLock");
        wakeLock.acquire();
    }
    public static void release() {
        if (wakeLock != null) wakeLock.release(); wakeLock = null;
    }
}

5.10. Tạo activity tên RegisterActivity

Thiết kế layout

google cloud messaging cho android 37

Viết xử lý

import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
public class RegisterActivity extends AppCompatActivity {
    AlertDialogManager alert = new AlertDialogManager();
    // Internet detector
    ConnectionDetector cd;
    // UI elements
    EditText txtName;
    EditText txtEmail;
    // Register button
    Button btnRegister;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_register);
        cd = new ConnectionDetector(getApplicationContext());
        // Check if Internet present
        if (!cd.isConnectingToInternet()) {
            // Internet Connection is not present
            alert.showAlertDialog(RegisterActivity.this,
                    "Internet Connection Error",
                    "Please connect to working Internet connection", false);
            // stop executing code by return
            return;
        }
        // Check if GCM configuration is set
        if (CommonUtilities.SERVER_URL == null || CommonUtilities.SENDER_ID == null || CommonUtilities.SERVER_URL.length() == 0
                || CommonUtilities.SENDER_ID.length() == 0) {
            // GCM sernder id / server url is missing
            alert.showAlertDialog(RegisterActivity.this, "Configuration Error!",
                    "Please set your Server URL and GCM Sender ID", false);
            // stop executing code by return
            return;
        }
        txtName = (EditText) findViewById(R.id.txtName);
        txtEmail = (EditText) findViewById(R.id.txtEmail);
        btnRegister = (Button) findViewById(R.id.btnRegister);
        /*
         * Click event on Register button
         * */
        btnRegister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View arg0) {
                // Read EditText dat
                String name = txtName.getText().toString();
                String email = txtEmail.getText().toString();
                // Check if user filled the form
                if (name.trim().length() > 0 && email.trim().length() > 0) {
                    // Launch Main Activity
                    Intent i = new Intent(getApplicationContext(), MainActivity.class);
                    // Registering user on our server
                    // Sending registraiton details to MainActivity
                    i.putExtra("name", name);
                    i.putExtra("email", email);
                    startActivity(i);
                    finish();
                } else {
                    // user doen't filled that data
                    // ask him to fill the form
                    alert.showAlertDialog(RegisterActivity.this, "Registration Error!", "Please enter your details", false);
                }
            }
        });
    }
}

5.11. Thiết kế và viết xử lý cho MainActivity

Thiết kế layout

google cloud messaging cho android 38

Viết xử lý

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;
import com.google.android.gcm.GCMRegistrar;
import static android.gcmdemo.CommonUtilities.DISPLAY_MESSAGE_ACTION;
import static android.gcmdemo.CommonUtilities.EXTRA_MESSAGE;
import static android.gcmdemo.CommonUtilities.SENDER_ID;
public class MainActivity extends AppCompatActivity {
    // label to display gcm messages
    TextView lblMessage;
    // Asyntask
    AsyncTask<Void, Void, Void> mRegisterTask;
    // Alert dialog manager
    AlertDialogManager alert = new AlertDialogManager();
    // Connection detector
    ConnectionDetector cd;
    public static String name;
    public static String email;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
//        GCMRegistrar.unregister(getApplicationContext());
        cd = new ConnectionDetector(getApplicationContext());
        // Check if Internet present
        if (!cd.isConnectingToInternet()) {
            // Internet Connection is not present
            alert.showAlertDialog(MainActivity.this,
                    "Internet Connection Error",
                    "Please connect to working Internet connection", false);
            // stop executing code by return
            return;
        }
        // Getting name, email from intent
        Intent i = getIntent();
        name = i.getStringExtra("name");
        email = i.getStringExtra("email");
        // Make sure the device has the proper dependencies.
        GCMRegistrar.checkDevice(this);
        // Make sure the manifest was properly set - comment out this line
        // while developing the app, then uncomment it when it's ready.
        GCMRegistrar.checkManifest(this);
        lblMessage = (TextView) findViewById(R.id.lblMessage);
        registerReceiver(mHandleMessageReceiver, new IntentFilter(DISPLAY_MESSAGE_ACTION));
        // Get GCM registration id
        final String regId = GCMRegistrar.getRegistrationId(this);
        // Check if regid already presents
        if (regId.equals("")) {
            // Registration is not present, register now with GCM
            GCMRegistrar.register(this, SENDER_ID);
        } else {
            // Device is already registered on GCM
            if (GCMRegistrar.isRegisteredOnServer(this)) {
                // Skips registration.
                Toast.makeText(getApplicationContext(), "Already registered with GCM", Toast.LENGTH_LONG).show();
            } else {
                // Try to register again, but not in the UI thread.
                // It's also necessary to cancel the thread onDestroy(),
                // hence the use of AsyncTask instead of a raw thread.
                final Context context = this;
                mRegisterTask = new AsyncTask<Void, Void, Void>() {
                    @Override
                    protected Void doInBackground(Void... params) {
                        // Register on our server
                        // On server creates a new user
                        ServerUtilities.register(context, name, email, regId);
                        return null;
                    }
                    @Override
                    protected void onPostExecute(Void result) {
                        mRegisterTask = null;
                    }
                };
                mRegisterTask.execute(null, null, null);
            }
        }
    }
    /**
     * Receiving push messages
     * */
    private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
            // Waking up mobile if it is sleeping
            WakeLocker.acquire(getApplicationContext());
            /**
             * Take appropriate action on this message
             * depending upon your app requirement
             * For now i am just displaying it on the screen
             * */
            // Showing received message
            lblMessage.append(newMessage + "\n");
            Toast.makeText(getApplicationContext(), "New Message: " + newMessage, Toast.LENGTH_LONG).show();
            // Releasing wake lock
            WakeLocker.release();
        }
    };
    @Override
    protected void onDestroy() {
        if (mRegisterTask != null) {
            mRegisterTask.cancel(true);
        }
        try {
            unregisterReceiver(mHandleMessageReceiver);
            GCMRegistrar.onDestroy(this);
        } catch (Exception e) {
            Log.e("UnRegister Receiver Error", e.getMessage());
        }
        super.onDestroy();
    }
}

5.12. Nội dung tập tin AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="android.gcmdemo">
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <permission
        android:name="android.gcmdemo.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="android.gcmdemo.permission.C2D_MESSAGE" />
    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
        </activity>
    <activity android:name=".RegisterActivity" >
        <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.gcm.GCMBroadcastReceiver"
        android:permission="com.google.android.c2dm.permission.SEND" >
        <intent-filter>
            <!-- Receives the actual messages. -->
            <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            <!-- Receives the registration id. -->
            <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
            <category android:name="android.gcmdemo" />
        </intent-filter>
    </receiver>
    <service android:name=".GCMIntentService"/>
    </application>
</manifest>

Một số lưu ý đối với tập tin AndroidManifest.xml

google cloud messaging cho android 39
google cloud messaging cho android 40

Thiết lập Emulator

Tại màn hình Settings -> chọn Account

google cloud messaging cho android 19

Chọn Google

google cloud messaging cho android 9
google cloud messaging cho android 11

Nhập tài khoản gmail của các bạn

google cloud messaging cho android 11

Chọn ACCEPT

google cloud messaging cho android 12

Chọn NEXT

google cloud messaging cho android 13

Các bạn đã hoàn thành xong bài hướng dẫn google cloud messaging cho android. Hãy chạy ứng dụng và cảm nhận kết quả.

Alert: You are not allowed to copy content or view source !!