Android 11+设备Espresso测试中模拟位置提供者启用异常排查
新版Android(11+)正确启用模拟位置的解决方案
在Android 11及以上版本中,系统对位置测试提供者的行为做了更严格的校验:如果测试提供者没有输出有效位置数据,系统会判定其不可用,进而触发onProviderDisabled回调。这就是你遇到的启用测试提供者后不久收到disabled回调的原因。
以下是修正后的实现步骤:
1. 确保测试应用具备模拟位置权限
在测试应用的AndroidManifest.xml中添加权限声明:
<uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION" android:maxSdkVersion="30" />
对于Android 11+,该权限属于签名级权限,instrumented测试应用与目标应用签名一致时会自动授予。也可以通过adb命令预先授权:
adb shell appops set com.your.test.package android:mock_location allow
2. 修正测试提供者的初始化逻辑
初始化测试提供者时,除了设置启用状态,还要主动标记提供者为可用状态,避免系统误判:
locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE); // 先移除已存在的同名测试提供者,避免重复添加报错 if (locationManager.getProvider(LOCATION_PROVIDER_NAME) != null) { locationManager.removeTestProvider(LOCATION_PROVIDER_NAME); } // 添加测试提供者 locationManager.addTestProvider(LOCATION_PROVIDER_NAME, false, false, false, false, true, true, true, LocationManager.POWER_USAGE_HIGH, ProviderProperties.ACCURACY_FINE); // 关键:设置提供者状态为可用 locationManager.setTestProviderStatus(LOCATION_PROVIDER_NAME, LocationProvider.AVAILABLE, null, System.currentTimeMillis()); // 初始设置为禁用 locationManager.setTestProviderEnabled(LOCATION_PROVIDER_NAME, false);
3. 启用测试提供者后发送有效位置数据
启用测试提供者后,必须立即发送至少一条模拟位置数据,让系统确认该提供者能正常输出位置:
locationManager.setTestProviderEnabled(LOCATION_PROVIDER_NAME, true); // 构造并发送模拟位置 Location mockLocation = new Location(LOCATION_PROVIDER_NAME); mockLocation.setLatitude(39.9042); // 示例纬度(北京) mockLocation.setLongitude(116.4074); // 示例经度 mockLocation.setAccuracy(5.0f); mockLocation.setTime(System.currentTimeMillis()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos()); } locationManager.setTestProviderLocation(LOCATION_PROVIDER_NAME, mockLocation); // 避免使用SystemClock.sleep,推荐用Espresso的IdlingResource或await方法等待回调 // 例如:Espresso.onView(isRoot()).perform(waitFor(200));
额外注意事项
- 不要依赖
SystemClock.sleep,改用Espresso的等待机制更可靠,避免测试不稳定。 - 测试完成后记得移除测试提供者,避免影响后续测试:
@After public void tearDown() { if (locationManager != null && locationManager.getProvider(LOCATION_PROVIDER_NAME) != null) { locationManager.removeTestProvider(LOCATION_PROVIDER_NAME); } }
内容的提问来源于stack exchange,提问作者Laurent D.
相关产品推荐
相关产品推荐

