进程保活-探索篇之1像素保活

转载请注明出处:
http://blog.csdn.net/BruceHurrican/article/details/61917990

背景:从产品的角度来说,任何一个 app 的 PM都希望自己的 app 在用户手机中的留存率高些,之前我接触到的一个业务需求也是如此,要求提升app 在国内第三方厂商 ROM中的存活率。

如前篇所述 踩坑篇 ,保活策略只在 android 原生系统中起作用,在国内第三方厂商 ROM中是没有效果的。为了提高 app 在第三方 ROM中的存活率,调研了一些方法,最终选择 某移动社交 app的 1像素保活方案,因为这个方案人家没有开源,所以只能自己动手。

针对国内第三方厂商 ROM在 熄屏后app很快被kill 的调查发现,原生系统在内存充足的情况下,用户执行熄屏的操作不会立即 kill app,但是第三方 ROM会,推测是 修改了 ROM在熄屏时执行了内存清理工作,不论此时手机内存是否充足都执行清理。对于没有加入到厂家 ROM清理白名单中的 app,不可避免的被 kill。当然有的人会不同意,说像 QQ、微信之类的就没有在熄屏后被杀,用户也没有手动将其加入系统白名单中。这种情况是 QQ和微信已经加入到系统的白名单中了,当然不需要用户手动添加了。不过这已经不是技术人员可以解决的了,需要双方的商务洽谈了。

我在使用国内第三方 ROM MIUI时发现,如果保持当前 app 在前台存活,执行熄屏,分别等待1分钟、5分钟、10分钟后,再次打开屏幕时,app会存活,即使被 kill 掉也会重新启动。基与此并结合1像素保活方案,我在 app 启动时注册一个监听器监听屏幕亮屏熄屏,当用户启动我的 app 时,并没有按退出 app,切换到其他 app 使我的 app 进入后台待机模式,只要我方 app 没有被 kill,当用户熄屏时,会启动 OnepxActivity,这样人为的制造了一个系统欺骗,告诉 ROM,用户执行熄屏时,当前 UI是我的 app。这样,当用户亮屏时,因为有监听,OnepxActivity 也会销毁,达到一个用户无感知同时又提高了我方 app 在第三方 ROM 中的存活率。

废话讲完,上代码。

public class OnepxActivity extends BaseActivity {
    private BroadcastReceiver br;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Window window = getWindow();
        window.setGravity(Gravity.LEFT | Gravity.TOP);
        WindowManager.LayoutParams params = window.getAttributes();
        params.x = 0;
        params.y = 0;
        params.height = 1;
        params.width = 1;
        window.setAttributes(params);
        br = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
// LogUtils.i(intent.getAction());
// LogUtils.i(context.toString());
// Intent intent1 = new Intent(Intent.ACTION_MAIN);
// intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
// intent1.addCategory(Intent.CATEGORY_HOME);
// startActivity(intent1);
                LogUtils.d("OnepxActivity finish ================");
                finish();
            }
        };
        registerReceiver(br, new IntentFilter("finish activity"));
        checkScreenOn("onCreate");
    }

    private void checkScreenOn(String methodName) {
        LogUtils.d("from call method: " + methodName);
        PowerManager pm = (PowerManager) OnepxActivity.this.getSystemService(Context.POWER_SERVICE);
        boolean isScreenOn = pm.isScreenOn();
        LogUtils.i("isScreenOn: "+isScreenOn);
        if(isScreenOn){
            finish();
        }

    }

    @Override
    protected void onDestroy() {
        LogUtils.i("===onDestroy===");
        try{
            unregisterReceiver(br);
        }catch (IllegalArgumentException e){
            LogUtils.e("receiver is not resisted: "+e);
        }
        super.onDestroy();
    }

    @Override
    protected void onResume() {
        super.onResume();
        checkScreenOn("onResume");
    }
}

params.height = 1;
params.width = 1;

就是1像素的 activity,当这个 activity 启动时,用户是看不到的,因为只有1像素嘛^V^

Intent intent1 = new Intent(Intent.ACTION_MAIN); intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent1.addCategory(Intent.CATEGORY_HOME);
startActivity(intent1);

这个代码块的作用是满足熄屏时返回 ROM HOME界面的业务需求,后期无些需求,所以注释了。

checkScreenOn 方法用于检测屏幕是否亮屏状态,如果亮屏则 OnepxActivity 执行销毁命令,检测的目的可以有效避免,用户频繁亮屏熄屏导致的保活失败。

讲完了1像素保活,下面介绍怎样使用这个1像素的 activity。

public class OnepxReceiver extends BroadcastReceiver {
    private static OnepxReceiver receiver;
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
            Intent it = new Intent(context, OnepxActivity.class);
            it.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(it);
            LogUtils.i("1px--screen off-");
        } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
            context.sendBroadcast(new Intent("finish activity"));
            LogUtils.i("1px--screen on-");
        }
    }

    public static void register1pxReceiver(Context context) {
        if (receiver == null) {
            receiver = new OnepxReceiver();
        }
        context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
        context.registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_ON));
    }

    public static void unregister1pxReceiver(Context context) {
        context.unregisterReceiver(receiver);
    }
}

这个是动态监听亮屏熄屏的 receiver,实际项目中,一般不会出现静态方法注册/反注册 亮屏熄屏的动作,这里是为了演示方便的写法。

填坑:在使用过程中我还遇到过,OnepxActivity 启动时会出现闪屏的状态,解决办法是,设置 OnepxActivity 的背景是透明的即可解决。

如果有更好的解决方案欢迎交流学习。

代码传送门

你可能感兴趣的:(android)