Android中的定位通过LocationManager实现

LocationManager locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);

获取位置信息

Location location = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
geocoder.getFromLocation(location.latitude, location.longitude, 1)

locationManager.requestLocationUpdates(
                        LocationManager.NETWORK_PROVIDER, 10000, 10F, listener
                    )

getLastKnownLocation获取的是上次的定位数据,在定位开关切换后(关闭又打开)会返回空,Location类包含定位数据,比如经纬度,速度之类的。通过Geocoder可以将经纬度逆编码成地址,获取国家,省份,城市之类的信息。requestLocationUpdates或许改名叫observeLocationUpdates更好,是注册地址更新的监听器,传入最小的更新间隔和距离,需要手动移除。

Android定位主要需要关注四个点,定位开关,定位精度(权限),定位方式,定位场景。

定位开关

检测定位开关状态

LocationManagerCompat.isLocationEnabled(locationManager)

点进去可以看到下面的代码,Android 9 以后使用系统API判断,Android 9 以下判断两种定位方式(GPS和网络)是否有至少一种可用。

if (VERSION.SDK_INT >= VERSION_CODES.P) {
     return locationManager.isLocationEnabled();
} else {
     return locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER)
     	|| locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
}

如果定位开关没有打开,需要跳转到设置内由用户手动开启,跳转Intent如下

startActivityForResult(Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS), 233)

定位精度

定位精确度其实也跟定位方式有关,主要分两种。
粗略定位,需要android.permission.ACCESS_COARSE_LOCATION权限,精确度大致会精确到 3 平方公里(约 1.2 平方英里)以内。
精确定位,需要android.permission.ACCESS_FINE_LOCATION权限,
通常可以精确到 50 米(160 英尺)以内,有时甚至可以精确到几米(10 英尺)以内。
以上两个权限需要在AndroidManifest上声明,并在运行时动态申请,与一般的动态申请权限一致。除非只需要粗略定位,否则需要同时申请两个权限。根据官方文档Android12及以后用户可以选择只授予应用粗略定位权限,如果这时只申请精确定位权限,那么系统会忽略权限请求,同时会在LogCat中打印日志

ACCESS_FINE_LOCATION must be requested with ACCESS_COARSE_LOCATION.

定位方式

可通过getProviders方法获取定位方式列表,true表示只返回可用的定位方式。getBestProvider可以用来添加约束,比如需要多大的定位精度之类的,返回推荐的定位方式。

locationManager.getProviders(true);
locationManager.getBestProvider(new Criteria(),true);

GPS定位

使用LocationManager.GPS_PROVIDER ,定位精度较高,需要android.permission.ACCESS_FINE_LOCATION权限。

网络定位(CellID, WiFi MACID)

网络定位模式(基站、wifi网络)、精度较低(1000米)、无海拔高度、初始定位速度快、耗电低。
使用LocationManager.NETWORK_PROVIDER 需要android.permission.ACCESS_COARSE_LOCATION权限。

被动定位

被动定位方式,精度取决于定位信息提供方。比较明显,就是用现成的,不主动请求位置信息,当其他应用使用定位更新了定位信息,系统会保存下来,该应用接收到消息后直接读取就可以了。
使用LocationManager.PASSIVE_PROVIDER 需要android.permission.ACCESS_FINE_LOCATION权限。

融合定位

结合上述三种定位方式提供定位,Android12之前Google Play Service提供的功能,Android12之后加入SDK。
使用LocationManager.FUSED_PROVIDER 需要android.permission.ACCESS_FINE_LOCATION权限。

定位场景

前台定位

前台定位就是一般情况下的定位,无需额外的权限。

后台定位

后台定位属于比较危险的行为,Google Play Store有相关的政策要求。Android10后新增了一个动态权限android.permission.ACCESS_BACKGROUND_LOCATION,这个权限应该在获得上述的关于精确度的权限后单独请求。主要是根据应用需求一开始只请求前台位置权限,在需要的时候再请求后台位置权限。Android11之后如果一起请求前后台权限(定位权限和后台定位权限),系统会忽略该请求,且不会向您的应用授予其中的任一权限。

关联拓展信息

android.permission.ACCESS_MOCK_LOCATION
需要接受假位置信息时(比如用于测试)的权限,API23已经移除。

android.permission.ACCESS_MEDIA_LOCATION
读取多媒体文件的定位信息,比如图片可能附带地址信息,需要此权限才能读取。Android 10加入,需要动态申请

参考链接