2023Android白名单保活(后台定位)分享

面对Android系统和厂商的严格限制,实现后台定位变得困难。本文分享了一个项目经验,通过白名单保活方式解决这一问题。涉及的关键点包括:获取自启动与后台运行权限、关闭电池优化、进程复活、保持CPU唤醒状态以及处理熄屏后定位权限。解决方案包括引导用户设置权限、启动服务、双进程保活等。同时,列举了vivo和华为设备的特定问题及处理建议。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android 系统已经更新到13了,各个Rom厂商也控制越来越严格了,还能做保活App。答案肯定是可以的,然而路线是很艰难的。

最近接到一个项目,需要安装一次app后,就需要一直获取定位。随着Android系统的不断完善,厂商rom的不断优化,想要实现后台不断定位的功能,要面临的问题很多。先总结下此次开发中遇到的难点和要点。首先确认的是一点,用白名单保活的方式来实现,如果是可以实现黑名单保活的大牛,此文请忽略。

需要解决的主要问题有以下几项:

1.白名单保活核心:权限-自启动管理 要求用户手动设置打开自启动和后台运行权限。

2.电池优化:关闭电池优化。或者说耗电管理

3.进程复活:即使开启了自启动权限也要有自身拉活机制。

4.维持cpu唤醒状态:此项很重要,某些机器不一定需要,但是某些机器不这么处理,程序百分之百死掉。比如华为的某些pad。

5.比保活还重要的是定位权限:如果是做后台定位的话,熄屏后失去定位权限的解决方案。

解决方案:

如果做白名单保活,那么在做权限获取的时候需要两部分来完成,软件自动调整权限设置页或者引导用户手动开启权限设置。

这套方案目前在大多数手机或pad中可以保证服务不死定位不停,个别设备需要单独进行设置或处理才行,文章末尾会说。

先看代码上能做的处理有哪些:

1.关闭电池优化

我的所有处理都是从MainActivity开始的,

int checkTime = 0;
在onCreate中执行
//忽略电池优化
KeepAliveUtils.Checkbattery(this, 0);
​​​​​​​checkTime++;
public static void Checkbattery(Activity activity, int time) {
        if (time > 1)
            return;

        PowerManager manager = (PowerManager) activity.getSystemService(Context.POWER_SERVICE);
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            boolean ignoringBatteryOptimizations = manager.isIgnoringBatteryOptimizations(activity.getPackageName());
            if (!ignoringBatteryOptimizations) {
                Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
                intent.setData(Uri.parse("package:" + activity.getPackageName()));
                activity.startActivityForResult(intent, 110);
            }


        }

    }

然后在MainActivity中处理

 @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode == 110) {
            KeepAliveUtils.Checkbattery(this, checkTime);
        }
    }

这段代码会弹出提示框提示用户是否关闭电池优化功能。

2.提示框提示用户手动打开自启动权限管理

int checkGoTime = 0;

在onCreate中执行

checkGoTime = KvUtils.getInstance().getInt("checkGoTime", 0);
        if (checkGoTime == 0) {
            KvUtils.getInstance().put("checkGoTime", 1);
            //打开自启动
            new XPopup.Builder(this)
                    .isDestroyOnDismiss(true)
                    .asCustom(new ConfirmCenterPop(this, "为保证App正常运行,请打开应用自启动权限和后台弹窗权限", new ConfirmCenterPop.OnSubmitListenner() {
                        @Override
                        public void onClick() {
//                            CheckPermissionUtils.startToAutoStartSetting(MainActivity.this);
                            JumpPermissionManagement.GoToSetting(MainActivity.this);
                        }
                    }))
                    .show();
        }

这段加了次数管理,避免弹出多次。

3.检查并申请定位权限和通知并开启服务

//请求权限开启定位
        XXPermissions.with(this)
                // 申请单个权限
                .permission(Permission.ACCESS_FINE_LOCATION)
                .permission(Permission.ACCESS_COARSE_LOCATION)
                .permission(Permission.ACCESS_BACKGROUND_LOCATION)
                // 申请多个权限
                // 设置权限请求拦截器(局部设置)
                //.interceptor(new PermissionInterceptor())
                // 设置不触发错误检测机制(局部设置)
                //.unchecked()
                .request(new OnPermissionCallback() {

                    @Override
                    public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                        if (!allGranted) {
                            ToastUtils.showShort("获取部分权限成功,但部分权限未正常授予");
                            return;
                        }
                        startService(new Intent(MainActivity.this, AliveService.class));
                        startService(new Intent(MainActivity.this, SAliveService.class));

                    }

                    @Override
                    public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                        if (doNotAskAgain) {
                            ToastUtils.showShort("被永久拒绝授权,请手动开启定位权限");
                            // 如果是被永久拒绝就跳转到应用权限系统设置页面
                            XXPermissions.startPermissionActivity(MainActivity.this, permissions);
                        } else {
                            ToastUtils.showShort("获取定位权限失败");
                        }
                    }
                });
        //获取通知权限,后台持续定位
        XXPermissions.with(this)
                // 申请单个权限
                .permission(Permission.POST_NOTIFICATIONS)
                // 申请多个权限
                // 设置权限请求拦截器(局部设置)
                //.interceptor(new PermissionInterceptor())
                // 设置不触发错误检测机制(局部设置)
                //.unchecked()
                .request(new OnPermissionCallback() {

                    @Override
                    public void onGranted(@NonNull List<String> permissions, boolean allGranted) {
                        if (!allGranted) {
                            ToastUtils.showShort("获取部分权限成功,但部分权限未正常授予");
                            return;
                        }
                        startService(new Intent(MainActivity.this, AliveService.class));
                        startService(new Intent(MainActivity.this, SAliveService.class));

                    }

                    @Override
                    public void onDenied(@NonNull List<String> permissions, boolean doNotAskAgain) {
                        if (doNotAskAgain) {
                            ToastUtils.showShort("被永久拒绝授权,请手动开启定位权限");
                            // 如果是被永久拒绝就跳转到应用权限系统设置页面
                            XXPermissions.startPermissionActivity(MainActivity.this, permissions);
                        } else {
                            ToastUtils.showShort("获取定位权限失败");
                        }
                    }
                });

之所以把定位权限和通知权限放在一起,是因为做后台定位的时候需要发送通知,将定位变成前台服务才能保证后台持续定位。

接下来就是核心中的核心

AliveService.class和SAliveService
双进程保活互相拉起,维持服务不死和定位权限不失的核心内容都在这两个服务里边处理

4.AliveService.class和SAliveService

public class AliveService extends Service {
    private MyBinder myBinder;
    /**
     * 连接对象
     */
    private Connection connection;

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return myBinder;
    }

    private static final int NOTIFICATION_ID = 1;
    private Runnable runnable;
    private Handler handler;
    PowerManager pm;
    @SuppressLint("InvalidWakeLockTag")
    PowerManager.WakeLock wakeLock;


    @Override
    public void onCreate() {
        super.onCreate();
        //创建NotificationChannel
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            startForeground(1, LocationUtils.buildNotification());
        }
        myBinder = new MyBinder();
        
Android白名单是指在Android系统中,通过将应用程序添加到系统的白名单中,以确应用程序在后台运行时不被系统主动杀死,从而实现持应用程序的持续运行和的目的。 Android系统为了优化电池寿命和系统性能,会对后台运行的应用程序进行管理和限制。当系统资源紧张或者应用程序长时间处于后台运行状态时,系统可能会主动关闭或者限制应用程序的运行,这就导致了一些需要在后台持续运行的应用程序无法正常工作。 为了解决这个问题,Android提供了一些机制来实现应用程序的白名单。具体的实现方式可能因Android版本和设备厂商而有所不同,以下是一些常见的实现方式: 1. 前台服务:通过将应用程序启动一个前台服务,使应用程序在通知栏显示一个持续运行的通知,从而提高应用程序在后台运行时被系统杀死的概率。 2. JobScheduler:Android 5.0及以上版本提供了JobScheduler API,可以使用该API来调度一些延迟执行或者周期性执行的任务,从而使应用程序在后台得到一定的执行时间。 3. AlarmManager:通过设置定时闹钟,使应用程序在指定时间唤醒并执行一些任务,从而持应用程序的运行。 4. 后台定位:通过使用后台定位服务,使应用程序在后台持续获取设备的位置信息,从而实现。 需要注意的是,Android系统对于白名单机制的使用有一定的限制和规范,滥用这些机制可能会导致用户体验下降、电池消耗增加等问题。因此,在使用白名单机制时,需要谨慎权衡利弊,并遵循相关的开发规范和最佳实践。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

子夜微凉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值