会社のOAはチェックインを忘れることが多く、そういえば家に帰るのが面倒くさい…
Androidの公式ドキュメントを参考にaddTestProvider、setTestProviderLocationの使い方を学び、緯度と経度 GPS 位置情報 チェックインし忘れたら使えない…
動作環境
機器:Xiaomi 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 はクラッシュします (抽象メソッド "void android.location.LocationListener.onProviderDisabled() ")。ドキュメントに表示される例外がキャッチされました。理由はわかりません.削除するだけでクラッシュします.場所は正常に使用できます...
公式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 はシミュレートされた位置を取得し、Gaode マップも取得します。