Android正确的保活方案,不要掉进保活需求死循环陷进

Android正确的保活方案,不要掉进保活需求死循环陷进

在开始前,还是给大家简单介绍一下,以前出现过的一些黑科技:

大概在6年前Github中出现过一个叫MarsDaemon,这个库通过双进程守护的方式实现保活,一时间风头无两。好景不长,进入 Android 8.0时代之后,这个库就废掉了。

最近2年Github上面出来一个Leoric 感兴趣的可以去看一下源码,谁敢用在生产环境呢,也就自己玩玩的才会用吧(不能因为保活而导致手机卡巴斯基),我没有试过这个,我想说的是:黑科技能黑的了一时,能黑的了一世吗?

没有规矩,不成方圆,要提升产品的存活率,最终还是要落到产品本身上面来,尊重用户,提升用户体验才是正道。

以前我也是深受保活需求的压迫,最近发现QQ群里有人又提到了如何保活,那么我们就来说一说,如何来正确保活App?


Android 8.0之后: 加强了应用后台限制,当时测试过一组数据:

应用处于前台,启动一个前台Service,里面使用JobScheduler启动定时任务(30秒触发一次), 此时手机锁屏,前10分钟内,定时任务都是正常执行;
大概在12分钟左右,发现应用进程就被kill掉了,解锁屏幕,app也不在前台了;

各大国产手机厂商底层都经过自己魔改,自家都有自己的一套自启动管理,小米手机更乱(当时有个神隐模式的概念,那也是杀后台高手),只能说当时Android手机各种性能方面都不足,各家都会有自己的一套省电模式,以此来达到省电和提高手机性能,Android 系统变得越来越完善,但是厂商定制的自启动、省电模式还在,所以我们要做保活。

1.Android 8.0之前-常用的保活方案

1.开启一个前台Service
2.Android 6.0+ 忽略电池优化开关(稍后会有代码)
3.无障碍服务(只针对有用这个功能的app,如支付宝语音增强提醒用了它)


2.Android 8.0之后-常用的保活方案

1.开启一个前台Service(可以加上,单独启用的话无法满足保活需求)
2.Android 6.0+ 忽略电池优化开关(稍后会有代码)
3.无障碍服务(只针对有用这个功能的app,如支付宝语音增强提醒用了它)
4.应用自启动权限(最简单的方案是针对不同系统提供教程图片-让用户自己去打开)
5.多任务列表窗口加锁(提供GIF教程图片-让用户自己去打开)
6.多任务列表窗口隐藏App(仅针对有这方面需求的App)
7.应用后台高耗电(仅针对Vivo手机)

3.保活方案实现步骤

(1). 前台Service

//前台服务
class ForegroundCoreService : Service() {
    override fun onBind(intent: Intent?): IBinder? = null
    private var mForegroundNF:ForegroundNF by lazy {
        ForegroundNF(this)
    }
     override fun onCreate() {
        super.onCreate()
        mForegroundNF.startForegroundNotification()
    }
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        if(null == intent){
            //服务被系统kill掉之后重启进来的
            return START_NOT_STICKY
        }
        mForegroundNF.startForegroundNotification()
        return super.onStartCommand(intent, flags, startId)
    }
    override fun onDestroy() {
        mForegroundNF.stopForegroundNotification()
        super.onDestroy()
    }
}
复制代码
//初始化前台通知,停止前台通知
class ForegroundNF(private val service: ForegroundCoreService) : ContextWrapper(service) {
    companion object {
        private const val START_ID = 101
        private const val CHANNEL_ID = "app_foreground_service"
        private const val CHANNEL_NAME = "前台保活服务"
    }
    private var mNotificationManager: NotificationManager? = null

    private var mCompatBuilder:NotificationCompat.Builder?=null

    private val compatBuilder: NotificationCompat.Builder?
            get() {
                if (mCompatBuilder == null) {
                    val notificationIntent = Intent(this, MainActivity::class.java)
                    notificationIntent.action = Intent.ACTION_MAIN
                    notificationIntent.addCategory(Intent.CATEGORY_LAUNCHER)
                    notificationIntent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
                    //动作意图
                    val pendingIntent = PendingIntent.getActivity(
                        this, (Math.random() * 10 + 10).toInt(),
                        notificationIntent, PendingIntent.FLAG_UPDATE_CURRENT
                    )
                    val notificationBuilder: NotificationCompat.Builder = NotificationCompat.Builder(this,CHANNEL_ID)
                    //标题
                    notificationBuilder.setContentTitle(getString(R.string.notification_content))
                    //通知内容
                    notificationBuilder.setContentText(getString(R.string.notification_sub_content))
                    //状态栏显示的小图标
                    notificationBuilder.setSmallIcon(R.mipmap.ic_coolback_launcher)
                    //通知内容打开的意图
                    notificationBuilder.setContentIntent(pendingIntent)
                    mCompatBuilder = notificationBuilder
                }
                return mCompatBuilder
            }

    init {
        createNotificationChannel()
    }

    //创建通知渠道
    private fun createNotificationChannel() {
        mNotificationManager =
            getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        //针对8.0+系统
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                CHANNEL_NAME,
                NotificationManager.IMPORTANCE_LOW
            )
            channel.lockscreenVisibility = Notification.VISIBILITY_PUBLIC
            channel.setShowBadge(false)
            mNotificationManager?.createNotificationChannel(channel)
        }
    }

    //开启前台通知
    fun startForegroundNotification() {
        service.startForeground(START_ID, compatBuilder?.build())
    }

    //停止前台服务并清除通知
    fun stopForegroundNotification() {
        mNotificationManager?.cancelAll()
        service.stopForeground(true)
    }
}
复制代码

(2).忽略电池优化(Android 6.0+)

1.我们需要在AndroidManifest.xml中声明一下权限

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
复制代码

2.通过Intent来请求忽略电池优化的权限(需要引导用户点击)

//在Activity的onCreate中注册ActivityResult,一定要在onCreate中注册
//监听onActivityForResult回调
mIgnoreBatteryResultContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
            //查询是否开启成功
            if(queryBatteryOptimizeStatus()){
               //忽略电池优化开启成功
            }else{
               //开启失败
            }
        }
复制代码

通过Intent打开忽略电池优化弹框:

val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS)
intent.data = Uri.parse("package:$packageName")
//启动忽略电池优化,会弹出一个系统的弹框,我们在上面的
launchActivityResult(intent)
复制代码

查询是否成功开启忽略电池优化开关:

fun Context.queryBatteryOptimizeStatus():Boolean{
    val powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager?
    return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
        powerManager?.isIgnoringBatteryOptimizations(packageName)?:false
    } else {
        true
    }
}
复制代码

(3).无障碍服务

看官方文档:创建自己的无障碍服务
它也是一个Service,它的优先级比较高,提供界面增强功能,初衷是帮助视觉障碍的用户或者是可能暂时无法与设备进行全面互动的用户完成操作。
可以做很多事情,使用了此Service,在6.0+不需要申请悬浮窗权限,直接使用WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY 挺方便的
(仅针对有需要此服务的app,可以开启增强后台保活)

(4).自启动权限(即:白名单管理列表页面)

是系统给用户自己去打开“自启动权限”开关的入口,我们需要针对不同的手机厂商和系统版本,弹出提示引导用户是否前去打开“自启动权限”
有的手机厂商叫:白名单管理,有的叫:自启动权限,两个是一个概念;
点击查看跳转到『手机自启动设置页面』完整代码

(需要注意:如果是代码控制跳转,无法保证永远可以调整,系统升级可能就给你屏蔽了, 最简单的方法是:显示一个如何找到自启动页面的引导图,下面以华为手机为例:)

[图片上传失败...(image-23e774-1636446995973)]
华为手机-自启动管理

(5).多任务列表窗口加锁

可以针对不同手机厂商,显示引导用户,开启App窗口加锁之后,点击清理加速不会导致应用被kill

[图片上传失败...(image-8c7a66-1636446995973)]
华为手机窗口加锁-教程图

(6).多任务列表窗口隐藏App窗口

刚刚上面多任务窗口加锁完,再提示用户去App里面把隐藏App窗口开关打开,这样用户就不会多任务列表里面把App窗口给手抖划掉

多任务窗口中『隐藏App窗口』,可以用如下代码控制:
(这个也只是针对有这方面需求App提供的一种增强方案罢了:因为隐藏了窗口,用户就不会去想他,不会去手痒去划掉它)

//在多任务列表页面隐藏App窗口
fun hideAppWindow(context: Context,isHide:Boolean){
        try {
            val activityManager: ActivityManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
            //控制App的窗口是否在多任务列表显示
            activityManager.appTasks[0].setExcludeFromRecents(isHide)
        }catch (e:Exception){
            .....
        }
    }
复制代码

(7).应用后台高耗电(Vivo手机独有)

开启的入口:“设置”>“电池”>“后台高耗电”>“找到xxxApp打开开关”

[图片上传失败...(image-d7e108-1636446995972)]
vivo允许后台高耗电


最后还是奉劝那些,仍然执着于找寻黑科技的开发者,醒醒吧,太阳晒屁股了。

如果说你的App用户群体不是普通用户,是专门给一些玩机大神们用的,都可以root手机的话,那么直接 move 到系统目录 priv/system/app 即可, 即使被用户强杀也会自动重新拉起

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容