这几天一直在做Android 消息推送接入前的准备工作
特此在这里将自己在加载第三方推送时出现的问题以及详细的接入步骤进行记录,已免后者踩坑
为什么选择友盟推送?
在刚开始准备接入消息推送时 首先我先想到的是极光推送,在大概看了一遍他们的接入流程并且根据他们的文档做了一个demo后,因为是第一次接入推送,所以不太清楚在app离线情况下是如何接收到推送的流程,在积极和他们的业务人员沟通后也没有得到一个我想要的回答 可能是因为自身原因(但是服务挺好的 会把你拉到一个相关的群聊里面 你可以和他们技术进行沟通 )。。。最后没选择激光推送的原因是他们的收费标准不清晰和两个业务员沟通得到的答复都不太一样 。然后在学长的推荐下查看了友盟推送。对于友盟的第一印象就是感觉他们的文档写的很通俗易懂,并且非常棒的一点是还提供了视频教学,虽然视频长度很短,但是该表达的都表现出来了,还是很赞的。当然了,最后也是最重要的一点就是他们的推送是分为免费版和Pro版的,免费版的完全够日常的使用。
接入前的准备:
- 友盟官方接入文档概述
这里推荐大家使用最新版的SDK (Push SDK 6.1.0及之后才支持AndroidQ) - 友盟推送产品后台管理
- 友盟推送官方demo
- 新手引导 如果你还没接触过友盟推送,建议先看一下推送集成的流程
打开官方示例
当我们从官网下载好推送的demo,因为是一个完整的项目直接编译即可。
编译完成后先不着急运行,我们首先需要在友盟推送产品后台管理新建一个新应用
这里测试阶段你可以先填入当前demo的详细包名,点击确认添加后就会进入到配置向导界面
这里你就可以拿到应用唯一的AppKey,Uming Message Secret,App Master Secret 这三个值很重要后期我们需要使用他们。
初始化SDK
进入我们的Android demo的MyApplication中,在UMConfigure.init()方法中分别填入我们的应用申请的Appkey和Umeng Message Secret对应信息
UMConfigure.init(this, "your appkey", "Umeng", UMConfigure.DEVICE_TYPE_PHONE, "umeng message secret");
然后运行一下我们的项目,拿到你设备专属的device_token
然后这时,进入我们的友盟推送后台管理,点击测试模式->创建测试任务
在创建测试任务最后一步点击完成
这时等待几秒钟后你的app就会接收到消息通知,(请先确保当前demo在前台)
欧克,到这一步我们就算接入成功我们的测试demo了,当然了这只算是刚刚开始,点击该通知就会自动跳转到我们的app中去,当然这里可以自定义我们收到通知后点击通知会跳转到的特定页面或者指定url等等,这里可以在后续动作进行设置,当然你也可以传递参数,我们再来新建一个测试任务测试一下吧
这里我们设置当用户接收到通知点击通知时跳转到我们指定的页面中,并且传递了参数,注意这里的指定页面必须要填写全路径。
这时你是不是想,这就结束了,原来接入推送这么简单啊 !
那你就错了哦,当前我们接入的是在线推送哦,这里先清除你的当前demo的任务,使app处于离线状态下,我们在来新建一个测试任务,点击发送你会发现接收不到该通知
离线推送
厂商推送
厂商推送指的就是手机硬件厂商提供的系统级别的推送服务。因为她是系统服务,随手机开机后她就一直存在着,有效地保证了推送通道的高可用性。在网络畅通和推送消息内容合法的情况下,通过厂商通道推送消息给该型号手机,不论应用是否存活,都保证消息推送到位。
友盟厂商通道接入
厂商通道接入详细文档
直接跟着文档一步步走就行了,里面有详细的接入步骤,效果图以及链接
点此链接即可获得神功!
这里需要注意的是:厂商推送账号必须注册为企业认证账号
发送离线推送
其实这里和在线推送略有差别
当我们集成好厂商通道后并完善我们的应用信息后,在这里点击勾选厂商通道,填入要打开的指定页面(必填)点击发送,当我们的app在离线状态下也可以接收到消息推送咯(这里上传的是我集成demo)。
app内接收到的参数:
第一个坑
这里我在离线推送有问题的时候和友盟的人工客服沟通,他非常坚定地告诉我离线推送消息后续行为只能设置为打开应用并且不可以传参,当时我就懵了,我跟他说不能传参我咋判断跳转到指定页面的业务逻辑处理呢,他也没给我具体的说法最后好像不了了之了
第二个坑
在我使用离线推送去推消息时,我测试了两种情况,分别时app运行在前台和清空后台任务两种情况,当我设置后续行为为打开应用推离线消息时,app离线状态下点击通知会跳转到指定界面(这里指的是勾选厂商推送后填写跳转的指定界面,不是行为动作跳转指定界面),但是当app在前台时点击通知不会跳转到指定界面,因为这里我们的后续行为设置的就是打开应用,我又和他们客服进行沟通,期间分别时和两个客服进行了沟通,但是两个给我的答复居然还都不一样,并且说没办法,然后还说让我推送时推送两个,一个在线的一个离线的 ,我感觉他就是在瞎扯,我说他们技术在实现功能时肯定有考虑这一点,然后我强烈要求和他们技术进行沟通,最后也没和他们技术进行沟通,不过最后也是找到了解决方法,就是在发送离线通知时,想行为动作也设置为跳转到指定页面,这样发送离线消息,不管是app离线还是在线都可以接收到信息,并且点击通知还可以跳转到指定界面,最后也是了解到,当app离线时走的时厂商通道,在线时走的时友盟通道,所以为了实现不管app在不在线直接设定两种都为跳转到指定页面的话都会执行这个结果。
这里忍不住吐槽友盟了,每个客服说的内容都相差太大,与实际不符,并且我们在接入时遇到的都是技术方面的问题,但是还不能和技术有一个很好的沟通,这点没有极光做的好,不过文档还是非常详细的。
这就是详细的接入步骤了,这里贴出我的跳转指定页面的activity
public class SecondActivity extends UmengNotifyClickActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
init();
}
private void init() {
Bundle bun = getIntent().getExtras();
if (bun != null) {
Set<String> keySet = bun.keySet();
for (String key : keySet) {
String value = bun.getString(key);
Log.i("testww", "#"+value);
//Toast.makeText(this,"@"+value,Toast.LENGTH_SHORT).show();
}
}
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
}
@Override
public void onMessage(Intent intent) {
super.onMessage(intent);
Log.i("unlineintent", "onMessage-------->");
String body = intent.getStringExtra(AgooConstants.MESSAGE_BODY);
Log.i("unlineintent", body);
}
}
服务端代码调用
这里有两种方式在后台调用,分别时调用API的方式和服务端调用
服务端下载地址
这里推荐使用JAVA sdk的方式进行下载,因为其它两个都太老了
当然你也可以选择直接调用API, 详情请戳->
这里我也下载了服务端代码,并且进行了稍微的修改,在Demo.java文件中新增了列播功能
//列播
public void sendAndroidListcast() throws Exception {
AndroidListcast listcast = new AndroidListcast(appkey,appMasterSecret);
// TODO Set your device token
listcast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd,");
listcast.setTicker( "通知栏提示文字");
listcast.setTitle( "通知标题");
listcast.setText( "通知文字描述");
//点击"通知"的后续行为,默认为打开app。
//unicast.goAppAfterOpen();
listcast.goActivityAfterOpen("com.example.wow.SecondActivity");
listcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
//正式模式 默认为true
listcast.setProductionMode();
// Set customized fields
listcast.setExtraField("test", "helloworld");
listcast.setExtraField("state", "ok");
//厂商指定跳转的activity
listcast.setChannelActivity("com.example.wow.SecondActivity");
//填写小米channel_id 选填给推送进行分类别
//unicast.setChannelProperties("abc");
//unicast.setChannelProperties("2882303761519015348");
client.send(listcast);
}
完整的Demo.java代码
package push;
import org.json.JSONArray;
import org.json.JSONObject;
import push.android.AndroidBroadcast;
import push.android.AndroidCustomizedcast;
import push.android.AndroidFilecast;
import push.android.AndroidGroupcast;
import push.android.AndroidListcast;
import push.android.AndroidUnicast;
import push.ios.IOSBroadcast;
import push.ios.IOSCustomizedcast;
import push.ios.IOSFilecast;
import push.ios.IOSGroupcast;
import push.ios.IOSUnicast;
public class Demo {
private String appkey = null;
private String appMasterSecret = null;
private String timestamp = null;
private PushClient client = new PushClient();
public Demo(String key, String secret) {
try {
appkey = key;
appMasterSecret = secret;
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
//广播:5次/分钟(发送量10次/天)
public void sendAndroidBroadcast() throws Exception {
AndroidBroadcast broadcast = new AndroidBroadcast(appkey,appMasterSecret);
broadcast.setTicker( "通知栏提示文字");
broadcast.setTitle( "我是广播");
broadcast.setText( "是否全员接收");
//broadcast.goAppAfterOpen();
broadcast.goActivityAfterOpen("com.example.wow.SecondActivity");
broadcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
broadcast.setProductionMode();
// Set customized fields
broadcast.setExtraField("test", "helloworld");
//厂商通道相关参数
broadcast.setChannelActivity("com.example.wow.SecondActivity");
//broadcast.setChannelProperties("abc");
client.send(broadcast);
}
//单播
public void sendAndroidUnicast() throws Exception {
AndroidUnicast unicast = new AndroidUnicast(appkey,appMasterSecret);
// TODO Set your device token
unicast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd");
unicast.setTicker( "通知栏提示文字");
unicast.setTitle( "通知标题");
unicast.setText( "通知文字描述");
//点击"通知"的后续行为,默认为打开app。
//unicast.goAppAfterOpen();
unicast.goActivityAfterOpen("com.example.wow.SecondActivity");
unicast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
//正式模式 默认为true
unicast.setProductionMode();
// Set customized fields
unicast.setExtraField("test", "helloworld");
unicast.setExtraField("state", "ok");
//厂商指定跳转的activity
unicast.setChannelActivity("com.example.wow.SecondActivity");
//填写小米channel_id 选填给推送进行分类别
//unicast.setChannelProperties("abc");
//unicast.setChannelProperties("2882303761519015348");
client.send(unicast);
}
//列播
public void sendAndroidListcast() throws Exception {
AndroidListcast listcast = new AndroidListcast(appkey,appMasterSecret);
// TODO Set your device token
listcast.setDeviceToken( "Aif9eEilatT-3JOYQJDm1HXmVh_S-2QLuoRH4let4tQd,");
listcast.setTicker( "通知栏提示文字");
listcast.setTitle( "通知标题");
listcast.setText( "通知文字描述");
//点击"通知"的后续行为,默认为打开app。
//unicast.goAppAfterOpen();
listcast.goActivityAfterOpen("com.example.wow.SecondActivity");
listcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
//正式模式 默认为true
listcast.setProductionMode();
// Set customized fields
listcast.setExtraField("test", "helloworld");
listcast.setExtraField("state", "ok");
//厂商指定跳转的activity
listcast.setChannelActivity("com.example.wow.SecondActivity");
//填写小米channel_id 选填给推送进行分类别
//unicast.setChannelProperties("abc");
//unicast.setChannelProperties("2882303761519015348");
client.send(listcast);
}
//组播 用户筛选条件,如用户标签、渠道等 不推荐使用
public void sendAndroidGroupcast() throws Exception {
AndroidGroupcast groupcast = new AndroidGroupcast(appkey,appMasterSecret);
/* TODO
* Construct the filter condition:
* "where":
* {
* "and":
* [
* {"tag":"test"},
* {"tag":"Test"}
* ]
* }
*/
JSONObject filterJson = new JSONObject();
JSONObject whereJson = new JSONObject();
JSONArray tagArray = new JSONArray();
JSONObject testTag = new JSONObject();
JSONObject TestTag = new JSONObject();
testTag.put("tag", "test");
TestTag.put("tag", "Test");
tagArray.put(testTag);
tagArray.put(TestTag);
whereJson.put("and", tagArray);
filterJson.put("where", whereJson);
groupcast.setFilter(filterJson);
groupcast.setTicker( "Android groupcast ticker");
groupcast.setTitle( "中文的title");
groupcast.setText( "Android groupcast text");
groupcast.goAppAfterOpen();
groupcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
groupcast.setChannelActivity("your channel activity");
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
groupcast.setProductionMode();
//厂商通道相关参数
groupcast.setChannelActivity("your channel activity");
groupcast.setChannelProperties("abc");
client.send(groupcast);
}
public void sendAndroidCustomizedcast() throws Exception {
AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
// TODO Set your alias here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification.
customizedcast.setAlias("alias", "alias_type");
customizedcast.setTicker( "Android customizedcast ticker");
customizedcast.setTitle( "中文的title");
customizedcast.setText( "Android customizedcast text");
customizedcast.goAppAfterOpen();
customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
customizedcast.setProductionMode();
//厂商通道相关参数
customizedcast.setChannelActivity("your channel activity");
customizedcast.setChannelProperties("abc");
client.send(customizedcast);
}
public void sendAndroidCustomizedcastFile() throws Exception {
AndroidCustomizedcast customizedcast = new AndroidCustomizedcast(appkey,appMasterSecret);
// TODO Set your alias here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification.
String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb"+"\n"+"alias");
customizedcast.setFileId(fileId, "alias_type");
customizedcast.setTicker( "Android customizedcast ticker");
customizedcast.setTitle( "中文的title");
customizedcast.setText( "Android customizedcast text");
customizedcast.goAppAfterOpen();
customizedcast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
// TODO Set 'production_mode' to 'false' if it's a test device.
// For how to register a test device, please see the developer doc.
customizedcast.setProductionMode();
//厂商通道相关参数
customizedcast.setChannelActivity("your channel activity");
customizedcast.setChannelProperties("abc");
client.send(customizedcast);
}
public void sendAndroidFilecast() throws Exception {
AndroidFilecast filecast = new AndroidFilecast(appkey,appMasterSecret);
// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens
String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
filecast.setFileId( fileId);
filecast.setTicker( "Android filecast ticker");
filecast.setTitle( "中文的title");
filecast.setText( "Android filecast text");
filecast.goAppAfterOpen();
filecast.setDisplayType(AndroidNotification.DisplayType.NOTIFICATION);
//厂商通道相关参数
filecast.setChannelActivity("your channel activity");
filecast.setChannelProperties("abc");
client.send(filecast);
}
public void sendIOSBroadcast() throws Exception {
IOSBroadcast broadcast = new IOSBroadcast(appkey,appMasterSecret);
//alert值设置为字符串
//broadcast.setAlert("IOS 广播测试");
//alert的值设置为字典
broadcast.setAlert("今日天气" , "" , "今日可能下雨🌂");
broadcast.setBadge( 0);
broadcast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
broadcast.setTestMode();
// Set customized fields
broadcast.setCustomizedField("test", "helloworld");
client.send(broadcast);
}
public void sendIOSUnicast() throws Exception {
IOSUnicast unicast = new IOSUnicast(appkey,appMasterSecret);
// TODO Set your device token
unicast.setDeviceToken( "your device_token");
//alert值设置为字符串
//unicast.setAlert("IOS 单播测试");
//alert的值设置为字典
unicast.setAlert("今日天气" , "" , "今日可能下雨🌂");
unicast.setBadge( 0);
unicast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
unicast.setTestMode();
// Set customized fields
unicast.setCustomizedField("test", "helloworld");
client.send(unicast);
}
public void sendIOSGroupcast() throws Exception {
IOSGroupcast groupcast = new IOSGroupcast(appkey,appMasterSecret);
/* TODO
* Construct the filter condition:
* "where":
* {
* "and":
* [
* {"tag":"iostest"}
* ]
* }
*/
JSONObject filterJson = new JSONObject();
JSONObject whereJson = new JSONObject();
JSONArray tagArray = new JSONArray();
JSONObject testTag = new JSONObject();
testTag.put("tag", "iostest");
tagArray.put(testTag);
whereJson.put("and", tagArray);
filterJson.put("where", whereJson);
System.out.println(filterJson.toString());
// Set filter condition into rootJson
groupcast.setFilter(filterJson);
//groupcast.setAlert("IOS 组播测试");
//alert的值设置为字典
groupcast.setAlert("今日天气" , "subtitle" , "今日可能下雨🌂");
groupcast.setBadge( 0);
groupcast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
groupcast.setTestMode();
client.send(groupcast);
}
public void sendIOSCustomizedcast() throws Exception {
IOSCustomizedcast customizedcast = new IOSCustomizedcast(appkey,appMasterSecret);
// TODO Set your alias and alias_type here, and use comma to split them if there are multiple alias.
// And if you have many alias, you can also upload a file containing these alias, then
// use file_id to send customized notification.
customizedcast.setAlias("alias", "alias_type");
//customizedcast.setAlert("IOS 个性化测试");
//alert的值设置为字典
customizedcast.setAlert("今日天气" , "" , "今日可能下雨🌂");
customizedcast.setBadge( 0);
customizedcast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
customizedcast.setTestMode();
client.send(customizedcast);
}
public void sendIOSFilecast() throws Exception {
IOSFilecast filecast = new IOSFilecast(appkey,appMasterSecret);
// TODO upload your device tokens, and use '\n' to split them if there are multiple tokens
String fileId = client.uploadContents(appkey,appMasterSecret,"aa"+"\n"+"bb");
filecast.setFileId( fileId);
//filecast.setAlert("IOS 文件播测试");
//alert的值设置为字典
filecast.setAlert("今日天气" , "" , "今日可能下雨🌂");
filecast.setBadge( 0);
filecast.setSound( "default");
// TODO set 'production_mode' to 'true' if your app is under production mode
filecast.setTestMode();
client.send(filecast);
}
public static void main(String[] args) {
// TODO set your appkey and master secret here
Demo demo = new Demo("your appkey", "master secret");
try {
//单播 处理一个设备的消息推送 推荐
//demo.sendAndroidUnicast();
//列播 处理2个以上500个以下的消息推送
demo.sendAndroidListcast();
//广播 5次/分钟(发送量10次/天) 向所有安装该app的用户发送推送 推荐
//demo.sendAndroidBroadcast();
//demo.sendAndroidCustomizedcastFile();
//组播 不推荐使用
//demo.sendAndroidGroupcast();
//不推荐
//* demo.sendAndroidCustomizedcast();
//* demo.sendAndroidFilecast();
//demo.sendIOSUnicast();
/* TODO these methods are all available, just fill in some fields and do the test
* demo.sendAndroidCustomizedcastFile();
* demo.sendAndroidBroadcast();
* demo.sendAndroidGroupcast();
* demo.sendAndroidCustomizedcast();
* demo.sendAndroidFilecast();
*
* demo.sendIOSBroadcast();
* demo.sendIOSUnicast();
* demo.sendIOSGroupcast();
* demo.sendIOSCustomizedcast();
* demo.sendIOSFilecast();
*/
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
看注释
以及还有新增的列播类
package push.android;
import push.AndroidNotification;
public class AndroidListcast extends AndroidNotification {
public AndroidListcast(String appkey,String appMasterSecret) throws Exception {
setAppMasterSecret(appMasterSecret);
setPredefinedKeyValue("appkey", appkey);
this.setPredefinedKeyValue("type", "listcast");
}
public void setDeviceToken(String tokens) throws Exception {
setPredefinedKeyValue("device_tokens", tokens);
}
}
最最最重要的事
欧克,到这里友盟推送的集成就算完成咯,这段关系只能到这了,如果非要说点什么的话,那就是爱过~