产品需求
像QQ、 微信、 高德, 永远不被杀掉。
那么他们是如何做到的呢?
- 跟手机厂商商务沟通,app放进系统白名单。
- 一像素保活法。
- 双进程守护保活法。
- 账号同步机制拉活。
- 后台播放一个无声的音频。
- 开启前台Service。
- JobScheduler拉活。
- sticky拉活。
他们这么做的原因是什么?
- IM(即时通信)保活 (重点 重点 重点)
但这样的做法过于流氓,影响Android手机的性能。不建议使用!!!!但是有时候又没有办法。
8.0之后就会有好的改观,毕竟8.0之后保活Android系统收紧(越来越难做了),但是统一推送联盟介入(IM可以保证),我觉得这事可以成。
统一推送联盟《中国绿色App公约》(以下简称“《公约》”)自2018年4月推出以来,得到了产业界和积极响应,并取得了行业的一致认可。2018年7月,泰尔终端实验室联合华为、小米、OPPO、vivo、腾讯、百度、阿里巴巴以及360共同发起联合行动:自2019年5月1日起,新上架和预置应用应基于Android8.0 (API等级26)及以上版本开发,拒绝上架和更新低API等级应用。这一方案将覆盖《公约》的绝大部分条款,使得正规渠道下载的安卓APP基本满足《公约》要求。
但是8.0之前还有一部分用户,所以保活还是要做,毕竟用户就是我们的“衣食父母”,如何保活呢?当然是降低omm_adj值,尽量保证进程不被系统杀死。
什么是oom_adj? 再介绍oom_adj是什么之前,我们需要知道Android的进程优先级
优先级 | 进程名称 | oom_adj |
---|---|---|
1 | 前台进程 | 0 |
2 | 可见进程 | 1 |
3 | 服务进程 | 5 |
4 | 后台进程 | 6 |
5 | 空进程 | 9-25 |
什么是oom_adj?
oom(Out of Memory Adjustment)是Android的机制,系统会根据进程的优先级,给每个进程一个oom权重值,android系统在内存不足情况下进行内存调整的重要参数,系统会根据这个优先级去选择将哪些进程杀掉,以腾出空间保证更高优先级的进程能正常运行。
omm_adj < 0时:是系统进程,不会被杀死。
所以为了app保活,我们尽量oom_adj 的值
app保活按类型分为两种 :保活 和 拉活
保活
-
一像素保活法:在屏幕关闭时打开一个1px的activity,屏幕亮时关闭此activity(主题透明)
KeepManagerUtils.getInstance().registerKeep(this);
/** * @author:jhonjson * @date:2019/11/18 14:56 AM * @describe:1像素保活法 Manager */ public class KeepManagerUtils { private static final KeepManagerUtils ourInstance = new KeepManagerUtils(); public static KeepManagerUtils getInstance() { return ourInstance; } private KeepManagerUtils() { } private KeepLiveReceiver keepLiveReceiver; private WeakReference<Activity> mKeepLiveActivity; /** * 注册 * @param context */ public void registerKeepReceiver(Context context){ IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_SCREEN_OFF); filter.addAction(Intent.ACTION_SCREEN_ON); keepLiveReceiver = new KeepLiveReceiver(); context.registerReceiver(keepLiveReceiver, filter); } /** * 反注册 * @param context */ public void unRegisterKeepReceiver(Context context){ if (null != keepLiveReceiver) { context.unregisterReceiver(keepLiveReceiver); } } /** * 启动1个像素的KeepLiveActivity * @param context */ public void startKeepLive(Context context) { Intent intent = new Intent(context,KeepLiveActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } /** * finish1个像素的KeepLiveActivity */ public void finishKeepLive() { if (null != mKeepLiveActivity) { Activity activity = mKeepLiveActivity.get(); if (null != activity) { activity.finish(); } mKeepActivity = null; } } public void setKeepActivity(KeepLiveActivity mKeepLiveActivity) { this.mKeepLiveActivity = new WeakReference<Activity>(mKeepLiveActivity); } }
public class KeepLiveReceiver extends BroadcastReceiver { private static final String TAG = "KeepLiveReceiver"; @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Log.e(TAG, "receive:" + action); if (TextUtils.equals(action, Intent.ACTION_SCREEN_OFF)) { //灭屏 开启1px activity KeepManagerUtils.getInstance().startKeepLive(context); } else if (TextUtils.equals(action, Intent.ACTION_SCREEN_ON)) { //亮屏 关闭 KeepManagerUtils.getInstance().finishKeepLive(); } } }
public class KeepLiveActivity extends Activity { private static final String TAG = "KeepLiveActivity"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.e(TAG, "启动keepLive"); 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); // KeepLiveActivity 创建一个弱引用 KeepManagerUtils.getInstance().setKeepLive(this); } @Override protected void onDestroy() { super.onDestroy(); Log.e(TAG, "关闭keepLive"); } }
-
前台服务保活:启动一个前台服务,提高应用的优先级
/** * 绑定服务 * * @param context */ public static void bindLocalService(Context context, ServiceConnection serviceConnection) { if (context == null || null == serviceConnection) { return; } //通过Intent指定服务端的服务名称和所在包,与远程Service进行绑定 Intent intent = new Intent(); intent.setClass(context, ForegroundService.class); Bundle bundle = new Bundle(); intent.putExtras(bundle); //绑定服务,传入intent和serviceConnection对象 context.bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE); } /** * 解绑服务 * * @param context */ public static void unBindLocalService(Context context, ServiceConnection serviceConnection) { if (context == null || null == serviceConnection) { return; } try { // 当需要多次调用doSomething()方法的时候,如果直接bindService是会报错的 context.unbindService(serviceConnection); } catch (Exception e) { e.printStackTrace(); } }
public class ForegroundService extends Service { private static final String TAG = "ForegroundService"; privtae static final String KEY_CHANNEL = "新消息" private static final int SERVICE_ID = 1; @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); Log.e(TAG, "ForegroundService 服务创建了"); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2) {//4.3以下 //将service设置成前台服务,并且不显示通知栏消息 startForeground(SERVICE_ID, new Notification()); } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { //Android4.3-->Android7.0 //将service设置成前台服务 startForeground(SERVICE_ID, new Notification()); //删除通知栏消息 startService(new Intent(this, InnerService.class)); } else { // 8.0 及以上 //通知栏消息需要设置channel NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); NotificationChannel channel = new NotificationChannel(KEY_CHANNEL, "xx", NotificationManager.IMPORTANCE_NONE); if (manager != null) { manager.createNotificationChannel(channel); Notification notification = new NotificationCompat.Builder(this, KEY_CHANNEL).build startForeground(SERVICE_ID, notification); } } } public static class InnerService extends Service { @Override public void onCreate() { super.onCreate(); Log.e(TAG, "InnerService 服务创建了"); // 让服务变成前台服务 startForeground(SERVICE_ID, new Notification()); // 关闭自己 stopSelf(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } } }
<service android:name="com.xx.service.ForegroundService" /> <service android:name="com.xx.service.ForegroundService$InnerService" />
参考资料:
Android之APP保活
Android后台Service已死 WorkManager崛起
史上最全android保活方案及比较分析