打瞌睡时在后台运行应用程序

Posted

技术标签:

【中文标题】打瞌睡时在后台运行应用程序【英文标题】:Run application in background when phone in Doze 【发布时间】:2017-09-16 10:50:23 【问题描述】:

应用程序正在运行 SDK 23 及更高版本。在完成任务并使用 AlaramManager (setExactAndAllowWhileIdle) 安排下一个任务后,我正在使用 Service 运行一些任务。这工作正常。如果手机连续闲置 2 或 3 天,则进入打盹模式。打盹模式后,应用程序失去网络和唤醒锁也不起作用。

即使手机处于打瞌睡状态,我们是否可以运行应用程序并解决任何网络插入问题。我试图保留应用程序 witelist,但我需要设备被植根。

adb shell dumpsys deviceidle whitelist +<Package Name>

任何人都可以建议我在不中断的情况下运行应用程序的最佳方式吗?

【问题讨论】:

【参考方案1】:

实际上,如果不运行前台服务,就无法做到这一点。列入白名单可能不适合您的应用程序,即使是这样,您仍要求用户授予您权限,从最终用户的角度来看,这可能会被视为危险的事情。

但是,我对此有一个窍门。收听android的广播,当您发现该设备将进入打盹模式时,启动前台服务。在大多数情况下,用户将无法看到您的前台通知图像,并且不会知道您正在运行服务。因为设备处于打盹模式,这意味着它在用户不看的地方是稳定的。所以你可以做任何需要的事情。

您还可以收听打瞌睡模式结束时发送的广播。发生这种情况时,请停止您的前台服务并使用警报管理器按照您的正常逻辑工作。

PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) 
    if(intent.getAction().equals("android.os.action.DEVICE_IDLE_MODE_CHANGED"))
        if (pm.isDeviceIdleMode()) 
            startForegroundService();
            //stopAlarmManagerLogic();
         else 
            stopForegroundService();
            //startAlarmManagerLogic();
            return;
        
        return;
    

【讨论】:

这个答案启发我找到了一个很好的解决方案,即使手机处于打盹模式也能永远运行服务。【参考方案2】:

编辑-WakefulBroadcastReceiver现已弃用

首先,不是直接在AlarmManager 中调用服务,而是调用广播接收器,然后再调用服务。

广播接收器应该扩展 WakefulBroadcastReceiver 而不是常规的 BroadcastReceiver

然后,让广播接收器安排一个新的警报,使用startWakefulService() 而不是startService() 启动服务

public class MyAwesomeReceiver extends WakefulBroadcastReceiver 
int interval=2*60*60*1000;
    @Override
    public void onReceive(Context context, Intent intent) 

        Intent serviceIntent = new Intent(context, MyAwesomeService.class);
        Intent receiverIntent = new Intent(context, MyAwesomeReceiver.class);

        PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 11, receiverIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(ALARM_SERVICE);
        alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,System.currentTimeMillis()+interval,alarmIntent);
        startWakefulService(context, serviceIntent);
        

WakefulBroadcastReceiverstartWakefulService() 将让您的应用有 10 秒的时间窗口让您完成需要做的事情。

还有,

您可以随时要求用户让您的应用忽略电池优化功能,使用 -

PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
Intent intent=new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
if (powerManager.isIgnoringBatteryOptimizations(getPackageName())) 
     intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);

else 
     intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
     intent.setData(Uri.parse("package:" + getPackageName()));
     startActivity(intent);

在清单中

<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"></uses-permission>

【讨论】:

WakefulBroadcastReceiver 现已弃用【参考方案3】:

您可以通过发送高优先级 GCM 消息请求 android 将您的应用列入打盹模式白名单。但请记住,这可能会使您的应用未被 Google Play 批准:

Intent intent = new Intent();
String packageName = context.getPackageName();
PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
if (pm.isIgnoringBatteryOptimizations(packageName))
    intent.setAction(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
else 
    intent.setAction(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
    intent.setData(Uri.parse("package:" + packageName));

context.startActivity(intent);

https://developer.android.com/training/monitoring-device-state/doze-standby.html#whitelisting-cases

【讨论】:

即使未经 Google Play 批准也没关系。是 FCM 高优先级消息,设备可以从 Doze 唤醒多长时间?我已经实现了这一点。上面的代码来自 app witelist。我该如何确认? @srikanth 代码在运行时请求ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS 的权限。如果您在这里阅读:developer.android.com/training/monitoring-device-state/… 您会看到他们的文档说它可以让您再次访问您的应用丢失的部分唤醒锁【参考方案4】:

在 Android N 之后,任何应用都不能永远在后台运行。但是,您可以使用 Firebase Job Dispatcher,即使它处于打盹模式,它也可以帮助您运行您的应用程序。在Firebase Job Dispatcher 的帮助下,您可以告诉系统您的应用程序应该在特定时间运行,如果提供的条件匹配。

【讨论】:

以上是关于打瞌睡时在后台运行应用程序的主要内容,如果未能解决你的问题,请参考以下文章

应用程序运行时在后台使用 SMTP Mailcore2 发送邮件

如何在应用程序运行 ios 时在后台进行服务调用

React Native:关闭应用程序时在 iOS 上运行后台任务的最佳方法?

收到推送通知时在后台执行代码

按下主页按钮时在后台播放音乐

如何在python中运行其他代码时在后台运行循环