Skip to content

zhongyiqwer/Ring

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 

Repository files navigation

最近在做一个需要进程保活的项目,所以来总结一下。

这里给出了我的进程保活方法和一些技巧,最后附源码

主要步骤如下:

总体来说就是5.0以下开启定时器来启动Service,5.0以上开启JobService来开启Service。 然后监听系统的锁屏和解锁广播,来开启一个1像素的Activity。 监听系统的开机广播或第三方推送广播来启动Service。 对与我们的Service开启一个通知栏通知提升为前台进程,并使其为无感知。 引导用户开启应用自启动来使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

About

进程保活实践

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages