利用GCM进行消息推送

原理

1、接收端向GCM注册registerid

2、发送端发消息给GCM服务器

这个过程需要三个参数:

(1)API Key

(2)registerid

(3)传递的数据

3、GCM端将消息转发给注册的设备(通过注册的registerid)

准备工作

1、projectid

这个是项目id,通过Google API控制台页面可以申请到。具体步骤不详细说了,网上好多。

申请网址: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类

 package com.example.gcmdemo;

 import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast; import com.google.android.gcm.GCMBaseIntentService; /**
* IntentService responsible for handling GCM messages.
*/
public class GCMIntentService extends GCMBaseIntentService { public GCMIntentService() {
super(CommonData.SENDER_ID);
} //Get the registered broadcast from GCM
@Override
protected void onRegistered(Context context, String registrationId) {
// TODO Register from the server
Log.i("GCMIntentService", "onRegistered注册成功, registrationId=" + registrationId);
} //Get the unregistered broadcast from GCM
//Not used yet
@Override
protected void onUnregistered(Context context, String registrationId) {
// TODO Unregister from the server
Log.i("GCMIntentService", "onRegistered注册失败");
} //Get the message broadcast from GCM
@Override
protected void onMessage(Context context, Intent intent) {
Log.i("GCMIntentService", "接收到一条新消息:"+intent.getStringExtra("mine"));
final String info = intent.getStringExtra("mine");
Handler handler = new Handler(Looper.getMainLooper());
handler.post(new Runnable() { @Override
public void run() {
Toast.makeText(getBaseContext(), "新消息:"+info, Toast.LENGTH_LONG).show();
}
});
} @Override
public void onError(Context context, String errorId) {
Log.e(TAG, "Received error: " + errorId);
} @Override
protected boolean onRecoverableError(Context context, String errorId) {
Log.e(TAG, "Received recoverable error: " + errorId);
return super.onRecoverableError(context, errorId);
}
}

注 :将protected void onRegistered(Context context, String registrationId)返回的registrationId发送到推送服务器

4)、实现主Activity类

 package com.example.gcmdemo;

 import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button; import com.google.android.gcm.GCMRegistrar; public class MainActivity extends Activity {
private static final String SENDER_ID = "655266950018";
private Context mContext = null; @Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); mContext = getApplicationContext(); //点击后注册GCM,接收消息
Button registerBtn = (Button) findViewById(R.id.register);
registerBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// checkDevice()检查系统版本及是否装有google service frame(GCM服务需要安装有谷歌服务包,且系统版本2.2及以上的才支持)
GCMRegistrar.checkDevice(mContext);
// 检查AndroidManifest.xml文件是否有配置有必须的权限及广播接收器是否有正确的权限和过滤器,是否可以正常接收广播)
GCMRegistrar.checkManifest(mContext); final String registerid= GCMRegistrar.getRegistrationId(mContext);
if (regId.equals("")) {
// 注册一个GCM服务,它会启动一个action名为com.google.android.c2dm.intent.REGISTER的服务
GCMRegistrar.register(mContext, SENDER_ID);
Log.i(CommonData.TAG, "新设备:"+GCMRegistrar.isRegistered(mContext)+GCMRegistrar.getRegistrationId(mContext));
} else {
Log.i(CommonData.TAG, "Already registered");
}
}
}); //点击后解除注册,不接收消息
Button unRegisterBtn = (Button) findViewById(R.id.unregister);
unRegisterBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
GCMRegistrar.unregister(getBaseContext());
}
});
} @Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}

注:1、SENDER_ID即为准备工作1中申请的projectid

OK,至此,客户端已经建立完成了。(^_^)

服务器

1)、工程建好之后,首先把gcm-server.jar包拷贝到lib目录下。

可以从SDK下的extras/google/gcm-demo-server目录下找到。

2)、推送服务器源码(java实现)

 package com.push.server;
import java.util.ArrayList;
import java.util.List; import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.MulticastResult;
import com.google.android.gcm.server.Sender; public class SendToGCM{
private static final String API_KEY = "AIzaSyB8t4b-Aj_ZP1Sn9BeILUEiWwJIiyfQ5yc"; public void send() {
System.out.println("send to GCM start............");
// 一对一推送
//Result result = null;
// 群发
MulticastResult result = null; List <String> registerids = new ArrayList<String>();
// "xxx" is registerId get from client
registerids.add(0, "registerid");
//send message
try {
Sender sender = new Sender(API_KEY);
Message message = new Message.Builder().collapseKey("1").timeToLive(3).
delayWhileIdle(true).addData("title", "新消息").
addData("message", "this is a new message!").build();
/************************Multicast*****************************/
result = sender.send(message, registerids, 5); System.out.println("result.getResults()=" + result.getResults()
+ "\nresult.getSuccess()=" + result.getSuccess()
+ "\nresult.getFailure()=" + result.getFailure()
+ "\nresult.getCanonicalIds()=" + result.getCanonicalIds()
+ "\nresult.getMulticastId()=" + result.getMulticastId()
+ "\nresult.getTotal()=" + result.getTotal()
+ "\nresult.getRetryMulticastIds()=" + result.getRetryMulticastIds()
);
if (result.getResults() != null) {
int canonicalRegId = result.getCanonicalIds();
if (canonicalRegId != 0) {
// same device has more than on registration ID: update database
System.out.println("same device has more than on registration ID: update database");
}
}
else {
int error = result.getFailure();
System.out.println("Broadcast failure: " + error);
}
/************************Multicast*****************************/ /************************Unicast******************************/
/*
result = sender.send(message, registerids.get(0), 5);
System.out.println("result.getMessageId()=" + result.getMessageId() +
"\nresult.getCanonicalRegistrationId()" + result.getCanonicalRegistrationId() +
"\nresult.getErrorCodeName()" + result.getErrorCodeName());
if (result.getMessageId() != null) {
String canonicalRegId = result.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// same device has more than on registration ID: update database
}
}
else {
String error = result.getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
// application has been removed from device - unregister database
}
}
*/
/************************Unicast******************************/
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("send to GCM end............");
}
}

注:

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只是简单的把收到的原始消息传递给程序。这个程序提供了处理这个消息的方法

消息推送之GCM的更多相关文章

  1. Android消息推送之GCM方式(二)

    <声明> 转载请保留本来源地址: http://blog.csdn.net/wzg_1987/article/details/9148023 上一节讲了GCM方式实现前的一些必要准备工作, ...

  2. Android消息推送之GCM方式(一)

    <声明> 转载请保留本来源地址: http://blog.csdn.net/wzg_1987/article/details/9140371 首先,你需要使用一个谷歌账号登录谷歌Api控制 ...

  3. Android P正式版即将到来:后台应用保活、消息推送的真正噩梦

    1.前言 对于广大Android开发者来说,Android O(即Android 8.0)还没玩热,Andriod P(即Andriod 9.0)又要来了.   下图上谷歌官方公布的Android P ...

  4. 基于APNs最新HTTP/2接口实现iOS的高性能消息推送(服务端篇)

    1.前言 本文要分享的消息推送指的是当iOS端APP被关闭或者处于后台时,还能收到消息/信息/指令的能力. 这种在APP处于后台或关闭情况下的消息推送能力,通常在以下场景下非常有用: 1)IM即时通讯 ...

  5. 了解iOS消息推送一文就够:史上最全iOS Push技术详解

    本文作者:陈裕发, 腾讯系统测试工程师,由腾讯WeTest整理发表. 1.引言 开发iOS系统中的Push推送,通常有以下3种情况: 1)在线Push:比如QQ.微信等IM界面处于前台时,聊天消息和指 ...

  6. 使用GCM服务(Google Cloud Messaging)实现Android消息推送

    最近在网上查了关于很多Android消息推送的资料,其中主要有四种方法. 1) 使用GCM服务(Google Cloud Messaging) 2) 使用XMPP协议(Openfire + Spark ...

  7. [转]PhoneGap使用PushPlugin插件实现消息推送

    本文转自:http://my.oschina.net/u/1270482/blog/217661 http://devgirl.org/2013/07/17/tutorial-implement-pu ...

  8. Android 基于Netty的消息推送方案之Hello World(一)

    消息推送方案(轮询.长连接) 轮询 轮询:比较简单的,最容易理解和实现的就是客户端去服务器上拉信息,信息的及时性要求越高则拉信息的频率越高.客户端拉信息的触发可以是一些事件,也可以是一个定时器,不断地 ...

  9. Android消息推送(二)--基于MQTT协议实现的推送功能

    国内的Android设备,不能稳定的使用Google GCM(Google Cloud Messageing)消息推送服务. 1. 国内的Android设备,基本上从操作系统底层开始就去掉了Googl ...

随机推荐

  1. Android应用框架浅析

    http://blog.csdn.net/yanbober/article/category/3206943 Android应用层View绘制流程与源码分析   http://blog.csdn.ne ...

  2. C++学习34 模板类

    C++除了支持模板函数,还支持模板类.模板类的目的同样是将数据类型参数化. 声明模板类的语法为: template<typename 数据类型参数 , typename 数据类型参数 , …&g ...

  3. Plan9 与 Plan9port

    Plan9 Plan9 是一个操作系统.由贝尔实验室开发的,其主要的负责人是Rob Pike(现在在google工作,负责Go语言的开发). 参考:http://www.cnblogs.com/yjf ...

  4. MSSQL中的随机函数

    随机函数:rand()在查询分析器中执行:select rand(),可以看到结果会是类似于这样的随机小数:0.36361513486289558,像这样的小数在实际应用中用得不多,一般要取随机数都会 ...

  5. Codeforces 716C[数论][构造]

    /* CF傻逼构造题 某人要经过n回合游戏,初始分值是2,等级为1. 每次有两种操作 1.无条件,分值加上自己的等级数. 2.当目前的数字是完全平方数并且该数字开方以后是等级数加1的整数倍,那么可以将 ...

  6. POJ 2396 Budget【网络流】

    题意: cas           //测试数据组数 n m         //行数 列数 a1 a2 ... an    //每行的和 b1 b2 ... bn   //每列的和 q       ...

  7. Java String 的实例(02)

    1.初始化数组以及数组的拷贝 int[] a={1,2,3,4};        //System.out.println(Arrays.toString(a));        a=new int[ ...

  8. 【转】关系映射文件***.hbm.xml详解

    http://blog.sina.com.cn/s/blog_7ffb8dd5010144yo.html 附.Oracle使用标准.可变长度的内部格式来存储数字.这个内部格式精度可以高达38位. NU ...

  9. OC基础(1)

    Objective-C简介 OC和C对比 第一个OC程序 面向对象思想 *:first-child { margin-top: 0 !important; } body > *:last-chi ...

  10. CODESOFT中线条形状该如何绘制

    CODESOFT条码设计软件提供了一系列工具,可帮助您设计完美的标签.在CODESOFT进行标签设计时,经常会需要创建除条码,文本对象除外的一些对象,那就是形状对象.如线条.圆形.矩形等.通过下面的示 ...