Android应用保活实践详解

发布时间:2019-08-08 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了Android应用保活实践详解脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

最近在做的项目中需要app在后台常驻,用于实时上传一些健康信息数据,便于后台实时查看用户的健康状况。自从AndROId7.0以上后台常驻实现越来越难,尤其是8.0及以上。关于保活的文章比比皆是,但是效果并不理想,关于保活的方法也就常说的哪几种,重点在于怎么组合运用。最终实现效果为:用户不主动强制杀死的话,能够一直存活(小米华为,vivo,oppo,三星)。其中三星s8,华为nova2s用户强制杀死也能存活。@H_360_1@

项目结构

Android应用保活实践详解 

常见的保活方案

关于Android应用保活的文章很多,这里不再阐述,可自行百度。重点在于运用这样方案来实现保活功能。

代码实现

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

在锁屏的时候启动一个1个像素的Activity,当用户解锁以后将这个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()     }   } }
@H_406_36@

2.双进程守护

定义一个本地服务,在该服务中播放无声音乐,并绑定远程服务。

 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和JobService是安卓在api 21中增加的接口,用于在某些指定条件下执行后台任务

定义一个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.播放无声音乐

这里使用的是有声的mP3文件,只是在代码中把声音设置成了0;如果使用真正的无声的音乐文件,在oppo手机上按下返回键会被立刻杀死,并且在三星手机,华为nova2s强制杀死也会被杀死,所有使用了有声的文件。

5.提高Service优先级

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

定义一个通知工具类,兼容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)   } }

使用

将保活的功能封装成了一个单独的库,依赖该库即可。

app中使用:

 KeepLive.startWork(this, KeepLive.RunMode.ROGUE, ForegroundNotification("Title", "message",     R.mipmap.ic_launcher, object : ForegroundNotificationClickListener {   override fun foregroundNotificationClick(context: Context, intent: Intent) {     //点击通知回调    } }), object : KeepLiveService {   override fun onStop() {     //可能调用多次,跟onWorking匹配调用   }    override fun onWorking() {     //一直存活,可能调用多次   } })

清单文件配置:

  <!--权限配置--> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.GET_TASKS" /> <uses-permission android:name="android.permission.REORDER_TASKS" />   <!--保活相关配置--> <receiver android:name="com.xiyang51.keeplive.receiver.NotificationClickReceiver" /> <activity android:name="com.xiyang51.keeplive.activity.OnePixelActivity" />  <service android:name="com.xiyang51.keeplive.service.LocalService" /> <service android:name="com.xiyang51.keeplive.service.HideForegroundService" /> <service   android:name="com.xiyang51.keeplive.service.JobHandlerService"   android:permission="android.permission.BIND_JOB_SERVICE" /> <service   android:name="com.xiyang51.keeplive.service.RemoteService"   android:process=":remote" />

代码地址 github

android教程
脚本网站
android studio

脚本宝典总结

以上是脚本宝典为你收集整理的Android应用保活实践详解全部内容,希望文章能够帮你解决Android应用保活实践详解所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。