• 消息推送之GCM


    利用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类

     1 package com.example.gcmdemo;
     2 
     3 import android.content.Context;
     4 import android.content.Intent;
     5 import android.os.Handler;
     6 import android.os.Looper;
     7 import android.util.Log;
     8 import android.widget.Toast;
     9 
    10 import com.google.android.gcm.GCMBaseIntentService;
    11 
    12 /**
    13  * IntentService responsible for handling GCM messages.
    14  */
    15 public class GCMIntentService extends GCMBaseIntentService {
    16 
    17     public GCMIntentService() {
    18         super(CommonData.SENDER_ID);
    19     }
    20 
    21     //Get the registered broadcast from GCM
    22     @Override
    23     protected void onRegistered(Context context, String registrationId) {
    24         // TODO Register from the server
    25         Log.i("GCMIntentService", "onRegistered注册成功, registrationId=" + registrationId);
    26     }
    27 
    28     //Get the unregistered broadcast from GCM
    29     //Not used yet
    30     @Override
    31     protected void onUnregistered(Context context, String registrationId) {
    32         // TODO Unregister from the server
    33         Log.i("GCMIntentService", "onRegistered注册失败");
    34     }
    35 
    36     //Get the message broadcast from GCM
    37     @Override
    38     protected void onMessage(Context context, Intent intent) {
    39         Log.i("GCMIntentService", "接收到一条新消息:"+intent.getStringExtra("mine"));
    40         final String info = intent.getStringExtra("mine");
    41         Handler handler = new Handler(Looper.getMainLooper());
    42         handler.post(new Runnable() {
    43             
    44             @Override
    45             public void run() {
    46                 Toast.makeText(getBaseContext(), "新消息:"+info, Toast.LENGTH_LONG).show(); 
    47             }
    48         });
    49     }
    50 
    51     @Override
    52     public void onError(Context context, String errorId) {
    53         Log.e(TAG, "Received error: " + errorId);
    54     }
    55 
    56     @Override
    57     protected boolean onRecoverableError(Context context, String errorId) {
    58         Log.e(TAG, "Received recoverable error: " + errorId);
    59         return super.onRecoverableError(context, errorId);
    60     }
    61 }

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

    4)、实现主Activity类

     1 package com.example.gcmdemo;
     2 
     3 import android.app.Activity;
     4 import android.content.Context;
     5 import android.os.Bundle;
     6 import android.util.Log;
     7 import android.view.Menu;
     8 import android.view.View;
     9 import android.view.View.OnClickListener;
    10 import android.widget.Button;
    11 
    12 import com.google.android.gcm.GCMRegistrar;
    13 
    14 public class MainActivity extends Activity {
    15     private static final String SENDER_ID = "655266950018";
    16     private Context mContext = null;
    17     
    18     @Override
    19     public void onCreate(Bundle savedInstanceState) {
    20         super.onCreate(savedInstanceState);
    21         setContentView(R.layout.activity_main);
    22         
    23         mContext = getApplicationContext();
    24         
    25         //点击后注册GCM,接收消息  
    26         Button registerBtn = (Button) findViewById(R.id.register); 
    27         registerBtn.setOnClickListener(new OnClickListener() {
    28             @Override 
    29             public void onClick(View v) {
    30                 // checkDevice()检查系统版本及是否装有google service frame(GCM服务需要安装有谷歌服务包,且系统版本2.2及以上的才支持)
    31                 GCMRegistrar.checkDevice(mContext);
    32                 // 检查AndroidManifest.xml文件是否有配置有必须的权限及广播接收器是否有正确的权限和过滤器,是否可以正常接收广播)
    33                 GCMRegistrar.checkManifest(mContext);
    34                 
    35                 final String registerid= GCMRegistrar.getRegistrationId(mContext); 
    36                 if (regId.equals("")) {
    37                     // 注册一个GCM服务,它会启动一个action名为com.google.android.c2dm.intent.REGISTER的服务
    38                     GCMRegistrar.register(mContext, SENDER_ID); 
    39                     Log.i(CommonData.TAG, "新设备:"+GCMRegistrar.isRegistered(mContext)+GCMRegistrar.getRegistrationId(mContext)); 
    40                 } else {
    41                     Log.i(CommonData.TAG, "Already registered"); 
    42                 }
    43             }
    44         });
    45         
    46         //点击后解除注册,不接收消息  
    47         Button unRegisterBtn = (Button) findViewById(R.id.unregister);
    48         unRegisterBtn.setOnClickListener(new OnClickListener() {
    49             @Override
    50             public void onClick(View v) {
    51                 GCMRegistrar.unregister(getBaseContext());
    52             }
    53         });
    54     }
    55 
    56     @Override
    57     public boolean onCreateOptionsMenu(Menu menu) {
    58         getMenuInflater().inflate(R.menu.activity_main, menu);
    59         return true;
    60     }
    61 }

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

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

    服务器

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

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

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

     1 package com.push.server;
     2 import java.util.ArrayList;
     3 import java.util.List;
     4 
     5 import com.google.android.gcm.server.Message;
     6 import com.google.android.gcm.server.MulticastResult;
     7 import com.google.android.gcm.server.Sender;
     8 
     9 public class SendToGCM{
    10     private static final String API_KEY = "AIzaSyB8t4b-Aj_ZP1Sn9BeILUEiWwJIiyfQ5yc";
    11 
    12     public void send() {
    13         System.out.println("send to GCM start............");
    14         // 一对一推送
    15         //Result result = null;
    16         // 群发
    17         MulticastResult result = null;
    18 
    19         List <String> registerids = new ArrayList<String>();
    20         // "xxx" is registerId get from client
    21         registerids.add(0, "registerid");
    22         //send message
    23         try {
    24             Sender sender = new Sender(API_KEY);
    25             Message message = new Message.Builder().collapseKey("1").timeToLive(3).
    26                     delayWhileIdle(true).addData("title", "新消息").
    27                     addData("message", "this is a new message!").build();
    28 /************************Multicast*****************************/
    29             result = sender.send(message, registerids, 5);
    30 
    31             System.out.println("result.getResults()=" + result.getResults()
    32                     + "
    result.getSuccess()=" + result.getSuccess()
    33                     + "
    result.getFailure()=" + result.getFailure()
    34                     + "
    result.getCanonicalIds()=" + result.getCanonicalIds()
    35                     + "
    result.getMulticastId()=" + result.getMulticastId()
    36                     + "
    result.getTotal()=" + result.getTotal()
    37                     + "
    result.getRetryMulticastIds()=" + result.getRetryMulticastIds()
    38                     );
    39             if (result.getResults() != null) {
    40                 int canonicalRegId = result.getCanonicalIds();
    41                 if (canonicalRegId != 0) {
    42                     // same device has more than on registration ID: update database
    43                     System.out.println("same device has more than on registration ID: update database");
    44                 }
    45             }
    46             else {
    47                 int error = result.getFailure();
    48                 System.out.println("Broadcast failure: " + error);
    49             }
    50 /************************Multicast*****************************/
    51 
    52 /************************Unicast******************************/
    53 /*
    54             result = sender.send(message, registerids.get(0), 5);
    55             System.out.println("result.getMessageId()=" + result.getMessageId() +
    56                     "
    result.getCanonicalRegistrationId()" + result.getCanonicalRegistrationId() +
    57                     "
    result.getErrorCodeName()" + result.getErrorCodeName());
    58             if (result.getMessageId() != null) {
    59                String canonicalRegId = result.getCanonicalRegistrationId();
    60                if (canonicalRegId != null) {
    61                // same device has more than on registration ID: update database
    62                }
    63             }
    64             else {
    65                String error = result.getErrorCodeName();
    66                if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
    67                // application has been removed from device - unregister database
    68                }
    69             }
    70 */
    71 /************************Unicast******************************/
    72         } catch (Exception e) {
    73             e.printStackTrace();
    74         }
    75         System.out.println("send to GCM end............");
    76     }
    77 }

    注:

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

  • 相关阅读:
    【Flume】数据采集引擎Flume
    【Spark】源码分析之SparkContext
    【Spark】源码分析之spark-submit
    【Hadoop故障处理】高可用(HA)环境DataNode问题
    【Hadoop故障处理】全分布下,DataNode进程正常启动,但是网页上不显示,并且DataNode节点为空
    【Hadoop故障处理】在高可用(HA)配置下,8088端口无法访问,resourcemanager进程无法启动问题
    【Spark】算子
    【Java】集合遍历--List和Map的多种遍历方式
    【Java】集合概述Collection、Map
    【Java】abstract,final,static,private,protected,public的区别
  • 原文地址:https://www.cnblogs.com/lidgblogs/p/4130057.html
Copyright © 2020-2023  润新知