Android8.0通知栏适配 — kotlin

从Android 8.0系统开始,Google引入了通知渠道这个概念。
什么是通知渠道呢?顾名思义,就是每条通知都要属于一个对应的渠道。每个App都可以自由地创建当前App拥有哪些通知渠道,但是这些通知渠道的控制权都是掌握在用户手上的。用户可以自由地选择这些通知渠道的重要程度,是否响铃、是否振动、或者是否要关闭这个渠道的通知。

拥有了这些控制权之后,用户就再也不用害怕那些垃圾推送消息的打扰了,因为用户可以自主地选择自己关心哪些通知、不关心哪些通知。举个具体的例子,我希望可以即时收到支付宝的收款信息,因为我不想错过任何一笔收益,但是我又不想收到支付宝给我推荐的周围美食,因为我没钱只吃得起公司食堂。这种情况,支付宝就可以创建两种通知渠道,一个收支,一个推荐,而我作为用户对推荐类的通知不感兴趣,那么我就可以直接将推荐通知渠道关闭,这样既不影响我关心的通知,又不会让那些我不关心的通知来打扰我了。

下面是个例子:

package com.example.notificationtest

import android.annotation.TargetApi
import android.app.NotificationManager
import android.content.Context
import android.graphics.BitmapFactory
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import kotlinx.android.synthetic.main.activity_main.*
import android.app.NotificationChannel
import android.app.PendingIntent
import android.content.Intent
import android.graphics.Color
import android.net.Uri
import android.os.Build
import android.provider.Settings
import android.support.v4.app.NotificationCompat
import android.widget.Toast


class MainActivity : AppCompatActivity(), View.OnClickListener {
    private val TAG = MainActivity::class.java.simpleName
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        send_notice.setOnClickListener(this)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {//检查当前系统API等级是否大于或等于26(8.0系统)
            //如果当前系统是8.0或以上系统就必须创建通知渠道,否则通知无法显示
            var channelId = "chat"
            var channelName = "聊天消息"
            var importance = NotificationManager.IMPORTANCE_HIGH //设置消息等级
            createNotificationChannel(channelId, channelName, importance)
            channelId = "subscribe"
            channelName = "订阅消息"
            importance = NotificationManager.IMPORTANCE_DEFAULT //设置消息等级
            createNotificationChannel(channelId, channelName, importance)
        }
    }

    @TargetApi(Build.VERSION_CODES.O)//将函数块内的API级别指定为Build.VERSION_CODES.O(26),忽略项目设置的API级别
    private fun createNotificationChannel(channelId: String, channelName: String, importance: Int) {
        //创建通道前的所有设置,通道创建成功后,之后的修改都不会生效,除非删除这个通知渠道从新创建,或者卸载APP后重新安装,新的设置才会生效。
        val channel = NotificationChannel(channelId, channelName, importance)
        channel.setShowBadge(true)//开启角标

        //设置通知时震动
        channel.enableVibration(true)//开启震动
        channel.vibrationPattern = longArrayOf(0, 1000, 1000, 1000, 1000, 1000, 1000, 1000)//设置震动模式

        /*设置通知声音,用的是res目录下raw文件夹中的msg.wav声音文件,注意路径一定要别搞错了,弄错了通知的时候是不会发出声音的,
        即使后面修改正确了也没用,除非删除这个通知渠道从新创建,或者卸载APP后重新安装,新的设置才会生效。*/
        //channel.setSound(Uri.parse("android.resource://$packageName/raw/msg"),null)//这种路径也是可以的,不可以带文件后缀
        channel.setSound(Uri.parse("android.resource://$packageName/${R.raw.msg}"), null)//推荐这种路径

        //设置LED灯(此功能未得到验证,没有呼吸灯手机)
        channel.enableLights(true)//开启LED灯
        channel.lightColor = Color.GREEN//设置LED灯颜色

        val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        manager.createNotificationChannel(channel)//创建通知渠道
    }

    override fun onClick(v: View) {
        when (v.id) {
            R.id.send_notice -> sendAChatMessage()
            else -> Log.d(TAG, "onClick: 没有匹配到view id")
        }
    }

    private fun sendAChatMessage() {
        val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = manager.getNotificationChannel("chat")//获取chat渠道设置
            if (channel.importance == NotificationManager.IMPORTANCE_NONE) {
                //渠道被关闭,提示用户打开
                Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS).run {
                    putExtra(Settings.EXTRA_APP_PACKAGE, packageName)
                    putExtra(Settings.EXTRA_CHANNEL_ID, channel.id)
                    startActivity(this)
                    Toast.makeText(this@MainActivity, "请手动将通知打开", Toast.LENGTH_SHORT).show()
                }
            }
            /* 除了以上管理通知渠道的方式之外,Android 8.0还赋予了我们删除通知渠道的功能,只需使用如下代码即可删除:
               val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
               manager.deleteNotificationChannel(channelId)
               但是这个功能非常不建议大家使用。因为Google为了防止应用程序随意地创建垃圾通知渠道,会在通知设置界面显示
               所有被删除的通知渠道数量。
               这样是非常不美观的,所以对于开发者来说最好的做法就是仔细规划好通知渠道,而不要轻易地使用删除功能。*/
        }
        //通知被点击后跳转到的活动
        val pendingIntent = Intent(this, NotificationActivity::class.java).run {
            PendingIntent.getActivity(this@MainActivity, 0, this, 0)
        }
        //要在android8.0系统中显示通知,必须用使用渠道,而使用的渠道必须是已经创建了的。
        val notification = NotificationCompat.Builder(this, "chat")
            .setContentTitle("Android 8.0还赋予了我们删除通知渠道的功能")
            .setStyle(//在通知中显示长文本,这个跟显示大图片不能同时显示
                NotificationCompat.BigTextStyle().bigText(
                    "但是这个功能非常不建议大家使用。因为Google为了防止" +
                            "应用程序随意地创建垃圾通知渠道,会在通知设置界面显示所有被删除的通知渠道数量。"
                )
            )
            .setStyle(//在通知里显示一张大图片,这个跟长文本不能同时显示
                NotificationCompat.BigPictureStyle().bigPicture(
                    BitmapFactory.decodeResource(
                        resources,
                        R.drawable.timg
                    )
                )
            )
            .setWhen(System.currentTimeMillis())
            .setSmallIcon(R.mipmap.ic_launcher)
            .setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
            .setNumber(2)//设置角标未读消息数量
            .setContentIntent(pendingIntent) //通知被点击后跳转的pendingIntent
            .setAutoCancel(true)//设置自动取消系统状态栏的图标
            .build()
        manager.notify(1, notification)
    }
}

更多通知栏详情请参考:
Android通知栏微技巧,8.0系统中通知栏的适配
https://blog.csdn.net/guolin_blog/article/details/79854070 (本文出处)

Android通知栏微技巧,那些你所没关注过的小细节
https://blog.csdn.net/guolin_blog/article/details/50945228

你可能感兴趣的:(Android)