环信技术博客

gcm推送

2015年07月27日|作者: |移动开发|标签:,

一.gcm前期准备

 

 

Apple有apns推送,Google有gcm推送,iOS接收通知调用系统通知栏提示,Android接收通知启动应用调用通知栏提示。

相对于apns,gcm则多了一些限制,需要一些必备条件达到才可以使用。

1.在国内,首先就是Google被墙,无法连接到Google服务器,需要你走VPN或者其它方式可以连接到Google服务器。

 

2.在你的开发环境下,需要通过Android SDK Manager—>Extras下安装Google Play services,成功之后在你的SDK文件/sdk/extras/google/google_play_services/libproject下会看到google-play-services_lib类库,可以从里面直接复制jar包到你的项目libs下

 

3.Android客户端,要求安装了Google核心服务Google Play服务,Google Play 商店才能使用gcm

 

以上是Google官方文档描述:

 

大意就是gcm要求设备运行在Android系统2.2或更高版本并且安装了Google play商店应用,或者虚拟机运行在Android系统2.2版本的并且支持Google API,但是并不限制你的应用必须部署在Google play 商店。

然而,如果你想要使用gcm 新的API就需要设备运行在Android系统2.3或更高版本,或者使用虚拟机运行在Android系统2.3并且支持Google API

在一个现有连接Google服务的设备上,对于前置3.0的设备,就要求在Android设备上设置Google账号,4.0.4或者更高版本则不需要设置Google账号

 

注:gcm只是简单的推送一个通知到客户端,其消息内容应小于4Kb,Google服务器存储时间为4个星期。在客户端,gcm是通过客户端设备注册一个系统广播来唤醒应用并发出通知提示,所以这个时候客户端不需要一直运行来接收消息,gcm一次发送最多可发送100个用户

 

二.官网创建项目获取信息

 

去Google Developers Console(https://console.developers.google.com/project)创建项目,输入你的project name和project id,创建成功如下图:

 

 

 

在应用中我们会用到这个project number,再去Credentials下创建一个server key,得到的api key会在自己的服务器端用到,如图

 

 

 

顺便说一下,默认Cloud Messaging for Android是可用的,如果不能用,就需要去API & auth—> API下查看Cloud Messaging for Android是否disable

 

三.创建一个客户端app

首先要在AndroidManifest.xml文件配置gcm权限等信息

1
2
3
4
5
6
7
<uses-permission android:name="android.permission.INTERNET" />  
  <uses-permission android:name="android.permission.GET_ACCOUNTS" />//当GCM需要谷歌账户(设备版本低于4.0.4时需要)  
  <uses-permission android:name="android.permission.WAKE_LOCK" />  
  <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />  
  <permission android:name="applicationPackage.permission.C2D_MESSAGE"  
      android:protectionLevel="signature" />  
  <uses-permission android:name="applicationPackage.permission.C2D_MESSAGE" />

applicationPackage要改成自己的报名

android:minSdkVersion="8"不得低于8

根据官网文档介绍:

1.我们应该在配置文件注册一个系统广播

1
2
3
4
5
6
7
8
9
<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="com.example.gcm" />  
           </intent-filter>  
       </receiver>

2.注册监听通知服务(在app中创建一个服务类并继承GcmListenerService类)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
<div>
<div>
<div><b>[html]</b> <a title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" href="http://blog.csdn.net/haiyoumeiyouwo/article/details/47082641#">view plain</a><a title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://blog.csdn.net/haiyoumeiyouwo/article/details/47082641#">copy</a>
<div><object id="ZeroClipboardMovie_3" width="18" height="18" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" align="middle" bgcolor="#ffffff"><param name="src" value="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" /><param name="pluginspage" value="http://www.macromedia.com/go/getflashplayer" /><param name="loop" value="loop" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="allowscriptaccess" value="always" /><param name="allowfullscreen" value="false" /><param name="flashvars" value="id=3&width=18&height=18" /><param name="wmode" value="transparent" /><embed id="ZeroClipboardMovie_3" width="18" height="18" type="application/x-shockwave-flash" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" loop="loop" menu="false" quality="best" allowscriptaccess="always" allowfullscreen="false" flashvars="id=3&width=18&height=18" wmode="transparent" align="middle" bgcolor="#ffffff" /></object></div>
</div>
</div>
<ol start="1">
	<li><pre name="code" class="html"><service</li>
	<li>            android:name="com.example.MyGcmListenerService"</li>
	<li>            android:exported="false" ></li>
	<li>            <intent-filter></li>
	<li>                <action android:name="com.google.android.c2dm.intent.RECEIVE" /></li>
	<li>            </intent-filter></li>
	<li>        </service></li>
	<li></li>
	<li>public class MyGcmListenerService extends GcmListenerService {</li>
	<li></li>
	<li>      @Override</li>
	<li>    public void onMessageReceived(String from, Bundle data) {</li>
	<li>        String message = data.getString("message");</li>
	<li>        /**</li>
	<li>         * Production applications would usually process the message here.</li>
	<li>         * Eg: - Syncing with server.</li>
	<li>         *     - Store message in local database.</li>
	<li>         *     - Update UI.</li>
	<li>         */</li>
	<li></li>
	<li>        /**</li>
	<li>         * In some cases it may be useful to show a notification indicating to the user</li>
	<li>         * that a message was received.</li>
	<li>         */</li>
	<li>        sendNotification(message);</li>
	<li>    }</li>
	<li>    // [END receive_message]</li>
	<li></li>
	<li>    /**</li>
	<li>     * Create and show a simple notification containing the received GCM message.</li>
	<li>     *</li>
	<li>     * @param message GCM message received.</li>
	<li>     */</li>
	<li>    private void sendNotification(String message) {</li>
	<li>        Intent intent = new Intent(this, MainActivity.class);</li>
	<li>        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);</li>
	<li>        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,</li>
	<li>                PendingIntent.FLAG_ONE_SHOT);</li>
	<li></li>
	<li>        Uri defaultSoundUri= RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);</li>
	<li>        NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this)</li>
	<li>                .setSmallIcon(R.drawable.ic_stat_ic_notification)</li>
	<li>                .setContentTitle("this is a new new GCM Message")</li>
	<li>                .setContentText(message)</li>
	<li>                .setAutoCancel(true)</li>
	<li>                .setSound(defaultSoundUri)</li>
	<li>                .setContentIntent(pendingIntent);</li>
	<li></li>
	<li>        NotificationManager notificationManager =</li>
	<li>                (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);</li>
	<li></li>
	<li>        notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());</li>
	<li>    }</li>
	<li>}</li>
</ol>
</div>
<pre>

 

3.注册监听token改变的服务(在app中创建一个服务类继承InstanceIDListenerService类,本服务存在于新的Google play服务版本上)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
android:name="com.example.MyInstanceIDListenerService"  
            android:exported="false">  
            <intent-filter>  
                <action android:name="com.google.android.gms.iid.InstanceID"/>  
            </intent-filter>  
        </service>  
 
public class MyInstanceIDListenerService extends InstanceIDListenerService {  
 
       @Override  
    public void onTokenRefresh() {  
        // Fetch updated Instance ID token and notify our app's server of any changes (if applicable).  
    }  
}

gcm通过注册的系统广播可以自行启动GcmListenerService类,所以不需要在app创建一个广播类

 

注册token

App发送 project number到GCM Server注册接收推送信息。 

GCM Server 向App返回token(token是GCM服务器自行生产的,能够保证某一终端设备上的某一个应用,很重要)。

 

在设备上应该先判断是否安装了Google play 服务

1
2
3
4
5
6
7
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);  
if (resultCode != ConnectionResult.SUCCESS) {  
    if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {  
        GooglePlayServicesUtil.getErrorDialog(resultCode, this, PLAY_SERVICES_RESOLUTION_REQUEST).show();//会提示错误对话框,其他错误信息可参考官网API  
    } else {  
        Log.i(TAG, "This device is not supported.”);  
    }

Google play服务存在,那接下来就需要去注册token了,在上边创建项目得到的project number在这里就需要用它来注册token

 

根据官网文档描述,文档上推荐使用的方式为Google play服务7.5或更高版本支持的新的注册token方式的API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
&nbsp;
 
&nbsp;
<div>
<div>
<div><b>[java]</b> <a title="view plain" onclick="dp.sh.Toolbar.Command('ViewSource',this);return false;" href="http://blog.csdn.net/haiyoumeiyouwo/article/details/47082641#">view plain</a><a title="copy" onclick="dp.sh.Toolbar.Command('CopyToClipboard',this);return false;" href="http://blog.csdn.net/haiyoumeiyouwo/article/details/47082641#">copy</a>
<div><object id="ZeroClipboardMovie_6" width="18" height="18" classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,40,0" align="middle" bgcolor="#ffffff"><param name="src" value="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" /><param name="pluginspage" value="http://www.macromedia.com/go/getflashplayer" /><param name="loop" value="loop" /><param name="menu" value="false" /><param name="quality" value="best" /><param name="allowscriptaccess" value="always" /><param name="allowfullscreen" value="false" /><param name="flashvars" value="id=6&width=18&height=18" /><param name="wmode" value="transparent" /><embed id="ZeroClipboardMovie_6" width="18" height="18" type="application/x-shockwave-flash" src="http://static.blog.csdn.net/scripts/ZeroClipboard/ZeroClipboard.swf" pluginspage="http://www.macromedia.com/go/getflashplayer" loop="loop" menu="false" quality="best" allowscriptaccess="always" allowfullscreen="false" flashvars="id=6&width=18&height=18" wmode="transparent" align="middle" bgcolor="#ffffff" /></object></div>
</div>
</div>
<ol start="1">
	<li>InstanceID instanceID = InstanceID.getInstance(this);</li>
	<li>String token = instanceID.getToken(PROJECT_NUMBER,</li>
	<li>GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);</li>
</ol>
</div>
&nbsp;

对于旧版本还是要使用以下方式来注册token(用于Google play 服务7.5版本之前)

1
GoogleCloudMessaging.getInstance(Context).register(PROJECT_NUMBER);

在自己的服务器端注册api key

App向我们自己服务器发送token(推送消息的时候要使用token,GCM服务器是使用token来确定某一终端设备上的某一个应用接收消息的,所以第三方服务器需要保存它,需要注意的是token很长,存数据库时需要注意字段长度) ,将我们在上边create new key 得到的apikey添加到自己的服务器端保存,我们的服务器向GCM Server发送消息,传递apikey和token ,GCM Server把消息推送给App

 

最后注意一下,关于app卸载出现的问题,看一下官方的介绍

app会发生卸载过程并不能很快完成,卸载app需要花时间从GCM移除当前关联的token,这个过程就会出现发送消息是成功的,但是不能到达app客户端,在最后,token被移除了,服务器端发送的消息失败,得到一个NotRegistered错误,这个时候就应该在服务器端删除相对应的token

本文章版权归环信所有,转载请注明出处。更多技术文章请访问http://blog.easemob.com/

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>