Google Cloud Message for Android(GCM推送)(最新版)
(GCM是google在2013年的IO大会发布的新服务,然后.....国内的大部分的开发者服务商都加了该功能,国内的话友盟为代表,要搞海外的话就只能用google了,用来推更新,推广告啥的,不过不能太频繁,不像36x手机助手,裤兜里装一会掏出来一屏幕通知栏推送,你在逗我吗?我这个刚刚写的新的,网上有好多之前写的,你发现流程图片和google的后台页面都变了)
google云推送服务允许你从自己的服务端发送数据到用户的Android设备,同时还可以接受来自同一链接发来的信息,GCM服务处理所有的消息队列来把消息交付给目标设备并在目标设备上运行,GCM是完全免费不管你有多大的数据请求。
一.重点功能
1.从服务端发送消息到用户的android设备:通过云端将轻量级的信息从服务端告诉你的app(例如,一个朋友上传的movie),或者能够上传包含4kb的有效数据(例如像一些及时通讯app可以直接使用)。
2.发送同步消息:发送“同步消息”通常是一个“痒”(不知道google为啥要用这样一个词),用来从服务器同步数据。比如,假设给你email app,当你的用户接收到一份新邮件从服务端,云将会告诉app去同步这份新邮件从服务端。
3.发送信息的有效载荷:不想一个发送同步消息,每个消息的传送有4kb的有效载荷。
二.新特新
1.返回收据:你可以使用!!去确认收到了一个消息,你的第三方服务端应用程序接受通知确认被发送的消息
2.开始:
三.概述
概述内容太长,我就不一一翻译了。内容大概就是介绍GCM到底是个啥,作为开发者我们只要学会怎么用就可以了,那么GCM到底是个啥呢?先看一下官方给出的图:
3rd-Party App Server:第三方服务端,就是我们应用自己的服务端。
手机:就是客户端
中间的云:google的gcm服务
那么说了这么多废话,到底是怎么推送的呢?看了上图之后你应该看出来了,我们需要一个服务端,一个客户端; 整个的推送流程就是,客户端先请求gcm服务,gcm会根据算法生成一个registerId,大概有30多个字符的字符串,接下来,客户端会把这个registerId发送到我们自己的第三方服务端,第三方服务端也就是我们自己的服务端了,第三方服务端会接受到很多registerId,推送的时候在服务端把registerId和要推送的信息封装成一个Json并发给google,google负责把消息推送给android设备(后面会引导大家注册APIkey),那么为什么我们不直接推送到android设备呢,我觉得google服务器那么多,你要是只做个推送功能的话全世界都可以推,用的是google的服务器,要用自己的服务端发给android设备的话就难了,google简化了过程。
服务端:先去https://console.developers.google.com/project,
1.登录帐号之后Create Project填写名称
2.左侧APIs & auth / Credentials 启用Google Cloud Messaging For Android API ---> 创建 Create New Key --> 选择Server Key 不要填写任何IP(之前我填写了自己服务端的IP地址,结果怎么都推送不了,允许任何IP之后就好了,低级错误)
3.注册流程图
2显示的是创建好的Server Key,我们要用其中生成的API Key。按文档说法,Server可以用XMPP和HTTP。
服务端要把一个拼接好的Json发给google。
For example:
{
"registration_ids":["收集到的设备id1","收集到的设备id2","收集到的设备id3","",""],
"data":{
...}}
data用HTTP时中可以传的字段:
registration_id:设备id
collapse_key:可选的崩溃信息
data:数据
delay_while_idle:没看明白,可选
time_to_live:可选
restricted_package_name:可选
dry_run:可选
发送数据之后google会返回结果(内容太多了,反悔结果说明又需要一篇博客说明)
客户端:
1.客户端:创建一个android项目之后就是添加各种权限,引用gcm.jar,新建GcmIntentService,调用注册,发送registerId到第三方服务端,等待接受推送消息。
注册的权限和Service,Reciver组件
<manifest package="com.example.gcm" ...> <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="17"/> <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="com.google.android.c2dm.permission.RECEIVE" /> <permission android:name="com.example.gcm.permission.C2D_MESSAGE" android:protectionLevel="signature" /> <uses-permission android:name="com.example.gcm.permission.C2D_MESSAGE" /> <application ...> <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.example.gcm" /> </intent-filter> </receiver> <service android:name=".GcmIntentService" /> </application> </manifest>新建一个类,类名必须是GcmIntentService,继承 IntentService,这个Service不需要我们自己启动,是有gcm自己我启动的,我们只需在主线程中调用注册就行了。剩下的交给gcm了。可见,该Service用一个Notification来展示接收到的信息。
public class GcmIntentService extends IntentService { public static final int NOTIFICATION_ID = 1; private NotificationManager mNotificationManager; NotificationCompat.Builder builder; public GcmIntentService() { super("GcmIntentService"); } @Override protected void onHandleIntent(Intent intent) { Bundle extras = intent.getExtras(); GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this); // The getMessageType() intent parameter must be the intent you received // in your BroadcastReceiver. String messageType = gcm.getMessageType(intent); if (!extras.isEmpty()) { // has effect of unparcelling Bundle /* * Filter messages based on message type. Since it is likely that GCM * will be extended in the future with new message types, just ignore * any message types you're not interested in, or that you don't * recognize. */ if (GoogleCloudMessaging. MESSAGE_TYPE_SEND_ERROR.equals(messageType)) { sendNotification("Send error: " + extras.toString()); } else if (GoogleCloudMessaging. MESSAGE_TYPE_DELETED.equals(messageType)) { sendNotification("Deleted messages on server: " + extras.toString()); // If it's a regular GCM message, do some work. } else if (GoogleCloudMessaging. MESSAGE_TYPE_MESSAGE.equals(messageType)) { // This loop represents the service doing some work. for (int i=0; i<5; i++) { Log.i(TAG, "Working... " + (i+1) + "/5 @ " + SystemClock.elapsedRealtime()); try { Thread.sleep(5000); } catch (InterruptedException e) { } } Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime()); // Post notification of received message. sendNotification("Received: " + extras.toString()); Log.i(TAG, "Received: " + extras.toString()); } } // Release the wake lock provided by the WakefulBroadcastReceiver. GcmBroadcastReceiver.completeWakefulIntent(intent); } // Put the message into a notification and post it. // This is just one simple example of what you might choose to do with // a GCM message. private void sendNotification(String msg) { mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE); PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, DemoActivity.class), 0); NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this) .setSmallIcon(R.drawable.ic_stat_gcm) .setContentTitle("GCM Notification") .setStyle(new NotificationCompat.BigTextStyle() .bigText(msg)) .setContentText(msg); mBuilder.setContentIntent(contentIntent); mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build()); } }
调用是这么调的,调之前要判断一下像小米这样的太监手机(被阉割了google服务的手机不能使用google推送的)
if (checkPlayServices()) { GcmRegistrar.checkDevice(this);GcmRegistrar.checkManifest(this);if (regid.isEmpty()) { GcmRegistrar.register();}else{提交到自己的后台;post/get不限 } } else { Log.i(TAG, "No valid Google Play Services APK found."); } 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; }推送:服务端接收到设备ID之后,推送消息,客户端就可以等着接受了。SDK中simple文件家下有个gcm demo文件夹,我这里有个从Github找的python的服务端,很基本的推送功能,csdn的下载功能不给力呀。
百度云:http://pan.baidu.com/s/1dDBzipz(修改Server的APIKEY,客户端的SEND_ID:截图中的一川数字,Server_url:自己的服务端地址)