[Google Android] GCM: Getting Started
GCM:入门
此文描述了如何使用GCM提供的辅助库(客户端和服务器)来编写一个Android应用程序和服务器端的逻辑。
创建一个谷歌API项目
要创建一个谷歌API项目:
- 打开谷歌API的控制台页面。
- 如果你还没有创建一个API项目,这个页面会提示你这样做:
注:如果您已经有项目,你看到的第一页将是仪表板页面。从那里你可以通过打开项目的下拉菜单(左上角),并选择Other>Create一个新的项目。
- 点击创建项目。你的浏览器URL将会改成这样的:
https://code.google.com/apis/console/#project:4815162342
-
注意#project:后面的值:(示例中的4815162342)。这是你的项目ID,并且后面会用作GCM发件人的ID。
启用GCM服务
为了启用GCM服务:
- 在谷歌API的控制页面的主页中,选择服务。
- 切换Google Cloud Messaging按钮的状态为ON。
- 在服务条款页面中接受这些条款。
获取一个API密钥
为了获取一个API密钥:
- 在谷歌API控制台主页面中,选择API Access。你将会看到一个类似于以下内容的页面:
2. 点击Create new Server key。会出现以下页面:
3. 点击 Create:
请注意在这个示例中API key 的值(YourKeyWillBeShownHere
),它稍后会被用到。
注:如果你想换掉这个密钥,请点击Generate new key。一个新的密钥就会创建,而之前的密钥在未来24内仍然有效。如果你想让之前的密钥立即失效(例如:你认为它已经被破解了),请点击Delete key。
安装辅助库
在执行下面章节描述的步骤之前,请确保已经安装好辅助库(参考:客户端和服务器)。打开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。
开始编写Android程序
此章节描述了用GCM编写Android程序的步骤。
步骤 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到你的服务器,这种情况你应当重试。请查看高级主题来了解处理这种情况的更多详情。
编写服务端程序
编写服务器程序请做如下准备:
- 拷贝SDK的gcm-server/dist目录下的gcm-server.jar到你服务器的classpath。
- 创建一个servlet(或其它服务器端机制),被Android程序用来发送从GCM收到的注册ID。Android程序可能也要发送一些其它的信息,例如用户的email地址或用户名,这样服务器就可以对注册ID和用户设备进行关联。
- 相似地,创建一个servlet用来注销注册ID。
- 当服务器需要发送一条消息到设备时,可以使用GCM库中的com.google.android.gcm.server.Sender辅助类。例如:
import com.google.android.gcm.server.*; Sender sender = new Sender(myApiKey); Message message = new Message.Builder().build(); MulticastResult result = sender.send(message, devices, 5);
上面的代码段实现了如下工作:
- 用你项目的API key创建一个Sender对象。
- 用获得的注册ID来创建一个消息(消息的构建者也要有方法来设置全部的消息参数,例如collapse key和有效负载数据)。
- 发送这个消息(如果GCM服务器无效的话,有5次重发机会),并保存响应给result。
现在就需要解析响应结果并对如下情况采取适当的措施:
- 如果消息被创建了,但是结果返回了一个被认可的注册ID,那么需要用这个认可的ID替换当前的注册ID。
- 如果返回的错误是NotRegistered,那么需要移除这个注册ID,因为那个设备没有安装此程序。
这有一个代码段来处理这两种情况:
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 } }