#android #mock-location
#Android #ложное местоположение
Вопрос:
Я создаю приложение ложного местоположения, но когда я его включаю, другие приложения (например, Google Maps) его не обнаруживают. В приложении я могу определить реальное местоположение, если включен gps, и ложное местоположение, если gps выключен, а приложение включено в приложениях для определения местоположения
Мой код:
MainActivity
package com.example.a;
import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.SystemClock;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.widget.TextView;
public class MainActivity extends Activity implements LocationListener
{
private FakeLocation task = null;
private TextView latituteField;
private TextView longitudeField;
private TextView prov;
private TextView other;
private TextView provList;
private LocationManager locationManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
latituteField = findViewById(R.id.TextView02);
longitudeField = findViewById(R.id.TextView04);
prov = findViewById(R.id.TextView06);
other = findViewById(R.id.TextView08);
provList = findViewById(R.id.TextView10);
locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED)
{
ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, 1222);
}
int permissionCheck = ContextCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_FINE_LOCATION);
if (PackageManager.PERMISSION_GRANTED == permissionCheck)
{
if(locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER))
{
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 0, 0, this);
Location auxLocation = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
prov.setText("GPS");
if(auxLocation != null)
{
onLocationChanged(auxLocation);
}
else
{
latituteField.setText("null");
longitudeField.setText("null");
}
}
else if(locationManager.isProviderEnabled(FakeLocation.FAKE_LOCATION))
{
// otherwise enable the mock GPS provider
if(!locationManager.getAllProviders().contains("FakeLocation"))
{
locationManager.addTestProvider(FakeLocation.FAKE_LOCATION, false, false, false, false, true, false, false, 0, 5);
locationManager.setTestProviderEnabled(FakeLocation.FAKE_LOCATION, true);
}
if(locationManager.isProviderEnabled(FakeLocation.FAKE_LOCATION))
{
prov.setText("FAKE");
locationManager.requestLocationUpdates(FakeLocation.FAKE_LOCATION, 0, 0, this);
try
{
other.setText("Inicia task");
task = new FakeLocation();
task.execute();
}
catch(Exception e)
{
other.setText("Excepcion en onCreate");
}
}
}
}
else
{
other.setText("Permisos NOK");
}
provList.setText(locationManager.getAllProviders().toString());
}
@Override
protected void onPause()
{
super.onPause();
locationManager.removeUpdates(this);
}
@Override
public void onLocationChanged(Location location)
{
int lat = (int) (location.getLatitude());
int lng = (int) (location.getLongitude());
latituteField.setText(String.valueOf(lat));
longitudeField.setText(String.valueOf(lng));
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) {}
@Override
public void onProviderEnabled(String provider) {}
@Override
public void onProviderDisabled(String provider) {}
private class FakeLocation extends AsyncTask<String, Integer, Void>
{
public static final String FAKE_LOCATION = "FakeLocation";
@Override
protected Void doInBackground(String... data)
{
double latitude = 40d;
double longitude = 20d;
double altitude = 0d;
Location location = new Location(FAKE_LOCATION);
location.setLatitude(latitude);
location.setLongitude(longitude);
location.setBearing(5);
location.setSpeed(5);
location.setAltitude(altitude);
location.setTime(System.currentTimeMillis());
location.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
location.setProvider(LocationManager.GPS_PROVIDER);
location.setAccuracy(100);
LocationManager locationManager = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
locationManager.setTestProviderLocation(FAKE_LOCATION, location);
onLocationChanged(location);
try
{
Thread.sleep(200);
if(Thread.currentThread().isInterrupted())
throw new InterruptedException("");
}
catch (InterruptedException e)
{
other.setText("doInBackground");
}
return null;
}
@Override
protected void onProgressUpdate(Integer... values)
{
other.setText("Actualizando...");
}
}
}
Манифест
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.a">
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"
tools:ignore="MockLocation,ProtectedPermissions" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
build.gradle (приложение)
apply plugin: 'com.android.application'
android {
compileSdkVersion 28
defaultConfig {
applicationId "com.example.a"
minSdkVersion 27
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
multiDexEnabled true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies
{
implementation 'com.google.android.gms:play-services-location:16.0.0'
//noinspection UseOfBundledGooglePlayServices
implementation 'com.google.android.gms:play-services:12.0.1'
implementation 'com.google.android.gms:play-services-base:16.1.0'
implementation 'com.google.android.gms:play-services-places:16.0.0'
implementation 'com.android.support:multidex:1.0.3'
}
Build.gradle (projecto)
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.2'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
subprojects {
project.configurations.all {
resolutionStrategy.eachDependency { details ->
if (details.requested.group == 'com.google.android.gms'
amp;amp; !details.requested.name.contains('multidex') ) {
details.useVersion "12.0.1"
}
}
}
}
}
}
allprojects {
repositories {
google()
jcenter()
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@ id/linearLayout1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="40dip"
android:orientation="horizontal" >
<TextView
android:id="@ id/TextView01"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="5dip"
android:text="Latitude: "
android:textSize="20dip" >
</TextView>
<TextView
android:id="@ id/TextView02"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="unknown"
android:textSize="20dip" >
</TextView>
</LinearLayout>
<LinearLayout
android:id="@ id/linearLayout2"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@ id/TextView03"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="5dip"
android:text="Longitute: "
android:textSize="20dip" >
</TextView>
<TextView
android:id="@ id/TextView04"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="unknown"
android:textSize="20dip" >
</TextView>
</LinearLayout>
<LinearLayout
android:id="@ id/linearLayout3"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@ id/TextView05"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="5dip"
android:text="Provider: "
android:textSize="20dip" >
</TextView>
<TextView
android:id="@ id/TextView06"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="unknown"
android:textSize="20dip" >
</TextView>
</LinearLayout>
<LinearLayout
android:id="@ id/linearLayout4"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@ id/TextView07"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="5dip"
android:text="Other info: "
android:textSize="20dip" >
</TextView>
<TextView
android:id="@ id/TextView08"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="unknown"
android:textSize="20dip" >
</TextView>
</LinearLayout>
<LinearLayout
android:id="@ id/linearLayout5"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<TextView
android:id="@ id/TextView09"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:layout_marginRight="5dip"
android:text="Provider List: "
android:textSize="20dip" >
</TextView>
<TextView
android:id="@ id/TextView10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="unknown"
android:textSize="20dip" >
</TextView>
</LinearLayout>
</LinearLayout>
Ответ №1:
Приложения должны явно запрашивать положение ложного местоположения. Если они не запрашивают макет, они получат реальное местоположение независимо от того, существует ли макет. Большинство разработчиков не оставляют запрос ложного разрешения в коде выпуска, чтобы приложение не было обмануто.
В общем, ложное местоположение — это инструмент для отладки ваших приложений, использующих местоположение, а не инструмент для обмана приложений, которые не хотят отлаживаться.