Android 12后台运行时getLastKnownLocation返回null问题求助
Android 12后台获取位置返回null问题解决
问题原因
这是Android 12(API 31)新增的后台位置权限限制导致的:
- 应用后台运行时,原有的
ACCESS_COARSE_LOCATION/ACCESS_FINE_LOCATION权限不再允许主动请求位置更新 getLastKnownLocation()在后台场景下会被系统限制,大概率返回null- 你的BroadcastReceiver在后台触发时属于后台进程,不符合Android 12的位置访问规则
解决方案
1. 添加后台位置权限
在AndroidManifest.xml中声明后台位置权限:
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
同时要在代码中动态申请这个权限——Android 12会单独弹出后台权限的授权弹窗,必须用户手动确认。
2. 改用前台服务获取位置
Android 12要求后台获取位置必须通过前台服务(会在通知栏显示提示,告知用户应用正在使用位置)。
步骤1:创建前台服务类
public class LocationForegroundService extends Service { private static final int NOTIFY_ID = 1001; private LocationManager locationManager; private LocationListener locationListener; @Override public void onCreate() { super.onCreate(); // 构建前台服务通知(必须显示,不能隐藏) Notification notification = new NotificationCompat.Builder(this, "LOCATION_CHANNEL") .setContentTitle("正在获取位置") .setContentText("应用后台运行中") .setSmallIcon(R.drawable.ic_notify) .build(); startForeground(NOTIFY_ID, notification); // 初始化位置监听 locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); locationListener = new LocationListener() { @Override public void onLocationChanged(@NonNull Location location) { // 拿到位置后的处理逻辑 double lat = location.getLatitude(); double lng = location.getLongitude(); } }; } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 检查权限后请求位置更新 if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED) { locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, 4000, 0, locationListener); // 尝试获取缓存的最后已知位置 Location lastLoc = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER); if (lastLoc != null) { double lat = lastLoc.getLatitude(); double lng = lastLoc.getLongitude(); } } return START_STICKY; } @Override public void onDestroy() { super.onDestroy(); // 停止位置更新,释放资源 if (locationManager != null && locationListener != null) { locationManager.removeUpdates(locationListener); } stopForeground(true); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
步骤2:修改BroadcastReceiver逻辑
把原来的位置获取代码替换为启动前台服务:
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE).equals(TelephonyManager.EXTRA_STATE_RINGING)) { Toast.makeText(context, "RINGING", Toast.LENGTH_SHORT).show(); // 启动前台服务处理位置获取 Intent serviceIntent = new Intent(context, LocationForegroundService.class); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } }
步骤3:在Manifest中注册服务
<service android:name=".LocationForegroundService" android:foregroundServiceType="location" /> <!-- Android 12+必须声明服务类型 -->
3. 关键注意点
- 必须拿到用户授权的
ACCESS_BACKGROUND_LOCATION权限,否则后台还是拿不到位置 - 前台服务的通知不能隐藏,这是Android的强制要求
- 位置使用完毕后记得停止服务,移除监听器,避免浪费资源
内容的提问来源于stack exchange,提问作者tahan yaf
相关产品推荐
相关产品推荐

