GCM 传递参数

最近用了很多时间做GCM,由于碰到很多问题,因此详细做一下记录,以方便各位网友,不用再走我的重复的路.不过我试了一下GCM在国内很不好用.假如开发国外的程序的话,用GCM倒是很不错的选择.国内基本上封得不成样子了,十个请求发出去,有一个相应就不错了,其他的九个都被长城防火墙拦住了.

Google 的GCM最权威的当然是官网了.刚开始我照着官网做的,为了更完善一些,部分地方我直接用了网上的材料.红色的地方表示比较重要的地方.

1准备工作

1.要创建一个谷歌API项目:

打开谷歌API的控制台页面。(https://code.google.com/apis/console/)

如果你还没有创建一个API项目,这个页面会提示你这样做

如果您已经有项目,你看到的第一页将是仪表板页面。从那里你可以通过打开项目的下拉菜单(左上角),并选择Other>Create一个新的项目。

点击创建项目。Google会自动生成一个project Id. 这是你的项目ID,请注意这个Id 项目ID:382396212935 下面很多地方用到了.

2启用GCM服务

  1. 在谷歌API的控制页面的主页中,选择OverviewèAPIs&authèAPIs
  2. 在右侧找到:Google Cloud Messaging forAndroid按钮的状态值为ON。
  3. 在服务条款页面中接受这些条款。

3 获取一个Server API密钥

为了获取一个API密钥:在谷歌API控制台主页面中,选择项目之后,右侧有Overview,谷歌的界面已经更新了,但是很多网上还是原先的界面,让我走了弯路了.下面是最新的页面.

如上面显示的.先进入:OverView==>API&auth==>Credentials==>会出现如下画面,中间一列的下面有Public API access,看到下面的Key for server applications 了吗,里面有个API key ,这就是Google为新建的这个项目分配的API 我的是:key. :AIzaSyAmCeG5SHgiJRqXWM4TyS2LiQhAsKHGOVA

注:如果你的没有key for server applications的话,切记是Server application .不是上面的client Application.请点击Generate new key。一个新的密钥就会创建,而之前的密钥在未来24内仍然有效。如果你想让之前的密钥立即失效(例如:你认为它已经被破解了),请点击Delete key

4安装辅助库

在执行下面章节描述的步骤之前,请确保已经安装好辅助库。打开Android SDK Manager,安装Extras > Google Cloud Messaging for Android Library。这会在YOUR_SDK_ROOT/extras/google/目录下创建一个gcm文件夹,gcm文件夹下包含:gcm-client,gcm-demo-appengine, gcm-demo-client, gcm-demo-server, and gcm-server子目录。

注:SDK Manager版本要求r20以上,之前的版本发现不了GCM库。所以先打开eclipse升级ADT。

  1. 我的路径在:E:\android\adt-bundle-windows-x86-20130729\sdk 找到SDK Manager.exe,双击后出现:

在Extra==>底下的好几个library,装上之后,进入硬盘的这是我的路径:E:\android\adt-bundle-windows-x86-20130729\sdk\extras\google\gcm

在里面有gcm-client,gcm-server,samples.等等.里面有需要的架包.

2 GCM的原理

准备工作完成,说一下原理:Google Cloude Message,其实是通过一个Google Cloude Message ,做为平台.用户做两个应用,一个是发信息的应用,一个是接受信息的应用.发信息的把信息发给GCM Server,然后,GCM Server,再发给接收信息的一端.发送信息的时候需要传给GCM 三个参数(1)GCM Server API key,也就是我们刚才生成的API key (2)DeviceID,也就是说接收端的DeviceId,这个是在接收端运行的时候,首先需要向GCM服务器注册得到的Id,这样,GCM Server服务器知道改把信息传给那个设备.(3)传送的数据.

3 开始建立程序

按照上面的分析,首先要建立接收端:下面是我直接用了网上的材料,假如觉得很繁琐的话,可以将我的例子下下来一边看,一边对照,这样理解的更深入一些.

可以先直接下载:客户端:

步骤 1:拷贝gcm.jar到程序的classpath目录下

在编写程序之前,请先拷贝SDK目录下gcm-client/dist目录下的gcm.jar文件到程序的classpath。

步骤 2:按照以下步骤更改项目的AndroidManifest.xml文件

1.  GCM需要Android2.2或更高版本,所以如果你的程序不依赖GCM就无法正常工作,那么请在AndroidManifest文件中添加以下内容,“xx”处替换为最新的目标SDK版本号:

<uses-sdkandroid:minSdkVersion="8"android:targetSdkVersion="xx"/>

2.  声明并使用一个自定义的权限以此来确保只有这个程序可以接收你的GCM消息:

<permissionandroid:name="my_app_package.permission.C2D_MESSAGE"android:protectionLevel="signature"/><uses-permissionandroid:name="my_app_package.permission.C2D_MESSAGE"/>

这个权限必须称作:my_app_package.permission.C2D_MESSAG(程序包名.permission.C2D_MESSAG,程序包名就是在manifest文件中定义包名),不然将不能正常运行。

注:如果你的程序针对的是4.1或更高版本的系统(即,minSdkVersion 16),那么就不需要这个权限。

3.  添加权限接收GCM消息:

<uses-permissionandroid:name="com.google.android.c2dm.permission.RECEIVE"/>

4.  添加以下广播接收器:

<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="my_app_package"/>

</intent-filter>

</receiver>

这个Broadcast receiver负责处理2个从GCM发来的Intent(com.google.android.c2dm.intent.RECEIVE和com.google.android.c2dm.intent.REGISTRATION),并且要在manifest文件中定义(而非通过编码实现)。因此,这些Intent甚至可以在程序未运行的情况下被接收到。通过设置com.google.android.c2dm.permission.SEND权限,可以确保这些Intent只能通过GCM系统框架发送到这个receiver(普通程序是没有权限发出这些Intent的)。

注意在category标签里的android:name必须替换成你程序的包名(如果程序是针对16或更高的minSdkVersion的平台那么就不需要有category这个标签了)。

5.  添加以下Intent服务:

<service android:name=".GCMIntentService"/>

在下一步中,这个Intent服务会被GCMBroadcastReceiver(由GCM库提供)调用。它必须称作my_app_package.GCMIntentService,除非你用重写了GCMBroadcastRecevier方法的子类来作为此服务的名字。

步骤 3:实现my_app_package.GCMIntentService类

下面来实现my_app_package.GCMIntentService类,重写下面的几个回调方法(这些方法会被GCMBroadcastReceiver调用):

  • onRegistered(Context context, String regId): 收到注册Intent后此方法会被调用,GCM分配的注册ID会做为参数传递到设备/应用程序对。通常,你应该发送regid到你的服务器,这样服务器就可以根据这个regid发消息到设备上。
  • onUnregistered(Context context, String regId): 当设备从GCM注销时会被调用。通常你应该发送regid到服务器,这样就可以注销这个设备了。
  • onMessage(Context context, Intent intent): 当你的服务器发送了一个消息到GCM后会被调用,并且GCM会把这个消息传送到相应的设备。如果这个消息包含有效负载数据,它们的内容会作为Intent的extras被传送。
  • onError(Context context, String errorId): 当设备试图注册或注销时,但是GCM返回错误时此方法会被调用。通常此方法就是分析错误并修复问题而不会做别的事情。
  • onRecoverableError(Context context, String errorId): 当设备试图注册或注销时,但是GCM服务器无效时。GCM库会使用应急方案重试操作,除非这个方式被重写并返回false。这个方法是可选的并且只有当你想显示信息给用户或想取消重试操作的时候才会被重写。

注: 上面的方法运行在Intent服务的线程里,因此可以自由访问网络而不会阻塞UI线程。

步骤 4:实现你程序的主Activity

在你程序的主activity里添加下面的导入语句:

import com.google.android.gcm.GCMRegistrar;

在onCreate()方法里添加下面的代码:

GCMRegistrar.checkDevice(this);

GCMRegistrar.checkManifest(this);

final String regId = GCMRegistrar.getRegistrationId(this);

if (regId.equals("")) {

GCMRegistrar.register(this, SENDER_ID);

} else {

Log.v(TAG, "Already registered");

}

checkDevice()方法用来验证设备是否支持GCM,如果不支持会抛出异常(例如,模拟器就不包含Google APIs)。相似地,checkManifest()方法来验证程序的manifest包含了在开始编写Android程序中所有符合要求的描述(这个方法只有你在开发程序的时候需要;一旦这个程序准备发布的时候,你就可以把它移除掉)。

一旦这些健康检查做完了,就可以调用GCMRegsistrar.register()通过传送注册GCM时得到的SENDER_ID来注册设备了。但是由于GCMRegistrar单例保持跟踪所有收到的注册Intent的注册ID,所以可以先调用GCMRegistrar.getRegistrationId()方法检查此设备是否已经注册。

注:可能设备已经成功注册到GCM,但是没有成功发送注册ID到你的服务器,这种情况你应当重试。请查看高级主题来了解处理这种情况的更多详情。

这是我已经做好的程序:客户端:

下面是我的代码:

1.如上图所示,里面有个需要注意的问题,第一SENDER_ID这个是你在Google上建立项目的时候分配的ProjectID,就是我在上面用红色的背景色标出的.ProjectID.

这个程序的意思是:这个程序拿着ProjectID去GCM服务器注册,然后GCM返回一个regId,,当然如果走的程序不同,regId也不同.这个regId就是下面提到的的服务器端发送的第二个参数.DeviceID.下面要用到的,我的是:APA91bHHssnk-BjaLoRgjP0zrSqRBHmmgrNJy0pdNhsGNTlVS9jLZf9WOSp69Jx0bVRojm9oI0UiHfOipfgzgeyQEYST6ktnlYf7hSjtm4X_gky8jpo-89kdYuMjka29i5MYhJoqIot7

  1. 需要注意的问题:在Activity中有个方法:

private final BroadcastReceiver mHandleMessageReceiver =
new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
intent=GCMIntentService.intentDefault;
newMessage += intent.getStringExtra("score");
newMessage += intent.getStringExtra("time"); 
mDisplay.append(newMessage + "\n");
}};

当客户端收到信息的时候,其实首先执行的并不是它而是:GCMIntentService.java中的@Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = getString(R.string.gcm_message);

displayMessage(context, message);

// notifies user
generateNotification(context, message);
// String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
GCMIntentService.intentDefault=intent;
// newMessage += intent.getStringExtra("score");
// newMessage += intent.getStringExtra("time"); 
// DemoActivity.mDisplay.append(newMessage + "\n");
}

所以当你需要得到传递过来的参数的时候,比如本例中的:

newMessage += intent.getStringExtra("score");
 newMessage +=
intent.getStringExtra("time");

一定要从GCMIntentService中的onMessage()这个方法中的Intent取出来.mHandleMessageReceiver 中的Intent并不是原始的Intent了.

好的,客户端我们完成了,

再看一下服务器端.

代码下载地址:服务器端.

服务器端其实就是一个简单的传递数据的类名称:GCMServerClass,它引用了GCMServerLib中的架包,我这里GCMSeverLib没有任何实际用处,就是为了存储GCMServerClass里面的架包,,我们看一下GCMServerClass.

图中有apiKey这个就是项目生成的Sever API key 我的是:AIzaSyAmCeG5SHgiJRqXWM4TyS2LiQhAsKHGOVA

还有个deviceRegId 我刚才提及的上面红色的地方.

刚才使用客户端注册的时候生成的regId;

传递参数的格式: new Message.Builder().addData("score",
"abcd").addData("time", "time3").build();

这样点击Run as ....在Console中可能会出现 java.net.ConnectException: Connection timed out: connect

这个问题是因为谷歌被封锁导致的,多试几次,GCM不稳定,国外应该用的很好,10次有3次会好一些当出现类似于:0:1387799674664999%2adac3a0f9fd7ecd说明没问题了.

如图:

恭喜,这样服务器端就走通了.在连起来看.当服务器端走完之后,在客户端的onMessage()应该立即有相应的.这样得到了两个参数的值.

当然服务器端发送数据,不光靠类实现,还有很多的方法,我之前还试过另一种方式就是利用谷歌的poster.

地址:谷歌Poster

安装步骤==>打开谷歌浏览器==>工具==>扩展程序==>

下载插件下来之后,直接拖拽进来就行了. 装上之后右侧有个P如图所示:

将刚才在服务器端的数据全部写入poster中:

写的方式为:
打开poster,填入地址信息:
URL 输入:https://android.googleapis.com/gcm/send

Headers中:

Name:Authorization:

Value:key=AIzaSyAmCeG5SHgiJRqXWM4TyS2LiQhAsKHGOVA;

然后点击:Add/Change按钮.继续输入:

Name:Content-Type:

Value:application/json for
JSON; application/x-www-form-urlencoded;charset=UTF-8for plain text

Content Body:输入:
{ "data": {
"score": "5x1",
"time": "15:10"
},
"registration_ids": ["APA91bHHssnk-BjaLoRgjP0zrSqRBHmmgrNJy0pdNhsGNTlVS9jLZf9WOSp69Jx0bVRojm9oI0UiHfOipfgzgeyQEYST6ktnlYf7hSjtm4X_gky8jpo-89kdYuMjka29i5MYhJoqIot7"]
}

里面的registration_ids就是我们刚才在客户端生成的regId;跟服务器端的原理相同的.

然后点击:POST按钮.如果谷歌服务好的话,直接发出去了,跟服务器端相同,然后,在客户端的onMessage就会收到信息.

完成了.

GCM 发送接收消息 Message Client Server 服务器端,客户端的更多相关文章

  1. 【Spring】使用Spring和AMQP发送接收消息(上)

    讲AMQP之前,先讲下传统的JMS的消息模型,JMS中主要有三个参与者:消息的生产者.消费者.传递消息的通道(队列或者主题),两种消息模型如下:通道是队列: 通道是队列: 通道是主题: 在JMS中,虽 ...

  2. XMPP客户端开发(2)--发送接收消息

    客户端连接上服务器并登录以后,可以发送.接收消息. 首先需要定义Chat,MessageListener和ChatMessageListener几个变量: private static Chat ch ...

  3. 【Spring】使用Spring和AMQP发送接收消息(中)

    上篇讲了RabbitMQ连接工厂的作用是用来创建RabbitMQ的连接,本篇就来讲讲RabbitMQ的发送消息.通过RabbitMQ发送消息最简单的方式就是将connectionFactory Bea ...

  4. python通过套接字来发送接收消息

    案例如下: 1.启动一个服务端套接字服务 2.启动一个客户端套接字服务 3.客户端向服务端发送一个hello,服务端则回复一个word,并打印 参考地址:https://www.cnblogs.com ...

  5. 【Spring】使用Spring和AMQP发送接收消息(下)

    上篇讲了使用RabbitMQ发送消息,本篇则来讲接收消息.在传统JMS中有两种从队列获取信息的方式,使用JmsTemplate的同步方式以及使用消息驱动pojo的异步方式.Spring AMQP也提供 ...

  6. 十一、模拟扫码登录微信(用Django简单的布置了下页面)发送接收消息

    为了能够模拟登陆QQ,并获取信息.对扫码登录微信进行了分析.简单的用了一下Django将获取的信息映射到页面上.(python3+pycharm) 主要过程就是: 1.获取二维码 2.扫码登录(有三种 ...

  7. 安装RabbitMq,写程序发送接收消息

    1.安装Erlang和RabbitMq 在安装RabbitMq之前需要安装的Erlang(esl-erlang_22.0_windows_amd64.exe): https://pan.baidu.c ...

  8. kafka控制测试发送接收消息

    kafaka,生产者:./kafka-console-producer.sh --broker-list localhost:9092 --topic testTopic 消费者:./kafka-co ...

  9. RTMPdump(libRTMP) 源代码分析 9: 接收消息(Message)(接收视音频数据)

    ===================================================== RTMPdump(libRTMP) 源代码分析系列文章: RTMPdump 源代码分析 1: ...

随机推荐

  1. appium-车友会欢迎界面向右滑动4次点击‘立即体验’进入首屏

    代码如下: driver.swipe(610, 2452, 658, 2452, 200) 只是示例滑动1页,可以使用循环,下一页比上一页x坐标大48

  2. UVA1220Party at Hali-Bula(树的最大独立集 + 唯一性判断)

    http://acm.hust.edu.cn/vjudge/contest/view.action?cid=105116#problem/H 紫书P282 员工和直属老板只能选一个,最多选多少人 思路 ...

  3. 高德地图3D版的使用方法

    坐标拾取器: http://lbs.amap.com/console/show/picker 其经纬度与LatLng()方法中的经纬度是对调的 SDK和实例下载: http://lbs.amap.co ...

  4. 调用MySql 分页存储过程带有输入输出参数

    Create PROCEDURE getuser ( IN pageIndex INT, IN pageSize INT, OUT count INT ) BEGIN )*pageSize; sele ...

  5. C++中虚函数的作用浅析

    虚函数联系到多态,多态联系到继承.所以本文中都是在继承层次上做文章.没了继承,什么都没得谈. 下面是对C++的虚函数这玩意儿的理解. 一, 什么是虚函数(如果不知道虚函数为何物,但有急切的想知道,那你 ...

  6. Radius 远程用户拨号认证系统

    RADIUS 锁定 本词条由“科普中国”百科科学词条编写与应用工作项目 审核 . RADIUS:Remote Authentication Dial In User Service,远程用户拨号认证系 ...

  7. Serenity框架官方文档翻译前言(什么是Serenity平台)

    什么是Serenity平台 Serenity是一个 ASP.NET MVC / Javascript 的已经建立在开源技术上的平台 它的目标是让开发变得更容易,同时降低维护成本,避免样板式代码,减少重 ...

  8. Java主流日志工具库

    在项目开发中,为了跟踪代码的运行情况,常常要使用日志来记录信息.在Java世界,有很多的日志工具库来实现日志功能,避免了我们重复造轮子.我们先来逐一了解一下主流日志工具. 1.java.util.lo ...

  9. 基于Node.js + jade + Mongoose 模仿gokk.tv

    原文摘自我的前端博客,欢迎大家来访问 http://www.hacke2.cn 关于gokk 大学的娱乐活动基本就是在寝室看电影了→_→,一般都会选择去goxiazai.cc上看,里面的资源多,质量高 ...

  10. 支付宝微信O2O大战,WiFi广告在夹缝中求生存

    支付宝微信O2O大战,WiFi广告在夹缝中求生存 来自工信部的数据显示,截至2013年底,中国智能手机的保有量已经达到5.8亿台.国内平均有46%的时间选择WiFi上网. 商用WiFi已经成为了移动互 ...