Android10 mockLocation 模拟定位

网上搜了半天,试了很多方法,大同小异,当然报错也是大同小异……

最经典的报错就是 IllegalArgumentException: Provider "gps" already exists 

这里介绍一下如何解决这个问题,并且给出正确的模拟定位方法。

首先当然是先在AndroidManifest里申请权限了

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"
        tools:ignore="MockLocation,ProtectedPermissions"/>

在Android 10里定位是危险权限,如果不是在编译系统的时候打包的apk,就需要动态申请权限:

private void initPermissions(Context context) {
        RequestPermissions(context, "android.permission.ACCESS_FINE_LOCATION");
        RequestPermissions(context, "android.permission.ACCESS_COARSE_LOCATION");
        RequestPermissions(context,"android.permission.ACCESS_MOCK_LOCATION");
    }

    public static boolean RequestPermissions(Context context, String permission) {
        if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
            Log.i("requestMyPermissions", ": 【 " + permission + " 】没有授权,申请权限");
            ActivityCompat.requestPermissions((Activity) context, new String[]{permission}, 100);
            return false;
        } else {
            Log.i("requestMyPermissions", ": 【 " + permission + " 】有权限");
            return true;
        }
    }

然后就是获取LocationManager、构建location 注意location参数必须设满,否则会报不完整错误:

java.lang.IllegalArgumentException: Incomplete location object

mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

        Location mockLocation = new Location(GPS_PROVIDER);
        mockLocation.setLatitude(116.397128);
        mockLocation.setLongitude(39.916527);
        mockLocation.setAltitude(0);
        mockLocation.setTime(System.currentTimeMillis());
        mockLocation.setSpeed(0.01f);
        mockLocation.setBearing(1f);
        mockLocation.setAccuracy(3f);
        mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            mockLocation.setBearingAccuracyDegrees(0.1f);
            mockLocation.setVerticalAccuracyMeters(0.1f);
            mockLocation.setSpeedAccuracyMetersPerSecond(0.01f);
        }

下一步就是直接mock location了:

这里需要在addTestProvider之前remove一次,否则会报 Provider "gps" already exists 

源码:frameworks/base/services/core/java/com/android/server/LocationManagerService.java

    @Override
    public void addTestProvider(String name, ProviderProperties properties, String opPackageName) {
        if (!canCallerAccessMockLocation(opPackageName)) {
            return;
        }

        if (PASSIVE_PROVIDER.equals(name)) {
            throw new IllegalArgumentException("Cannot mock the passive location provider");
        }

        synchronized (mLock) {
            long identity = Binder.clearCallingIdentity();
            try {
                LocationProvider oldProvider = getLocationProviderLocked(name);
                if (oldProvider != null) {
                    if (oldProvider.isMock()) {
                        throw new IllegalArgumentException(
                                "Provider \"" + name + "\" already exists");
                    }

                    removeProviderLocked(oldProvider);
                }

mock代码:

public void mockGps(Location location) throws SecurityException {
        location.setProvider(GPS_PROVIDER);
        try{
            // @throws IllegalArgumentException if a provider with the given name already exists
            mLocationManager.addTestProvider(GPS_PROVIDER, false, false, false, false, false, true, true, 0, 5);
        }  catch (IllegalArgumentException ignored){}

        try{
            // @throws IllegalArgumentException if no provider with the given name exists
            mLocationManager.setTestProviderEnabled(GPS_PROVIDER, true);
        } catch (IllegalArgumentException ignored){
            mLocationManager.addTestProvider(GPS_PROVIDER, false, false, false, false, false, true, true, 0, 5);
        }

        try{
            // @throws IllegalArgumentException if no provider with the given name exists
            mLocationManager.setTestProviderLocation(GPS_PROVIDER, location);
        } catch (IllegalArgumentException ignored){
            // IllegalArgumentException: Provider "gps" already exists
            mLocationManager.removeTestProvider(GPS_PROVIDER);
            mLocationManager.addTestProvider(GPS_PROVIDER, false, false, false, false, false, true, true, 0, 5);
            mLocationManager.setTestProviderEnabled(GPS_PROVIDER, true);
            mLocationManager.setTestProviderLocation(GPS_PROVIDER, location);
        }
    }

如此一来就模拟成功了,当然安装apk成功后,记得在开发者模式里设置 “选择模拟位置信息位置 ”为当前app。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android应用程序中模拟定位,可以按照以下步骤进行: 1. 在应用程序的build.gradle文件中,添加以下依赖项: ``` implementation 'com.google.android.gms:play-services-location:17.1.0' ``` 2. 在应用程序中创建一个LocationProvider类,该类实现LocationProvider接口: ```java public class MockLocationProvider implements LocationProvider { private LocationManager locationManager; private String providerName; public MockLocationProvider(Context context) { locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); providerName = LocationManager.GPS_PROVIDER; } @Override public void startMocking(Location location) { locationManager.setTestProviderEnabled(providerName, true); locationManager.setTestProviderStatus(providerName, LocationProvider.AVAILABLE, null, System.currentTimeMillis()); locationManager.setTestProviderLocation(providerName, location); } @Override public void stopMocking() { locationManager.setTestProviderEnabled(providerName, false); } } ``` 3. 在应用程序的MainActivity中使用MockLocationProvider类来模拟定位: ```java public class MainActivity extends AppCompatActivity { private MockLocationProvider mockLocationProvider; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mockLocationProvider = new MockLocationProvider(getApplicationContext()); Location mockLocation = new Location(LocationManager.GPS_PROVIDER); mockLocation.setLatitude(37.422); mockLocation.setLongitude(-122.084); mockLocationProvider.startMocking(mockLocation); } @Override protected void onDestroy() { super.onDestroy(); mockLocationProvider.stopMocking(); } } ``` 在上面的示例中,我们在MainActivity的onCreate方法中使用MockLocationProvider类来模拟一个位置,然后在MainActivity的onDestroy方法中停止模拟定位。请注意,模拟定位需要您的设备或模拟器已经启用了开发者选项中的“允许模拟位置”。如果您需要模拟移动的定位,可以在MockLocationProvider类中使用Handler或Timer来更新位置
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值