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

Run application in background when phone in Doze

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

即使 phone 打瞌睡,我们是否可以 运行 具有任何网络干预的应用程序 issues.I 试图保留应用程序白名单,但我需要设备被 root。

adb shell dumpsys deviceidle whitelist +<Package Name>

谁能建议我不间断地 运行 应用程序的最佳方式?

您可以请求 android 通过发送高优先级 GCM 消息将您的应用列入休眠模式白名单。但请记住,这可能会使您的应用无法获得 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

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

不过,我有一个窍门。收听 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;
    }
}

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

Edit-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 秒的时间 window 来完成它需要做的事情。

此外,

您始终可以要求用户使用-

让您的应用忽略电池优化功能
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>