您需要在运行时实际请求位置权限(请注意代码中的注释)。
使用 Kotlin 和 API 31(Android 12)更新:
从 API 30 开始,必须单独请求后台位置。此示例使用 targetSdk 31
和 compileSdk 31
。
请注意,在 API 29 上可以将后台位置请求与主位置请求捆绑在一起,但是为了做到这一点,您需要维护三个单独的代码路径。
对于 API 29 及以上版本,将其拆分为单独的请求更容易。
确保在应用程序级别的 Gradle 中包含最新的位置服务(在撰写本文时为 18.0.0):
implementation "com.google.android.gms:play-services-location:18.0.0"
在清单文件中包含位置权限:
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
这是一个简化的示例,可以处理大多数情况,但是以简化的方式进行。如果用户选择“不再询问”,则在下一次应用程序启动时,它将打开设置,让用户手动启用权限。
完整的活动代码:
import android.Manifest
import android.app.AlertDialog
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Looper
import android.provider.Settings
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.google.android.gms.location.*
class MainActivity : AppCompatActivity() {
private var fusedLocationProvider: FusedLocationProviderClient? = null
private val locationRequest: LocationRequest = LocationRequest.create().apply {
interval = 30
fastestInterval = 10
priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY
maxWaitTime = 60
}
private var locationCallback: LocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
val locationList = locationResult.locations
if (locationList.isNotEmpty()) {
val location = locationList.last()
Toast.makeText(
this@MainActivity,
"Got Location: " + location.toString(),
Toast.LENGTH_LONG
)
.show()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
fusedLocationProvider = LocationServices.getFusedLocationProviderClient(this)
checkLocationPermission()
}
override fun onResume() {
super.onResume()
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED
) {
fusedLocationProvider?.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
}
}
override fun onPause() {
super.onPause()
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
== PackageManager.PERMISSION_GRANTED
) {
fusedLocationProvider?.removeLocationUpdates(locationCallback)
}
}
private fun checkLocationPermission() {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
) {
AlertDialog.Builder(this)
.setTitle("Location Permission Needed")
.setMessage("This app needs the Location permission, please accept to use location functionality")
.setPositiveButton(
"OK"
) { _, _ ->
requestLocationPermission()
}
.create()
.show()
} else {
requestLocationPermission()
}
} else {
checkBackgroundLocation()
}
}
private fun checkBackgroundLocation() {
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_BACKGROUND_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
requestBackgroundLocationPermission()
}
}
private fun requestLocationPermission() {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
),
MY_PERMISSIONS_REQUEST_LOCATION
)
}
private fun requestBackgroundLocationPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
ActivityCompat.requestPermissions(
this,
arrayOf(
Manifest.permission.ACCESS_BACKGROUND_LOCATION
),
MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION
)
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
MY_PERMISSIONS_REQUEST_LOCATION
)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
when (requestCode) {
MY_PERMISSIONS_REQUEST_LOCATION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
fusedLocationProvider?.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
checkBackgroundLocation()
}
} else {
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show()
if (!ActivityCompat.shouldShowRequestPermissionRationale(
this,
Manifest.permission.ACCESS_FINE_LOCATION
)
) {
startActivity(
Intent(
Settings.ACTION_APPLICATION_DETAILS_SETTINGS,
Uri.fromParts("package", this.packageName, null),
),
)
}
}
return
}
MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION -> {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) == PackageManager.PERMISSION_GRANTED
) {
fusedLocationProvider?.requestLocationUpdates(
locationRequest,
locationCallback,
Looper.getMainLooper()
)
Toast.makeText(
this,
"Granted Background Location Permission",
Toast.LENGTH_LONG
).show()
}
} else {
Toast.makeText(this, "permission denied", Toast.LENGTH_LONG).show()
}
return
}
}
}
companion object {
private const val MY_PERMISSIONS_REQUEST_LOCATION = 99
private const val MY_PERMISSIONS_REQUEST_BACKGROUND_LOCATION = 66
}
}
在Android 10(API 29)中,它将为用户提供选择,在初始位置请求后授予后台位置权限:
![enter image description here](https://istack.dev59.com/el9pa.webp)
![enter image description here](https://istack.dev59.com/1OfF1.webp)
在Android 12(API 31)中,它也会执行相同的操作,但界面不同:
![enter image description here](https://istack.dev59.com/XvqYG.webp)
![enter image description here](https://istack.dev59.com/hmvvN.webp)
![enter image description here](https://istack.dev59.com/sIeKt.webp)
Java原始答案:
这是经过测试的可用代码,用于请求位置权限。
将此代码放入活动中:
public static final int MY_PERMISSIONS_REQUEST_LOCATION = 99;
public boolean checkLocationPermission() {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
!= PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_FINE_LOCATION)) {
new AlertDialog.Builder(this)
.setTitle(R.string.title_location_permission)
.setMessage(R.string.text_location_permission)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
})
.create()
.show();
} else {
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
MY_PERMISSIONS_REQUEST_LOCATION);
}
return false;
} else {
return true;
}
}
@Override
public void onRequestPermissionsResult(int requestCode,
String permissions[], int[] grantResults) {
switch (requestCode) {
case MY_PERMISSIONS_REQUEST_LOCATION: {
if (grantResults.length > 0
&& grantResults[0] == PackageManager.PERMISSION_GRANTED) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
} else {
}
return;
}
}
}
然后在onCreate()
中调用checkLocationPermission()
方法:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
checkLocationPermission();
}
你可以像问题中一样使用
onResume()
和
onPause()
。以下是更简洁的版本:
@Override
protected void onResume() {
super.onResume();
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationManager.requestLocationUpdates(provider, 400, 1, this);
}
}
@Override
protected void onPause() {
super.onPause();
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_FINE_LOCATION)
== PackageManager.PERMISSION_GRANTED) {
locationManager.removeUpdates(this);
}
}
provider
变量在这个问题中是如何使用的:String provider = locationManager.getBestProvider(new Criteria(), false);
- Daniel Nugentandroid.Manifest
。Android Studio似乎默认使用my.app.package.Manifest
。 - gts101checkLocationPermission()
的调用从onResume()
移动到onMapReady()
中。 - hexicleonCreate()
中调用checkLocationPermission()
,所以我修改了答案来做到这一点。有了这个解决方案,您可以像问题中一样使用onResume()
和onPause()
。感谢您让我注意到这一点,干杯! - Daniel Nugent