Features
- No sign up
- No quotas
- Battery efficiency
- Supports JSON and plaintext
Caveats
- Requires the user to set up a Google account
- Message delivery is NOT guaranteed
GCM vs C2DM
- Simple API key from Google API console page
- Sender ID is the project id rather than email address
- Supports JSON and plaintext
- Multicast message
- Multiple senders
- Messages have Time To Live
- 4kb max payload size
Why GCM?
- Scalability and extensibility
- Better use of device resources
- Cheaper than SMS
- No need to implement message queue
- Simpler application design
Architecture
- Server sends message to GCM server
- GCM queues message
- GCM sends message if device is online
- Android receives message and sends a broadcast
- App wakes up
- App processes the message
Device Requirements
- At least Froyo
- Google play services
- Google account
Server Requirements
- Able to store GCM registration ID
- Exponential backoff in case GCM server is down
- The usual request - response handling
Manifest
<receiver android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.hastagqq.app" />
</intent-filter>
</receiver>
<service android:name=".GcmIntentService" />
<meta-data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
Broadcast Receiver
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
private static final String TAG = GcmBroadcastReceiver.class.getSimpleName();
@Override
public void onReceive(Context context, Intent intent) {
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Intent Service
public class GcmIntentService extends IntentService {
private static final String TAG = GcmIntentService.class.getSimpleName();
public static final int NOTIFICATION_ID = 1;
public GcmIntentService() {
super(Constants.SENDER_ID);
}
@Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (extras != null && !extras.isEmpty()) {
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType)) {
sendNotification(getString(R.string.msg_view_news));
}
}
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
...
}
Intent Service cont.
private void sendNotification(String msg) {
NotificationManager notificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, MainActivity.class), 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(getString(R.string.msg_new_news))
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
builder.setContentIntent(contentIntent);
notificationManager.notify(NOTIFICATION_ID, builder.build());
}
Server
from gcm import GCM
gcm = GCM("YOUR_SERVER_KEY")
def send_gcm(db, location, message, gcm_id=None):
clients = [
device.gcm_id
for device in db.query(Device).filter(Device.location == location)
] if gcm_id is None and gcm_id == '' else [gcm_id]
gcm.json_request(registration_ids=clients, data=message)
Server cont.
class DeviceRegistrationHandler(web.RequestHandler):
def post(self):
...
gcm_message = {
'message': "New news item in your location.",
'timestamp': time.strftime('%Y-%m-%d %H:%M:%S', time.gmtime())
}
db.query(News).filter(News.location == location).count() > 0\
and send_gcm(db, location, gcm_message, gcm_id=device.gcm_id)
Other Alternatives
- Firebase
- Parse?
- Socket.io
- Autobahn
Who am I?
- Evan Dale Aromin
- coins.ph
- Android, Python, NodeJS
- @avendael
- avendael.com