我正在开发一个需要用户能够对通过相机拍摄的照片进行地理标记的应用程序。该应用程序旨在鼓励用户对树进行地理标记,以鼓励造林并减少全球变暖。
是否可以实现此功能,我该如何实现?
注意:这是我的第一个主要项目。
创建具有位置感的舒适用户体验是一项艰巨的任务。这些是您必须解决的一些问题:
该应用可能没有使用位置的权限。 您想请求用户许可。 您不想一遍又一遍地打扰用户。 寻求许可意味着暂停您的活动,而转向需要许可的系统活动。 当用户响应时,您的活动将恢复,您需要重写一个特殊的回调方法来接收结果。 仅在需要时询问位置是不好的。可能需要一些时间。相反,您必须请求Android向您推送位置更新。 用户在使用应用程序时可能会撤销位置权限,您必须不断地重新检查权限,以应对突发异常,并在位置权限恢复时重复请求以接收位置更新。 以下是我项目中的一些片段,可以帮助您入门:
private val Context.fusedLocationProviderClient get() = getFusedLocationProviderClient(this)
private suspend fun FusedLocationProviderClient.tryFetchLastLocation(): Location? =
lastLocation.await()
?.also { info { "Got response from getLastLocation()" } }
?: run { warn { "getLastLocation() returned null" }; null }
suspend fun Context.canUseLocationFg() =
appHasLocationPermission() &&
locationSettingsException(locationRequestFg, locationRequestBg) == null
import android.Manifest.permission.ACCESS_FINE_LOCATION
import androidx.core.content.PermissionChecker.PERMISSION_GRANTED
fun Context.appHasLocationPermission() =
checkSelfPermission(this, ACCESS_FINE_LOCATION) == PERMISSION_GRANTED
suspend fun Context.locationSettingsException(
vararg locationRequests: LocationRequest
): ApiException? = try {
getSettingsClient(this)
.checkLocationSettings(LocationSettingsRequest.Builder()
.addAllLocationRequests(locationRequests.asList()).build())
.await()
null
} catch (e: ApiException) { e }
const val CODE_REQUEST_FINE_LOCATION = 13
const val CODE_RESOLVE_API_EXCEPTION = 14
suspend fun Fragment.checkAndCorrectPermissionsAndSettings() {
with(context!!) {
if (!appHasLocationPermission()) {
warn { "FG: our app has no permission to access fine location" }
delay(WAIT_MILLISECONDS_BEFORE_ASKING)
if (!appHasLocationPermission()) {
startIntentRequestLocationPermission()
return
}
}
if (locationSettingsException(locationRequestFg, locationRequestBg) == null) return
warn { "FG: ResolvableApiException for location request (probably location disabled)" }
if (!mainPrefs.shouldAskToEnableLocation) return
delay(WAIT_MILLISECONDS_BEFORE_ASKING)
locationSettingsException(locationRequestFg, locationRequestBg)
?.let { it as? ResolvableApiException }
?.also { startIntentResolveException(it) }
}
}
fun Fragment.startIntentRequestLocationPermission() =
requestPermissions(arrayOf(ACCESS_FINE_LOCATION), CODE_REQUEST_FINE_LOCATION)
fun Fragment.startIntentResolveException(e: ResolvableApiException) =
startIntentSenderForResult(e.resolution.intentSender, CODE_RESOLVE_API_EXCEPTION, null, 0, 0, 0, null)
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
if (requestCode != CODE_REQUEST_FINE_LOCATION) return
permissions.zip(grantResults.asList())
.find { (perm, _) -> perm == ACCESS_FINE_LOCATION }
?.also { (_, result) ->
if (result == PermissionChecker.PERMISSION_GRANTED) {
info { "User has granted us the fine location permission" }
} else {
warn { "User hasn't granted us the fine location permission (grant result: ${grantResults[0]})" }
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode != CODE_RESOLVE_API_EXCEPTION) return
if (resultCode == Activity.RESULT_OK) {
info { "ResolvableApiException is now resolved" }
} else {
warn { "ResolvableApiException resolution failed with code $resultCode" }
activity!!.mainPrefs.applyUpdate { setShouldAskToEnableLocation(false) }
}
}
val locationRequestFg = LocationRequest().apply {
interval = 1000
fastestInterval = 10
priority = PRIORITY_BALANCED_POWER_ACCURACY
}
suspend fun Context.receiveLocationUpdatesFg(locationState: LocationState) {
fusedLocationProviderClient.apply {
tryFetchLastLocation()?.also {
info { "lastLocation: ${it.description}" }
locationState.location = it
}
LocationCallbackFg.locationState = locationState
requestLocationUpdates(locationRequestFg, LocationCallbackFg, null).await()
info(CC_PRIVATE) { "FG: started receiving location updates" }
}
}
object LocationCallbackFg : LocationCallback() {
var locationState: LocationState? = null
override fun onLocationResult(result: LocationResult) {
val lastLocation = result.lastLocation
info { "FG: received location ${lastLocation.description}" }
locationState?.apply { location = lastLocation }
?: warn { "LocationCallbackFg received an event while not in use" }
}
}
代码依赖Task.await(),这在Kotlin的库中kotlinx-coroutines-play-services。
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。