Android如何不打开应用24小时后台运行任务 实现定时发送短信功能
方案1:前台服务(Foreground Service)+ 定时触发器
你当前使用的普通后台Service在Android 8.0(API 26)及以上版本会被系统严格限制,应用退到后台几分钟后就会被回收,转成前台服务后优先级更高,会在通知栏显示常驻通知,被系统杀死的概率大幅降低。具体实现步骤如下:
- 第一步:添加必要权限,在
AndroidManifest.xml中声明:
<!-- 基础前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Android 14以上数据同步类前台服务需要额外加这个权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" /> <!-- Android 13以上需要通知权限才能显示前台服务通知 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <!-- 发送短信权限 --> <uses-permission android:name="android.permission.SEND_SMS" />
- 第二步:改造现有Service为前台服务,在Service的
onCreate方法中添加如下代码:
@Override public void onCreate() { super.onCreate(); // Android 8.0以上必须先创建通知渠道 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel("sms_sync_channel", "短信同步服务", NotificationManager.IMPORTANCE_LOW); NotificationManager manager = getSystemService(NotificationManager.class); manager.createNotificationChannel(channel); } // 构建前台服务通知 Notification notification = new NotificationCompat.Builder(this, "sms_sync_channel") .setContentTitle("短信同步服务运行中") .setContentText("正在定时拉取短信发送任务") .setSmallIcon(R.mipmap.ic_launcher) // 替换为你应用的图标资源 .build(); // 启动前台服务,通知ID不能为0 startForeground(1001, notification); }
- 第三步:替换原有Handler定时逻辑,Handler在后台容易因为系统休眠出现偏差甚至被回收,推荐用
WorkManager实现定时任务,兼容性更好还能适配Doze模式:
首先在Module级的build.gradle中添加依赖:
dependencies { def work_version = "2.8.1" implementation "androidx.work:work-runtime:$work_version" }
创建执行核心逻辑的Worker类:
public class SmsSyncWorker extends Worker { public SmsSyncWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) { super(context, workerParams); } @NonNull @Override public Result doWork() { // 在这里写你的Retrofit拉取服务器数据、发送短信的逻辑 return Result.success(); } }
在Service的onStartCommand方法中启动周期任务:
// 定义每2分钟执行一次的周期任务 PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(SmsSyncWorker.class, 2, TimeUnit.MINUTES) .build(); // 启动唯一周期任务,避免重复创建 WorkManager.getInstance(this).enqueueUniquePeriodicWork("sms_sync_task", ExistingPeriodicWorkPolicy.KEEP, periodicWork);
- 第四步:启动服务时适配高版本系统要求:
Intent intent = new Intent(context, YourSmsService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(intent); } else { context.startService(intent); }
注意事项
- 小米、华为、OPPO等国产ROM有自定义的后台管控逻辑,即使配置了前台服务,也需要引导用户手动打开应用的「自启动权限」「后台活动权限」,否则应用退到后台依然可能被杀死。
- 系统进入Doze模式后会拉长周期任务的执行间隔,如果你必须严格保证2分钟执行一次,可以申请忽略电池优化权限,先在清单中声明权限:
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />
再主动弹框引导用户同意权限申请即可。
- Android 6.0以上
SEND_SMS属于危险权限,需要先动态申请权限,不能只在清单文件中声明。
内容的提问来源于stack exchange,提问作者Dinesh Gangwar
相关产品推荐
相关产品推荐

