Android正确的保活方案,拒绝陷入需求死循环!
刘望舒
共 7245字,需浏览 15分钟
·
2022-03-18 20:15
大家好,我是刘望舒,腾讯最具价值专家,著有三本业内知名畅销书,连续五年蝉联电子工业出版社年度优秀作者,百度百科收录的资深技术专家。
前华为面试官、独角兽公司技术总监。
想要加入 BATcoder技术群,公号回复BAT
即可。
作者:Halifax
https://juejin.cn/post/7003992225575075876
正文
Android 8.0之前-常用的保活方案
开启一个前台Service Android 6.0+ 忽略电池优化开关(稍后会有代码) 无障碍服务(只针对有用这个功能的app,如支付宝语音增强提醒用了它)
Android 8.0之后-常用的保活方案
开启一个前台Service(可以加上,单独启用的话无法满足保活需求) Android 6.0+ 忽略电池优化开关(稍后会有代码) 无障碍服务(只针对有用这个功能的app,如支付宝语音增强提醒用了它) 应用自启动权限(最简单的方案是针对不同系统提供教程图片-让用户自己去打开) 多任务列表窗口加锁(提供GIF教程图片-让用户自己去打开) 多任务列表窗口隐藏App(仅针对有这方面需求的App) 应用后台高耗电(仅针对Vivo手机)
保活方案实现步骤
//前台服务
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)
}
}
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
//在Activity的onCreate中注册ActivityResult,一定要在onCreate中注册
//监听onActivityForResult回调
mIgnoreBatteryResultContract = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
//查询是否开启成功
if(queryBatteryOptimizeStatus()){
//忽略电池优化开启成功
}else{
//开启失败
}
}
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
}
}
https://developer.android.google.cn/guide/topics/ui/accessibility/service
https://gist.github.com/TheMelody/5044dd1b697707b18e94b89f97f55db6
//在多任务列表页面隐藏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){
.....
}
}
• 耗时2年,Android进阶三部曲第三部《Android进阶指北》出版!
为了防止失联,欢迎关注我的小号
微信改了推送机制,真爱请星标本公号👇
评论