健康证明的数字化在疫苗接种记录、体检报告、国际旅行健康凭证等场景中被广泛采用,Android作为全球用户量最大的移动操作系统,承载了大量健康证明类应用的开发需求。本文将从数据模型、密钥签名、二维码展示与验证、安全加固四个方面,完整讲解Android端健康证明功能的实现思路与代码实践。

一、健康证明的数据模型设计
设计健康证明的第一步是定义清晰的数据结构。一份典型的健康证明通常包含持有人信息(姓名、证件号、出生日期)、健康数据(疫苗接种记录、检测结果、有效期限)以及签发方信息(签发机构、签发时间、数字签名)。国际上比较通用的规范是欧盟数字证书所采用的HCERT结构,它使用CBOR编码承载数据,再通过COSE进行签名封装,最后以Base45编码生成二维码内容。这套方案的优点是压缩率高、签名机制成熟,适合在扫码场景下传输有限的数据量。
在Android端落地时,可以先定义一个简单直观的数据模型。例如:
public class HealthCertificate {
private String holderName; // 持有人姓名
private String holderId; // 证件号码
private String vaccineName; // 疫苗或检测名称
private String doseNumber; // 接种剂次
private String dateOfVaccination; // 接种日期
private String issuer; // 签发机构
private long validUntil; // 有效期截止时间戳
private String signature; // 数字签名
// getter与setter省略
}如果只需实现私有体系,可以直接用JSON序列化后签名;如果要与国际规范接轨,则建议引入CBOR相关的库,比如用Jackson的cbor模块处理HCERT格式。两种方式在数据结构上大同小异,核心区别在于编码效率和跨平台互认能力,开发者应根据业务场景选择。
二、使用Android Keystore完成签名与验签
健康证明最核心的安全要求是不可伪造、不可篡改,这必须依赖数字签名。签名的正确做法是:签发方在服务端使用私钥对证明数据签名,客户端只持有公钥用于验签,私钥绝不能下发到终端。而对于Android端本地生成的个人健康记录,如果需要具备抗抵赖性,可以使用Android Keystore系统在安全硬件(TEE或StrongBox)中生成不可导出的密钥对。
下面演示如何通过Keystore生成用于签名的密钥对,并对健康证明数据做本地签名:
// 在Keystore中生成EC密钥对,密钥不可导出
KeyPairGenerator kpg = KeyPairGenerator.getInstance(
KeyProperties.KEY_ALGORITHM_EC, "AndroidKeyStore");
kpg.initialize(new KeyGenParameterSpec.Builder(
"health_cert_key",
KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY)
.setAlgorithmParameterSpec(new ECGenParameterSpec("secp256r1"))
.setDigests(KeyProperties.DIGEST_SHA256)
.build());
KeyPair keyPair = kpg.generateKeyPair();
// 对证明数据做SHA256摘要后签名
Signature signature = Signature.getInstance("SHA256withECDSA");
signature.initSign(keyPair.getPrivate());
signature.update(jsonBytes);
byte[] signBytes = signature.sign();验证端则从Keystore或内置证书中取出公钥完成验签:
Signature verify = Signature.getInstance("SHA256withECDSA");
verify.initVerify(publicKey);
verify.update(jsonBytes);
boolean isValid = verify.verify(signBytes);需要注意,Keystore生成的密钥与设备绑定,换机后原签名无法在本机复现,因此对于需要长期有效的证明,推荐由服务端统一签发,客户端只做展示与验签。这样既能保证私钥安全,也便于密钥轮换和吊销管理。
三、二维码生成与扫描验证的实现
健康证明最常见的展示载体是二维码。Android端生成二维码可以使用ZXing库,将签名后的证明数据编码后渲染成图片。考虑到二维码容量限制,建议对数据做压缩处理,如果数据超过两千字节,普通的QR码扫码成功率会明显下降。
生成二维码的核心代码如下:
// build.gradle中引入 implementation 'com.google.zxing:core:3.5.2'
public Bitmap generateQrCode(String content, int size) {
Map<EncodeHintType, Object> hints = new HashMap<>();
hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M);
try {
BitMatrix matrix = new QRCodeWriter()
.encode(content, BarcodeFormat.QR_CODE, size, size, hints);
Bitmap bitmap = Bitmap.createBitmap(size, size, Bitmap.Config.RGB_565);
for (int x = 0; x < size; x++) {
for (int y = 0; y < size; y++) {
bitmap.setPixel(x, y, matrix.get(x, y) ? 0xFF000000 : 0xFFFFFFFF);
}
}
return bitmap;
} catch (WriterException e) {
return null;
}
}扫描验证方面,可以使用MLKit的条码扫描API,它基于设备端机器学习模型,识别速度和准确率都优于传统方案。扫描得到内容后,验证流程分为三步:先做Base45或Base64解码,再进行哈希验签,最后校验有效期与持有人信息。离线验证不依赖网络,适合口岸、场馆等弱网环境,但公钥更新需要随应用版本迭代;在线验证可以实时查询吊销列表,安全性更高,但要求网络可用。实际项目中通常两者结合,离线验签通过后再异步请求服务端做二次确认。
四、安全加固与隐私保护要点
健康数据属于敏感个人信息,开发时必须在安全上下功夫。首先是传输与存储加密,本地数据库建议使用SQLCipher加密,网络传输必须走HTTPS并配合证书锁定,防止中间人截获数据。其次是展示环节的防截屏,可以在展示健康证明的Activity中调用getWindow().setFlags(WindowManager.LayoutParams.FLAG_SECURE, WindowManager.LayoutParams.FLAG_SECURE),阻止截屏与录屏,降低证明图片被冒用的风险。
另一个容易被忽视的点是防伪造截图。一些成熟的方案会在二维码中加入时间戳和动态水印,二维码每隔三十秒刷新一次,包含当前时间的签名数据,这样即使截图泄露,验证时也会因为时间戳过期而失效。同时要限制二维码的刷新频率,避免过于频繁的刷新影响扫码体验。
最后是权限最小化原则。健康证明应用应只申请必要的权限,扫码使用相机权限即可,尽量避免读取通讯录、位置等无关权限。对于持有人照片等身份信息,展示时应做局部遮挡处理。遵循这些原则,配合前文的数据签名与验证机制,就能构建一套完整可信的Android健康证明方案,既满足业务需求,也符合个人信息保护的相关法规要求。
Android Health Certificate健康证明数字签名验证修改时间:2026-09-14 08:46:55