Android推送 利用REST API实现从客户端推送(百度云推送)

随着谷歌开发者大会在中国的成功举行,也带来激动人心的消息,2016年12月8日Google Developers中文网站正式发布了。以后学习Android,获取Android Studio、安卓最新版SDK等最新开发资源也变得更加轻松了。直接访问Google Developers官网 https://developers.google.cn/ 即可。好了,激动之余让我们来看看今天为大家带来的关于消息推送的博文,这次还是使用Android Studio进行开发,不过Eclipse的集成开发也和下面要介绍的内容差不太多。按照惯例,还是先来看看程序的效果图:



1. 集成SDK前的准备工作

1.1 开发者身份认证

登录百度云推送官网后,点击创建应用,如果没有申请过,则会跳转到认证页面,通过填写一系列的认证信息,完成认证。


1.2 下载SDK

官网下载最新版的SDk



扫描二维码关注公众号,回复: 11402651 查看本文章

1.3 创建项目

1.3.1 在编辑器中创建好项目

利用Android Studio新建好项目,并记好包名。

1.3.2 在百度云推送官网创建应用

再次点击百度云推送“创建应用”的菜单项,成功跳转后点击“创建新应用”按钮后开始创建应用,过程中需要填写项目的包名,就不再细说了。最后得到下图的API Key等信息,后面马上就要派上用场了。



2. 如何在项目中集成SDK

集成的步骤和调用SDK的方法都可以在文档中心查阅,还算是写的比较详细的了。

2.1 导入Jar包

解压好之前下载的SDK,把libs目录下的 pushservice-5.5.0.50.jar 复制到工程目录下的libs文件夹中。

2.2 导入so文件

在工程目录 src/main 下新建一个jniLibs文件夹,把libs目录下除Jar包以外的文件(so文件)复制到里面。最后工程目录的结构如下图所示:


2.3 添加依赖

① 修改项目下的 build.gradle 文件,在android节点下,定义 sourceSets 内容为 jniLibs 路径,这样才能使用so库文件;

② 同样地,修改 build.gradle 文件,添加Jar包的依赖项。

最后,添加好依赖以后文件的部分内容(其他部分暂时用省略号替代)如下所示:

apply plugin: 'com.android.application'

android {
    ......
    sourceSets {
        main {
            jniLibs.srcDirs = ['src/main/jniLibs']
        }
    }
}

dependencies {
    ......
    compile files('libs/pushservice-5.5.0.50.jar')
}

2.4 配置AndroidManifest文件

2.4.1 添加相关权限

在 manifest 节点下添加权限:

<!-- Push service 运行需要的权限 -->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<!-- 富媒体需要声明的权限 -->
<uses-permission android:name="android.permission.ACCESS_DOWNLOAD_MANAGER"/>
<uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION" />
<uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />

<!-- 适配Android N系统必需的ContentProvider写权限声明,写权限包含*自己的应用包名*-->
<uses-permission
    android:name="baidu.push.permission.WRITE_PUSHINFOPROVIDER.com.project.baidupushtest" />
<permission
    android:name="baidu.push.permission.WRITE_PUSHINFOPROVIDER.com.project.baidupushtest"
    android:protectionLevel="normal">
</permission>

2.4.2 注册Receiver 和 Service

在application节点中注册广播接收器和服务:

<!-- push service start -->
<!-- 用于接收系统消息以保证PushService正常运行 -->
<receiver android:name="com.baidu.android.pushservice.PushServiceReceiver"
    android:process=":bdservice_v1" >
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        <action android:name="com.baidu.android.pushservice.action.notification.SHOW" />
        <action android:name="com.baidu.android.pushservice.action.media.CLICK" />
        <!-- 以下四项为可选的action声明,可大大提高service存活率和消息到达速度 -->
        <action android:name="android.intent.action.MEDIA_MOUNTED" />
        <action android:name="android.intent.action.USER_PRESENT" />
        <action android:name="android.intent.action.ACTION_POWER_CONNECTED" />
        <action android:name="android.intent.action.ACTION_POWER_DISCONNECTED" />
    </intent-filter>
</receiver>
<!-- Push服务接收客户端发送的各种请求-->
<receiver android:name="com.baidu.android.pushservice.RegistrationReceiver"
    android:process=":bdservice_v1" >
    <intent-filter>
        <action android:name="com.baidu.android.pushservice.action.METHOD" />
        <action android:name="com.baidu.android.pushservice.action.BIND_SYNC" />
    </intent-filter>
    <intent-filter>
        <action android:name="android.intent.action.PACKAGE_REMOVED" />
        <data android:scheme="package" />
    </intent-filter>
</receiver>
<service android:name="com.baidu.android.pushservice.PushService" 
    android:exported="true"
    android:process=":bdservice_v1" >
    <intent-filter >
        <action android:name="com.baidu.android.pushservice.action.PUSH_SERVICE" />
    </intent-filter>
</service>
<!-- 4.4版本新增的CommandService声明,提升小米和魅族手机上的实际推送到达率 -->
<service android:name="com.baidu.android.pushservice.CommandService"
    android:exported="true" />

<!-- 适配Android N系统必需的ContentProvider声明,写权限包含应用包名-->
<provider
    android:name="com.baidu.android.pushservice.PushInfoProvider"
    android:authorities="com.baidu.push.example.bdpush"
    android:writePermission="baidu.push.permission.WRITE_PUSHINFOPROVIDER.com.baidu.push.example"
    android:protectionLevel = "signature"
    android:exported="true" />
<!-- push结束 -->

2.5 自定义Receiver

我们需要通过继承 com.baidu.android.pushservice.PushMessageReceiver 实现一个Receiver,并在 AndroidManifest 文件中注册,来接受推送的消息,处理通知的点击事件等。

2.5.1 继承实现Receiver类

由于只是简单的接收一下推送消息,所以只重写了 onBind 方法。部分代码如下:

public class MyPushMessageReceiver extends PushMessageReceiver {
    @Override
    public void onBind(Context context, int errorCode, String s, String s1,
		String s2, String s3) {
        if (errorCode == 0) {
            Toast.makeText(context, "绑定成功!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(context, "绑定失败!"+errorCode, Toast.LENGTH_SHORT).show();
        }

    }
    ......
}

2.5.2 注册自定义Receiver

在application节点中注册自定义的Receiver

<!-- 此处Receiver名字修改为当前包名路径 -->
<receiver android:name=".MyPushMessageReceiver">
    <intent-filter>
        <!-- 接收push消息 -->
        <action android:name="com.baidu.android.pushservice.action.MESSAGE" />
        <!-- 接收bind、setTags等method的返回结果-->
        <action android:name="com.baidu.android.pushservice.action.RECEIVE" />
        <!-- 接收通知点击事件,和通知自定义内容 -->
        <action android:name="com.baidu.android.pushservice.action.notification.CLICK" />
    </intent-filter>
</receiver>

2.6 启动云推送

① 在 MainActivity 中添加如下代码进行初始化,将最后一个参数替换成自己的API Key。

PushManager.startWork(getApplicationContext(), PushConstants.LOGIN_TYPE_API_KEY, 
        Constants.APIKEY_VALUE);

② 程序启动的时候,显示“绑定成功”则表示可以接收推送信息了(之前在自定义Receiver类中写的)。利用云推送控制台简单测试一下,在应用列表页面,点击创建推送 —> 创建通知 —> 填写相关内容后发送,能成功收到信息,我们就已经成功了一大半了。


3. 通过客户端请求推送通知
依照上两节的内容,我们已经可以推送/接收通知了,但是推送还是要使用网页控制台才能完成。接下来,就让我们来看看如何利用REST API实现客户端推送。同样地,也有相应的文档介绍了其具体的用法:http://push.baidu.com/doc/restapi/sdk_developer
3.1 请求的URL
百度提供了REST风格的htttp和https接口,如下所示:

http[s]://api.tuisong.baidu.com/rest/3.0/{class}/{method}?{query_string}
{class}是所要请求的资源类别,如我们想要推送通知,则为push;

{method}是具体的操作方法名称,如要推送给安装了我们程序的所有用户,则为all;即:

http://api.tuisong.baidu.com/rest/3.0/push/all

{query_string}是具体的请求参数,有几点要注意一下:
① 对于GET请求,{query_string}放在“?”后面传递;
② 对于POST请求,{query_string}放在POST参数中传递
③ {query_string}由通用参数和具体API调用参数2个部分组成;
④ {query_string}中的key/value对都必须经过urlencode处理,且必须是UTF-8编码;
⑤ 目前查询接口同时支持POST和GET方式,非查询接口仅支持POST方式。

我们请求推送使用的是POST的方式。

3.2 请求的参数
可划分为①公共请求参数:即每次请求都需要传递的参数;②API调用参数:每种请求类型都会有相对应的请求参数。
3.2.1 公共请求参数

通过下表更进一步了解一下通用参数:

参数名 类型 必需 描述
 apikey  string  是  应用的Api Key,用于标识应用。
 timestamp             number        是  用户发起请求时的unix时间戳。本次请求签名的有效时间为以该时间戳开始的10分钟。
 sign  string  是  通过签名算法生成,与apikey成对出现。用于防止请求内容被篡改。下一小节详细介绍。
 expires  number  否  用户指定本次请求签名的失效时间。格式为unix时间戳形式,用于防止 replay 型攻击。为保证防止 replay攻击算法的正确有效,需保证客户端系统时间正确。
 device_type number  否  当一个应用同时支持多个设备平台类型(比如:Android和iOS),请务必设置该参数。其余情况可不设置。Android对应的参数值为3,IOS为4.

3.2.2 API调用参数

① 这里主要讲一下推送广播消息的请求参数,同样的利用官网API(http://push.baidu.com/doc/restapi/restapi)的表格来熟悉一下:

参数名 类型 必需 限制 描述
 msg_type  number  否  取值如下:0:消息;1:通知。默认为0  消息类型
 msg  string  是  消息/通知数据格式详见下方介绍  消息内容,json格式
 msg_expires  number  否  0~604800(86400*7),默认为5小时(18000秒)  消息过期时间,单位为秒
 deploy_status     number    否  取值为:1:开发状态;2:生产状态; 若不指定,则默认设置为生产状态。  设置iOS应用的部署状态,仅iOS应用推送时使用
 send_time  number   否  指定的实际发送时间,必须在当前时间60s以外,1年以内  定时推送,用于指定的实际发送时间
② Android平台的消息无格式要求,开发者可以自定义。详情可见: http://push.baidu.com/doc/restapi/msg_struct

{  
    "title" : "hello" ,  
    "description": "hello world" //必选  
    "notification_builder_id": 0, //可选  
    "notification_basic_style": 7, //可选  
    "open_type":0, //可选  
    "url": "http://developer.baidu.com", //可选  
    "pkg_content":"", //可选  
    "custom_content":{"key":"value"},  
}
代码就比较随意了,直接贴出来:

String msg = String.format("{" + Constants.TITLE + ":\"%s\"," 
                + Constants.DESCRIPTION + ":\"%s\"," 
                + Constants.NOTIFICATION_BUILDER_ID + ":0," 
                + Constants.NOTIFICATION_BASIC_STYLE + ":7}", title, contents);
requestData.put(Constants.MSG, msg);
拼接好之后放入请求Map中,用于后面的传递。

3.3 签名算法

云推送API使用的签名算法(http://push.baidu.com/doc/restapi/sdk_developer#签名算法)如下:
① 获取请求的http method;
② 获取请求的url,包括host和sheme,但不包括query_string的部分;
③ 将所有参数(包括GET或POST的参数,但不包含签名字段)格式化为“key=value”格式,如“k1=v1”、“k2=v2”、“k3=v3”;
④ 将格式化好的参数键值对以字典序升序排列后,拼接在一起,如“k1:v1,k2 :v2,k3:v3”,并将http method和url按顺序拼接在这个字符串前面;
⑤ 在拼接好的字符串末尾追加上应用的secret_key,并进行urlencode,形成base_string;

了解签名算法的规则后,让我们来看看代码是怎么写的:

/**
     * 通过签名算法得到sign值
     *
     * @param data
     * @return
     * @throws NoSuchAlgorithmException
     * @throws UnsupportedEncodingException
     */
    private StringBuilder getSign(RequestData data) 
            throws NoSuchAlgorithmException, UnsupportedEncodingException {
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append(Constants.POST);
        stringBuilder.append(Constants.REQUEST_URL);
        for (Map.Entry<String, String> i : data.entrySet())
        {
            stringBuilder.append(i.getKey());
            stringBuilder.append('=');
            stringBuilder.append(i.getValue());
        }
        stringBuilder.append(Constants.SECRETKEY_VALUE);

        MessageDigest messageDigest = MessageDigest.getInstance("MD5");
        messageDigest.reset();

        Log.e("TAG", stringBuilder.toString());
        messageDigest.update(urlEncode(stringBuilder.toString()).getBytes());
        byte[] md5 = messageDigest.digest();

        stringBuilder.setLength(0);
        for (byte b : md5) {
            stringBuilder.append(String.format("%02x", b & 0xff));
        }

        return stringBuilder;
    }

    /**
     * url编码方式
     *
     * @param str
     *            指定编码方式,默认为utf-8
     * @return
     * @throws UnsupportedEncodingException
     */
    private String urlEncode(String str) throws UnsupportedEncodingException {
        String rc = URLEncoder.encode(str, "utf-8");
        return rc.replace("*", "%2A");
    }
最后请求的时候,记得要设置请求Header中的Content-Type和User-Agent的值。大致的内容就这些,大家可以去云推送官网查看详细的API文档,完整的代码可以通过下方的链接下载。 如若文中或代码有任何写的不对或者不好的地方,欢迎大家指出。


程序源代码:

Android推送 利用REST API实现从客户端推送(百度云推送)

猜你喜欢

转载自blog.csdn.net/u013347241/article/details/53415121