对于AndroID来说,保活主要有以下一些方法:
@H_502_2@开启前台Service(效果好,推荐)Service中循环播放一段无声音频(效果较好,但耗电量高,谨慎使用)双进程守护(AndroID 5.0前有效)JobScheduler(AndroID 5.0后引入,8.0后失效)1 像素activity保活方案(不推荐)广播锁屏、自定义锁屏(不推荐)第三方推送SDK唤醒(效果好,缺点是第三方接入)下面是具体的实现方案:
1.监听锁屏广播,开启1个像素的Activity@H_502_21@最早见到这种方案的时候是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, 双进程守护@H_502_21@双进程守护,在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(@R_301_1613@::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: @R_301_1613@) { 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(@R_301_1613@::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@H_502_21@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优先级@H_502_21@在onStartCommand()方法中开启一个通知,提高进程的优先级。注意:从AndroID 8.0(API级别26)开始,所有通知必须要分配一个渠道,对于每个渠道,可以单独设置视觉和听觉行为。然后用户可以在设置中修改这些设置,根据应用程序来决定哪些通知可以显示或者隐藏。
首先,定义一个通知工具类,此工具栏兼容AndroID 8.0。
class NotificationUtils(context: Context) : Contextwrapper(context) { private var manager: notificationmanager? = null private var ID: String = context.packagename + "51" private var name: String = context.packagename private var context: Context = context private var channel: NotificationChannel? = null companion object { @Suppresslint("StaticFIEldLeak") private var notificationUtils: NotificationUtils? = null fun createNotification(context: Context, Title: String, content: String, icon: Int, intent: Intent): Notification? { if (notificationUtils == null) { notificationUtils = NotificationUtils(context) } var notification: Notification? = null notification = if (Build.VERSION.SDK_INT >= 26) { notificationUtils?.createNotificationChannel() notificationUtils?.getChannelNotification(Title, content, icon, intent)?.build() } else { notificationUtils?.getNotification_25(Title, content, icon, intent)?.build() } return notification } } @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) } } private fun 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) return Notification.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) return NotificationCompat.Builder(context, ID) .setContentTitle(Title) .setContentText(content) .setSmallicon(icon) .setautoCancel(true) .setVibrate(longArrayOf(0)) .setSound(null) .setlights(0, 0, 0) .setContentIntent(pendingIntent) }}
5,Workmanager方式@H_502_21@
Workmanager是AndroID JetPac中的一个API,借助Workmanager,我们可以用它来实现应用饿保活。使用前,我们需要依赖Workmanager库,如下:
implementation "androID.arch.work:work-runtime:1.0.0-Alpha06"
Worker是一个抽象类,用来指定需要执行的具体任务。
public class KeepliveWork extends Worker { private static final String TAG = "KeepliveWork"; @NonNull @OverrIDe public WorkerResult doWork() { Log.d(TAG, "keep-> doWork: startKeepService"); //启动job服务 startJobService(); //启动相互绑定的服务 startKeepService(); return WorkerResult.SUCCESS; }}
然后,启动keepWork方法,
public voID startKeepWork() { 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); }
总结
以上是内存溢出为你收集整理的Android 8.0以上系统应用如何保活全部内容,希望文章能够帮你解决Android 8.0以上系统应用如何保活所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)