通知权限

总通知权限

获取:

省流:NotificationManagerCompat.from(context.applicationContext).areNotificationsEnabled()

SDK < 24,需要反射AppOpsManager获取;

SDK >= 24,可直接从notificationManager.areNotificationsEnabled()获取;

SDK >= 33,新增了Manifest.permission.POST_NOTIFICATIONS权限,也可走动态权限申请那一套获取,即ActivityCompat.requestPermissions

然而NotificationManagerCompat.from(context.applicationContext).areNotificationsEnabled()已经帮我们完成了适配,直接调用即可。

申请:

SDK < 33,系统默认授予通知权限,有的魔改系统会在app第一次打开时弹出动态申请对话框,手动申请需要跳转到对应的通知设置界面。

SDK < 26,没有官方的跳转,只能跳转到应用设置界面

val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)
intent.data = ("package:" + activity.packageName).toUri()
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
activity.startActivity(intent)

SDK >= 26,可以直接跳转到通知设置

val intent = Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.packageName)
activity.startActivity(intent)

SDK >= 33,还可以走动态权限申请(推荐),当已有权限时不会弹出申请框。

ActivityCompat.requestPermissions(
    activity,
    arrayOf(Manifest.permission.POST_NOTIFICATIONS),
    requestCode
)

Tip:SDK >= 33时,可以干脆一打开app就直接走动态申请,类似于各种国产毒瘤,一打开app就弹个通知申请小窗。

渠道通知

SDK >= 26时,新增渠道通知,发送通知前需要创建通知渠道,同时,通知权限也细分到了每个渠道,可单独开关渠道的权限。

悬浮通知(横幅通知)

悬浮通知就像收到微信消息时屏幕顶部弹出的通知,过个几秒后自动消失。关闭悬浮通知的话,发送通知只会在通知栏里显示,并不会像微信那样弹出来。目前的国产系统除白名单外默认关闭悬浮通知,需要手动打开。

获取:

val notifyChannel = NotificationChannel(
    NotificationUtils.NOTIFICATION_ID,
    NotificationUtils.NOTIFICATION_NAME,
    NotificationManager.IMPORTANCE_HIGH
)
manager.createNotificationChannel(notifyChannel)
manager.getNotificationChannel(NotificationUtils.NOTIFICATION_ID)
val channel = manager.getNotificationChannel(NotificationUtils.NOTIFICATION_ID)
return channel.importance == NotificationManager.IMPORTANCE_HIGH && notifyChannel.importance == NotificationManager.IMPORTANCE_HIGH

申请:

val intent = Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS)
intent.putExtra(Settings.EXTRA_APP_PACKAGE, activity.packageName)
intent.putExtra(Settings.EXTRA_CHANNEL_ID, NotificationUtils.NOTIFICATION_ID)
activity.startActivity(intent)

其中NOTIFICATION_ID用于标识通知渠道,NOTIFICATION_NAME则会在通知设置界面显示出来。渠道需要先创建了才能申请。

桌面角标

桌面角标目前安卓各家实现的比较混乱,各家的实现方式和策略都不相同,而且大部分都有白名单,建议使用ShortcutBadger解决,或者直接和产品battle。

后台运行

如果需要后台接收通知,建议接入厂家推送,用户量少的也可直接接入极光。如果是需要蓝牙连接外设的,只要蓝牙连接还在就保持后台。至于网上流传的一像素悬浮窗,监听系统广播,双进程相互保活,大多失效或者存在局限性。如果实在需要后台保持运行,则需要跳转设置让用户自行打开。

电池优化白名单

电池优化在类原生上比较好用,国产魔改系统大部分已经不认电池优化,只开电池优化也有概率后台被关。

获取:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager?
    if (powerManager != null) {
        return powerManager.isIgnoringBatteryOptimizations(context.getPackageName())
    }
    return false
}
return true

申请:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    try {
        val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
        intent.data = ("package:" + activity.packageName).toUri()
        activity.startActivity(intent)
    } catch (e: Exception) {
        e.printStackTrace()
    }
}

厂商后台运行权限

这部分需要自行适配各家的跳转。目前提供的代码仅供参考。

if(checkManufacturer("huawei") || checkManufacturer("honor")){
    val packNames = arrayOf(
        "com.huawei.systemmanager",
        "com.hihonor.systemmanager",
    )
    val classNames = arrayOf(
        ".startupmgr.ui.StartupNormalAppListActivity",
        ".appcontrol.activity.StartupAppControlActivity",
        ".optimize.bootstart.BootStartActivity",
    )
    flag@ for(p in packNames){
        for(c in classNames){
            for(pp in packNames){
                try{
                    toActivity(activity, p, pp+c)
                    break@flag
                }catch (e : Exception){

                }
            }
        }
    }
    toast(activity, "找到应用“${activity.getString(R.string.app_name)}”,关闭自动管理,并打开允许后台运行")
}

if(checkManufacturer("vivo")){
    toAppDetail(activity)
    toast(activity, "找到 “电量” -> “后台耗电管理” -> “允许后台高耗电”")
}
if(checkManufacturer("oppo") || checkManufacturer("oneplus")){
    toAppDetail(activity)
    toast(activity, "找到 “耗电管理”, 打开 “允许完全后台行为”")
}
if(checkManufacturer("xiaomi")){
    activity.startActivity(Intent().apply {
        setClassName("com.miui.powerkeeper", "com.miui.powerkeeper.ui.HiddenAppsConfigActivity")
        putExtra("package_name", activity.packageName)
        putExtra("package_label", activity.getString(R.string.app_name))
        //addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    })
    toast(activity, "请将后台配置设为“无限制”")
}

不要问我为什么huawei和honor要这样写,实测有的设备activity真的是com.hihonor.systemmanager/com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity