方案名称 | 方案简述 | 优点 | 缺点 | 适用情况 |
---|---|---|---|---|
1像素保活 | 在屏幕关闭时打开一个1px的activity,屏幕亮时关闭此activity | 易于实现 | 锁屏时才能提高优先级,不稳定 | 适用于搭配其他方案一起使用 |
前台服务保活 | 启动一个前台服务,提高应用的优先级 | 系统机制 | 增加冗余服务 | 适用于常用保活 |
广播拉活 | 在接收到特定广播时拉起应用 | 易于实现 | 小厂使用,不够稳定 | 可作为辅助方案 |
sticky拉活 | 利用service的粘性来拉起应用 | 系统唤醒,方式文明 | 应用被杀死4-5次后系统不再拉起应用 | 此方式效果不明显,不推荐 |
账户同步拉活 | 利用账户同步机制拉活 | 系统唤醒,比较稳定 | 时间不能把控 | 适用于间隔性拉活需求,应用不需要持续存在 |
JobScheduler拉活 | 定时任务拉起应用 | 保活稳定 | 非常消耗性能 | 适用于流氓应用 |
双进程保活 | 两个进程相互拉起来保活 | 稳定 | 增加系统开销 | 适用于常用保活 |
注:需要注意的是上述保活指的是仅能提高进程优先级,系统不会自动杀死,但是如果用户主动杀死,应用便死了,拉活指的是被用户杀死仍然可以再拉起来,在低版本和部分厂商机型上适用,但在部分厂商和高版本安卓系统中,清理时会全部杀死,除非加入系统白名单,但上述方式仍可以使用来提高进程优先级,使系统自动清理时不杀死我们的应用
github地址:https://github.com/dingjiaxing/KeepAliveDemo/
//1像素的activity,主题设为透明
public class OnePixelActivity extends Activity{
private static final String TAG = "OnePixelActivity";
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Window window=getWindow();
window.setGravity(Gravity.START|Gravity.TOP);
WindowManager.LayoutParams params=window.getAttributes();
params.width = 1;
params.height = 1;
params.x = 0;
params.y = 0;
window.setAttributes(params);
KeepManager.getInstance().setOnePixelActivity(this);
}
}
//广播接受者,接受广播
public class OnePixelKeepReceiver extends BroadcastReceiver {
private static final String TAG = "OnePixelKeepReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if(action!=null){
if(action.equals(Intent.ACTION_SCREEN_OFF)){
//屏幕关闭,打开1像素activity
KeepManager.getInstance().startOnePixel(context);
}else if(action.equals(Intent.ACTION_SCREEN_ON)){
//屏幕打开,关闭1像素activity
KeepManager.getInstance().finishOnePixel();
}
}
}
}
//第一个activity中启动前台service
startService(new Intent(this,ForegroundService.class));
//ForegroundService.class
public class ForegroundService extends Service {
private static final String TAG = "ForegroundService";
private static int SERVICE_ID=137890;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"ForegroundService onCreate");
if(Build.VERSION.SDK_INT 7.0,7.0以前,先启动一个notification,再启动一个相同id的service,再关闭该service,系统会认定该notification也关闭,8.0以上解决了此bug
startForeground(SERVICE_ID,new Notification());
startService(new Intent(this,InnerService.class));
}else {
//8.0以上,系统会提示“进程正在运行中”
NotificationManager manager= (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
NotificationChannel channel=new NotificationChannel("channel","xx",NotificationManager.IMPORTANCE_NONE);
if(manager==null){
manager.createNotificationChannel(channel);
Notification notification=new NotificationCompat.Builder(this,"channel").build();
startForeground(SERVICE_ID,notification);
}
}
}
public static class InnerService extends Service{
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"InnerService onCreate");
startForeground(SERVICE_ID,new Notification());
stopSelf();
}
}
//反编译支付宝后,发现支付包有如下拉活操作
public class StickyService extends Service {
private static final String TAG = "StickyService";
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG,"onCreate");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand");
//返回START_STICKY时,如果该service被关闭,系统会重新再打开该service,如果用户连续杀死四五次,系统便不会再打开该service
return START_STICKY;
// return super.onStartCommand(intent,flags,startId);
}
}
//添加账户
public static void addAccount(Context context){
AccountManager accountManager=(AccountManager)context.getSystemService(Context.ACCOUNT_SERVICE);
Account[] accounts=accountManager.getAccountsByType(ACCOUNT_TYPE);
if(accounts.length>0){
Log.d(TAG,"账户已存在");
return;
}
Account account=new Account("xx",ACCOUNT_TYPE);
accountManager.addAccountExplicitly(account,"xx",new Bundle());
}
//设置自动同步
public static void autoSync(){
Account account=new Account("xx",ACCOUNT_TYPE);
ContentResolver.setIsSyncable(account,"com.xx.provider",1);
ContentResolver.setSyncAutomatically(account,"com.xx.daemon.provider",true);
ContentResolver.addPeriodicSync(account,"com.xx.daemon.provider",new Bundle(),1);
}
public static void startJob(Context context){
JobScheduler jobScheduler= (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
JobInfo.Builder builder=new JobInfo.Builder(8,new ComponentName(context.getPackageName(),MyJobService.class.getName())
).setPersisted(true);
//小于 7.0
if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N){
//每隔 1s 执行一次 job
builder.setPeriodic(1000);
}else {
//延迟执行任务
builder.setMinimumLatency(1000);
}
jobScheduler.schedule(builder.build());
}
@Override
public boolean onStartJob(JobParameters params) {
Log.d(TAG,"onStartJob");
//7.0以上轮训
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.N){
startJob(this);
}
return false;
}
//manifest中配置不同的进程
//LocalService.class,RemoteService与此类似
public class LocalService extends Service {
private static final String TAG = "LocalService";
ServiceConnection serviceConnection;
MyBinder binder;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
@Override
public void onCreate() {
super.onCreate();
if(binder==null){
binder=new MyBinder();
}
serviceConnection=new MyServiceConnection();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
bindService(new Intent(LocalService.this,RemoteService.class),
serviceConnection,BIND_AUTO_CREATE);
return START_STICKY;
}
class MyBinder extends IRemoteConnection.Stub{
@Override
public String getProcessName() throws RemoteException {
return "LocalService";
}
}
class MyServiceConnection implements ServiceConnection{
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d(TAG,"remote service 可能被杀死了,拉活");
startService(new Intent(LocalService.this,RemoteService.class));
bindService(new Intent(LocalService.this,RemoteService.class),
serviceConnection,BIND_AUTO_CREATE);
}
}
public static class InnerService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
startForeground(16,new Notification());
stopSelf();
}
}
}