安卓进程保活那些事,你知道多少?

本文深入探讨了APP保活技术,解析了QQ、微信等应用如何通过与手机厂商合作、一像素保活法、前台Service启动等手段防止被系统清理,同时介绍了Android 8.0后的新变化及统一推送联盟的影响。

产品需求


 像QQ、 微信、 高德, 永远不被杀掉。

那么他们是如何做到的呢?

  1. 跟手机厂商商务沟通,app放进系统白名单。
  2. 一像素保活法。
  3. 双进程守护保活法。
  4. 账号同步机制拉活。
  5. 后台播放一个无声的音频。
  6. 开启前台Service。
  7. JobScheduler拉活。
  8. sticky拉活。

他们这么做的原因是什么?

  1. 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保活按类型分为两种 :保活 和 拉活

保活

  1. 一像素保活法:在屏幕关闭时打开一个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");
        }
    }
    
  2. 前台服务保活:启动一个前台服务,提高应用的优先级

    /**
         * 绑定服务
         *
         * @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保活方案及比较分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值