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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 07:45:19