GCM Google官方示例的简单介绍和使用

GCM Google官方示例的简单介绍和使用

准备工作

翻墙

  先翻墙,翻不了墙一切都白搭……

Google账号

  • 申请Google账号
  • 进入Google开发管理台
  • 创建工程(Google管理台上的Project)
  • 开启Google Cloud Messaging API。

Demo工程

  参考google官方指导文档,在google中搜索GCM,或者直接点击此处打开。本文均以Android为例,打开页面后,点击左上方的”TRY IT ON ANDROID”按钮,进入针对安卓的指导页。以下步骤官方指导写的比较详细的,本文就不赘述,一笔带过,有需要注意的会补充。

  1. 下载Android示例工程
      下载下来是个压缩包,GCM的工程目录为google-services-master/android/gcm,简单介绍下各个类的作用:

    • MyGcmListenerService.java
      GCM接收监听服务类,接收GCM发过来的通知消息,并显示到手机状态栏中。
      对应的AndroidManifest.xml配置如下:
      <!-- [START gcm_receiver] -->
      <receiver
        android:name="com.google.android.gms.gcm.GcmReceiver"
        android:exported="true"
        android:permission="com.google.android.c2dm.permission.SEND">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
            <category android:name="gcm.play.android.samples.com.gcmquickstart"/>
        </intent-filter>
      </receiver>
      <!-- [END gcm_receiver] -->
      <!-- [START gcm_listener] -->
      <service
        android:name=".MyGcmListenerService"
        android:exported="false">
        <intent-filter>
            <action android:name="com.google.android.c2dm.intent.RECEIVE"/>
        </intent-filter>
      </service>
      <!-- [END gcm_listener] -->

    GcmReceiver接收,然后发送给GcmListenerService,我们在GcmListenerServcie的实现类中处理收到的gcm消息。Google官方对GcmReceiver的解释(原文链接):

    WakefulBroadcastReceiver that receives GCM messages and delivers them to an application-specific GcmListenerService subclass.

    如何将通知消息展示到状态栏:

    Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)
                .setSmallIcon(R.drawable.ic_stat_ic_notification)
                .setContentTitle("GCM Message")
                .setContentText(message + count)
                .setAutoCancel(true)
                .setSound(defaultSoundUri)
                .setContentIntent(pendingIntent);
    
    NotificationManager notificationManager =
                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
    
    int notificationId = Integer.parseInt(("" + System.currentTimeMillis()).substring(10));
    notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
    • RegistrationIntentService.java
      向GCM服务器进行设备注册,获取注册token,该token会作为通知消息接收设备的标识,该类中还进行了topics的订购。
    • MyInstanceIDListenerService.java
      接收token更新通知,收到通知后会重新通过RegistrationIntentService获取新的token。
    • GcmSender.java
      推送消息发送类,通过该类向GCM发送HTTP消息,GCM再推送给终端设备。该类并不是必需的,下文也提到了,可以通过Postman等工具直接发送HTTP消息。

  2. 下载配置文件。
      下载过程中会给出API Key和Sender ID。(没记住也没关系,管理台上也可以查到,分别对应API Key和Project number)

  3. 将配置文件放入工程

    注意,工程下载好后,里面默认代码使用的API Key以及Sender ID需要修改。

    API Key: GcmSender.java(模拟服务器向Google发送推送消息使用,后面可以不用main函数,直接用浏览器插件发消息的方式,更方便点。)

    Sender ID:RegistrationIntentService.java(代码默认使用的是”R.string.gcm_defaultSenderId”)。

  4. 安装并运行示例App
      工程打开时会向Google注册,并获取注册Token,logcat日志中会打出来。后面发送消息时以获取到的token作为客户端设备标识。

02-23 10:39:18.709 19735-19763/gcm.play.android.samples.com.gcmquickstart I/RegIntentService: GCM Registration Token:
 dnbhEeyYCWg:APA91bH_yYRmgPsuzpC7qMKp86JV3jR5d...Iw6VvPHilRa2d9u7sW4Xs6El2S1nsqtGM4yO2vVjHv-nSs_DkF3-sdn3b...7mxrbdsyl5xb53


发送通知消息

  下载下来的工程中GcmSender.java这个类就是专门发消息的,Google的指导中有给出调用其Main函数的命令,本文推荐直接通过浏览器插件或工具发送(反正就是个HTTPS的消息,用什么发都一样,对吧)。
  推荐”Postman”,通过Chrome网上应用店安装,有独立的应用版本。

消息内容如下:
其中消息头中的key为API Key(Google管理台上可以查),token为上文第四步中提到的注册token。

https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "to": "/topics/foo-bar",
  "data": {
    "message": "This is a GCM Topic Message!",
   }
}
  • 消息2:指定发送给一个设备,to即上文提到的注册token。
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "to": "token",
  "data": {
    "message": "This is a GCM token Message!",
   }
}
  • 消息3:发送给多个设备,token1、token2即上文提到的注册token。
https://gcm-http.googleapis.com/gcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
{
  "registration_ids": ["token1","token2"],
  "data": {
    "message": "This is a GCM token Message!",
   }
}


可能遇到的问题

  1. Gradle编译不过,提示无法下载play-services-gcm:8.4.0。
    可能jcenter还没有收录这个版本(也可能是网络问题),尝试使用早一点的版本,例如build.gradle文件中改为8.3.0就好了。顺便提醒下别忘了在SDK Manager中,安装Extras下面的Google Play services,这个组件默认是不安装的。

  2. 使用命令行调用main函数的方式发送消息,连接超时或失败。
    没用到proxy,使用postman等工具发送。

  3. app运行过程中,日志打印Notification.xxx方法找不到。
    升级android sdk到最新版本,官网下载的代码依赖的sdk是比较新的。

  4. 发给topics的消息终端无法收到
    Google给的消息示例中to的值为/topics/foo-bar,实际测试时发现是收不到这个推送消息的,查看RegistrationIntentService.java代码发现针对topics的消息,需要在获取到token后,订购相应的topics(默认只订购了/topics/global,所以发向/topics/foo-bar的收不到)。
    相关代码:

/**
 * Subscribe to any GCM topics of interest, as defined by the TOPICS constant.
 *
 * @param token GCM token
 * @throws IOException if unable to reach the GCM PubSub service
 */
// [START subscribe_topics]
private void subscribeTopics(String token) throws IOException {
    GcmPubSub pubSub = GcmPubSub.getInstance(this);
    for (String topic : TOPICS) {
        pubSub.subscribe(token, "/topics/" + topic, null);
    }
}
// [END subscribe_topics]


几个常用参数

1. 在收到多条推送消息时,状态栏如何控制弹多条还是保持一条。

MyGcmListenerService.java中,弹出状态栏消息时会设置一个notification ID,不同ID会弹出不同的通知,同一个ID会一直刷新同一个通知。
设置固定的ID就可以做到”收到xx条新消息”这种提示啦。

notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());

2. App最小化或Activity销毁后,点击状态栏通知要打开指定的Activity

MyGcmListenerService.java中,”PendingIntent.FLAG_ONE_SHOT”改为”PendingIntent.FLAG_UPDATE_CURRENT”(或者”0”?)即可,具体每个flag的含义参考其注释。

Intent intent = new Intent(this, Main2Activity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */
  , intent, PendingIntent.FLAG_ONE_SHOT);
/**
 * Flag indicating that this PendingIntent can be used only once.
 * For use with {@link #getActivity}, {@link #getBroadcast}, and
 * {@link #getService}. <p>If set, after
 * {@link #send()} is called on it, it will be automatically
 * canceled for you and any future attempt to send through it will fail.
 */
public static final int FLAG_ONE_SHOT = 1<<30;
/**
 * Flag indicating that if the described PendingIntent does not
 * already exist, then simply return null instead of creating it.
 * For use with {@link #getActivity}, {@link #getBroadcast}, and
 * {@link #getService}.
 */
public static final int FLAG_NO_CREATE = 1<<29;
/**
 * Flag indicating that if the described PendingIntent already exists,
 * the current one should be canceled before generating a new one.
 * For use with {@link #getActivity}, {@link #getBroadcast}, and
 * {@link #getService}. <p>You can use
 * this to retrieve a new PendingIntent when you are only changing the
 * extra data in the Intent; by canceling the previous pending intent,
 * this ensures that only entities given the new data will be able to
 * launch it.  If this assurance is not an issue, consider
 * {@link #FLAG_UPDATE_CURRENT}.
 */
public static final int FLAG_CANCEL_CURRENT = 1<<28;
/**
 * Flag indicating that if the described PendingIntent already exists,
 * then keep it but replace its extra data with what is in this new
 * Intent. For use with {@link #getActivity}, {@link #getBroadcast}, and
 * {@link #getService}. <p>This can be used if you are creating intents where only the
 * extras change, and don't care that any entities that received your
 * previous PendingIntent will be able to launch it with your new
 * extras even if they are not explicitly given to it.
 */
public static final int FLAG_UPDATE_CURRENT = 1<<27;

/**
 * Flag indicating that the created PendingIntent should be immutable.
 * This means that the additional intent argument passed to the send
 * methods to fill in unpopulated properties of this intent will be
 * ignored.
 */
public static final int FLAG_IMMUTABLE = 1<<26;
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值