You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android后台GPS服务使用:未启动APP时触发距离通知

解决Android后台位置监测与通知推送问题

嘿,作为Android新手碰到这种后台功能的问题太正常了——毕竟Android为了省电和性能,对后台运行的限制挺严格的。不过别担心,咱们可以通过几个核心步骤实现你要的功能,下面给你详细拆解:

1. 先搞定必要的权限

首先得让APP有获取位置和推送通知的权限,在AndroidManifest.xml里加上这些:

<!-- 精准/粗略位置权限 -->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<!-- 后台位置权限(Android 10+ 必须) -->
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<!-- Android 13+ 推送通知需要单独权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

⚠️ 这些都是危险权限,一定要在APP运行时动态申请,而且得给用户讲清楚为什么需要这些权限(比如“需要后台监测位置来提醒您到达目标区域”),不然用户大概率会拒绝。

2. 用前台服务保持位置监听存活

Android 8.0之后,普通后台服务很容易被系统杀死,所以咱们得用前台服务——它会在状态栏显示一个通知,告诉用户APP正在后台运行,这样系统就不会轻易终止它。

核心代码示例(Kotlin)

创建一个继承Service的位置监测服务:

class LocationMonitorService : Service() {
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    // 目标位置,你可以提前配置或者从本地存储读取
    private val targetLocation = Location("").apply {
        latitude = 39.9042 // 示例纬度
        longitude = 116.4074 // 示例经度
    }

    // 位置更新回调
    private val locationCallback = object : LocationCallback() {
        override fun onLocationResult(locationResult: LocationResult) {
            locationResult.lastLocation?.let { currentLoc ->
                // 调用你已经掌握的距离计算方法
                val distanceInMeters = currentLoc.distanceTo(targetLocation)
                if (distanceInMeters < 1000) { // 小于1公里时推送通知
                    sendArrivalNotification()
                }
            }
        }
    }

    override fun onCreate() {
        super.onCreate()
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 创建前台通知,必须显示这个才能让服务在前台运行
        val foregroundNotification = NotificationCompat.Builder(this, "LOCATION_MONITOR_CHANNEL")
            .setContentTitle("位置监测中")
            .setContentText("后台正在帮你留意目标区域")
            .setSmallIcon(R.drawable.ic_location)
            .build()
        // 启动前台服务,传入通知ID和通知实例
        startForeground(1001, foregroundNotification)

        // 配置位置更新请求
        val locationRequest = LocationRequest.create().apply {
            interval = 60000 // 1分钟更新一次位置,可根据需求调整
            fastestInterval = 30000
            priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY // 平衡精度和耗电
        }

        // 开始监听位置更新
        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())

        return START_STICKY // 服务被杀死后尝试重启
    }

    // 推送到达通知的方法
    private fun sendArrivalNotification() {
        val notificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        // Android 8.0+ 需要先创建通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val alertChannel = NotificationChannel(
                "ARRIVAL_ALERT_CHANNEL",
                "到达提醒",
                NotificationManager.IMPORTANCE_HIGH
            )
            notificationManager.createNotificationChannel(alertChannel)
        }

        val alertNotification = NotificationCompat.Builder(this, "ARRIVAL_ALERT_CHANNEL")
            .setContentTitle("已到达目标区域!")
            .setContentText("你离设定的位置已经不足1公里啦")
            .setSmallIcon(R.drawable.ic_alert)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build()

        notificationManager.notify(1002, alertNotification)
    }

    override fun onBind(intent: Intent?): IBinder? = null

    override fun onDestroy() {
        super.onDestroy()
        // 停止位置监听,避免内存泄漏
        fusedLocationClient.removeLocationUpdates(locationCallback)
    }
}

3. 启动服务的正确姿势

  • 用户第一次打开APP并授权后,就可以启动服务:
    if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) {
        startService(Intent(this, LocationMonitorService::class.java))
    }
    
  • 如果希望设备重启后服务自动启动,可以注册BOOT_COMPLETED广播接收器,但注意Android 10+之后广播的触发条件变严,可能需要结合WorkManager来兜底。

4. 优化小技巧

  • 调整位置更新间隔:别太频繁,比如1-5分钟一次就够了,不然耗电会很严重
  • 用WorkManager做周期性检查:如果不需要实时监听,只是每隔一段时间检查一次位置,可以用WorkManager来调度,这样更省电,系统也会更友好
  • 适配厂商省电策略:国内很多厂商有自己的省电模式,会限制后台服务,最好在APP里加个引导,告诉用户把APP加入省电白名单

内容的提问来源于stack exchange,提问作者Jamal Alkelani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 10:36:31