Android通知工具类,含8.0通知适配,打开通知设置页面适配
16lz
2022-03-14
先贴上代码,之后简单分析一下:
package com.lct.customview.wholeimport android.annotation.TargetApiimport android.app.NotificationChannelimport android.app.NotificationManagerimport android.app.PendingIntentimport android.content.Contextimport android.content.Intentimport android.graphics.BitmapFactoryimport android.net.Uriimport android.os.Buildimport android.provider.Settingsimport android.support.annotation.RequiresApiimport android.support.v4.app.NotificationCompatimport android.support.v4.app.NotificationManagerCompatimport android.support.v7.app.AlertDialog/** * Author:SkySmile * Date:2019/2/28 * Description:App的通知渠道配置 */@TargetApi(Build.VERSION_CODES.N)object AppNotification { //通知ID //对于通知来说ID相同即为同一条通知,如果通知ID已存在,则更新通知内容,否则发送一条新的通知 //这里为了每次都能发送一条新的通知,对ID进行累加 private var id = 1 //影视类通知渠道 const val mediaChannelId = "0x1" //通知渠道ID const val mediaChannelName = "影视" //通知渠道名称,显示在手机上该APP的通知管理中 const val mediaChannelImportance = NotificationManager.IMPORTANCE_HIGH //通知渠道重要性 //美食类通知渠道 const val foodChannelId = "0x2" //通知渠道ID const val foodChannelName = "美食" //通知渠道名称,显示在手机上该APP的通知管理中 const val foodChannelImportance = NotificationManager.IMPORTANCE_DEFAULT //通知渠道重要性 /** * 创建通知渠道 * * @param applicationContext 上下文 * @param channelId 渠道ID * @param channelIdName 渠道名称,显示在手机上该APP的通知管理中 * @param channelIdImportance 渠道重要程度 */ fun createNotificationChannel(applicationContext: Context, channelId: String, channelIdName: String, channelIdImportance: Int) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val notificationManager = applicationContext.getSystemService( Context.NOTIFICATION_SERVICE) as NotificationManager val notificationChannel = NotificationChannel(channelId, channelIdName, channelIdImportance) notificationManager.createNotificationChannel(notificationChannel) } } /** * 发送通知,根据需要进行扩展 * * @param context 上下文 * @param channelId 渠道ID(必须对应已创建的渠道ID) * @param title 通知标题 * @param text 通知内容 * @param smallIcon 通知小图标(显示在状态栏中的),必须设置 * @param largeIcon 通知大图标(下拉状态栏可见,显示在通知栏中), * 注意:这里的图片ID不能是mipmap文件夹下的,因为BitmapFactory.decodeResource方法只能 * 获取到 drawable, sound, and raw resources; * @param pi 点击通知打开的页面 * */ fun sendNotification(context: Context, channelId: String, title: String, text: String, smallIcon: Int, largeIcon: Int, pi: PendingIntent) { //判断通知是否开启 if (!isNotificationEnabled(context)) { AlertDialog.Builder(context) .setTitle("提示") .setMessage("是否开启通知?") .setPositiveButton("确定") { _, _ -> openNotification(context) } .setNegativeButton("取消", null) .show() return } //判断某个渠道的通知是否开启 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (!isNotificationChannelEnabled(context, channelId)) { val message = when (channelId) { mediaChannelId -> mediaChannelName foodChannelId -> foodChannelName else -> "" } AlertDialog.Builder(context) .setTitle("提示") .setMessage("是否开启${message}通知?") .setPositiveButton("确定") { _, _ -> openNotificationChannel(context, channelId) } .setNegativeButton("取消", null) .show() return } } //发送通知 val notification = NotificationCompat.Builder(context, channelId) .setContentTitle(title) .setContentText(text) .setWhen(System.currentTimeMillis()) .setSmallIcon(smallIcon) .setLargeIcon(BitmapFactory.decodeResource(context.resources, largeIcon)) .setContentIntent(pi) .setAutoCancel(true) .build() val notificationManager = context.getSystemService( Context.NOTIFICATION_SERVICE) as NotificationManager notificationManager.notify(id++, notification) } /** * 判断App通知是否开启 * 注意这个方法判断的是通知总开关,如果APP通知被关闭,则其下面的所有通知渠道也被关闭 */ fun isNotificationEnabled(context: Context): Boolean { val notificationManagerCompat = NotificationManagerCompat .from(context) return notificationManagerCompat.areNotificationsEnabled() } /** * 判断APP某个通知渠道的通知是否开启 */ @RequiresApi(Build.VERSION_CODES.O) fun isNotificationChannelEnabled(context: Context, channelId: String): Boolean { val notificationManager = context.getSystemService( Context.NOTIFICATION_SERVICE) as NotificationManager val channel = notificationManager.getNotificationChannel(channelId) return channel.importance != NotificationManager.IMPORTANCE_NONE } /** * 打开通知设置页面 */ fun openNotification(context: Context) { val packageName = context.packageName val uid = context.applicationInfo.uid val intent = Intent() when { Build.VERSION.SDK_INT >= Build.VERSION_CODES.O -> { intent.action = Settings.ACTION_APP_NOTIFICATION_SETTINGS intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName) intent.putExtra(Settings.EXTRA_CHANNEL_ID, uid) } Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP -> { intent.action = "android.settings.APP_NOTIFICATION_SETTINGS" intent.putExtra("app_package", packageName) intent.putExtra("app_uid", uid) } Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT -> { intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS intent.addCategory(Intent.CATEGORY_DEFAULT) intent.data = Uri.parse("package:$packageName") } else -> intent.action = Settings.ACTION_SETTINGS } context.startActivity(intent) } /** * 打开通知渠道设置页面 */ @RequiresApi(Build.VERSION_CODES.O) fun openNotificationChannel(context: Context, channelId: String) { val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS) intent.putExtra(Settings.EXTRA_APP_PACKAGE, context.packageName) intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId) context.startActivity(intent) }}
通知渠道是在android 8.0加入的。如果有多个渠道,则在手机的通知管理中会显示出每个渠道的名称,并且可以对每个通知渠道进行单独的设置,比如开启或者关闭。如果通知渠道只有一个,则不显示渠道名称。如下图:
左侧是只有一个通知渠道显示的页面,右侧是有两个通知渠道显示的页面。
上图使用的是华为android 8.0手机,不同厂商显示的可能不一样(华为手机系统比较接近Android原生)
createNotificationChannel方法的作用是创建通知渠道,渠道只能创建一次,即创建过后渠道名称不能再通过代码更改,除非是卸载APP重新安装,但是可以通过代码删除渠道,不过删除后,在手机的通知管理中会显示出已删除的渠道。
建议在Application的onCreate方法中调用,eg:
package com.lct.customviewimport android.app.Applicationimport com.lct.customview.whole.AppNotification/** * Author:SkySmile * Date:2019/2/28 * Description:Application */class MyApplication : Application() { override fun onCreate() { super.onCreate() //创建影视通知渠道 AppNotification.createNotificationChannel(this, AppNotification.mediaChannelId, AppNotification.mediaChannelName, AppNotification.mediaChannelImportance) //创建美食通知渠道 AppNotification.createNotificationChannel(this, AppNotification.foodChannelId, AppNotification.foodChannelName, AppNotification.foodChannelImportance) }}
sendNotification方法的作用是发送通知。方法中首先判断了APP通知是否开启,没开启的话,则跳转到通知设置页面或APP详情页面引导用户开启通知权限。其次判断了(8.0及以上系统)某个通知渠道是否被开启,没开启的话,则跳转到对应的通知渠道页面引导用户开启。满足上述条件,则发送通知。
调用试例:
package com.lct.customviewimport android.app.PendingIntentimport android.content.Intentimport android.os.Bundleimport android.support.v7.app.AppCompatActivityimport com.lct.customview.whole.AppNotificationimport kotlinx.android.synthetic.main.activity_notification.*class NotificationActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_notification) btnMedia.setOnClickListener { val intent = Intent(this, MediaActivity::class.java) val pi = PendingIntent.getActivity(this, 0, intent, 0) AppNotification.sendNotification(this, AppNotification.mediaChannelId, "热门影视", "新版倚天屠龙记正式开播", R.mipmap.ic_launcher, R.drawable.ic_launcher_round, pi) } btnFood.setOnClickListener { val intent = Intent(this, MediaActivity::class.java) val pi = PendingIntent.getActivity(this, 0, intent, 0) AppNotification.sendNotification(this, AppNotification.foodChannelId, "露露鲜果", "新摘的大苹果,好吃实惠", R.mipmap.ic_launcher, R.mipmap.ic_launcher, pi) } }}
注意8.0及以上系统,不设置通知渠道的话,通知无法显示出来。
其它方法代码中已明确注释,此处就不做解释了。
参考博客:
Android通知栏微技巧,8.0系统中通知栏的适配
更多相关文章
- Android硬件加速
- USB UMS MTP设置过程 (一)
- [Gradle] Gradle 构建 android 应用常见问题解决指南
- android源码浅析--notification
- android弹出框2(相当于通知)
- android弹出框2(相当于通知)
- 【Android(安卓)设计】:模式_ Android新特性
- Android(安卓)Studio Error : Instant Run requires 'Tools | An
- Android(安卓)更新升级下载 自定义Updates 兼容版