先贴上代码,之后简单分析一下:

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通知适配,打开通知设置页面适配_第1张图片                Android通知工具类,含8.0通知适配,打开通知设置页面适配_第2张图片

左侧是只有一个通知渠道显示的页面,右侧是有两个通知渠道显示的页面。

上图使用的是华为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系统中通知栏的适配

更多相关文章

  1. ReactNative 在用react-navigation组件时,没有 navigator.getCurr
  2. Android Studio第三十八期 - HIOS跳转协议解决URI跳转原生页面并
  3. Android 自定义View跟随页面切换小圆点
  4. 在屏幕上方是actionBar tab的ViewPager页面里面嵌套子tab并显示
  5. android弹出框2(相当于通知)
  6. Android之WebView 防止调用系统浏览器打开页面
  7. Android 简单欢迎页面设计
  8. Android手机定位未开启,跳转到GPS开启页面
  9. android webview 自定义404错误页面!

随机推荐

  1. android TextView的跑马灯效果的实现
  2. Android(安卓)通过继承TextView类自定义
  3. Android核心基础(五)
  4. android 跳转到当前应用的详情页面
  5. android intent.setType指定浏览本地多种
  6. Android中NDK各版本下载
  7. android 笔记
  8. Android推荐资源
  9. view measure详解
  10. Android(安卓)获取手机信息