由于最近在开发的App要使用到卫星定位,同时要求是真实的定位信息,为了防止用户模拟定位构造虚假的位置信息,研究了一下Android中检测虚拟定位的一些方法。
一、检测位置信息来源
开发者选项中有模拟位置的选项可选,开发者可以用过模拟位置来伪造地理位置信息。大部分人通过安装虚拟定位软件,并在开发者选项中选择定位来源指向到虚拟软件发的方式来构造虚拟定位信息,这种方式是官方的方式,也是最常用的方式。过滤掉这种方式也就能排除大部分的虚拟定位。
具体就是Location 对象的isFromMockProvider()方法:
public boolean isMockLocationOn(Location location, Context context) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
return location.isFromMockProvider;
else {
String mockLocation = "0";
try {
mockLocation = android.provider.Settings.Secure.getString(context.getContentResolver(),
android.provider.Settings.Secure.ALLOW_MOCK_LOCATION);
}
catch (Exception e) {
e.printStackTrace();
}
return!mockLocation.equals("0");
}
}
二、检测安装的应用是否具有ACCESS_MOCK_LOCATION权限
fun areThereMockPermissionApps(context: Context): Boolean {
var count = 0
val pm = context.packageManager
val packages = pm.getInstalledApplications(PackageManager.GET_META_DATA)
for (applicationInfo in packages) {
try {
val packageInfo = pm.getPackageInfo(applicationInfo.packageName,
PackageManager.GET_PERMISSIONS)
// Get Permissions
val requestedPermissions = packageInfo.requestedPermissions
if (requestedPermissions != null) {
for (i in requestedPermissions.indices) {
if (requestedPermissions[i] == "android.permission.ACCESS_MOCK_LOCATION" && applicationInfo.packageName != context.packageName) {
count++
}
}
}
} catch (e: NameNotFoundException) {
Log.e("Got exception " + e.getMessage())
}
}
return count > 0
}
三、定位前使用removeTestProvider
在定位前先调用removeTestProvider方法,移除虚拟定位。某些模拟定位app会通过addTestProvider方法添加虚拟定位信息,所以此方法也可移除一部分虚拟定位信息。
fun mock(providerName: String, location: Location) {
val locationManager = AppUtils.application.applicationContext.getSystemService(Context.LOCATION_SERVICE) as LocationManager
locationManager.addTestProvider(providerName, false, true, true, false, true, true, true, android.location.Criteria.POWER_HIGH, android.location.Criteria.ACCURACY_FINE)
locationManager.setTestProviderEnabled(providerName, true)
locationManager.setTestProviderStatus(providerName, LocationProvider.AVAILABLE, null, System.currentTimeMillis())
locationManager.setTestProviderLocation(providerName, location)
}
四、检测NMEA数据
NMEA data是用于通信或接收GPS数据的海事电子报文协议标准,在真实的GPS定位中,每次取得位置信息,都会回调NmeaListener的onNmeaReceived方法,而虚拟定位则不会。
我们可以通过监听NmeaListener是否改变来判断此次的定位是否是真实的:
locationManager.addNmeaListener(nmeaListener);
五、检测手机是否开启了开发者模式
很多模拟定位软件需要手机打开开发者模式才能实现定位,通过检测手机是否开启了开发者模式来检测。如果开启了就要求用户关闭。
六、检测手机是否Root
对于root机型,几乎无法从根源上反作弊,所以检测是否root保证用户无法通过root伪造。
参考链接:
Android 定位信息https://juejin.cn/post/6844903686380978190Android GPS 反作弊 | Verne in GitHubAndroid 防止模拟位置方法
https://einverne.github.io/post/2016/11/android-prevent-gps-fake.html