最近在做一個需要進程保活的項目,所以來總結一下。
這裏給出了我的進程保活方法和一些技巧,最後附源碼
主要步驟如下:
- 總體來說就是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
參考文章: