android進程保活總結

最近在做一個需要進程保活的項目,所以來總結一下。

這裏給出了我的進程保活方法和一些技巧,最後附源碼

主要步驟如下:

  1. 總體來說就是5.0以下開啓定時器來啓動Service,5.0以上開啓JobService來開啓Service。
  2. 然後監聽系統的鎖屏和解鎖廣播,來開啓一個1像素的Activity。
  3. 監聽系統的開機廣播或第三方推送廣播來啓動Service。
  4. 對與我們的Service開啓一個通知欄通知提升爲前臺進程,並使其爲無感知。
  5. 引導用戶開啓應用自啓動來使app在被手動或自動殺死後能從新被拉起來。

下面進行詳細的描述:

 1. 5.0以下開啓定時器來啓動Service,5.0以上開啓JobService來開啓Service。

       5.0一下在Application中開啓定時器

private fun startLongConn() {
        val systemService = getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val intent = Intent(this, LongConnService::class.java)
        val pendingIntent = PendingIntent.getService(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        val realtime = SystemClock.elapsedRealtime()
        systemService.setRepeating(AlarmManager.RTC_WAKEUP,realtime,60*1000,pendingIntent)
    }

    5.0以上使用JobService,並在其中接收屏幕解鎖和鎖屏的廣播,來實現1像素Activity的開關,JobService的作用簡單來說就是開啓一個可以在5.0以上使用的定時器,在間隔時間執行一次onStartJob方法。但是當被用戶殺死或在系統內存嚴重不足時也會被殺死,被系統標記爲stopped,從而無法啓動。(解決辦法看下面的自啓動)

      ps:鎖屏和解鎖廣播要動態註冊,靜態註冊無效。若不清楚JobService的用法請自行百度

class JobLongConnService:JobService() {

    companion object {
        private const val TAG = "JobLongConnService:"
        const val jobId = 1
    }

    lateinit var myServiceBroadcast: MyServiceBroadcast

    override fun onCreate() {
        super.onCreate()
        myServiceBroadcast = MyServiceBroadcast()
        val intentFilter = IntentFilter()
        intentFilter.addAction(Intent.ACTION_SCREEN_OFF)
        intentFilter.addAction(Intent.ACTION_SCREEN_ON)
        registerReceiver(myServiceBroadcast, intentFilter)

    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        println("start$TAG")
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            val jobScheduler = getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler
            val builder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                println("7.0走15分鐘間隔$TAG")
                JobInfo.Builder(jobId, ComponentName(applicationContext, JobLongConnService::class.java))
                        .setPeriodic(15 * 60 * 1000, 5 * 60 * 1000)
                        .setRequiresCharging(true)
                        .setRequiresDeviceIdle(true)
                        .setPersisted(true)
            } else {
                println("走2分鐘間隔$TAG")
                JobInfo.Builder(jobId, ComponentName(applicationContext, JobLongConnService::class.java))
                        .setPeriodic(30 * 1000)
                        .setRequiresCharging(true)
                        .setRequiresDeviceIdle(true)
                        .setPersisted(true)
            }
            if (jobScheduler.schedule(builder.build()) == JobScheduler.RESULT_SUCCESS) {
                println("工作成功$TAG")
            } else {
                println("工作失敗$TAG")
            }
        }
        return Service.START_STICKY
    }

    override fun onStartJob(params: JobParameters?): Boolean {
        println("job啓動$TAG")
        if (!ServiceUtils.isServiceRunning(this, "com.example.ring.LongConnService")) {
            val serviceIntent = Intent(this, LongConnService::class.java)
            this.startService(serviceIntent)
        } else {
            if (BleManager.getInstance().allConnectedDevice.size == 0) {
                val serviceIntent = Intent(this, LongConnService::class.java)
                this.startService(serviceIntent)
            }
        }
        return false
    }

    override fun onStopJob(params: JobParameters?): Boolean {
        println("job停止$TAG")
        if (!ServiceUtils.isServiceRunning(this, "com.example.ring.LongConnService")) {
            val serviceIntent = Intent(this, LongConnService::class.java)
            this.startService(serviceIntent)
        } else {
            if (BleManager.getInstance().allConnectedDevice.size == 0) {
                val serviceIntent = Intent(this, LongConnService::class.java)
                this.startService(serviceIntent)
            }
        }
        return false
    }

    override fun onDestroy() {
        super.onDestroy()
        val intent = Intent("com.example.ring.destroy")
        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
        sendBroadcast(intent)
        unregisterReceiver(myServiceBroadcast)
    }

    inner class MyServiceBroadcast : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            when (intent!!.action) {
                Intent.ACTION_SCREEN_OFF -> {
                    KeepLiveManager.startKeepLiveActivity(this@JobLongConnService)
                }
                Intent.ACTION_SCREEN_ON -> {
                    KeepLiveManager.finishKeepLiveActivity()
                }
            }
        }
    }
}

   對於我們自己的Service爲了實現不輕易被殺死,我們開啓爲前臺進程,提高優先級,在開啓無感知

class LongConnService: Service() {
   
    private val TAG = "LongConnService"


    inner class LocalBinder :Binder(){
        fun getService():LongConnService {
            return LongConnService()
        }
    }

    override fun onBind(intent: Intent?): IBinder? {
        println("$TAG 返回binder")
        return null
    }

    override fun onUnbind(intent: Intent?): Boolean {
        println("$TAG 返回onUnbind")
        return super.onUnbind(intent)
    }

    //第一次創建的時候調用
    override fun onCreate() {
        super.onCreate()
        println("$TAG onCreate")
    }

    //每次startService的時候調用
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        println("$TAG onStartCommand")
        if (Build.VERSION.SDK_INT<18){
            this.startForeground(1000,  getNotification())
        }else if (Build.VERSION.SDK_INT<25){
            this.startForeground(1000,  getNotification())
            this.startService(android.content.Intent(this,InnerService::class.java))
        }else{
            this.startForeground(1000,  getNotification())
        }

        //做自己的處理

        return START_STICKY
    }

   
    override fun onDestroy() {
        println("$TAG onDestroy")
        stopForeground(true)
        val intent = Intent("com.example.ring.destroy")
        intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
        sendBroadcast(intent)
        super.onDestroy()
    }

    private fun getNotification(): Notification {
        val intent = Intent(this, MainActivity::class.java)
        val pi = PendingIntent.getActivity(this, 0, intent, 0)
        return NotificationCompat.Builder(this)
                .setContentTitle("Ring")
                .setContentText("Ring service is running")
                .setWhen(System.currentTimeMillis())
                .setSmallIcon(R.drawable.ic_launcher_round)
                .setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
                .setContentIntent(pi)
                .setAutoCancel(false)
                .build()
    }

    //是爲了讓用戶無感知
    companion object {
         class InnerService:Service(){
            override fun onBind(intent: Intent?): IBinder? {
                return null
            }

            override fun onCreate() {
                super.onCreate()
                try {
                    println("開啓內部InnerService")
                    val intent = Intent(this, MainActivity::class.java)
                    val pi = PendingIntent.getActivity(this, 0, intent, 0)
                    val notification = NotificationCompat.Builder(this)
                            .setContentTitle("Ring")
                            .setContentText("Ring service is running")
                            .setWhen(System.currentTimeMillis())
                            .setSmallIcon(R.drawable.ic_launcher_round)
                            .setLargeIcon(BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher))
                            .setContentIntent(pi)
                            .setAutoCancel(false)
                            .build()
                    startForeground(1000,notification)
                }catch (throwable:Throwable){
                    throwable.printStackTrace()
                }
                stopSelf()
            }
        }
    }

}

  1像素Activity和其manager代碼

class KeepLiveActivity:AppCompatActivity() {

    lateinit var broadcast:MyBroadcast

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        KeepLiveManager.keepLiveActivity = this
        window.setGravity(Gravity.START)
        window.attributes.run {
            x=0
            y=0
            width=1
            height=1
        }
    }
object KeepLiveManager {
    var keepLiveActivity:KeepLiveActivity?=null

    fun startKeepLiveActivity(context: Context){
        println("創建KeepLive")
        val intent = Intent(context, KeepLiveActivity::class.java)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        context.startActivity(intent)
    }

    fun finishKeepLiveActivity(){
        println("finish KeepLive")
        keepLiveActivity?.finish()
    }
}

另外在創建一個BroadcastReceiver來接收系統註冊靜態廣播或第三方廣播,來啓動Service

class MyReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        println("廣播:"+intent.action)
        when {
            intent.action == "com.example.ring.destroy" -> {
                println("longService服務掛了...")
                checkRunning(context)
            }
            intent.action == Intent.ACTION_BOOT_COMPLETED->{
                println("手機開機了...")
                checkRunning(context)
            }
            Intent.ACTION_USER_PRESENT == intent.action->{
                println("手機解鎖了...")
                checkRunning(context)
            }
            intent.action == "cn.jpush.android.intent.DaemonService"->{
                println("極光推送拉起...")
                checkRunning(context)
            }
        }
    }

    private fun checkRunning(context: Context){
        if (Build.VERSION.SDK_INT>= Build.VERSION_CODES.LOLLIPOP){
            if (!ServiceUtils.isServiceRunning(context,"com.example.ring.JobLongConnService")){
                val serviceIntent = Intent(context, JobLongConnService::class.java)
                context.startService(serviceIntent)
            }
        }else{
            if (!ServiceUtils.isServiceRunning(context,"com.example.ring.LongConnService")){
                val serviceIntent = Intent(context, LongConnService::class.java)
                context.startService(serviceIntent)
            }
        }
    }
}

最後爲了在app被手動kill掉之後還能起來,我們需要引導用戶開啓自啓動

object SettingUtils {

    fun enterWhiteListSetting(context: Context) {
        try {
            context.startActivity(getSettingIntent())
        } catch (e: Exception) {
            context.startActivity(Intent(Settings.ACTION_SETTINGS))
        }
    }

    private fun getSettingIntent(): Intent {

        var componentName: ComponentName? = null

        val brand = android.os.Build.BRAND

        when (brand.toLowerCase()) {
            "samsung" -> componentName = ComponentName("com.samsung.android.sm",
                    "com.samsung.android.sm.app.dashboard.SmartManagerDashBoardActivity")
            "huawei" -> componentName = ComponentName("com.huawei.systemmanager",
                    "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity")
            "xiaomi" -> componentName = ComponentName("com.miui.securitycenter",
                    "com.miui.permcenter.autostart.AutoStartManagementActivity")
            "vivo" -> componentName = ComponentName("com.iqoo.secure",
                    "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")
            "oppo" -> componentName = ComponentName("com.coloros.oppoguardelf",
                    "com.coloros.powermanager.fuelgaue.PowerUsageModelActivity")
            "360" -> componentName = ComponentName("com.yulong.android.coolsafe",
                    "com.yulong.android.coolsafe.ui.activity.autorun.AutoRunListActivity")
            "meizu" -> componentName = ComponentName("com.meizu.safe",
                    "com.meizu.safe.permission.SmartBGActivity")
            "oneplus" -> componentName = ComponentName("com.oneplus.security",
                    "com.oneplus.security.chainlaunch.view.ChainLaunchAppListActivity")
            "nubia"->{
                componentName = ComponentName("cn.nubia.security2",
                        "cn.nubia.security.appmanage.selfstart.ui.SelfStartActivity")
            }
            else -> {
            }
        }

        val intent = Intent()
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        if (componentName != null) {
            intent.component = componentName
        } else {
            intent.action = Settings.ACTION_SETTINGS
        }
        return intent
    }
}

然後你就會發現若是不關閉自啓動,app是殺不死的,kill了之後一會兒又會起來。(你們看微信也是開啓了自啓動)

上面開啓自啓動的適合大部分機型,少部分沒有的可以自己添加,手機進入自啓動界面,然後使用adb命令獲取路徑

完整代碼已上傳至github:https://github.com/zhongyiqwer/Ring

參考文章:

https://blog.csdn.net/findsafety/article/details/80388430

https://blog.csdn.net/cspecialy/article/details/80161258

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章