Preventing iOS/Android users from faking their GPS location
There is pretty much no way to validate the correctness of your GPS readings. However, there are workarounds you could use to detect possible spoofing:
First, you can detect if they Mock Location setting is on (which is commonly used by GPS faking apps). To do so, lookup Settings.Secure.ALLOW_MOCK_LOCATION)
setting and check if it's enabled or not. Then check which apps have that permission (namely android.permission.ACCESS_MOCK_LOCATION
). If there are apps present that use that permission and that setting is on, there is a high change they may be faking user's location.
You could also try to use Location.isFromMockProvider
, although I am not sure how accurate the result is. The function returns true if the location you're checking has been acquired through a GPS faking app.
Disable / Check for Mock Location (prevent gps spoofing)
I have done some investigation and sharing my results here,this may be useful for others.
First, we can check whether MockSetting option is turned ON
public static boolean isMockSettingsON(Context context) {
// returns true if mock location enabled, false if not enabled.
if (Settings.Secure.getString(context.getContentResolver(),
Settings.Secure.ALLOW_MOCK_LOCATION).equals("0"))
return false;
else
return true;
}
Second, we can check whether are there other apps in the device, which are using android.permission.ACCESS_MOCK_LOCATION
(Location Spoofing Apps)
public static boolean areThereMockPermissionApps(Context context) {
int count = 0;
PackageManager pm = context.getPackageManager();
List<ApplicationInfo> packages =
pm.getInstalledApplications(PackageManager.GET_META_DATA);
for (ApplicationInfo applicationInfo : packages) {
try {
PackageInfo packageInfo = pm.getPackageInfo(applicationInfo.packageName,
PackageManager.GET_PERMISSIONS);
// Get Permissions
String[] requestedPermissions = packageInfo.requestedPermissions;
if (requestedPermissions != null) {
for (int i = 0; i < requestedPermissions.length; i++) {
if (requestedPermissions[i]
.equals("android.permission.ACCESS_MOCK_LOCATION")
&& !applicationInfo.packageName.equals(context.getPackageName())) {
count++;
}
}
}
} catch (NameNotFoundException e) {
Log.e("Got exception " , e.getMessage());
}
}
if (count > 0)
return true;
return false;
}
If both above methods, first and second are true, then there are good chances that location may be spoofed or fake.
Now, spoofing can be avoided by using Location Manager's API.
We can remove the test provider before requesting the location updates from both the providers (Network and GPS)
LocationManager lm = (LocationManager) getSystemService(LOCATION_SERVICE);
try {
Log.d(TAG ,"Removing Test providers")
lm.removeTestProvider(LocationManager.GPS_PROVIDER);
} catch (IllegalArgumentException error) {
Log.d(TAG,"Got exception in removing test provider");
}
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, locationListener);
I have seen that removeTestProvider(~) works very well over Jelly Bean and onwards version. This API appeared to be unreliable till Ice Cream Sandwich.
Flutter Update:
Use Geolocator and check Position
object's isMocked
property.
How to prevent the detection of fake GPS?
The calls
invoke-virtual {p1}, Landroid/location/Location;->isFromMockProvider()Z
move-result v1
returns 1
(true) if a mock provider is used and 0
otherwise. The result is stored in v1
.
Later the value is used for a conditional branch in
if-eqz v1, :cond_1e // if v1==0 GOTO cond_1e
So only if there is no mock provider used (v1=0) it jumps to a special code part. Otherwise it continues with a code part that handles the mock location which is most likely what you don't want.
So you have to tweak that check and for doing so you have two possibilities:
- Overwrite
v1
with 0 before the check, e.g. via the commandconst/4 v1, 0x0
- Replace the conditional branch
if-eqz v1, :cond_1e
with a non-conditionalgoto :cond_1e
so it doesn't matter what valuev1
has.
How to detect mock location in flutter for ios and android
you can use TrustLocation
permissions:
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
usage :
import 'package:trust_location/trust_location.dart';
/* Assuming in an async function */
/// query the current location.
LatLongPosition position = await TrustLocation.getLatLong;
/// check mock location on Android device.
bool isMockLocation = await TrustLocation.isMockLocation;
using steam:
// input seconds into parameter for getting location with repeating by timer.
// this example set to 5 seconds.
TrustLocation.start(5);
/// the stream getter where others can listen to.
TrustLocation.onChange.listen((values) =>
print('${values.latitude} ${values.longitude} ${values.isMockLocation}')
);
/// stop repeating by timer
TrustLocation.stop();
Example:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:trust_location/trust_location.dart';
import 'package:location_permissions/location_permissions.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _latitude;
String _longitude;
bool _isMockLocation;
/// initialize state.
@override
void initState() {
super.initState();
requestLocationPermission();
// input seconds into parameter for getting location with repeating by timer.
// this example set to 5 seconds.
TrustLocation.start(5);
getLocation();
}
/// get location method, use a try/catch PlatformException.
Future<void> getLocation() async {
try {
TrustLocation.onChange.listen((values) => setState(() {
_latitude = values.latitude;
_longitude = values.longitude;
_isMockLocation = values.isMockLocation;
}));
} on PlatformException catch (e) {
print('PlatformException $e');
}
}
/// request location permission at runtime.
void requestLocationPermission() async {
PermissionStatus permission =
await LocationPermissions().requestPermissions();
print('permissions: $permission');
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Trust Location Plugin'),
),
body: Padding(
padding: const EdgeInsets.all(20.0),
child: Center(
child: Column(
children: <Widget>[
Text('Mock Location: $_isMockLocation'),
Text('Latitude: $_latitude, Longitude: $_longitude'),
],
)),
),
),
);
}
}
for more information you can see https://pub.dev/packages/trust_location
github link : https://github.com/wongpiwat/trust-location
Related Topics
Sending Files Using Post With Httpurlconnection
Android Adb Doesn't See Device
React-Native Run-Android Has Error, How to Fix It
How to Set Button Click Effect in Android
How to Avoid the Frame Layout Is Pushed Up When the Soft Keyboard Appears
Programmatically Retrieve Imei Number for Dual Sim in Android
How to Make My App Work in All Devices
How to Fix White Screen on App Start Up
Reactnative Metro Bundler Not Starting Automatically
How to Remove Focus from Edittext When User Is Done Editing
Android No on Screen Keybord ( Only Voice )
Send Text to Specific Contact Programmatically (Whatsapp)
How to Quit Android Application Programmatically
Limitations on Opening Pdf File in Android
How to Remove Set-Device-Owner in Android Dpm
Getting Simple Json Object Response Using Retrofit Library
Full Screen Without Navigation & Status Bars
How to Disable All User Inputs (Click, Touch) on an Android View