利用GCM进行消息推送
原理
1、接收端向GCM注册registerid
2、发送端发消息给GCM服务器
这个过程需要三个参数:
(1)API Key
(2)registerid
(3)传递的数据
3、GCM端将消息转发给注册的设备(通过注册的registerid)
准备工作
1、projectid
这个是项目id,通过Google API控制台页面可以申请到。具体步骤不详细说了,网上好多。
class="p0">申请网址:https://code.google.com/apis/console/
2、API Key
这个是Google为新建的项目分配的API,大概类似下面这样。与上面projectid可以一块申请到。
apikey:AIzaSyAmCeG5SHgiJRqXWM4TyS2LiQhAsKHGOVA
3、安装Google服务
打开Android SDK Manager,安装Extras > Google Cloud Messaging for Android Library。
安装完之后会在你的SDK路径下的extras/google/目录下创建一个gcm文件夹,gcm文件夹下包含:gcm-client,gcm-demo-appengine, gcm-demo-client, gcm-demo-server, and gcm-server子目录。
好了,到此为止,准备工作做完了,下面直接上代码。
客户端
1)、工程建好之后,首先把gcm.jar和google-play-services.jar两个jar包拷贝到libs目录下。
两个包可以从SDK下的extras/google/gcm-client目录下找到。
2)、配置AndroidManifest.xml文件
添加权限:
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="工程的包名.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="工程的包名.permission.C2D_MESSAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
添加服务:
<service android:name=".GCMIntentService" />
添加广播接收器:
<receiver
android:name="com.google.android.gcm.GCMBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<category android:name="工程的包名" />
</intent-filter>
</receiver>
3)、实现GCMIntentService类
1 package com.example.gcmdemo; 2 3 import android.content.Context; 4 import android.content.Intent; 5 import android.os.Handler; 6 import android.os.Looper; 7 import android.util.Log; 8 import android.widget.Toast; 9 10 import com.google.android.gcm.GCMBaseIntentService; 11 12 /** 13 * IntentService responsible for handling GCM messages. 14 */ 15 public class GCMIntentService extends GCMBaseIntentService { 16 17 public GCMIntentService() { 18 super(CommonData.SENDER_ID); 19 } 20 21 //Get the registered broadcast from GCM 22 @Override 23 protected void onRegistered(Context context, String registrationId) { 24 // TODO Register from the server 25 Log.i("GCMIntentService", "onRegistered注册成功"); 26 } 27 28 //Get the unregistered broadcast from GCM 29 //Not used yet 30 @Override 31 protected void onUnregistered(Context context, String registrationId) { 32 // TODO Unregister from the server 33 Log.i("GCMIntentService", "onRegistered注册失败"); 34 } 35 36 //Get the message broadcast from GCM 37 @Override 38 protected void onMessage(Context context, Intent intent) { 39 Log.i("GCMIntentService", "接收到一条新消息:"+intent.getStringExtra("mine")); 40 final String info = intent.getStringExtra("mine"); 41 Handler handler = new Handler(Looper.getMainLooper()); 42 handler.post(new Runnable() { 43 44 @Override 45 public void run() { 46 Toast.makeText(getBaseContext(), "新消息:"+info, Toast.LENGTH_LONG).show(); 47 } 48 }); 49 } 50 51 @Override 52 public void onError(Context context, String errorId) { 53 Log.e(TAG, "Received error: " + errorId); 54 } 55 56 @Override 57 protected boolean onRecoverableError(Context context, String errorId) { 58 Log.e(TAG, "Received recoverable error: " + errorId); 59 return super.onRecoverableError(context, errorId); 60 } 61 }
4)、实现主Activity类
1 package com.example.gcmdemo; 2 3 import android.app.Activity; 4 import android.content.Context; 5 import android.os.Bundle; 6 import android.util.Log; 7 import android.view.Menu; 8 import android.view.View; 9 import android.view.View.OnClickListener; 10 import android.widget.Button; 11 12 import com.google.android.gcm.GCMRegistrar; 13 14 public class MainActivity extends Activity { 15 private static final String SENDER_ID = "655266950018"; 16 private Context mContext = null; 17 18 @Override 19 public void onCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 23 mContext = getApplicationContext(); 24 25 //点击后注册GCM,接收消息 26 Button registerBtn = (Button) findViewById(R.id.register); 27 registerBtn.setOnClickListener(new OnClickListener() { 28 @Override 29 public void onClick(View v) { 30 // checkDevice()检查系统版本及是否装有google service frame(GCM服务需要安装有谷歌服务包,且系统版本2.2及以上的才支持) 31 GCMRegistrar.checkDevice(mContext); 32 // 检查AndroidManifest.xml文件是否有配置有必须的权限及广播接收器是否有正确的权限和过滤器,是否可以正常接收广播) 33 GCMRegistrar.checkManifest(mContext); 34 35 final String registerid= GCMRegistrar.getRegistrationId(mContext); 36 if (regId.equals("")) { 37 // 注册一个GCM服务,它会启动一个action名为com.google.android.c2dm.intent.REGISTER的服务 38 GCMRegistrar.register(mContext, SENDER_ID); 39 Log.i(CommonData.TAG, "新设备:"+GCMRegistrar.isRegistered(mContext)+GCMRegistrar.getRegistrationId(mContext)); 40 } else { 41 Log.i(CommonData.TAG, "Already registered"); 42 } 43 } 44 }); 45 46 //点击后解除注册,不接收消息 47 Button unRegisterBtn = (Button) findViewById(R.id.unregister); 48 unRegisterBtn.setOnClickListener(new OnClickListener() { 49 @Override 50 public void onClick(View v) { 51 GCMRegistrar.unregister(getBaseContext()); 52 } 53 }); 54 } 55 56 @Override 57 public boolean onCreateOptionsMenu(Menu menu) { 58 getMenuInflater().inflate(R.menu.activity_main, menu); 59 return true; 60 } 61 }
注:1、SENDER_ID即为准备工作1中申请的projectid
2、GCMRegistrar.getRegistrationId(mContext); 的返回值作为推送服务器的registerid
OK,至此,客户端已经建立完成了。(^_^)
服务器
1)、工程建好之后,首先把gcm-server.jar包拷贝到lib目录下。
可以从SDK下的extras/google/gcm-demo-server目录下找到。
2)、推送服务器源码(java实现)
1 package com.push.server; 2 import java.util.ArrayList; 3 import java.util.List; 4 5 import com.google.android.gcm.server.Message; 6 import com.google.android.gcm.server.MulticastResult; 7 import com.google.android.gcm.server.Sender; 8 9 public class SendToGCM{ 10 private static final String API_KEY = "AIzaSyB8t4b-Aj_ZP1Sn9BeILUEiWwJIiyfQ5yc"; 11 12 public void send() { 13 System.out.println("send to GCM start............"); 14 // 一对一推送 15 //Result result = null; 16 // 群发 17 MulticastResult result = null; 18 19 List <String> registerids = new ArrayList<String>(); 20 // "xxx" is registerId get from client 21 registerids.add(0, "registerid"); 22 //send message 23 try { 24 Sender sender = new Sender(API_KEY); 25 Message message = new Message.Builder().collapseKey("1").timeToLive(3). 26 delayWhileIdle(true).addData("title", "新消息"). 27 addData("message", "this is a new message!").build(); 28 /************************Multicast*****************************/ 29 result = sender.send(message, registerids, 5); 30 31 System.out.println("result.getResults()=" + result.getResults() 32 + "\nresult.getSuccess()=" + result.getSuccess() 33 + "\nresult.getFailure()=" + result.getFailure() 34 + "\nresult.getCanonicalIds()=" + result.getCanonicalIds() 35 + "\nresult.getMulticastId()=" + result.getMulticastId() 36 + "\nresult.getTotal()=" + result.getTotal() 37 + "\nresult.getRetryMulticastIds()=" + result.getRetryMulticastIds() 38 ); 39 if (result.getResults() != null) { 40 int canonicalRegId = result.getCanonicalIds(); 41 if (canonicalRegId != 0) { 42 // same device has more than on registration ID: update database 43 System.out.println("same device has more than on registration ID: update database"); 44 } 45 } 46 else { 47 int error = result.getFailure(); 48 System.out.println("Broadcast failure: " + error); 49 } 50 /************************Multicast*****************************/ 51 52 /************************Unicast******************************/ 53 /* 54 result = sender.send(message, registerids.get(0), 5); 55 System.out.println("result.getMessageId()=" + result.getMessageId() + 56 "\nresult.getCanonicalRegistrationId()" + result.getCanonicalRegistrationId() + 57 "\nresult.getErrorCodeName()" + result.getErrorCodeName()); 58 if (result.getMessageId() != null) { 59 String canonicalRegId = result.getCanonicalRegistrationId(); 60 if (canonicalRegId != null) { 61 // same device has more than on registration ID: update database 62 } 63 } 64 else { 65 String error = result.getErrorCodeName(); 66 if (error.equals(Constants.ERROR_NOT_REGISTERED)) { 67 // application has been removed from device - unregister database 68 } 69 } 70 */ 71 /************************Unicast******************************/ 72 } catch (Exception e) { 73 e.printStackTrace(); 74 } 75 System.out.println("send to GCM end............"); 76 } 77 }
注:
1、API_KEY 即为准备工作2中申请到的apikey
2、registerid即为主Activity中GCMRegistrar.getRegistrationId(mContext); 的返回值
OK,至此,服务端的构筑也已经完成了。
特点
下面总结一下GCM的优缺点,不全,欢迎补足指正
优点:
1、Google提供的服务,原生,简单,不需实现部署服务器端
2、提供群发和单一推送功能
3、提供延时发送功能。如果当前手机不在线,Google会把这个消息入队并存储这个消息,当用户在线时再进行发送。存活时间在发送端进行指定。
4、应用程序不需要提前运行来接收这个消息。在手机端,系统使用适当的permission通过Intent broadcast把这个消息broadcast到特定的程序,然后特定的程序获得这个消息。这样就唤醒了这个程序。
缺点:
1、android版本的限制(android2.2以上)
2、该服务在国内不够稳定,尤其现在,Google被封,所以要想在国内使用建议还是放弃
3、不能保证消息的发送和消息的发送顺序
4、它不提供任何的用户界面或者其他的东西来处理消息。C2DM只是简单的把收到的原始消息传递给程序。这个程序提供了处理这个消息的方法