Android 如何实现保活 app(电池医生实现)

基础理论

保活Service需要做什么

  1. 应用被关闭的时候保活(最难)
  2. 在内存占用过大,系统自动释放内存时保活(优先杀死占用较高的Service)
  3. 重启手机后自动开启Service
  4. 手机息屏后不被释放内存
  5. 手机清理内存时保活

进程的五个常用级别:

  • 前台进程(Foreground process):前台进程就是用户当前要处理的所有事情都必须要使用的进程。满足下面的各种情况则认为是前台进程。 杀死前台进程需要用户交互,前台进程的优先级最高
    • 进程持有一个正在和用户交互的 Activity。
    • 进程持有一个 Service,这个 Service 处于这几种状态:1. Service 与用户正在交互的 Activity 绑定。 2. Service 是在前台运行的。 3. Service 正在执行它的生命周期 onCreate() ,onStrarCommandonDestroy。 4. 进程持有一个 BroadcastReceiver 这个 BroadcastReceiver 正在执行它的 onReceiver 方法。
  • 可见进程(Visible process):如果一个进程不含任何前台的组件,但仍可被用户在屏幕上看到。当满足下面任意一条的时候,进程被认为是可见的。 可见的进程也被认为很重要,一般不会被销毁,除非是为了保证所有前台进程的运行而不得已不杀死可见进程的时候
    • 进程持有一个 activity,这个 activity 不在前台。但是仍然可见的情况。
    • 进程持有一个 Service ,这个 Service 与一个可见的 Activity 绑定。
  • 服务进程(Service process):如果一个进程中运行着一个 Service,这个 Service 是通过 startService() 开启的,并且不属于上面两种较高优先级的情况下,这个进程就是一个服务进程。尽管服务进程没有和用户可以看到的东西绑定,但是它们一般在做的事情是用户关心的,比如后台播放音乐,后台下载数据等。所以系统会尽量维持它们的运行,除非系统内存不足以维持前台进程和可见进程的运行需要(这句话和没说一样)
  • 后台进程(Background process):如果进程不属于上面三种情况,但是进程持有一个用户不可见的 activity (activity 的 onStop 被调用,但是 onDestroy 没有被调用的状态)就认为进程是一个后台进程。 后台进程不直接影响用户体验,系统会为了前台进程、可见进程、服务进程而任意杀死后台进程,通常情况下会有很多后台进程存在,他们会被保存在一个 LRU(least recently used)列表中,这样就可以确保用户最近使用的 Activity 最后被销毁,先销毁时间最远的 Activity。
  • 空进程:如果一个进程不包含任何活跃的应用组件,则认为是空进程。例如:一个进程当中已经没有数据运行了,但是内存当中还为这个应用保留了一个进程空间。保存这种进程的唯一理由是为了缓存的需要,为了加快下次启动这个进程中组件的启动时间,这种空进程经常被杀死。

为了提高优先级我们可以使用startForeground()方法将Service设置为前台进程。

BindService() 方法中的 flag 参数:

  • BIND_AUOT_CREATE: 只要绑定存在就会自动创建这个 Service,虽然创建了 Service,但是它的 `onStartCommand` 方法是不会调用的,因为这个方法只有在 `startService` 的时候被调用。 在 Android 4.0 以前,不提供这个标志的话,会影响系统判定当前 Service 进程的重要性(会把它认为是后台进程),当要设置的时候,告诉系统进程重要性的唯一方式是,通过 `bindService` 来实现,在这种情况下,只有 Activity 在前台才会起作用。(这样 Service 进程的优先级等同于启动它的进程的优先级)。 现在要想把 Service 进程的优先级降低,必须提供新的` falg` (BIND_ADJUST_WITH_ACTIVITY)。考虑到兼容性,如果没有指定 BIND_AUTO_CREATE 的时候,系统会自动加上 BIND_WAIVE_PRIORITY 和 BIND_ADJUST_WITH_ACTIVITY 来实现降低优先级的效果。因为在 Android 4.0 以前 Service 的优先级默认是后台进程,在 Android 4.0 之后默认是等同于宿主进程,所以只有设置了 BIND_WAIVE_PRIORITY 后才会 4.0 和 4.0以前都兼容起来被当做后台任务对待。
  • BIND_DEBUG_UNBIND: 用来 debug 使用的
  • BIND_NOT_FOREGROUND 不允许将绑定的 Service 的进程提升到前台进程的优先级,它将仍然拥有和客户端同样的内存优先级,所以在宿主进程没有被杀死的情况下,Service 的进程也是不会被杀死的。但是 cpu 可能会把它放在后台执行。仅仅在这种情况下会有作用,宿主进程在前端,Service 进程在后台
  • BIND_ABOVE_CLIENT 在这种情况下,Service 进程比 App 本身的进程还有重要,当设置后,内存溢出的时候,将会在关闭 Service 进程前关闭 App 进程。但是这种情况不能保证。
  • BIND_ALLOW_OOM_MANAGEMENT 允许内存管理系统管理 Service 的进程,允许系统在内存不足的时候删除这个进程。
  • BIND_WAIVE_PRIORITY 不影响 Service 进程的优先级的情况下,允许 Service 进程被加入后台队列中。
  • BIND_IMPORITANT 这个服务对于这个客户端来说是非常重要的,所以应该提升到前台进程的级别。一般这个进程 会提升到可见的级别,甚至客户端在后台的时候。
  • BIND_ADJUST_WITH_ACTIVITY 如果从一个 Activity 绑定,则这个 Service 进程的优先级和 Activity 是否对用户可见有关。

实现具体步骤

实现步骤简述

  1. 正常一般只需要开启前台服务
  2. 要求高保活,可以通过双进程服务互相持有

AndroidManifest中添加Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<service
android:name="com.atom.battery.service.BatteryKeepService"
android:priority="1000" //设置高优先级
android:enabled="true"
android:exported="true" />

<service
android:name="com.atom.battery.support.keepalive.KeepService"
android:process=":resident" //放入新的进程 />

<service
android:name="com.atom.battery.support.keepalive.AssistantService" //辅助服务
android:enabled="true"
android:exported="true"
android:process=":remote" //放入新的进程/>

双进程服务互相绑定保护

创建aidl实现跨进程通信

1
2
3
4
5
6
7
8
9
10
interface IKeepAlive {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
// void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
// double aDouble, String aString);

String getName();
}

创建当前主要服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
class BatteryKeepService : Service(), BatteryStateUtil.BatteryChangeLinstener {


// 全局变量,方便复用
private var mNotificationManager: NotificationManagerCompat? = null
private var mChannel: NotificationChannelCompat? = null
private var mRemoteViews: RemoteViews? = null
private var mBuilder: NotificationCompat.Builder? = null
private var mNotification: Notification? = null


/**
* 当前状态 see[BatteryStateUtil.sStatus]
*/
private var mBatteryStatus: Int? = null

/**
* 是否正在充电
*/
private var mIsCharging: Boolean = false

/**
* 默认冲至100提醒
*/
private var mChargeToXxNotify: Int = 100

override fun onCreate() {
super.onCreate()
bindAssistantService()
createChannel()
BatteryStateUtil.addLinstener(javaClass.simpleName,this)
}

override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
LanguageUtil.checkAndSetLanguage(this)
// re创建
createForegroundNotification()
return START_STICKY //START_STICKY 销毁时自动重建

}

/**
* 创建前台notification,将service置为前台service,gc优先级降低
*/
private fun createForegroundNotification() {
val needCreate =
mNotificationManager == null || mNotification == null || mRemoteViews == null
if (needCreate) {
createChannel()
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mNotificationManager?.getNotificationChannel(mChannel?.id!!)?.lockscreenVisibility =
Notification.VISIBILITY_PUBLIC
}

// 设置点击通知跳转的Intent
val nfIntent = Intent(this, MainActivity::class.java)
// 最后一个参数可以为PendingIntent.FLAG_CANCEL_CURRENT 或者 PendingIntent.FLAG_UPDATE_CURRENT
val pendingIntent = PendingIntent.getActivity(this, 1, nfIntent, 0)

mRemoteViews = RemoteViews(packageName, R.layout.notification_keep_remoteview)

// 适配语言
mRemoteViews?.setTextViewText(
R.id.notify_keep_rv_tv,
getString(R.string.widget_app_running)
)

//构建一个Notification构造器
mBuilder = NotificationCompat.Builder(this, Constant.CHANNEL_ID_FOREGROUND)
.setShowWhen(true)
.setContentIntent(pendingIntent) // 设置点击跳转界面
.setWhen(0)
.setCustomContentView(mRemoteViews)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setDefaults(NotificationCompat.FLAG_ONLY_ALERT_ONCE)
.setVibrate(null)
.setLights(0, 0, 0)
.setSound(null)
.setSmallIcon(R.drawable.atombattery_logo_small_25) // 必须要有这个
.setPriority(NotificationCompat.PRIORITY_HIGH) //优先级高
mNotification = mBuilder?.build() // 获取构建好的Notification
mNotification!!.flags =
mNotification!!.flags or NotificationCompat.FLAG_ONGOING_EVENT //将此通知放到通知栏的"Ongoing"即"正在运行"组中
mNotification!!.flags =
mNotification!!.flags or NotificationCompat.FLAG_NO_CLEAR //表明在点击了通知栏中的"清除通知"后,此通知不清除,常与FLAG_ONGOING_EVENT一起使用
}

// lable 启动前台服务
// 参数一:唯一的通知标识;参数二:通知消息。
startForeground(Constant.NOTIFICATION_ID_KEEP_ALIVE, mNotification) // 开始前台服务
}

/**
* notify--channel
*/
private fun createChannel() {
// 在Android进行通知处理,首先需要重系统哪里获得通知管理器NotificationManager,它是一个系统Service。
mNotificationManager = NotificationManagerCompat.from(this)
if (mChannel == null) {
// channel
mChannel = NotificationChannelCompat.Builder(
Constant.CHANNEL_ID_FOREGROUND,
NotificationManagerCompat.IMPORTANCE_DEFAULT
)
.setName(getString(R.string.widget_permanent_notification_name))
.setLightsEnabled(false)
.setVibrationEnabled(false)
.setVibrationPattern(longArrayOf(0))
.setSound(null, null)
.setShowBadge(false) // 不显示在shortcut上方
.build()
}
mNotificationManager?.createNotificationChannel(mChannel!!)
}

override fun onDestroy() {
super.onDestroy()
try {
stopForeground(true)

// 启动自己
val intent = Intent(CommonUtil.getApp(), BatteryKeepService::class.java)
Log.d("zfr", "KeepAliveService destroy and restart")
ContextCompat.startForegroundService(this,intent)
createForegroundNotification()
} catch (tr: Throwable) {
// system error
}
}


// <editor-folder desc="以下是serivice相互绑定的保活相关">

override fun onBind(intent: Intent?): IBinder? {
Timber.tag("zfr").d("onBind")
// stopForeground(true); // <- remove notification
return keepAliveStub //返回aidl
}

override fun onRebind(intent: Intent?) {
// stopForeground(true); // <- remove notification
// createForegroundNotification();
}

override fun onUnbind(intent: Intent?): Boolean {
// createForegroundNotification();
return true
}

private val keepAliveStub: IKeepAlive.Stub = object : IKeepAlive.Stub() {

override fun getName(): String = "我是 KeepAliveService"
}

private var serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
val iAssistant: IKeepAlive = IKeepAlive.Stub.asInterface(service)
if (iAssistant != null) {
try {
Timber.tag("zfr").d("收到AssistantService的数据:name=" + iAssistant.getName())
} catch (e: RemoteException) {
e.printStackTrace()
}
}
}

override fun onServiceDisconnected(name: ComponentName) {
bindAssistantService() // 断开链接时绑定辅助服务
}
}

/**
* 与[AssistantService]相互绑定监听,起到保活作用
*/
fun bindAssistantService() {
val intent = Intent(CommonUtil.getApp(), AssistantService::class.java)
bindService(intent, serviceConnection, BIND_AUTO_CREATE)
}

// </editor-folder>
}

创建辅助服务

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
public class AssistantService extends Service {
@Nullable
@Override
public IBinder onBind(Intent intent) {
return assistantStub;
}

@Override
public void onCreate() {
super.onCreate();
Log.d("zfr", "onCreate AssistantService");
//提升Service的优先级
Notification notification = new Notification();
notification.flags = Notification.FLAG_ONGOING_EVENT;
notification.flags |= Notification.FLAG_NO_CLEAR;
notification.flags |= Notification.FLAG_FOREGROUND_SERVICE;
// startForeground(1, notification);
//绑定主要服务
bindKeepAliveService();
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return Service.START_STICKY;
}

@Override
public void onDestroy() {
Log.d("zfr", "Assistant Destroy");

try {
// 启动自己
Intent intent = new Intent(CommonUtil.INSTANCE.getApp(), AssistantService.class);
startService(intent);
} catch (Throwable tr) {
// system error
}
super.onDestroy();
}

@Override
public boolean onUnbind(Intent intent) {
Log.d("zfr", "Assistant onUnbind");
return super.onUnbind(intent);
}



private IKeepAlive iKeepAlive;
private IKeepAlive.Stub assistantStub = new IKeepAlive.Stub() {
@Override
public String getName() throws RemoteException {
return "我是 AssistantService";
}
};

private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
iKeepAlive = IKeepAlive.Stub.asInterface(service);
if (iKeepAlive != null) {
try {
Log.d("zfr",
"收到KeepAliveService的数据:name="
+ iKeepAlive.getName());
} catch (RemoteException e) {
e.printStackTrace();
}
}
}

@Override
public void onServiceDisconnected(ComponentName name) {
//重新绑定
bindKeepAliveService();
}
};

private void bindKeepAliveService() {
try {
Intent clientIntent = new Intent(CommonUtil.INSTANCE.getApp(), BatteryKeepService.class);
bindService(clientIntent, serviceConnection, Context.BIND_AUTO_CREATE);
} catch (Throwable tr) {
// system error
}
}
}
返回参数含义:orange START_STICKY:orange 在Service被关闭后,重新开启Service

START_NOT_STICKY:服务被异常杀掉后,系统将会被设置为started状态,系统不会重启该服务,直到startService(Intent intent)方法再次被调用。
START_REDELIVER_INTENT:重传Intent,使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。

使用JobService来实现应用退出后重启Service

AndroidManifest中添加Service和权限

1
2
3
4
<service
android:name="com.atom.battery.support.keepalive.AliveJobService"
android:exported="true"
android:permission="android.permission.BIND_JOB_SERVICE" />

JobService 代码 (具体就是为了保证当app被杀死时重新启动服务)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public class AliveJobService extends JobService {
private final static String TAG = "zfr";
// 告知编译器,这个变量不能被优化
private volatile static Service mKeepAliveService = null;

public static boolean isJobServiceAlive() {
return mKeepAliveService != null;
}

private static final int MESSAGE_ID_TASK = 0x01;

private Handler mHandler = new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
// 具体任务逻辑
if (AppUtil.isAppRunning(CommonUtil.INSTANCE.getApp(), CommonUtil.INSTANCE.getApp().getPackageName())) {
Log.d(TAG, "KeepAliveService----->APP活着的...");
} else {
Intent alive = new Intent(getApplicationContext(), BatteryKeepService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(alive);
} else {
startService(alive);
}
Log.d(TAG, "KeepAliveService----->APP被杀死,重启...");
}
// 通知系统任务执行结束
jobFinished((JobParameters) msg.obj, false);
return true;
}
});

@Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG, "KeepAliveService----->JobService服务被启动...");
mKeepAliveService = this;
// 返回false,系统假设这个方法返回时任务已经执行完毕;
// 返回true,系统假定这个任务正要被执行
Message msg = Message.obtain(mHandler, MESSAGE_ID_TASK, params);
mHandler.sendMessage(msg);
return true;
}

@Override
public boolean onStopJob(JobParameters params) {
mHandler.removeMessages(MESSAGE_ID_TASK);
Log.d(TAG, "KeepAliveService----->JobService服务被关闭");
return false;
}
}

JobSchedulerManger管理类代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
public class JobSchedulerManager {
private static final int JOB_ID = 1;
private static JobSchedulerManager mJobManager;
private JobScheduler mJobScheduler;
private static Context mContext;

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
private JobSchedulerManager(Context ctxt){
this.mContext = ctxt;
mJobScheduler = (JobScheduler)ctxt.getSystemService(Context.JOB_SCHEDULER_SERVICE);
}

@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public final static JobSchedulerManager getJobSchedulerInstance(Context ctxt){
if(mJobManager == null){
mJobManager = new JobSchedulerManager(ctxt);
}
return mJobManager;
}
@TargetApi(21)
public void startJobScheduler(){
// 如果JobService已经启动或API<21,返回
if(AliveJobService.isJobServiceAlive() || isBelowLOLLIPOP()){
return;
}
// 构建JobInfo对象,传递给JobSchedulerService
JobInfo.Builder builder = new JobInfo.Builder(JOB_ID,new ComponentName(mContext, AliveJobService.class));
// 设置每30秒执行一下任务
builder.setPeriodic(30_000);
// 设置设备重启时,执行该任务
builder.setPersisted(true);
// 当插入充电器,执行该任务
builder.setRequiresCharging(true);
JobInfo info = builder.build();
//开始定时执行该系统任务
mJobScheduler.schedule(info);
}
@TargetApi(21)
public void stopJobScheduler(){
if(isBelowLOLLIPOP())
return;
mJobScheduler.cancelAll();
}
private boolean isBelowLOLLIPOP(){
// API< 21
return Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP;
}
}

引入第三方库KeepAlive 保活

Application中初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 初始化keepAlive
*/
private fun initKeepAlive(base: Context) {
val configs = KeepAliveConfigs(KeepAliveConfigs.Config(base.packageName + ":resident", KeepService::class.java.canonicalName))
// configs.ignoreBatteryOptimization();
// configs.rebootThreshold(10*1000, 3);
configs.setOnBootReceivedListener { context, intent ->
Timber.d("onReceive boot")
try {
// 设置服务自启
context.startService(Intent(context, KeepService::class.java))
} catch (e: Exception) {
}
}
KeepAlive.init(base, configs)
}

创建保活服务用于检查主服务是否死了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
* Intent: 对接loctl保活方式,会自动拉起主进程
*/
public class KeepService extends KeepAliveService_2 {

private static final String TAG = KeepService.class.getSimpleName();

private FlowableEmitter<Integer> mEmitter;
private Subscription mSubscription;

@Override
public void onCreate() {
super.onCreate();
Timber.tag(TAG).d("KeepService--onCreate...");
}

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
int result = START_STICKY;
Timber.tag(TAG).d("onStartCommand--%d",startId);

// 是否同意隐私协议
boolean agreed = (boolean) SPUtil.get(CommonUtil.INSTANCE.getApp(), SpConstant.INSTANCE.POLICY_AGREE,false);
if(!agreed) return result;

// 检查常驻通知是否死了
if(mEmitter != null){
mEmitter.onNext(startId);
}else {
checkKeepAliveService();
}


return result;
}

/**
* 检查常驻通知是否死了
*/
private void checkKeepAliveService(){
try {

Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull FlowableEmitter<Integer> emitter) {
mEmitter = emitter;
}
}, BackpressureStrategy.LATEST)
.map(new Function<Integer, Integer>() {
@Override
public Integer apply(@NonNull Integer integer) {

try {
ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
if (activityManager != null) {
List<ActivityManager.RunningServiceInfo> runningServices =
activityManager.getRunningServices(Integer.MAX_VALUE);// 获取正在运行的服务列表
if (runningServices.size() < 0) {
return 0;
}
for (int i = 0; i < runningServices.size(); i++) {
ComponentName service = runningServices.get(i).service;
// Timber.tag(TAG).d("检查KeepAliveService是否死了--%d---className=%s。。。",integer,service.getClassName());
if (service.getClassName().equals(BatteryKeepService.class.getName())) {
return 0;
}
}
// 死了--拉起
return 1;
}
}finally {
return 0;
}
}
}).compose(RxUtil.INSTANCE.ioAndMainFlowable())
.subscribe(new FlowableSubscriber<Integer>() {
@Override
public void onSubscribe(@NonNull Subscription s) {
mSubscription = s;
mSubscription.request(1);
}

@Override
public void onNext(Integer integer) {
Timber.tag(TAG).d("onNext--%d",integer);
try {
if(integer == 1){
Timber.tag(TAG).d("KeepAliveService死了---准备拉起。。。");
Intent alive = new Intent(KeepService.this, BatteryKeepService.class);
ContextCompat.startForegroundService(KeepService.this,alive);
}
}finally {
mSubscription.request(1);
}
}

@Override
public void onError(Throwable t) {
Timber.tag(TAG).e(t);
}

@Override
public void onComplete() {

}
});

}catch (Exception e){}
}

@Override
public void onDestroy() {
super.onDestroy();
if(mSubscription != null){
mSubscription.cancel();
}
mEmitter = null;
mSubscription = null;
}
}

确保App保活需要的其他操作

开启忽略电池优化权限

1
2
<!--    电池白名单-->
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>

开启无障碍服务

1
2
3
<!--    无障碍权限-->
<uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE"
tools:ignore="ProtectedPermissions" />

还需要创建服务并开启

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class BatteryAccessibilityService : AccessibilityService() {
override fun onServiceConnected() {
super.onServiceConnected()
// setServiceInfo();//这个方法同样可以实现xml中的配置信息
}

override fun onUnbind(intent: Intent): Boolean {
//关闭服务时,调用
return super.onUnbind(intent)
}

override fun onAccessibilityEvent(event: AccessibilityEvent) {}
override fun onInterrupt() {}
}

开启自启动权限

使用第三方工具类,让用户开启