Firebase Test Lab中Location API及谷歌地图异常的解决咨询
Firebase Test Lab中使用位置服务的可行方案及问题排查
核心结论
Firebase Test Lab(FTL)支持位置服务,但需要适配FTL的特殊测试环境,同时修正密钥配置和测试Mock逻辑的问题。
一、修正测试中的位置Mock逻辑
你目前Mock了IsUserLocal用例,但FusedLocationProviderClient的回调仍无响应,说明Mock没有覆盖到FTL中实际触发的位置请求路径:
- 确保完全Mock FusedLocationProviderClient的相关方法,而不仅仅是业务层的
IsUserLocal判断。比如在Instrumented测试中,用Mockito或自定义Fake类替代真实的客户端:// 示例:用Mockito Mock FusedLocationProviderClient val mockLocationClient = mock(FusedLocationProviderClient::class.java) val mockLocation = Location("mock_provider").apply { latitude = 37.7749 longitude = -122.4194 } `when`(mockLocationClient.lastLocation).thenReturn(Task.forResult(mockLocation)) // 将Mock实例注入到你的位置服务依赖中 - 避免在测试中依赖真实的Location API回调,FTL测试设备可能限制了后台位置服务的主动触发,直接Mock返回预期位置或业务结果更可靠。
二、解决API密钥的安全异常
日志中的包名和SHA256不匹配问题,是FTL测试设备的特殊签名导致的:
- FTL运行测试时,会使用Firebase测试签名证书重新签名你的APK,而非你本地的开发/发布签名。你需要把FTL的SHA256指纹添加到Google Cloud控制台的API密钥限制中:
- 从FTL测试日志的安全异常信息里,提取测试设备使用的SHA256指纹;
- 打开Google Cloud控制台的「API和服务 -> 凭据」页面,找到你的Maps/位置API密钥,添加该SHA256指纹+应用包名的组合到密钥限制列表。
- 不要直接取消密钥限制(存在安全风险),优先添加FTL的签名指纹。
三、适配FTL的位置服务环境
即使配置正确,FTL的测试设备可能默认禁用了位置服务,需要在测试代码中主动启用:
- 在Instrumented测试的
@Before方法中,通过系统设置启用高精度定位:@Before public void setupLocationSettings() { ContentResolver resolver = InstrumentationRegistry.getInstrumentation().getTargetContext().getContentResolver(); Settings.Secure.putString(resolver, Settings.Secure.LOCATION_MODE, String.valueOf(Settings.Secure.LOCATION_MODE_HIGH_ACCURACY)); } - 确保测试APK已声明
ACCESS_FINE_LOCATION或ACCESS_COARSE_LOCATION权限,同时用Espresso自动处理权限弹窗:// 处理位置权限授权弹窗 Espresso.onView(ViewMatchers.withId(android.R.id.button1)).perform(ViewActions.click())
四、解决地图空白问题
地图空白除了密钥问题,还可能是FTL设备的组件兼容问题:
- 确保应用使用最新版的Google Maps SDK for Android,旧版本可能和FTL设备的系统版本不兼容;
- 用Espresso的
IdlingResource等待地图加载完成,避免测试操作过早执行:class MapIdlingResource(private val googleMap: GoogleMap?) : IdlingResource { private var callback: IdlingResource.ResourceCallback? = null override fun getName() = "MapIdlingResource" override fun isIdleNow(): Boolean { val isIdle = googleMap?.isLoaded == true if (isIdle) callback?.onTransitionToIdle() return isIdle } override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback?) { this.callback = callback } } // 测试中使用 val mapIdlingResource = MapIdlingResource(supportMapFragment.map) IdlingRegistry.getInstance().register(mapIdlingResource) // 执行测试操作 IdlingRegistry.getInstance().unregister(mapIdlingResource)
内容的提问来源于stack exchange,提问作者Barry Irvine
相关产品推荐
相关产品推荐

