Android平台的Contact Tracing(密接追踪)功能基于Google与Apple联合制定的Exposure Notification规范实现,其核心依赖低功耗蓝牙(BLE)广播与扫描来完成设备间近距离接触的记录。由于这套机制涉及系统级API、隐私限制和复杂的密钥轮换逻辑,开发者在测试阶段经常会遇到广播不可见、暴露密钥无法匹配、权限被系统静默拒绝等问题。本文将从原理、测试环境搭建和实际验证方法三个层面,完整梳理一套可落地的测试方案。

一、理解Contact Tracing的工作原理与角色分配
Contact Tracing的基本流程分为广播和扫描两个角色。处于发送模式的设备会通过BLE以固定间隔广播Rolling Proximity Identifier(滚动邻近标识符,简称RPI),而处于接收模式的设备则持续扫描周边的广播包,并将收到的RPI连同时间戳和信号强度一起写入本地数据库。当某个用户被确诊后,其诊断密钥会上传到服务器,其他设备下载这些密钥后,本地重新推导出对应的RPI,再与扫描记录比对,从而判断是否存在密切接触。
这里有一个容易被忽视的细节:RPI每10分钟左右会轮换一次,它由Temporary Exposure Key(TEK,每日轮换一次)通过HMAC推导生成。这意味着测试时不能简单地抓一次广播包就认为捕获了设备的全部标识,而是要验证轮换逻辑是否按预期触发。如果测试设备长时间静置,收到的RPI数量应该呈阶梯式增长,而不是一成不变。
另外需要注意,Exposure Notification API在Android上由Google Play Services提供,应用本身无法直接访问原始BLE广播数据,只能通过系统提供的接口获取已经过隐私处理的暴露信息。因此测试的第一步是确认设备上的Google Play Services版本是否支持该API,通常要求版本号在20.x以上。
二、搭建测试环境与准备测试代码
测试至少需要两台支持BLE的Android设备,一台作为广播端(模拟确诊者角色),一台作为扫描端(模拟接触者角色)。两台设备都需要安装Google Play Services,并且系统版本在Android 6.0以上。为了观察原始BLE包,建议再准备一台支持BLE嗅探的设备或使用nRF Connect工具辅助验证广播是否真实发出。
广播端的测试代码核心是获取TEK并启动广播。下面是一段简化的示例代码,展示了如何调用Exposure Notification API:
ExposureNotificationClient client =
ExposureNotification.getClient(context);
// 启动广播与扫描,需要用户授权
client.start()
.addOnSuccessListener(aVoid -> {
Log.d("TraceTest", "广播与扫描已启动");
})
.addOnFailureListener(e -> {
Log.e("TraceTest", "启动失败", e);
});
// 获取当前的TEK列表,用于模拟确诊者上传密钥
client.getTemporaryExposureKeyHistory()
.addOnSuccessListener(keys -> {
for (TemporaryExposureKey key : keys) {
Log.d("TraceTest",
"滚动周期: " + key.getRollingStartIntervalNumber());
}
});扫描端的验证则依赖provideDiagnosisKeys接口,将模拟的诊断密钥文件喂给系统,由系统完成本地匹配。测试时可以先在广播端导出TEK,打包成系统识别的密钥格式(通常是二进制或JSON的导出文件),再传输到扫描端调用匹配接口。
权限配置也是测试顺利进行的先决条件。除了蓝牙权限外,Android 12以上设备需要申请BLUETOOTH_SCAN和BLUETOOTH_ADVERTISE权限,部分国产ROM还会额外要求定位权限甚至后台弹窗白名单,建议在真机上逐一验证。
三、执行密接匹配验证与常见问题排查
完成环境搭建后,具体的验证流程如下:让广播端启动广播并保持开机30分钟以上,扫描端放在同一位置持续扫描;之后在广播端调用密钥导出接口,将TEK传给扫描端执行匹配。匹配结果通过ExposureSummary或ExposureInformation回调返回,重点关注匹配次数、接触持续时长和距离衰减估算值三个指标是否合理。
ExposureConfiguration config = new ExposureConfiguration.ExposureConfigurationBuilder()
.setMinimumRiskScore(1)
.setAttenuationThresholds(new int[]{55, 63})
.build();
client.provideDiagnosisKeys(keyFiles, token, config)
.addOnSuccessListener(aVoid -> {
Log.d("TraceTest", "密钥匹配完成,等待结果回调");
});如果匹配结果为空,排查思路建议按顺序执行:先用nRF Connect确认广播端确实发出了服务UUID为FD-6F开头的广播包(这是Exposure Notification协议约定的固定服务标识);再检查扫描端的电池优化设置,因为国产ROM普遍会冻结后台BLE扫描;最后确认两端设备的日期时间是否准确,RPI的推导与时间强相关,时间偏差超过一个滚动周期就会导致匹配失败。
还有一个高频问题是密钥历史获取需要用户在系统界面二次确认,无法在测试代码中静默完成。针对自动化测试,Google提供了开发者专用的mock模式,可以通过adb命令开启测试开关,让API返回预设的密钥数据,从而绕过用户交互环节,适合在CI流水线中做回归验证。
四、不同机型上的兼容性测试要点
由于Exposure Notification运行在Google Play Services之上,各机型的行为差异主要体现在后台调度策略而非API本身。测试时应覆盖三类设备:原生或近原生系统的机型(如Pixel)、深度定制的国产ROM机型,以及Android 12以下的旧设备。重点观察熄屏状态下扫描是否持续、RPI轮换周期是否稳定、以及系统重启后广播能否自动恢复。
信号衰减阈值也需要分场景校准。同样的两台设备,中间有无遮挡、是否贴身放置,收到的衰减值差异可能达到20dB以上,直接接触风险等级的计算结果。建议在测试用例中固定设备间距(如1米、2米、3米各一组),记录不同距离下的衰减分布,为线上配置合理的阈值提供数据支撑。
通过以上步骤,一套完整的Contact Tracing测试流程就搭建完成了。从广播验证、密钥导出到本地匹配和结果回调,每个环节都有明确的观测点和排查手段,开发者可以据此在真实机型上快速定位问题环节,保证密接追踪功能的可靠性。
AndroidContact Tracing密接追踪测试修改时间:2026-09-05 16:46:50