当前位置: 首页 > article >正文

Android 高版本兼容的原生定位工具类封装(支持 Android 5.0 到 Android 14)

本文提供了一个完整的 Android 原生定位工具类封装,支持从 Android 5.0 到最新的 Android 14 版本。该工具类基于 LocationManager,实现了定位权限检查、定位开关检测、实时位置更新监听以及获取最后一次已知位置的功能。针对高版本 Android 系统的权限变化和后台定位限制,工具类进行了适配优化,确保在不同系统版本上都能稳定运行。代码简洁易用,可直接集成到项目中,适合需要定位功能的 Android 应用开发者。
完整代码
1. 工具类:NativeLocationHelper.java

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Build;
import android.os.Bundle;
import android.os.Looper;
import android.provider.Settings;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;

public class NativeLocationHelper {

    private Context context;
    private LocationManager locationManager;
    private LocationListener locationListener;
    private OnLocationUpdateListener onLocationUpdateListener;

    // 定位更新回调接口
    public interface OnLocationUpdateListener {
        void onLocationUpdate(Location location); // 位置更新回调
        void onLocationError(String errorMessage); // 定位失败回调
    }

    public NativeLocationHelper(Context context) {
        this.context = context;
        this.locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    }

    /**
     * 开始定位
     *
     * @param minTime     最小更新时间(毫秒)
     * @param minDistance 最小更新距离(米)
     * @param listener    定位更新回调
     */
    public void startLocationUpdates(long minTime, float minDistance, OnLocationUpdateListener listener) {
        this.onLocationUpdateListener = listener;

        // 检查定位权限
        if (!checkLocationPermission()) {
            onLocationUpdateListener.onLocationError("Location permission not granted");
            return;
        }

        // 检查定位是否开启
        if (!isLocationEnabled()) {
            onLocationUpdateListener.onLocationError("Location services are disabled");
            return;
        }

        // 创建定位监听器
        locationListener = new LocationListener() {
            @Override
            public void onLocationChanged(Location location) {
                if (onLocationUpdateListener != null) {
                    onLocationUpdateListener.onLocationUpdate(location);
                }
            }

            @Override
            public void onStatusChanged(String provider, int status, Bundle extras) {}

            @Override
            public void onProviderEnabled(String provider) {}

            @Override
            public void onProviderDisabled(String provider) {
                if (onLocationUpdateListener != null) {
                    onLocationUpdateListener.onLocationError("Location provider disabled");
                }
            }
        };

        // 请求位置更新
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, minTime, minDistance, locationListener, Looper.getMainLooper());
            locationManager.requestLocationUpdates(LocationManager.NETWORK_PROVIDER, minTime, minDistance, locationListener, Looper.getMainLooper());
        }
    }

    /**
     * 停止定位
     */
    public void stopLocationUpdates() {
        if (locationManager != null && locationListener != null) {
            locationManager.removeUpdates(locationListener);
        }
    }

    /**
     * 获取最后一次已知位置
     *
     * @return 最后一次已知位置,如果不存在则返回 null
     */
    public Location getLastKnownLocation() {
        if (!checkLocationPermission() || !isLocationEnabled()) {
            return null;
        }

        Location lastKnownLocation = null;
        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                || ActivityCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            if (lastKnownLocation == null) {
                lastKnownLocation = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
            }
        }
        return lastKnownLocation;
    }

    /**
     * 检查定位服务是否开启
     *
     * @return true 表示定位服务已开启,false 表示未开启
     */
    public boolean isLocationEnabled() {
        return locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER)
                || locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
    }

    /**
     * 检查定位权限
     *
     * @return true 表示权限已授予,false 表示未授予
     */
    private boolean checkLocationPermission() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                    || ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED
                    || ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) == PackageManager.PERMISSION_GRANTED;
        } else {
            return ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                    || ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
        }
    }

    /**
     * 打开定位设置页面
     */
    public void openLocationSettings() {
        Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
        context.startActivity(intent);
    }
}

2. 在 AndroidManifest.xml 中添加权限

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />

3. 前台服务声明(适用于 Android 14)
如果需要在后台获取位置更新,可以使用前台服务,并在 AndroidManifest.xml 中声明服务类型:

<service
    android:name=".LocationForegroundService"
    android:foregroundServiceType="location" />

4. 在 Activity 中使用工具类

import android.location.Location;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import android.Manifest;
import android.content.pm.PackageManager;
import android.util.Log;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    private static final int LOCATION_PERMISSION_REQUEST_CODE = 1001;
    private NativeLocationHelper locationHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 初始化定位工具类
        locationHelper = new NativeLocationHelper(this);

        // 检查并请求定位权限
        if (checkLocationPermission()) {
            startLocationUpdates();
        } else {
            requestLocationPermission();
        }
    }

    /**
     * 检查定位权限
     */
    private boolean checkLocationPermission() {
        return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
                || ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
    }

    /**
     * 请求定位权限
     */
    private void requestLocationPermission() {
        ActivityCompat.requestPermissions(
                this,
                new String[]{Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION},
                LOCATION_PERMISSION_REQUEST_CODE
        );
    }

    /**
     * 开始定位更新
     */
    private void startLocationUpdates() {
        locationHelper.startLocationUpdates(10000, 10, new NativeLocationHelper.OnLocationUpdateListener() {
            @Override
            public void onLocationUpdate(Location location) {
                double latitude = location.getLatitude();
                double longitude = location.getLongitude();
                Log.d("Location", "Lat: " + latitude + ", Lng: " + longitude);
                Toast.makeText(MainActivity.this, "Location: " + latitude + ", " + longitude, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onLocationError(String errorMessage) {
                Log.e("Location", errorMessage);
                Toast.makeText(MainActivity.this, errorMessage, Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 停止定位更新
        locationHelper.stopLocationUpdates();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        if (requestCode == LOCATION_PERMISSION_REQUEST_CODE) {
            if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                startLocationUpdates();
            } else {
                Toast.makeText(this, "Location permission denied", Toast.LENGTH_SHORT).show();
            }
        }
    }
}

总结
该工具类已适配到最高 Android 14,支持最新的权限管理和定位功能。

针对 Android 14 的隐私和安全增强,工具类增加了对前台服务和权限请求的适配。

如果你有更多需求或问题,欢迎继续提问!


http://www.kler.cn/a/589136.html

相关文章:

  • kotlin中的模块化结构组件
  • 机器人交社保属于“无稽之谈”?
  • 《Operating System Concepts》阅读笔记:p309-p330
  • uni-app 生命周期
  • 数学建模 第二节
  • 深度学习模型压缩:非结构化剪枝与结构化剪枝的定义与对比
  • 基于C#的以太网通讯实现:TcpClient异步通讯详解
  • 政策助力,3C 数码行业数字化起航
  • 考研408-数据结构完整代码 线性表的顺序存储结构 - 顺序表
  • 运维工具推荐 -- 宝塔面板:一键部署服务器
  • nexus的使用
  • Linux搭建conda虚拟环境流程
  • never_give_up
  • 聊一下CSS层叠
  • Centos离线安装perl
  • redis zset基本介绍以及底层实现
  • 【网络】Caddy 服务器如何提供 TLS(Transport Layer Security)(传输层安全协议)
  • 短视频下载去水印,用什么工具好?
  • 使用 Chrome Flags 设置(适用于 HTTP 站点开发)
  • Spring WebSocket 像写http接口一样处理WebSocket消息(Stomp协议)