这几天在做安卓的推送对接,因为内网的使用场景以及费用问题,公司使用RabbitMQ的框架进行消息推送,但是在完成了简单的推送以及接受代码之后。APP消息通知遇到了两个问题:1.没有类似于微信的锁屏通知,2.没有类似于微信收到消息之后的顶部通知。在经过两天的摸索之后有了答案,先看下实际的实现效果图吧(部分通知内容因为隐私问题进行了模糊处理):
哈哈,这个不知道是不是你想要的效果,如果是的话,请继续往下看:
起初,我以为顶部通知以及锁屏通知都是开发自定义做的,所以在网上百度了一波。结果呢,网上五花八门,大多数都是自定义Toast实现,但是效果和微信、qq收到消息的效果大相径庭,所以抱着试试看的态度,我打开了应用的通知权限管理页面。
上图是已经代码设置好之后的状态,具体的代码实现下面再说。起初,悬浮通知开关是关闭的,经过百度,了解到需要假如如下权限:
我习惯使用AndPermission框架申请权限,一顿查询之后发现没有上述两个权限的申请代码,所以我直接加上权限配置,run了下app,还是不行,最终经过一天的折腾,结论是这里需要用户自己去打开!(安卓O以上才需要进行处理)跳转代码是:
var isFirstOpen = Acache.get(this).getAsString(AppContentValue.AppAcacheKey.IsFirstOpen);
if (isEmpty(isFirstOpen)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, this.packageName);
startActivity(intent);
showToast(this, "请允许通知的相关权限,否则可能导致无法接收消息!")
}
// else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
// val localIntent = Intent()
// localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
// localIntent.setData(Uri.fromParts("package", this.packageName, null));
// this.startActivity(localIntent);
// }
}
Acache.get(this).put(AppContentValue.AppAcacheKey.IsFirstOpen, "no");
接着继续顺藤摸瓜,点开上图最下面消息通知按钮(这里要注意,app在收到任意一次通知之后才会展示),“消息通知”这个名称是在NotificationChannel中设置的。
下面关键来了,要想实现通知来了之后,顶部通知,就需要设置重要程度为“紧急”,这样Notification就会自动去匹配了,哈哈!就是这么简单,不知道为何网上有那么多误导人的博客文章。。。
接下来贴出所有的展示通知的代码:
/**
* 展示通知
*/
@SuppressLint("WrongConstant")
fun showNotification(context: Activity, sb: String, content: String) {
context.runOnUiThread {
var id = Acache.get(context).getAsString("notifyNum").toInt();
id++;
Acache.get(context).put("notifyNum", id.toString());
//1.获取通知管理器类
val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
/**
* 兼容Android版本8.0系统
*/
val channeId = "1"
val channelName = "消息通知"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(channeId, channelName, NotificationManager.IMPORTANCE_MAX)
channel.enableLights(true) // 开启指示灯,如果设备有的话
channel.lightColor = Color.RED // 设置指示灯颜色
// channel.setShowBadge(true) // 检测是否显示角标
// 设置通知出现时的震动(如果 android 设备支持的话)
channel.enableVibration(true);
// 设置通知出现时声音,默认通知是有声音的
// channel.setSound(null, null);
notificationManager.createNotificationChannel(channel)
}
//2.构建通知类
val builder: NotificationCompat.Builder = NotificationCompat.Builder(context, id.toString())
builder.setSmallIcon(R.mipmap.ic_launcher_trans) //设置小图标
builder.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.mipmap.ic_launcher_notify))//设置大图标
builder.setContentTitle("消息通知") //标题
builder.setColor(Color.parseColor("#00000000"))
builder.setContentText(sb) //内容
builder.setWhen(System.currentTimeMillis()) //时间
builder.setDefaults(Notification.DEFAULT_SOUND)
val intent = Intent(context, NotificationClickReceiver::class.java)
val bundle = Bundle()
bundle.putString("notifyNum", id.toString())
intent.action = "MessageHandleService"
intent.putExtra("bundle", bundle)
val pendingIntent = PendingIntent.getBroadcast(context, id, intent, 0)
builder.setContentIntent(pendingIntent)
builder.setPriority(NotificationCompat.PRIORITY_MAX)
//3.获取通知
val notification: Notification = builder.build()
// 4. 发送通知
notificationManager.notify(id, notification)
//收到信息刷新通知
val info = MessageEventInfo("refresh", false)
EventBus.getDefault().post(info)
}
}
其中的Acache是一个工具类,类似于SharedPreference,大家可以参考下,主要的作用是来区分channelID,保证每个消息都会在通知栏出现。如果不动态去加1的话,会导致最后一条通知覆盖第一条通知。(这里的坑还真不少,哈哈!)
锁屏通知的话,重点就在通知权限的配置,我这里的处理是跳到设置页面,让用户手动打开相关权限:
var isFirstOpen = Acache.get(this).getAsString(AppContentValue.AppAcacheKey.IsFirstOpen);
if (isEmpty(isFirstOpen)) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, this.packageName);
startActivity(intent);
showToast(this, "请允许通知的相关权限,否则可能导致无法接收消息!")
}
// else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT) {
// val localIntent = Intent()
// localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
// localIntent.setData(Uri.fromParts("package", this.packageName, null));
// this.startActivity(localIntent);
// }
}
Acache.get(this).put(AppContentValue.AppAcacheKey.IsFirstOpen, "no");
设置成默认,系统回去自己处理,哈哈!