我目前正在使用FusedLocationProviderClient
开发一个位置功能来跟踪设备位置。当应用程序可见时,跟踪功能在所有Android版本上都按预期工作。但当切换到前台(应用程序不可见)时,Android 12+上不再提供位置功能,我在logcat中遇到以下错误:LocationUpdateReceiver - LocationEngineResult == null
。对于运行在Android 12以下的设备,我收到的位置信息比使用LocationRequest设置的maxInterval
要少
我不知道我做错了什么,因为我遵循了不同的Android文档关于服务/位置。
我的AndroidManifest是这样的:
...
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
...
<service
android:name=".app.services.RecordingService"
android:foregroundServiceType="location"/>
我的位置存储库,处理跟踪位置:
class PlayServicesDataStore(private val context: Context, private val logger: Logger) : LocationDataStore {
override val userLocationState: MutableStateFlow<PointZ?> = MutableStateFlow(null)
private val fusedLocationProviderClient: FusedLocationProviderClient =
LocationServices.getFusedLocationProviderClient(context)
private val locationCallback = Callback()
private inner class Callback : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
locationResult.lastLocation?.let { lastLocation ->
logger.logMessage("New GPS location: $lastLocation")
/**
* We want to keep only location that have an accuracy of [MAX_ACCURACY_METER]
*/
if (lastLocation.hasAccuracy() && lastLocation.accuracy <= MAX_ACCURACY_METER) {
userLocationState.update {
PointZ(lastLocation.latitude, lastLocation.longitude, lastLocation.altitude)
}
}
}
}
}
override fun startListeningLocationUpdates() {
val locationRequest = LocationRequest.create().apply {
interval = TimeUnit.SECONDS.toMillis(1)
fastestInterval = TimeUnit.SECONDS.toMillis(1)
maxWaitTime = TimeUnit.SECONDS.toMillis(2)
priority = Priority.PRIORITY_HIGH_ACCURACY
}
try {
fusedLocationProviderClient
.requestLocationUpdates(locationRequest, locationCallback, Looper.getMainLooper())
} catch (exception: SecurityException) {
logger.logException(exception, "Missing permission to request Location Updates")
}
}
override fun stopListeningLocationUpdates() {
try {
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
} catch (exception: SecurityException) {
logger.logException(exception, "Missing permission to remove Location Updates")
}
}
private companion object {
const val MAX_ACCURACY_METER = 20
}
}
该处:
...
class RecordingService : LifecycleService(), HasAndroidInjector {
....
private val notificationManager by lazy {
applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
}
private var started = false
private var configurationChange = false
private var serviceRunningInForeground = false
private val localBinder = LocalBinder()
override fun onCreate() {
AndroidInjection.inject(this)
super.onCreate()
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
super.onStartCommand(intent, flags, startId)
// This action comes from our ongoing notification. The user requested to stop updates.
if (intent?.action == ACTION_STOP_UPDATES) {
stopListeningLocationUpdates()
generateRecordingNotification(...)
}
if (!started) {
started = true
lifecycleScope.launch {
recordingInteractor
.recordingProgressState
.collect {
updateRecordingNotification(...)
}
}
}
// Tells the system not to recreate the service after it's been killed.
return START_NOT_STICKY
}
override fun onBind(intent: Intent): IBinder {
super.onBind(intent)
// AppActivity (client) comes into foreground and binds to service, so the service can
// become a background services.
stopForeground(STOP_FOREGROUND_REMOVE)
serviceRunningInForeground = false
configurationChange = false
return localBinder
}
override fun onRebind(intent: Intent) {
// AppActivity (client) returns to the foreground and rebinds to service, so the service
// can become a background services.
stopForeground(STOP_FOREGROUND_REMOVE)
serviceRunningInForeground = false
configurationChange = false
super.onRebind(intent)
}
override fun onUnbind(intent: Intent): Boolean {
// MainActivity (client) leaves foreground, so service needs to become a foreground service
// to maintain the 'while-in-use' label.
// NOTE: If this method is called due to a configuration change in AppActivity,
// we do nothing.
if (!configurationChange) {
val notification = generateRecordingNotification(
notificationTitle = getString(R.string.trail_recording_live_activity_recording_status_active),
context = applicationContext,
paused = false,
recordingDuration = getDurationText(recordingInteractor.recordingProgressState.value.time),
)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(NOTIFICATION_ID, notification, FOREGROUND_SERVICE_TYPE_LOCATION)
} else {
startForeground(NOTIFICATION_ID, notification)
}
serviceRunningInForeground = true
}
// Ensures onRebind() is called if AppActivity (client) rebinds.
return true
}
override fun onConfigurationChanged(newConfig: Configuration) {
super.onConfigurationChanged(newConfig)
configurationChange = true
}
fun startListeningLocationUpdates() {
// Binding to this service doesn't actually trigger onStartCommand(). That is needed to
// ensure this Service can be promoted to a foreground service, i.e., the service needs to
// be officially started (which we do here).
startService(Intent(applicationContext, RecordingService::class.java))
locationRepository.startListeningLocationUpdates()
}
fun stopListeningLocationUpdates() {
stopSelf()
locationRepository.stopListeningLocationUpdates()
}
/**
* Class used for the client Binder. Since this service runs in the same process as its
* clients, we don't need to deal with IPC.
*/
internal inner class LocalBinder : Binder() {
fun getService(): RecordingService = this@RecordingService
}
}
不知道我错过了什么,使它正常工作,任何帮助将不胜感激,谢谢!
1条答案
按热度按时间0pizxfdo1#
如果您的应用面向较新的Android版本,则必须确保声明后台权限。
并确保用户赠款应用程序后台权限。根据用户的Android版本,您必须将其发送到应用程序的设置中才能实现这一点。有关详细信息,请参阅请求后台位置权限的官方文档。