android系统应用保活_Android 8.0以上系统应用如何保活

对于Android来说,保活主要有以下一些方法:

开启前台Service(效果好,推荐)

Service中循环播放一段无声音频(效果较好,但耗电量高,谨慎使用)

双进程守护(Android 5.0前有效)

JobScheduler(Android 5.0后引入,8.0后失效)

1 像素activity保活方案(不推荐)

广播锁屏、自定义锁屏(不推荐)

第三方推送SDK唤醒(效果好,缺点是第三方接入)

下面是具体的实现方案:

1.监听锁屏广播,开启1个像素的Activity

最早见到这种方案的时候是2015年,有个FM的app为了向投资人展示月活,在Android应用中开启一个1像素的Activity。

由于Activity的级别是比较高的,所以开启1个像素的Activity的方式就可以保证进程是不容易被杀掉的。

具体来说,定义一个1像素的Activity,在该Activity中动态注册自定义的广播。

class OnePixelActivity : AppCompatActivity() {

private lateinit var br: BroadcastReceiver

override fun onCreate(savedInstanceState: Bundle?) {

super.onCreate(savedInstanceState)

//设定一像素的activity

val window = window

window.setGravity(Gravity.LEFT or Gravity.TOP)

val params = window.attributes

params.x = 0

params.y = 0

params.height = 1

params.width = 1

window.attributes = params

//在一像素activity里注册广播接受者 接受到广播结束掉一像素

br = object : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {

finish()

}

}

registerReceiver(br, IntentFilter("finish activity"))

checkScreenOn()

}

override fun onResume() {

super.onResume()

checkScreenOn()

}

override fun onDestroy() {

try {

//销毁的时候解锁广播

unregisterReceiver(br)

} catch (e: IllegalArgumentException) {

}

super.onDestroy()

}

/**

* 检查屏幕是否点亮

*/

private fun checkScreenOn() {

val pm = this@OnePixelActivity.getSystemService(Context.POWER_SERVICE) as PowerManager

val isScreenOn = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {

pm.isInteractive

} else {

pm.isScreenOn

}

if (isScreenOn) {

finish()

}

}

}

2, 双进程守护

双进程守护,在Android 5.0前是有效的,5.0之后就不行了。首先,我们定义定义一个本地服务,在该服务中播放无声音乐,并绑定远程服务

class LocalService : Service() {

private var mediaPlayer: MediaPlayer? = null

private var mBilder: MyBilder? = null

override fun onCreate() {

super.onCreate()

if (mBilder == null) {

mBilder = MyBilder()

}

}

override fun onBind(intent: Intent): IBinder? {

return mBilder

}

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {

//播放无声音乐

if (mediaPlayer == null) {

mediaPlayer = MediaPlayer.create(this, R.raw.novioce)

//声音设置为0

mediaPlayer?.setVolume(0f, 0f)

mediaPlayer?.isLooping = true//循环播放

play()

}

//启用前台服务,提升优先级

if (KeepLive.foregroundNotification != null) {

val intent2 = Intent(applicationContext, NotificationClickReceiver::class.java)

intent2.action = NotificationClickReceiver.CLICK_NOTIFICATION

val notification = NotificationUtils.createNotification(this, KeepLive.foregroundNotification!!.getTitle(), KeepLive.foregroundNotification!!.getDescription(), KeepLive.foregroundNotification!!.getIconRes(), intent2)

startForeground(13691, notification)

}

//绑定守护进程

try {

val intent3 = Intent(this, RemoteService::class.java)

this.bindService(intent3, connection, Context.BIND_ABOVE_CLIENT)

} catch (e: Exception) {

}

//隐藏服务通知

try {

if (Build.VERSION.SDK_INT < 25) {

startService(Intent(this, HideForegroundService::class.java))

}

} catch (e: Exception) {

}

if (KeepLive.keepLiveService != null) {

KeepLive.keepLiveService!!.onWorking()

}

return Service.START_STICKY

}

private fun play() {

if (mediaPlayer != null && !mediaPlayer!!.isPlaying) {

mediaPlayer?.start()

}

}

private inner class MyBilder : GuardAidl.Stub() {

@Throws(RemoteException::class)

override fun wakeUp(title: String, discription: String, iconRes: Int) {

}

}

private val connection = object : ServiceConnection {

override fun onServiceDisconnected(name: ComponentName) {

val remoteService = Intent(this@LocalService,

RemoteService::class.java)

this@LocalService.startService(remoteService)

val intent = Intent(this@LocalService, RemoteService::class.java)

this@LocalService.bindService(intent, this,

Context.BIND_ABOVE_CLIENT)

}

override fun onServiceConnected(name: ComponentName, service: IBinder) {

try {

if (mBilder != null && KeepLive.foregroundNotification != null) {

val guardAidl = GuardAidl.Stub.asInterface(service)

guardAidl.wakeUp(KeepLive.foregroundNotification?.getTitle(), KeepLive.foregroundNotification?.getDescription(), KeepLive.foregroundNotification!!.getIconRes())

}

} catch (e: RemoteException) {

e.printStackTrace()

}

}

}

override fun onDestroy() {

super.onDestroy()

unbindService(connection)

if (KeepLive.keepLiveService != null) {

KeepLive.keepLiveService?.onStop()

}

}

}

然后再定义一个远程服务,绑定本地服务。

class RemoteService : Service() {

private var mBilder: MyBilder? = null

override fun onCreate() {

super.onCreate()

if (mBilder == null) {

mBilder = MyBilder()

}

}

override fun onBind(intent: Intent): IBinder? {

return mBilder

}

override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {

try {

this.bindService(Intent(this@RemoteService, LocalService::class.java),

connection, Context.BIND_ABOVE_CLIENT)

} catch (e: Exception) {

}

return Service.START_STICKY

}

override fun onDestroy() {

super.onDestroy()

unbindService(connection)

}

private inner class MyBilder : GuardAidl.Stub() {

@Throws(RemoteException::class)

override fun wakeUp(title: String, discription: String, iconRes: Int) {

if (Build.VERSION.SDK_INT < 25) {

val intent = Intent(applicationContext, NotificationClickReceiver::class.java)

intent.action = NotificationClickReceiver.CLICK_NOTIFICATION

val notification = NotificationUtils.createNotification(this@RemoteService, title, discription, iconRes, intent)

this@RemoteService.startForeground(13691, notification)

}

}

}

private val connection = object : ServiceConnection {

override fun onServiceDisconnected(name: ComponentName) {

val remoteService = Intent(this@RemoteService,

LocalService::class.java)

this@RemoteService.startService(remoteService)

this@RemoteService.bindService(Intent(this@RemoteService,

LocalService::class.java), this, Context.BIND_ABOVE_CLIENT)

}

override fun onServiceConnected(name: ComponentName, service: IBinder) {}

}

}

/**

* 通知栏点击广播接受者

*/

class NotificationClickReceiver : BroadcastReceiver() {

companion object {

const val CLICK_NOTIFICATION = "CLICK_NOTIFICATION"

}

override fun onReceive(context: Context, intent: Intent) {

if (intent.action == NotificationClickReceiver.CLICK_NOTIFICATION) {

if (KeepLive.foregroundNotification != null) {

if (KeepLive.foregroundNotification!!.getForegroundNotificationClickListener() != null) {

KeepLive.foregroundNotification!!.getForegroundNotificationClickListener()?.foregroundNotificationClick(context, intent)

}

}

}

}

}

3,JobScheduler

JobScheduler是Android从5.0增加的支持一种特殊的任务调度机制,可以用它来实现进程保活,不过在Android8.0系统中,此种方法也失效。

首先,我们定义一个JobService,开启本地服务和远程服务。

@SuppressWarnings(value = ["unchecked", "deprecation"])

@RequiresApi(Build.VERSION_CODES.LOLLIPOP)

class JobHandlerService : JobService() {

private var mJobScheduler: JobScheduler? = null

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {

var startId = startId

startService(this)

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {

mJobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler

val builder = JobInfo.Builder(startId++,

ComponentName(packageName, JobHandlerService::class.java.name))

if (Build.VERSION.SDK_INT >= 24) {

builder.setMinimumLatency(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS) //执行的最小延迟时间

builder.setOverrideDeadline(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS) //执行的最长延时时间

builder.setMinimumLatency(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS)

builder.setBackoffCriteria(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS, JobInfo.BACKOFF_POLICY_LINEAR)//线性重试方案

} else {

builder.setPeriodic(JobInfo.DEFAULT_INITIAL_BACKOFF_MILLIS)

}

builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)

builder.setRequiresCharging(true) // 当插入充电器,执行该任务

mJobScheduler?.schedule(builder.build())

}

return Service.START_STICKY

}

private fun startService(context: Context) {

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {

if (KeepLive.foregroundNotification != null) {

val intent = Intent(applicationContext, NotificationClickReceiver::class.java)

intent.action = NotificationClickReceiver.CLICK_NOTIFICATION

val notification = NotificationUtils.createNotification(this, KeepLive.foregroundNotification!!.getTitle(), KeepLive.foregroundNotification!!.getDescription(), KeepLive.foregroundNotification!!.getIconRes(), intent)

startForeground(13691, notification)

}

}

//启动本地服务

val localIntent = Intent(context, LocalService::class.java)

//启动守护进程

val guardIntent = Intent(context, RemoteService::class.java)

startService(localIntent)

startService(guardIntent)

}

override fun onStartJob(jobParameters: JobParameters): Boolean {

if (!isServiceRunning(applicationContext, "com.xiyang51.keeplive.service.LocalService") || !isServiceRunning(applicationContext, "$packageName:remote")) {

startService(this)

}

return false

}

override fun onStopJob(jobParameters: JobParameters): Boolean {

if (!isServiceRunning(applicationContext, "com.xiyang51.keeplive.service.LocalService") || !isServiceRunning(applicationContext, "$packageName:remote")) {

startService(this)

}

return false

}

private fun isServiceRunning(ctx: Context, className: String): Boolean {

var isRunning = false

val activityManager = ctx

.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager

val servicesList = activityManager

.getRunningServices(Integer.MAX_VALUE)

val l = servicesList.iterator()

while (l.hasNext()) {

val si = l.next()

if (className == si.service.className) {

isRunning = true

}

}

return isRunning

}

}

4,提高Service优先级

在onStartCommand()方法中开启一个通知,提高进程的优先级。注意:从Android 8.0(API级别26)开始,所有通知必须要分配一个渠道,对于每个渠道,可以单独设置视觉和听觉行为。然后用户可以在设置中修改这些设置,根据应用程序来决定哪些通知可以显示或者隐藏。

首先,定义一个通知工具类,此工具栏兼容Android 8.0。

classNotificationUtils(context: Context) : ContextWrapper(context) {private var manager: NotificationManager? = null

private var id: String = context.packageName + "51"

private var name: String =context.packageNameprivate var context: Context =contextprivate var channel: NotificationChannel? = nullcompanion object {

@SuppressLint("StaticFieldLeak")private var notificationUtils: NotificationUtils? = nullfun createNotification(context: Context, title: String, content: String, icon: Int, intent: Intent): Notification?{if (notificationUtils == null) {

notificationUtils=NotificationUtils(context)

}

var notification: Notification? = nullnotification= if (Build.VERSION.SDK_INT >= 26) {

notificationUtils?.createNotificationChannel()

notificationUtils?.getChannelNotification(title, content, icon, intent)?.build()

}else{

notificationUtils?.getNotification_25(title, content, icon, intent)?.build()

}returnnotification

}

}

@RequiresApi(api=Build.VERSION_CODES.O)

fun createNotificationChannel() {if (channel == null) {

channel=NotificationChannel(id, name, NotificationManager.IMPORTANCE_MIN)

channel?.enableLights(false)

channel?.enableVibration(false)

channel?.vibrationPattern = longArrayOf(0)

channel?.setSound(null, null)

getManager().createNotificationChannel(channel)

}

}privatefun getManager(): NotificationManager {if (manager == null) {

manager=getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

}return manager!!}

@RequiresApi(api=Build.VERSION_CODES.O)

fun getChannelNotification(title: String, content: String, icon: Int, intent: Intent): Notification.Builder {//PendingIntent.FLAG_UPDATE_CURRENT 这个类型才能传值

val pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)returnNotification.Builder(context, id)

.setContentTitle(title)

.setContentText(content)

.setSmallIcon(icon)

.setAutoCancel(true)

.setContentIntent(pendingIntent)

}

fun getNotification_25(title: String, content: String, icon: Int, intent: Intent): NotificationCompat.Builder {

val pendingIntent= PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)returnNotificationCompat.Builder(context, id)

.setContentTitle(title)

.setContentText(content)

.setSmallIcon(icon)

.setAutoCancel(true)

.setVibrate(longArrayOf(0))

.setSound(null)

.setLights(0, 0, 0)

.setContentIntent(pendingIntent)

}

}

5,Workmanager方式

Workmanager是Android JetPac中的一个API,借助Workmanager,我们可以用它来实现应用饿保活。使用前,我们需要依赖Workmanager库,如下:

implementation "android.arch.work:work-runtime:1.0.0-alpha06"

Worker是一个抽象类,用来指定需要执行的具体任务。

public class KeepLiveWork extendsWorker {private static final String TAG = "KeepLiveWork";

@NonNull

@OverridepublicWorkerResult doWork() {

Log.d(TAG,"keep-> doWork: startKeepService");//启动job服务

startJobService();//启动相互绑定的服务

startKeepService();returnWorkerResult.SUCCESS;

}

}

然后,启动keepWork方法,

public voidstartKeepWork() {

WorkManager.getInstance().cancelAllWorkByTag(TAG_KEEP_WORK);

Log.d(TAG,"keep-> dowork startKeepWork");

OneTimeWorkRequest oneTimeWorkRequest= new OneTimeWorkRequest.Builder(KeepLiveWork.class)

.setBackoffCriteria(BackoffPolicy.LINEAR,5, TimeUnit.SECONDS)

.addTag(TAG_KEEP_WORK)

.build();

WorkManager.getInstance().enqueue(oneTimeWorkRequest);

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值