云箭消息推送: 为YunOS提供的系统级消息上行和下行服务
CMNS:CloudApp Message Notify Service 实现消息推送的长链接通道
DeviceToken:YunOS 系统上设备唯一标识
APP Server:业务方应用服务器
通知消息:业务方从APP Server 将消息发送到YunOS通知中心,用户点击后,将唤起应用指定功能
透传消息:业务方从APP Server 将消息发送到YunOS应用,系统将唤醒应用接收消息,应用获取消息后可自行决定该消息的使用方式
云箭是YunOS 的移动应用消息推送解决方案,基于开放、通用、安全、轻量的连接协议,为第三方应用开发者快速构建稳定、高效的消息上行和下行推送服务;
云箭的下行服务
提供了两种消息推送形式,应用开发者可以使用常规的通知消息满足日常的运营需求,也可以借助透传消息实现业务相关的特定功能,同时云箭还提供丰富的标签画像定位用户群体,用于业务的消息精准推送
云箭的上行服务(即将开放 敬请期待)
提供了自定义标签上传,以及通过长连接通道上传应用的自定义数据,为应用的精细化运营提供了可靠便捷的方式
1 消息下行服务
2 消息上行服务(暂未开放 敬请期待)
注册并登录YunOS开放平台,并按照系统提示完成身份验证、手机号绑定等。
进入“控制台”,左侧栏中打开 “应用配置” 并创建应用,按要求填写应用信息,如下图,创建应用后请等待工作人员审核即可(审核期间,API有调用次数限制,审核通过后无限制)
1.进入应用管理页,点击“查看”
2.点击 “客户端SDK”
3.点击 “生成SDK”
4.获取SDK
请上传应用,并选择所需的SDK包,“YunOS基础包”为必选,在“YunOS基础包”中已集成“云箭推送SDK”选择完成后请点击“生成最新的SDK
点击左侧列表”客户端SDK下载“,在右侧会显示目前已经上传的SDK,然后“点击下载”,在下载的文件里面,找到res/drawable/yw_1222.jpg,这就是安全图片,如下图:
注:**上传的apk包的包名,必须与注册应用的包名一致,否则将收不到任何推送消息。**
2.点击链接进入用户协议页面
3.点击“确认”返回页面,点击“消息推送(已开通)”即可进入云箭页面
服务端SDK下载路径:
登录开放平台–> 控制台–> 应用管理 –> 查看–> 服务端SDK, 选择相应的语言版本下载SDK
将消息通过该接口发送到指定设备上的指定应用,由应用决定直接消费或再转发到通知中心。
该接口实现向指定的设备ID发送透传消息,开发者可通过DeviceToken API 获取设备ID
yunos.ospush.open.app.push.device
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
session_id | String | 必须 | 自定义随机字符串,用以标识本次调用。每次调用值不要相同 |
token_type | Number | 必须 | 设备类型, 1为device_token,2为IMEI, 3为UUID |
device_tokens | String | 必须 | 设备值,最大一次性不超过500个设备 |
message | PushMessage | 必须 | 发送的消息信息 |
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
msg_title | String | 可选 | 消息主标题 |
msg_sub_title | String | 可选 | 消息副标题 |
msg_content | String | 必须 | 透传消息体 |
validity_hour | Number | 必须 | 消息失效时间,单位是小时。在某个或某些手机无法触达时,在消息失效后,将不再向该手机发送该消息 |
page_link | String | 可选 | Cloud APP应用接收PUSH消息的PageLink,完整的Page格式为 page://domain/Main, domain接口会自动获取,用户只需要page_link中输入Main即可 |
TaobaoClient client = new DefaultTaobaoClient(url, appkey, secret); YunosOspushOpenAppPushDeviceRequest req = new YunosOspushOpenAppPushDeviceRequest(); req.setSessionId(UUIDUtils.newId()); req.setTokenType(1L); req.setDeviceTokens("1,2,3"); PushMessage obj1 = new PushMessage(); obj1.setMsgTitle("主标题"); obj1.setMsgSubTitle("副标题"); obj1.setMsgContent("透传消息体"); obj1.setValidityHour(5L); obj1.setPageLink("Main"); req.setMessage(obj1); YunosOspushOpenAppPushDeviceResponse rsp = client.execute(req); System.out.println(rsp.getBody());
字段 | 类型 | 描述 |
---|---|---|
result | TopResult | result 对象 |
字段 | 类型 | 描述 |
---|---|---|
code | String | 当code为10000时,才表示调用成功 |
msg | String | 结果描述信息 |
model | PushTaskResult | 结果对象 |
字段 | 类型 | 描述 |
---|---|---|
task_type | Number | 任务类型 |
task_id | Number | 任务id |
session_id | String | session_id |
{ "yunos_ospush_open_app_push_device_response":{ "result":{ "model":{ "task_type":2, "task_id":1234, "session_id":"DX1234" }, "code":"10000", "msg":"操作成功" } } }
{ "error_response":{ "code":50, "msg":"Remote service error", "sub_code":"isv.invalid-parameter", "sub_msg":"非法参数" } }
将消息通过该接口发送到指定设备上的指定应用,由应用决定直接消费或再转发到通知中心。
该接口使用OS公共标签圈定人群,然后向该人群发送透传消息。
yunos.ospush.open.app.push.pubtag
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
session_id | String | 必须 | 自定义随机字符串,用以标识本次调用。每次调用值不要相同 |
task_info | TaskInfo | 必须 | 任务参数对象 |
tag_condition_lists | Tagconditionlists [] | 必须 | 用户标签列表,注意:1、此列表List的总数不允许超过20个。2、tagValues的总数不能超过30个 |
message | PushMessage | 必须 | 发送的消息信息 |
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
task_name | String | 可选 | 本次调用任务名称,如果不传,系统会自动命名 |
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
tag_code | String | 必须 | 标签Code。 |
tag_values | String | 必须 | 标签值。1、checkbox类型:多值用逗号分隔。比如“男,女” 2、date类型:小值在前,大值在后,用逗号分隔。比如“2016-05-01,2016-10-01” 3、number类型:小值在前,大值在后,用逗号分隔。比如“1,10”表示大于等于1,小于等于10;“1,”表示大于等于1;“,10”表示小于等于10 |
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
msg_title | String | 可选 | 消息主标题 |
msg_sub_title | String | 可选 | 消息副标题 |
msg_content | String | 必须 | 透传消息体 |
validity_hour | Number | 必须 | 消息失效时间,单位是小时。在某个或某些手机无法触达时,在消息失效后,将不再向该手机发送该消息 |
page_link | String | 可选 | Cloud APP应用接收PUSH消息的PageLink,完整的Page格式为 page://domain/Main, domain接口会自动获取,用户只需要page_link中输入Main即可 |
TaobaoClient client = new DefaultTaobaoClient(url, appkey, secret); YunosOspushOpenAppPushPubtagRequest req = new YunosOspushOpenAppPushPubtagRequest(); req.setSessionId(UUIDUtils.newId()); TaskInfo obj1 = new TaskInfo(); obj1.setTaskName("taskName"); req.setTaskInfo(obj1); List<Tagconditionlists> list3 = new ArrayList<Tagconditionlists>(); Tagconditionlists obj4 = new Tagconditionlists(); list3.add(obj4); obj4.setTagCode("test_tag"); obj4.setTagValues("test_tag"); req.setTagConditionLists(list3); PushMessage obj5 = new PushMessage(); obj5.setMsgTitle("主标题"); obj5.setMsgSubTitle("副标题"); obj5.setMsgContent("透传消息体"); obj5.setValidityHour(5L); obj5.setPageLink("Main"); req.setMessage(obj5); YunosOspushOpenAppPushPubtagResponse rsp = client.execute(req); System.out.println(rsp.getBody());
字段 | 类型 | 描述 |
---|---|---|
result | TopResult | result 对象 |
字段 | 类型 | 描述 |
---|---|---|
code | String | 当code为10000时,才表示调用成功 |
msg | String | 结果描述信息 |
model | PushTaskResult | 结果对象 |
字段 | 类型 | 描述 |
---|---|---|
task_type | Number | 任务类型 |
task_id | Number | 任务id |
session_id | String | session_id |
{ "yunos_ospush_open_app_push_pubtag_response":{ "result":{ "model":{ "task_type":1, "task_id":1234, "session_id":"DX1234" }, "code":"10000", "msg":"操作成功" } } }
{ "error_response":{ "code":50, "msg":"Remote service error", "sub_code":"isv.invalid-parameter", "sub_msg":"非法参数" } }
将消息通过该接口发送到指定设备上的通知中心。
该接口使用OS公共标签圈定人群,然后向该人群发送通知消息
yunos.ospush.open.notify.push.pubtag
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
session_id | String | 必须 | 自定义随机字符串,用以标识本次调用。每次调用值不要相同 |
task_info | TaskInfo | 必须 | 任务参数对象 |
tag_condition_lists | Tagconditionlists [] | 必须 | 用户标签列表,注意:1、此列表List的总数不允许超过20个。2、tagValues的总数不能超过30个 |
message | PushMessage | 必须 | 发送的消息信息 |
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
task_name | String | 可选 | 本次调用任务名称,如果不传,系统会自动命名 |
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
tag_code | String | 必须 | 标签Code。 |
tag_values | String | 必须 | 标签值。1、checkbox类型:多值用逗号分隔。比如“男,女” 2、date类型:小值在前,大值在后,用逗号分隔。比如“2016-05-01,2016-10-01” 3、number类型:小值在前,大值在后,用逗号分隔。比如“1,10”表示大于等于1,小于等于10;“1,”表示大于等于1;“,10”表示小于等于10 |
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
msg_title | String | 必须 | 消息主标题,不超过30个字符 |
msg_sub_title | String | 必须 | 消息副标题,不超过30个字符 |
msg_content | String | 可选 | 透传消息体, json格式 ,按照通知消息类型输入对应消息,1打开应用(无需传值) ,3打开uri: {“uri”: “xiami://collect/11332531"},4浏览器打开url: {”uri“: ”https://www.taobao.com"} |
validity_hour | Number | 必须 | 消息失效时间,单位是小时。在某个或某些手机无法触达时,在消息失效后,将不再向该手机发送该消息 |
page_link | String | 可选 | Cloud APP应用接收PUSH消息的PageLink,完整的Page格式为 page://domain/Main, domain接口会自动获取,用户只需要page_link中输入Main即可 |
msg_type | String | 必须 | 通知消息类型 1:打开应用, 3:打开uri, 4:浏览器打开url |
TaobaoClient client = new DefaultTaobaoClient(url, appkey, secret); YunosOspushOpenNotifyPushPubtagRequest req = new YunosOspushOpenNotifyPushPubtagRequest(); req.setSessionId(UUIDUtils.newId()); TaskInfo obj1 = new TaskInfo(); obj1.setTaskName("taskName"); req.setTaskInfo(obj1); List<TagCondition> list3 = new ArrayList<TagCondition>(); TagCondition obj4 = new TagCondition(); list3.add(obj4); obj4.setTagCode("test_tag"); obj4.setTagValues("test_tag"); req.setTagConditionLists(list3); PushMessage obj5 = new PushMessage(); obj5.setMsgTitle("主标题"); obj5.setMsgSubTitle("副标题"); obj5.setMsgContent("通知消息体"); obj5.setValidityHour(5L); obj5.setMsgType(1L); obj5.setPageLink("Main"); req.setMessage(obj5); YunosOspushOpenNotifyPushPubtagResponse rsp = client.execute(req); System.out.println(rsp.getBody());
字段 | 类型 | 描述 |
---|---|---|
result | TopResult | result 对象 |
字段 | 类型 | 描述 |
---|---|---|
code | String | 当code为10000时,才表示调用成功 |
msg | String | 结果描述信息 |
model | PushTaskResult | 结果对象 |
字段 | 类型 | 描述 |
---|---|---|
task_type | Number | 任务类型 |
task_id | Number | 任务id |
session_id | String | session_id |
{ "yunos_ospush_open_notify_push_pubtag_response":{ "result":{ "model":{ "session_id":"DX1234", "task_id":1234, "task_type":1 }, "code":"10000", "msg":"操作成功" } } }
{ "error_response":{ "code":50, "msg":"Remote service error", "sub_code":"isv.invalid-parameter", "sub_msg":"非法参数" } }
yunos.ospush.open.push.task.result
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
session_id | String | 必须 | 自定义随机字符串,用以标识本次调用。每次调用值不要相同 |
task_id | String | 必须 | 透传接口返回的taskId |
task_type | Number | 必须 | 透传接口返回的type,1是圈定人群发送结果查询,2是指定特定设备查询。其中task_type=1的查询有效期只有15天,即发送的任务如果在15天后查询,是没有值的 |
TaobaoClient client = new DefaultTaobaoClient(url, appkey, secret); YunosOspushOpenPushTaskResultRequest req = new YunosOspushOpenPushTaskResultRequest(); req.setSessionId(UUIDUtils.newId()); req.setTaskId("1234"); req.setTaskType(1L); req.setCondMapString("{}"); YunosOspushOpenPushTaskResultResponse rsp = client.execute(req); System.out.println(rsp.getBody());
字段 | 类型 | 描述 |
---|---|---|
result | TopResult | result 对象 |
字段 | 类型 | 描述 |
---|---|---|
code | String | 当code为10000时,才表示调用成功 |
msg | String | 结果描述信息 |
model | TaskStatsResult | 结果对象 |
字段 | 类型 | 描述 |
---|---|---|
arrive_count | Number | 到达数 |
send_count | Number | 发送数 |
session_id | String | session_id |
{ "yunos_ospush_open_push_task_result_response":{ "result":{ "model":{ "arrive_count":99, "send_count":100, "session_id":"DX1234" }, "code":"10000", "msg":"操作成功" } } }
{ "error_response":{ "code":50, "msg":"Remote service error", "sub_code":"isv.invalid-parameter", "sub_msg":"非法参数" } }
yunos.ospush.open.tagcode.get
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
session_id | String | 必须 | 自定义随机字符串,用以标识本次调用。每次调用值不要相同 |
tag_type | Number | 必须 | 查询类型:1为公共标签;2为应用私有标签 |
page_start | Number | 必须 | 每页起始查询参数 |
page_size | Number | 必须 | 每页查询数量 |
TaobaoClient client = new DefaultTaobaoClient(url, appkey, secret); YunosOspushOpenTagcodeGetRequest req = new YunosOspushOpenTagcodeGetRequest(); req.setSessionId(UUIDUtils.newId()); req.setTagType(1L); req.setPageStart(0L); req.setPageSize(100L); YunosOspushOpenTagcodeGetResponse rsp = client.execute(req); System.out.println(rsp.getBody());
字段 | 类型 | 描述 |
---|---|---|
result | TopResult | result 对象 |
字段 | 类型 | 描述 |
---|---|---|
code | String | 当code为10000时,才表示调用成功 |
msg | String | 结果描述信息 |
model | OpenTagInfoResult | 结果对象 |
字段 | 类型 | 描述 |
---|---|---|
session_id | String | 自定义随机字符串,用以标识本次调用 |
total_size | Number | 查询到标签的总数量 |
tag_info_lists | OpenTagInfo[] | 标签列表 |
字段 | 类型 | 描述 |
---|---|---|
control_type | String | checkbox是枚举类型,data是日期类型,number是长整形 |
tag_name | String | tagName |
tag_code | String | 标签code |
{ "yunos_ospush_open_tagcode_get_response":{ "result":{ "model":{ "session_id":"DX1234", "total_size":1, "tag_info_lists":{ "open_tag_info":[ { "control_type":"checkbox", "tag_name":"测试标签", "tag_code":"test001" } ] } }, "code":"10000", "msg":"操作成功" } } }
{ "error_response":{ "code":50, "msg":"Remote service error", "sub_code":"isv.invalid-parameter", "sub_msg":"非法参数" } }
yunos.ospush.open.tagvalue.get
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
session_id | String | 必须 | 自定义随机字符串,用以标识本次调用。每次调用值不要相同 |
tag_code | String | 必须 | 需要查询值的标签code |
page_start | Number | 必须 | 每页起始查询参数 |
page_size | Number | 必须 | 每页查询数量 |
TaobaoClient client = new DefaultTaobaoClient(url, appkey, secret); YunosOspushOpenTagvalueGetRequest req = new YunosOspushOpenTagvalueGetRequest(); req.setSessionId(UUIDUtils.newId()); req.setTagCode("tag1"); req.setPageStart(0L); req.setPageSize(100L); YunosOspushOpenTagvalueGetResponse rsp = client.execute(req); System.out.println(rsp.getBody());
字段 | 类型 | 描述 |
---|---|---|
result | TopResult | result 对象 |
字段 | 类型 | 描述 |
---|---|---|
code | String | 当code为10000时,才表示调用成功 |
msg | String | 结果描述信息 |
model | OpenTagValueResult | 结果对象 |
字段 | 类型 | 描述 |
---|---|---|
session_id | String | 自定义随机字符串,标识本次调用 |
tag_code | String | 标签code |
total_size | Number | 标签值总数 |
tag_value_list | OpenTagValue [] | 标签值列表 |
字段 | 类型 | 描述 |
---|---|---|
value_code | String | 标签值code |
value_name | String | 标签值名称 |
{ "yunos_ospush_open_tagvalue_get_response":{ "result":{ "model":{ "session_id":"DX1234", "tag_code":"tag1", "total_size":1000, "tag_value_list":{ "open_tag_value":[ { "value_code":"1", "value_name":"测试值1" } ...... ] } }, "code":"10000", "msg":"操作成功" } } }
{ "error_response":{ "code":50, "msg":"Remote service error", "sub_code":"isv.invalid-parameter", "sub_msg":"非法参数" } }
错误码 | 错误描述 | 解决方案 |
---|---|---|
10100 | 参数错误 | 返回的msg中有错误的明细信息,请对照 |
10050 | tokenType非法 | tokenType非法 |
10042 | 任务没有匹配到设备 | 任务没有匹配到设备 |
10040 | 超出单次接口调用发送人数限制(500) | 超出单次接口调用发送人数限制(500) |
10020 | push渠道非法 | 请检查自己的appkey是否被授权 |
12040 | 新建任务失败 | 新建任务失败,请检查msg_content是否为json格式,或联系管理员排查问题 |
10010 | push任务失败 | push任务失败,可以联系管理员排查问题 |
10090 | 您的文案中有敏感词 | 您的文案中有敏感词 |
12010 | 查询类型错误 | 查询类型错误,请检查是否填入需要查询的Type |
12020 | 未找到发送记录 | 未找到发送记录,请检查输入的查询信息是否正确 |
12021 | 尚未有发送数据 | 可以等一会再来查询 |
12022 | 该任务的查询记录已过期 | 该任务的查询记录已过期,如果是指定标签发送人群的数据,请在15天内查询。 |
12030 | 查询失败 | 查询失败,可以联系管理员排查问题 |
12023 | 未能找到发送Task | 请检查输入的Task信息 |
13000 | tagCode查询失败 | 检查tagCode |
13001 | 未找到此tagCode | 未找到此tagCode |
13100 | 标签value查询失败! | 可以联系管理员查看 |
13101 | 未找到此tagCode对应的标签值 | 未找到此tagCode对应的标签值 |
13102 | 此tagCode非checkbox类型 | 非checkBox的tagCode不能查询 |
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="yunos.permission.ACCESS_CMNS" /> <uses-permission android:name="com.yunos.ad.PERMISSION" /> <uses-permission android:name="com.yunos.ad.PERMISSION.input_caller_package"/>
注:在Android 5.0或者更高版本,android.permission.READ_PHONE_STATE
与WRITE_EXTERNAL_STORAGE
可能需要动态申请,申请方式为:
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.READ_PHONE_STATE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 0);
<receiver android:name="com.yunos.cmns.CMNSMessageReceiver"> <intent-filter> <action android:name="com.yunos.cmns.intent.SEND_NOTIFICATION"/> <action android:name="com.yunos.cmns.intent.CANCEL_NOTIFICATION"/> <action android:name="com.yunos.cmns.intent.PASSTHROUGH"/> <action android:name="com.yunos.cmns.intent.NOTIFICATION_CLICKED"/> <action android:name="com.yunos.cmns.intent.NOTIFICATION_REMOVE"/> <!-- 注意:在YunOS上,需要增加自己的包名,可以保持长连通道一直有效,在Android上不需要此项 --> <action android:name="com.xx.xx.your package name"/> </intent-filter> </receiver> <receiver android:name="com.yunos.ad.cmnspush.ReportReceiver" android:enabled="true"> <intent-filter> <action android:name="com.yunos.report.action"/> <category android:name="android.intent.category.DEFAULT"/> <data android:scheme="yunosad" <!-- 注意android:host必须填写为当前应用包名,否则无法接上传上报信息 --> android:host="com.xx.xx.your package name" /> </intent-filter> </receiver> <receiver android:name="com.yunos.ad.cmnspush.NetChangeReport" > <intent-filter> <action android:name="android.net.conn.CONNECTIVITY_CHANGE" /> </intent-filter> </receiver>
<service android:name="com.yunos.cmns.service.CMNSService" android:exported="true" android:process="com.yunos.cmns.service.remote.CMNSService"> <intent-filter> <category android:name="android.intent.category.DEFAULT" /> <action android:name="com.yunos.cmns.service.CMNSService" /> </intent-filter> </service>
注:**安全保镖,安全图片,资源文件,assets文件,AndroidManifest.xml内容,均需要按照上面方法正确操作,否则将引起Push接入失败。**
描述:Push SDK初始化 。
application.onCreate
里面调用初始化。接口原型:
/** Push SDK初始化 * @param applicationContext Context 应用Context * @param listener PushAsyncListener 初始化完成后的回调 */ void init(Context applicationContext, PushAsyncInitListener listener);
其中PushAsyncInitListener
如下:
public interface PushAsyncInitListener { /** PushAsyncListener * @param errorCode int 返回码,0表示成功,错误码详见PushError.java */ void onInit(int errorCode); }
调用示例:
public class MyApplication extends Application { @Override public void onCreate() { super.onCreate(); PushClient.getInstance().init(this, new PushAsyncInitListener() { @Override public void onInit(final int errorCode) { Log.d(TAG, "init " + errorCode == PushErrorCode.ERROR_OK ? "success" : "failed"); } }); } }
描述:在完成 初始化Push SDK后,请立即调用该接口 建立长连接通道。该建连有可能复用已经存在的长连接通道,当前若无可用通道,则会自行建立长连通道。
接口原型:
/** Push建联,如果建联不成功,Push内部会等待重试直到成功,成功后再回调 * 如果回调错误了,表示此错误不能通过重试解决。 * 如果中间因为网络断开等情况导致Push连接断开,Push内部也会等待重试,connect方法只需要调用一次 * @param listener PushConnectionListener 建联回调 */ void connect(PushConnectionListener listener);
接口需要的相关类与方法如下:
public interface PushConnectionListener { /** Push通道建联回调 * @param errorCode int 错误码,详见PushErrorCode.java */ void onConnect(int errorCode); }
调用示例:
PushClient.getInstance().init(this, new PushAsyncInitListener() { @Override public void onInit(final int errorCode) { if (errorCode == ErrorCode.ErrorOK) { PushClient.getInstance().connect(new PushConnectionListener() { @Override public void onConnect(final int errorCode) { Log.d(TAG, "onConnect: " + errroCode); } }); } else { Log.e(TAG, "init failed for reason: " + errorCode); } } });
注:
建联接口需要在init回调后才能调用,不然还未初始化成功就调用connect,会导致connect的失败。
此接口可能长时间没有返回,是因为网络等原因暂时连接不上,Push底层会多次重试,直到连接成功。
?
描述:获取Push SDK长连接通道状态(是否在线)。
接口原型:
/** * @return isConnected boolean 设备是否在线 */ boolean isConnected();
调用示例:
boolean isConnnected = PushClient.getInstance().isConnecte(); Log.d("Push", "connect status: " + isConnected ? "connected" : "disconnected");
注:在某些情况下,比如网络不好、ssl证书验证失败等情况下,Push通道会不存在,调用setTag
,delTag
,sendMessage
,sendMessageWithReply
等接口,需要判断Push服务的连接状态,如果Push通道不存在,需要接入方选择**丢弃不发**或者**等待通道恢复延迟发送**。
描述:设置消息监听可以收到Push服务端下发的透传消息、以及通知消息的点击回调
接口原型:
/** * @param listener PushMessageListener 消息回调 */ void setMessageListener(PushMessageListener listener);
其中相关类与方法如下:
public class PushMessage { /** 获取消息的id * @return long 消息id */ public long getMessageId(); /** 获取消息主体内容 * @return String 消息主体内容 */ public String getPayload(); } interface PushMessageListener { /** 当收到Push服务端透传的消息时回调 * @param context Context * @param msg PushMessage 透传的消息 */ void onPassThroughMessage(Context context, PushMessage msg); /** 当用户点击通知中心消息时回调 * @param context Context * @param msg PushMessage 通知中心点击的消息 */ void onNotificationClicked(Context context, PushMessage msg); }
调用示例:
PushClient.getInstance().setMessageListener(new PushMessageListener() { // 透传消息回调,PushMessage为Push服务端下发的回调消息。 @Override public void onPassThroughMessage(Context context, PushMessage msg) { Log.d(TAG, "pass mid: " + msg.getMessageId() + "\tmsg: " + msg.getPayload()); } // 通知中心点击事件,在用户手动点击通知中心消息后回调,PushMessage为Push服务端下发的通知消息。 @Override public void onNotificationClicked(Context context, PushMessage msg) { Log.d(TAG, "click mid: " + msg.getMessageId() + "\tmsg: " + msg.getPayload()); } });
注:**setMessageListenr
接口需要在Application.onCreate
中设置,因为推送消息会通过com.yunos.cmns.CMNSMessageReceiver
唤醒应用,如果不在Application.onCreate
里面调用,唤醒状态无法设置消息监听者,应用就无法感知消息回调。**
通过Push服务端推送 “通知消息” ,会带有五个Intent对象:Action
,Component
,Data
,Type
,Category
,点击通知中心的点击消息,会通过这五个Intent对象去打开相应的应用页面。
Action规定了Intent要完成的动作,在打开页面的过程中,需要在目标组件的AndroidManifest.xml中声明过滤器规则,将Action加入其中。
默认action是Intent.ACTION_VIEW
,即android.intent.action.View
,也可以根据具体需求需求设置其他Action。Action设置方法如下:
xml <activity android:name="MessageClickActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity>
如果应用服务端传给Push服务端的字段中带有Component这个属性的话,将直接使用它指定的组件。指定了这个属性以后,Intent的其它所有属性都是可选的。
收到带有Component的消息,Push SDK会取其中的class和package字段放到Intent中,去完成相应的操作。
如果应用服务端传给Push服务端的字段中带有Category这个属性的话,SDK会在Intent中添加多个类别,那就要求被匹配的组件必须同时满足这多个类别,才能匹配成功。
默认category是android.intent.category.DEFAULT,也可以根据具体需求设置其他Category。配置方法如下:
xml <activity android:name="MessageClickActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="com.yunos.push.category.DEFAULT" /> </intent-filter> </activity>
Data字段指定了一个Uri,表示需要访问的数据。通常情况下,我们可以使用Action加Data两个属性来描述一个意图。
Data与Action、Category声明方式相同,也是描述在<intent-filter>
中,设置方法如下:
xml <activity android:name="MessageClickActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:scheme="http" android:host="yunos.com"/> </intent-filter> </activity>
如果Intent对象中既包含Uri又包含Type,那么,在<intent-filter>
中也必须二者都包含才能通过测试。
Type属性用于明确指定Data属性的数据类型或MIME类型,但是通常来说,当Intent不指定Data属性时,Type属性才会起作用,否则Android系统将会根据Data属性值来分析数据的类型,所以无需指定Type属性。
配置方法如下:
xml <activity android:name="MessageClickActivity"> <intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:type="audio/mpeg" android:scheme="http" android:host="yunos.com" /> </intent-filter> </activity>
这五个Intent对象可以在云箭平台设置,通过这五个对象组合,可以发送以下几种类型的消息:
点击通知中心里面的H5消息,会使用系统默认的浏览器打开http链接,如果uri不是http格式,系统会默认匹配uri,使用系统默认应用去打开uri,如uri=taobao://m.taobao.com
,会跳转到淘宝首页。
点击通知中心的消息,会打开应用的默认Activity,需要应用在AndroidManifest.xml
中Activiy的<intent-filter>
中添加action
。
点击通知中心里面的应用内消息,会根据AndroidManifest.xml
中的配置去打开相应的界面,即需要应用在AndroidManifest.xml
中,给相应Activity的<intent-filter>
属性增加action
和data
,详见上面Data
字段的介绍。
透传消息不会显示在通知中心,会通过PushSDK的回调接口告知应用,可以在后台运行。
?
描述:Push服务端颁发设备 Device token,应用客户端获取后,可通过应用服务端将消息发到指定的设备上。
接口原型:
/** * @param listener PushGetDeviceTokenListener 获取token回调 */ void getDeviceToken(PushGetDeviceTokenListener listener);
接口需要的相关类与方法如下:
interface PushGetDeviceTokenListener { /** 获取设备token回调 * @param errorCode int 错误码,详见PushErrorCode.java * @param token String 设备token */ void onGetDeviceToken(int errorCode, String token); }
调用示例:
PushClient.getInstance().getDeviceToken(new PushGetDeviceTokenListener() { @Override public void onGetDeviceToken(final int errorCode, final String token) { Log.d(TAG, "getDeviceToken errorCode:" + errorCode + "\ttoken: " + token); } });
描述:给当前设备设置一个tag,每个appKey最多可以设置10个tag,每个tag不能超过45个字符。
接口原型:
/** * @param tag String 设备标签 * @param listener PushUpdateTagListener 标签更新回调 */ void setTag(String tag, PushUpdateTagListener listener);
接口需要的相关类与方法如下:
interface PushUpdateTagListener { /** 获取tag回调 * @param errorCode int 设置标签错误码,详见PushErrorCode.java */ void onUpdateTag(int errorCode); }
调用示例:
PushClient.getInstance().setTag("小清新", new PushUpdateTagListener() { @Override public void onUpdateTag(final int errorCode) { Log.d(TAG, "onSetTag: " + errorCode); } });
描述:删除当前设备的一个标签,每个appKey最多可以设置10个tag。
接口原型:
/** * @param tag String 设备标签 * @param listener PushUpdateTagListener 标签更新回调 */ void delTag(String tag, PushUpdateTagListener listener);
接口需要的相关类与方法如下:
interface PushUpdateTagListener { /** 获取tag回调 * @param errorCode int 删除标签错误码,详见PushErrorCode.java */ void onUpdateTag(int errorCode); }
调用示例:
PushClient.getInstance().delTag("小清新", new PushUpdateTagListener() { @Override public void onUpdateTag(final int errorCode) { Log.d(TAG, "onDelTag: " + errorCode); } });
描述:上传消息到应用对用的appKey的metaq上,此接口适用于不关注成功性的接口,比如上报位置信息等(Push底层也会多次重传,尽量保证上传成功率,只是没有成功与否的返回)。
接口原型:
/** * @param tag String 上行消息的tag,服务端用来过滤 * @param msg String 上行的消息 */ void sendMessage(String tag, String msg);
调用示例:
PushClient.getInstance().sendMessage("place", "在杭州");
描述:上传消息到应用对用的appKey的metaq上,此接口会返回相关错误码。
接口原型:
/** * @param tag String 上行消息的tag,服务端做过滤消息用 * @param msg String 上行的消息 * @param listener PushSendMessageListener 上行消息的回调 */ void sendMessageWithReply(String tag, String msg, PushSendMessageListener listener);
接口需要的相关类与方法如下:
interface PushSendMessageListener { /** 上行消息回调 * @param errorCode int 上行消息错误码,详见PushErrorCode.java */ void onSendMessage(int errorCode); }
调用示例:
PushClient.getInstance().sendMessageWithReply("place", "在杭州", new PushSendMessageListener() { @Override public void onSendMessage(final int errorCode) { Log.d(TAG, "onSendMessage: " + errorCode); } });
注:如果网络状态不佳,上行消息可能会超时(可能数据已经上传到服务端,但是客户端没有收到回包),如果选择重发,Push服务端可能会收到多条一样的数据,此时需要应用服务端到metaq中取数据时做数据去重。
混淆规则如下:
# push sdk proguard -keep public class com.yunos.cmns.** { public *; } # push sdk proguard -keep public class com.rhino.common.** { public *; } # security box proguard -keep public class com.alibaba.wireless.security.** { public *; } # push sdk proguard -keep class com.yunos.ad.** {*;} -dontwarn com.yunos.cmns.** -dontwarn com.rhino.common.** -dontwarn com.yunos.ad.**
// 错误码见: com.yunos.push.api.ErrorCode // 成功 public static final int ERROR_OK = 0; // 网络错误 public static final int ERROR_NETWORK_ERROR = -1000; // 返回的消息内容错误 public static final int ERROR_BAD_PARA = -999; // 服务端返回了空的内容 public static final int ERROR_SERVER_RETURN_EMPTY = -997; // 请求被强制取消,一般是设备证书问题导致,比如系统时间戳不对等 public static final int ERROR_CANCELLED = -996; // http状态码错误,比如404、500等。 public static final int ERROR_RESPONSE_CODE_ERROR = -995; // 4xxxx为本地运行过程中出现的错误 // Push系统通道服务没有初始化 public static final int ERROR_SERVICE_IS_NOT_INITIALIZED = 41002; // Push系统通道没有建联 public static final int ERROR_SYSTEM_SERVICE_IS_NOT_CONNECTED = 41003; // Push系统通道不可用 public static final int ERROR_SYSTEM_SERVICE_IS_NOT_AVALIABLE = 41004; // PushSDK通道不可用 public static final int ERROR_SDK_SERVICE_IS_NOT_AVALIABLE = 41005; // 安全保镖初始化失败 public static final int ERROR_SECURITYBOX_INITIALIZE_FAILED = 41006; // 安全保镖获取appKey失败 public static final int ERROR_SECURITYBOX_GETAPPKEY_ERROR = 41007; // 调用Push SDK Service方法错误 public static final int ERROR_UNEXPECT_RUN_ERROR = 41008; // 本地不存在ys_p_1111文件,可以增加ys_p_1111文件,也可以等待后台wifi下载 public static final int ERROR_NO_FULL_PACKAGE = 41009; // 本地版本过旧,升级导致接口不匹配 public static final int ERROR_NO_SUCH_API = 41010; // Push SDK Service已经关闭,碰到此错误码,可重试调用接口,等到新的Service启动 public static final int ERROR_SERVICE_SHUTDOWN = 41011; // 700xx为建联过程中,服务端返回的错误码 // 账号Token过期 public static final int ERROR_NOT_AUTHORIZED_EXPIRED = 70005; // 账号Token非法 public static final int ERROR_NOT_AUTHORIZED_ILLEGAL = 70006; // 账号中心异常 public static final int ERROR_ACCOUNT_CENTER_ERR = 70007; // 账号中心未配置 public static final int ERROR_NO_ACCOUNT_CENTER_FOR_APPKEY = 70008; // IMEI或者UUID重复 public static final int ERROR_DUPLICATE_IMEI_OR_UUID = 70009; // SID 中心异常 public static final int ERROR_SID_CENTER_ERR = 70010; // IMIE非法 public static final int ERROR_CLIENTID_IMEI_ILLEGAL = 70011; // Push ClientID为空 public static final int ERROR_CLIENTID_ISNULL = 70013; // Push Password为空 public static final int ERROR_PASSWORD_ISNULL = 70014; // Push UserName为空 public static final int ERROR_USERNAME_ISNULL = 70015; // Push UserName非法 public static final int ERROR_USERNAME_ILLEGAL = 70016; // Push UserName长度非法 public static final int ERROR_USERNAME_LENGTH_ILLEGAL = 70017; // YunOS UUID非法 public static final int ERROR_UUID_ILLEGAL = 70018; // YunOS UUID中心异常 public static final int ERROR_UUID_CENTER_ERR = 70019; // 应用appKey非法,一般是安全图片问题 public static final int ERROR_APPKEY_ILLEGAL = 70020; // 应用secret不存在,一般是安全图片问题 public static final int ERROR_SECRET_NOT_EXIST = 70030; // 本地时间戳不正确 public static final int ERROR_SIGN_TIMER_ILLEGAL = 70031; // 应用签名不对,一般是安全图片问题 public static final int ERROR_SIGN_ILLEGAL = 70032; // 800xx为Push相关接口调用服务端返回的错误码 // 无效json public static final int ERROR_INVALID_JSON = 80001; // 应用appKey错误 public static final int ERROR_APPKEY_ERROR = 80010; // 应用secret非法,一般是安全图片问题 public static final int ERROR_SECRET_ILLEGAL = 80011; // 应用无上行消息权限,请到Push申请权限 public static final int ERROR_NO_UPLOAD_PERMISSION = 80012; // 上行消息到指定应用的appKey非法 public static final int ERROR_PAPPKEY_ILLEGAL = 80013; // 上行消息到指定应用的appKey无效 public static final int ERROR_PAPPKEY_INVALID = 80014; // 上行消息本地时间戳不正确 public static final int ERROR_TIMESTAMP_ILLEGAL = 80020; // 标签长度超过45个字符 public static final int ERROR_TAG_LENGTH_ILLEGAL = 80030; // 当前设备设置的标签总数超过了10个 public static final int ERROR_TAG_COUNT_ILLEGAL = 80031;
Q:有哪些情况可能导致Push通道建联失败?
A:PushSDK的建联失败主要分为三种,一种是PushSDK本地没有更新包(41009),连接wifi更新包即可下载成功;一种是直接返回了失败,表示该设备存在某种异常情况,导致设备无法建联,通过重试也无法解决问题,常见的如:安全图片问题(70020,70030)、本地时间戳错误导致ssl证书校验失败(-996)、本地无imei或者uuid等设备唯一id(70011);另外一种不会直接返回失败,是因为某些临时的情况导致的暂时建联失败,比如网络原因等,此时PushSDK内部维护了一套恢复机制,会一直等待环境的恢复,待建联成功后再回调上层。
Q:当应用活跃时可以收到消息,但是应用没有启动的时候,无法收到消息,应该怎么解决?
A:可以从以下三个步骤检查:
确保PushClient.getInstance().init
是否是在application.onCreate
里面调用的,如果不在application.onCreate里面调用,会导致唤醒应用时无法初始化而进行后面的步骤。
确保AndroidManifest.xml
中的CMNSMessageReceiver
有配置<action android:name="com.xx.xx.your package name"/>
。
确保注册应用预留的action为包名,如果不能确认,请联系内部人员解决。
Q:我的应用首次进入时,会弹窗告知用户授权使用网络,应该怎么对接PushSDK?
A:当调用PushSDK的init接口时,会有连接网络的行为,如果需要用户授权使用网络,可参考demo中的做法。setMessageListener
不会调用网络,可以直接在application.onCreate
中调用。
Q:为什么消息发送完成了,通知中心无法显示消息?
A:可能是用户在通知中心屏蔽了该应用的通知,请在通知中心设置中打开该开关。
Q:为什么点击了通知中心的消息,却无法打开应用指定的页面?
A:这种情况很可能是服务端推送下来的Intent对象(Data、Action、Category、Component、Type)与本地应用的AndroidManifest.xml
中指定Activity的<intent-filter>
的配置不一致导致的,请检查本地配置或者服务端推送的参数。
Q:为什么服务端发送的是一条富媒体消息,在客户端上显示的却是一条普通的通知消息?
A:富媒体消息的显示依赖多种环境,复杂的客户端环境或者服务端发送了错误的参数,可能会导致图片等资源下载失败、富媒体模板解析失败,多次重试失败后,会降级为普通的通知消息。服务端在发送富媒体消息的同时,也需要做好富媒体消息降级的准备。
Q:安全图片是什么?有什么作用?为什么会加载安全图片失败?怎么解决?
A:安全保镖是阿里巴巴集团安全部推出的一套保障移动平台应用完整性、应用执行环境可信性、数据机密性的专业完整的安全解决方案。PushSDK依赖安全保镖去保存应用的关键秘钥,确保应用的秘钥不会泄露出去。
在YunOS开放平台上,开发者需要上传已经签好名的应用到服务端,服务端取出应用的签名信息,然后通过一系列安全的加密手段将秘钥放到安全图片中并通过SDK下载的方式返回给开发者,在PushSDK运行时,安全保镖会去校验应用的多种参数(比如签名、包名等),如果校验失败,秘钥是取不出来的,就会导致加载安全图片失败,进而导致PushSDK建联失败。
如果出现安全图片加载失败的情况,首先检查应用内部是否存在安全图片(res/drawable/yw_1222.jpg);如果存在再次检查该图片是否是从YunOS开放平台下载的,如果不是,请从YunOS开放平台下载重新下载安全图片;如果图片来源也正确,请检查生成安全图片的apk,包名以及签名的keystore文件是否与当前运行的apk一致,如果最后依然存在问题,请联系开发人员解决。