Android应用关闭时发送通知:非前台服务的位置监听方案咨询
无需前台服务实现APP关闭时的位置监听与通知方案
针对你需要在APP关闭时监听位置并发送通知的需求,有以下几种替代前台服务的方案:
1. Google Geofencing API(首选方案)
这是专门为「进入/离开特定地理区域触发事件」设计的系统级API,无需APP持续运行或前台服务,系统会在满足条件时主动触发回调,即使APP处于关闭状态也能正常工作。
实现步骤:
- 申请权限:需要
ACCESS_FINE_LOCATION(或ACCESS_COARSE_LOCATION),Android 10及以上额外需要ACCESS_BACKGROUND_LOCATION。 - 创建Geofence:定义目标地点的坐标、范围半径,以及触发条件(如进入区域)。
- 注册Geofence:通过
GeofencingClient将Geofence与PendingIntent绑定,触发时系统会发送该Intent到你的广播接收器。
示例代码:
创建并注册Geofence
// 构建Geofence对象 Geofence targetGeofence = new Geofence.Builder() .setRequestId("remind_office") // 唯一标识 .setCircularRegion(39.9042, 116.4074, 500) // 纬度、经度、半径(米) .setExpirationDuration(Geofence.NEVER_EXPIRE) // 永不过期 .setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER) // 触发条件:进入区域 .build(); // 构建Geofencing请求 GeofencingRequest geofencingRequest = new GeofencingRequest.Builder() .addGeofence(targetGeofence) .setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_ENTER) // 初始进入也触发 .build(); // 创建PendingIntent,触发时通知广播接收器 PendingIntent geofenceIntent = PendingIntent.getBroadcast( getApplicationContext(), 0, new Intent(getApplicationContext(), GeofenceTriggerReceiver.class), PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE ); // 注册Geofence GeofencingClient geofencingClient = LocationServices.getGeofencingClient(this); geofencingClient.addGeofences(geofencingRequest, geofenceIntent) .addOnSuccessListener(aVoid -> Log.d("Geofence", "注册成功")) .addOnFailureListener(e -> Log.e("Geofence", "注册失败:" + e.getMessage()));
广播接收器处理触发事件
public class GeofenceTriggerReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { GeofencingEvent event = GeofencingEvent.fromIntent(intent); if (event.hasError()) { Log.e("Geofence", "触发错误:" + event.getErrorCode()); return; } int transitionType = event.getGeofenceTransition(); if (transitionType == Geofence.GEOFENCE_TRANSITION_ENTER) { // 用户进入目标区域,发送提醒通知 sendReminderNotification(context, "已到达预设地点", "该处理待办事项啦"); } } private void sendReminderNotification(Context context, String title, String content) { NotificationManager manager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { NotificationChannel channel = new NotificationChannel( "location_remind", "位置提醒", NotificationManager.IMPORTANCE_DEFAULT ); manager.createNotificationChannel(channel); } NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "location_remind") .setSmallIcon(R.drawable.ic_notify) .setContentTitle(title) .setContentText(content) .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setAutoCancel(true); manager.notify(1, builder.build()); } }
注意事项:
- 每个APP最多可注册100个Geofence;
- 设备重启后Geofence会失效,需在
BOOT_COMPLETED广播接收器中重新注册; - 部分厂商系统可能需要将APP加入后台白名单,否则可能无法触发。
2. WorkManager 结合周期性位置查询
如果你的场景不是固定区域提醒,而是需要定期检查位置,可以用WorkManager实现周期性后台任务,即使APP关闭也能执行位置查询逻辑。
实现步骤:
- 创建Worker类:在
doWork()方法中获取当前位置并判断是否满足提醒条件; - 配置周期性任务:用
PeriodicWorkRequest设置任务执行间隔(系统最小允许15分钟); - 申请后台位置权限:Android 10+必须申请
ACCESS_BACKGROUND_LOCATION。
示例代码:
Worker类实现
public class LocationCheckWorker extends Worker { public LocationCheckWorker(@NonNull Context context, @NonNull WorkerParameters params) { super(context, params); } @NonNull @Override public Result doWork() { FusedLocationProviderClient locationClient = LocationServices.getFusedLocationProviderClient(getApplicationContext()); // 检查后台位置权限 if (ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) { return Result.failure(); } // 获取最新位置 locationClient.getLastLocation() .addOnSuccessListener(location -> { if (location != null) { // 对比当前位置与预设地点的距离 if (isNearTargetLocation(location)) { sendReminderNotification(getApplicationContext()); } } }); return Result.success(); } private boolean isNearTargetLocation(Location currentLoc) { // 预设地点坐标 Location targetLoc = new Location(""); targetLoc.setLatitude(39.9042); targetLoc.setLongitude(116.4074); // 判断距离是否小于500米 return currentLoc.distanceTo(targetLoc) < 500; } private void sendReminderNotification(Context context) { // 实现通知发送逻辑,同Geofence示例 } }
启动周期性任务
// 每15分钟执行一次,允许±5分钟弹性时间 PeriodicWorkRequest checkRequest = new PeriodicWorkRequest.Builder( LocationCheckWorker.class, 15, TimeUnit.MINUTES, 5, TimeUnit.MINUTES ).build(); WorkManager.getInstance(getApplicationContext()).enqueue(checkRequest);
注意事项:
- 系统会限制后台任务的执行频率,无法做到实时监听;
- 频繁的位置查询会增加电池消耗,仅适合非实时的场景。
3. 权限与系统限制说明
- Android 10及以上必须申请
ACCESS_BACKGROUND_LOCATION权限,且用户可随时在系统设置中关闭该权限,需处理权限被拒绝的情况; - 国内厂商(小米、华为、OPPO等)的系统可能有严格的后台管控,需引导用户将APP加入「后台运行白名单」或关闭「省电模式」,否则任务可能无法正常触发。
内容的提问来源于stack exchange,提问作者nortain32
相关产品推荐
相关产品推荐

