Android模拟地图gps定位


公司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,可以正常使用位置…
官方APIhttps://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 获取的是这个模拟的位置,高德地图也是

在这里插入图片描述在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_35193677/article/details/126520022
今日推荐