公司OA经常忘了打卡,想起来就到家了,这就很烦…
参考Android官方文档,学习使addTestProvider,setTestProviderLocation,实现简单指定经纬度GPS位置,要是忘了打卡,可不能用这个…
运行环境
设备:小米K30s
系统:Android12
状态:位置正常
1.判断权限
AndroidManifest.xml
<!--MOCK-->
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
<!--网络-->
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<!--GPS-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
object MockLocationUtils {
/**
* 是否选择应用
* Android 6.0以下,通过Setting.Secure.ALLOW_MOCK_LOCATION判断
* Android 6.0及以上,需要【开发者选项 选择应用】通过addTestProvider是否可用判断
* @param context Context .
* @return Boolean .
*/
@SuppressLint("WrongConstant")
fun isAllowMockLocation(context: Context): Boolean {
var canMockPosition = false
if (Build.VERSION.SDK_INT <= 22) { //6.0以下
canMockPosition = Settings.Secure.getInt(
context.contentResolver,
Settings.Secure.ALLOW_MOCK_LOCATION, 0
) != 0
} else {
try {
val locationManager =
context.getSystemService(Context.LOCATION_SERVICE) as LocationManager
val providerStr = LocationManager.GPS_PROVIDER
val provider = locationManager.getProvider(providerStr)
if (provider != null) {
locationManager.addTestProvider(
provider.name,
provider.requiresNetwork(),
provider.requiresSatellite(),
provider.requiresCell(),
provider.hasMonetaryCost(),
provider.supportsAltitude(),
provider.supportsSpeed(),
provider.supportsBearing(),
provider.powerRequirement,
provider.accuracy
)
} else {
locationManager.addTestProvider(
providerStr,
true,
true,
false,
false,
true,
true,
true,
Criteria.POWER_HIGH,
Criteria.ACCURACY_FINE
)
}
locationManager.setTestProviderEnabled(providerStr, true)
locationManager.setTestProviderStatus(
providerStr,
LocationProvider.AVAILABLE,
null,
System.currentTimeMillis()
)
// 可用
canMockPosition = true
locationManager.setTestProviderEnabled(providerStr, false)
locationManager.removeTestProvider(providerStr)
} catch (e: SecurityException) {
canMockPosition = false
}
}
return canMockPosition
}
}
2.开始定位(GPS位置)
通过setTestProviderLocation(),设置GPS测试位置,实现模拟地图位置.注意位置的更新频率,不是设置一次就行.
/**
* 开始位置
*/
@SuppressLint("MissingPermission")
private fun startLocation() {
val provider = mLocManager.getProvider(LocationManager.GPS_PROVIDER)
if (provider != null) {
mLocManager.addTestProvider(
provider.getName(),
provider.requiresNetwork(),
provider.requiresSatellite(),
provider.requiresCell(),
provider.hasMonetaryCost(),
provider.supportsAltitude(),
provider.supportsSpeed(),
provider.supportsBearing(),
provider.getPowerRequirement(),
provider.getAccuracy()
)
} else {
//Log.i(TAG, "startLocation: provider=null")
Toast.makeText(this, "LocationProvider", Toast.LENGTH_LONG).show()
return
}
/* 创建新的Location对象,并设定必要的属性值 */
val location = Location(LocationManager.GPS_PROVIDER)
location.latitude = CoordinateUtils.WGSLat(lat, lng)
location.longitude = CoordinateUtils.WGSLon(lat, lng)
location.accuracy = 500f
location.time = System.currentTimeMillis();
location.elapsedRealtimeNanos = SystemClock.elapsedRealtimeNanos();
binding.btStart.tag = "end"
try {// 开启测试Provider
mLocManager.setTestProviderEnabled(LocationManager.GPS_PROVIDER, true)
mLocManager.setTestProviderStatus(
LocationManager.GPS_PROVIDER,
LocationProvider.AVAILABLE,
null,
System.currentTimeMillis()
)
mLocManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
1000,
10.0f,
object : LocationListener {
override fun onLocationChanged(location: Location) {
Log.i(
TAG,
"onLocationChanged: lat:" + location.latitude + "lng:${location.longitude}"
)
}
})
lifecycleScope.launch {
while (binding.btStart.tag == "end") {
delay(500)
// 设置最新位置,一定要在requestLocationUpdate完成后进行,才能收到监听
if (binding.btStart.tag == "end") {
mLocManager.setTestProviderLocation(LocationManager.GPS_PROVIDER, location);
Log.i(TAG, "startLocation: " + System.currentTimeMillis())
}
}
}
binding.btStart.text = "关闭"
binding.btStart.setBackgroundColor(Color.RED)
binding.btStart.tag = "end"
} catch (e: Exception) {
Toast.makeText(this, "开启定位失败${e.message}", Toast.LENGTH_LONG).show()
//
binding.btStart.text = "开始"
binding.btStart.setBackgroundColor(Color.parseColor("#FF6200EE"))
binding.btStart.tag = "start"
}
}
3.关闭位置
removeTestProvider我自己的手机测试调用是正常的(Android11),在我同事Android10会crash(
abstract method “void android.location.LocationListener.onProviderDisabled()
).已经捕捉了文档上会出现的异常.不知道为啥. 只是移除会crash,可以正常使用位置…
官方API
https://developer.android.google.cn/reference/kotlin/android/location/LocationManager?hl=en#removetestprovider
try {
mLocManager.removeTestProvider(LocationManager.GPS_PROVIDER)
} catch (e1: IllegalArgumentException) {
// 未成功addTestProvider时报错,为防万一有重复调用remove
Log.i(TAG, "initView: ${e1.message}")
} catch (e2: SecurityException) {
Log.i(TAG, "initView: ${e2.message}")
}
4.实现效果
调用正常,OA 获取的是这个模拟的位置,高德地图也是
版权声明:本文为qq_35193677原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。