利用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. Stream语法详解

    1. Stream初体验 我们先来看看Java里面是怎么定义Stream的: A sequence of elements supporting sequential and parallel agg ...

  2. shell 统计 awk

    time awk '{a[$1]++}END{for(i in a){printf("%d\t%s\n",a[i],i)}}' access.log | sort -nr | he ...

  3. C# 操作网页标签

    1  元素的 显示与隐藏   C# HTML: <div Id="div1" runat="server" style="display:non ...

  4. spring错误:<context:property-placeholder>:Could not resolve placeholder XXX in string value XXX

    spring同时集成redis和mongodb时遇到多个资源文件加载的问题 这两天平台中集成redis和mongodb遇到一个问题 单独集成redis和单独集成mongodb时都可以正常启动程序,但是 ...

  5. oracle客户端精简绿色版-环境变量配置

    大型项目开发中,常用的数据库,当属Oracle.但Oracle 客户端安装就要一张光盘,体积很大.而且安装后,基本上就用2个功能:TNS配置服务名,SqlPlus.在开发过程中,大量使用Toad和PL ...

  6. XMLHttpRequest的五步使用方法

    <html> <head> <title>Demo</title> <style> body,input,button,select,h1{ ...

  7. SparkSQL External Datasource简易使用之CSV

    下载源码&编译: git clone https://github.com/databricks/spark-csv.git sbt/sbt assembly Maven GAV: group ...

  8. HDFS副本机制&负载均衡&机架感知&访问方式&健壮性&删除恢复机制&HDFS缺点

    副本机制 1.副本摆放策略 第一副本:放置在上传文件的DataNode上:如果是集群外提交,则随机挑选一台磁盘不太慢.CPU不太忙的节点上:第二副本:放置在于第一个副本不同的机架的节点上:第三副本:与 ...

  9. HDU 4786 Fibonacci Tree

    Fibonacci Tree Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) P ...

  10. 手机app测试之我见

    app端功能测试不是单纯的点点点,在实际的工作中,测试小白需要从业务入手,熟悉基本测试点.测试技巧和方法,以点带面,从功能和思维入手,避免眼高手低: app端测试,首先我们需要考虑不同的机型系统.不同 ...