Triển khai GCM với Android (phần 2)

Ở phần một, mình đã giới thiệu GCM và hướng dẫn xây dựng được server side, phần tiếp theo sẽ là xây dựng client side. Let’s go!

Để tiếp tục phần hai, hãy chắc chắn bạn đã hoàn thành phần một (đã có file google-service.json trong thư mục app của project).

1. Khai báo thư viện

  • Tiến hành mở file build.gradle của app và khai báo như sau:
apply plugin: 'com.google.gms.google-services'
dependencies {
  compile "com.google.android.gms:play-services-gcm:8.4.0"
}
  • Tiếp tục mở file build.gradle của project
dependencies {
    classpath 'com.android.tools.build:gradle:1.5.0'
    classpath 'com.google.gms:google-services:2.0.0-alpha3'
}

Sau đó, tiến hành rebuild lại Project.

2. Khai báo GCM permission

Ứng dụng cần truy cập Internet và wake lock để gửi, nhận thông báo từ GCM server.

<manifest package="com.hungdh.gcmdemo">
  <uses-permission android:name="android.permission.INTERNET" />
  <uses-permission android:name="android.permission.WAKE_LOCK" />
  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
  <permission android:name="com.hungdh.gcmdemo.permission.C2D_MESSAGE"
      android:protectionLevel="signature" />
  <uses-permission android:name="com.hungdh.gcmdemo.permission.C2D_MESSAGE" />
</manifest>

3. Code, code, và code

Cấu trúc chương trình: ngoài class Main ra thì ta cần 3 class với chức năng như sau:

  1. RegistrationIntentService.java: một IntentService tiến hành tạo token và đăng kí token đó cho server mà ta đã xây dựng.

  2. MyInstanceIDListenerService.java: khi token thay đổi, sẽ gọi đến nó với phương thức onTokenRefresh.

  3. MyGcmListenerService.java: lắng nghe các thông tin từ GCM server (không phải server của ta tự xây dựng đâu) với phương thức onMessageReceived.

RegistrationIntentService.java

Như đã giới thiệu ở trên, class này sẽ tạo một instance ID từ Google và nó là duy nhất cho thiết bị và ứng dụng của bạn.

@Override
protected void onHandleIntent(Intent intent) {        
    ...
    // [START get token]
    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, "GCM Registration Token: " + token);
    ...
}

Giả sử yêu cầu này là thành công, bạn sẽ có một token. Và khi đó, ta sẽ tiến hành đăng kí token này lên server do chúng ta xây dựng với các tham số như đã xây dựng trong bảng gcm_users bằng phương thức sendRegistrationToServer.

Hãy nhớ đăng kí service này trong AndroidManifest.xml

</application>
    ...
    <service
        android:name=".RegistrationIntentService"
        android:exported="false">
    </service>
	...
</application>
MyInstanceIDListenerService.java

Theo tài liệu chính thức của Google, InstanceID sẽ có hạn sử dụng tối đa là 6 tháng. Để khắc phục điều này, ta cần extend từ InstanceIDListenerService để xử lý những thay đổi khi refresh token. Vì vậy, ta nên tạo MyInstanceIDListenerService.java để chạy RegistrationIntentService - giúp chúng ta lấy được token mới.

public class MyInstanceIDListenerService extends InstanceIDListenerService {
    @Override
    public void onTokenRefresh() {
        // Fetch updated Instance ID token and notify of changes
        Intent intent = new Intent(this, RegistrationIntentService.class);
        startService(intent);
    }
}
</application>
    <!-- [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] -->
</application>
Tạo Broadcast Receiver và Message Handler

Khai báo trong AndroidManifest.xml:

<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.codepath.gcmquickstart" />
  </intent-filter>
</receiver>
MyGcmListenerService.java

Tạo file MyGcmListenerService.java được extends từ GcmListenerService - sẽ xử lý việc nhận các thông báo từ phía GCM server:

public class MyGcmListenerService extends GcmListenerService {

    private static final String TAG = "MyGcmListenerService";

    // [START receive_message]
    @Override
    public void onMessageReceived(String from, Bundle data) {
        String message = data.getString("message");
        Log.d(TAG, "From: " + from);
        Log.d(TAG, "Message: " + message);
       
        sendNotification(message);
        // [END_EXCLUDE]
    }
    // [END receive_message]

    private void sendNotification(String message) {
        Intent intent = new Intent(this, MainActivity.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, 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("GCM Message")
                .setContentText(message)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);

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

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

Và không thể thiếu phần đăng kí service cho class

<service
android:name=".MyGcmListenerService"
android:exported="false" >
    <intent-filter>
        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
    </intent-filter>
</service>
MainActivity.java

4. Demo

Truy cập vào giao diện quản lý của server. Viết nội dung và gửi thông báo cho client.

Screenshot

Source code bạn có thể tham khảo tại đây.