在移动端身份校验场景里,Android Signature Recognition签名识别指的是采集用户在屏幕上手写签名时的轨迹与行为特征,并以此判断操作者是否为本人。它属于行为生物特征识别范畴,和人脸、指纹这种生理特征不同,签名识别更关注书写过程中的动态习惯。系统通常会记录落笔坐标、时间戳、笔锋压力和接触面积,再把这些序列转成可计算的特征向量。

签名数据的采集与特征提取原理
Android平台上获取签名轨迹主要依赖触控事件分发机制。开发者可以在自定义View里重写onTouchEvent方法,从MotionEvent对象中拿到getX、getY、getEventTime以及getPressure等字段。原始点序列往往带有噪声,需要先做滤波与重采样,保证不同书写速度下点距相对均匀,这一步对后续比对稳定性非常关键。
特征提取阶段通常不会直接拿原始坐标去比对,而是构造更具区分度的描述子。常见做法包括计算轨迹的曲率变化、分段速度均值、整体书写时长,以及利用离散傅里叶变换把空间路径映射到频域。下面是一段简化版的轨迹重采样代码,用于把不均匀的点序列规整为固定数量的特征点:
import android.graphics.PointF;
import java.util.ArrayList;
import java.util.List;
public class Resampler {
public static List<PointF> resample(List<PointF> points, int n) {
float totalLen = 0;
for (int i = 1; i < points.size(); i++) {
float dx = points.get(i).x - points.get(i - 1).x;
float dy = points.get(i).y - points.get(i - 1).y;
totalLen += (float) Math.sqrt(dx * dx + dy * dy);
}
float interval = totalLen / (n - 1);
List<PointF> result = new ArrayList<>();
result.add(points.get(0));
float dist = 0;
int i = 1;
while (i < points.size() && result.size() < n) {
float dx = points.get(i).x - points.get(i - 1).x;
float dy = points.get(i).y - points.get(i - 1).y;
float d = (float) Math.sqrt(dx * dx + dy * dy);
if (dist + d >= interval) {
float t = (interval - dist) / d;
float nx = points.get(i - 1).x + t * dx;
float ny = points.get(i - 1).y + t * dy;
PointF np = new PointF(nx, ny);
result.add(np);
points.add(i, np);
dist = 0;
} else {
dist += d;
i++;
}
}
while (result.size() < n) {
result.add(points.get(points.size() - 1));
}
return result;
}
}
上述代码展示了重采样的基本思路,实际工程中还要处理压力维度与时间间隔的同步。如果只比对形状而忽略速度节奏,攻击者用照片描摹也能够通过,因此行为维度必须进入特征模板。经过提取后的模板通常以浮点数组形式存在,不应以明文图片保存在应用私有目录之外。
比对算法与阈值判定方案
由于每次签名的长度和节奏都不完全一致,不能直接做等长逐点相减。动态时间规整(DTW)是最常用的对齐算法,它允许两条序列在点级别上弹性匹配,找出累积距离最小的路径。DTW计算出的距离越小,说明两次签名越相似。在Android端可以预先用离线数据训练一个用户专属阈值,比如取注册阶段多次签名的内部最大距离乘以安全系数。
除了DTW,也有团队使用隐马尔可夫模型或神经网络编码器把签名压成固定维度向量,再用余弦相似度判断。下表对比了几种常见方案的差异:
| 方案 | 优点 | 缺点 |
|---|---|---|
| DTW | 无需训练,小样本可用 | 计算量随序列增长较快 |
| HMM | 对节奏建模自然 | 注册样本需较多 |
| 神经网络 | 精度高且可端侧加速 | 初期开发与数据成本大 |
在普通业务App中,DTW往往是最务实的选择。下面示例演示了如何用简单欧氏距离配合重采样结果做粗略比对,真实项目会把距离函数换成DTW并加入压力权重:
public static float compare(List<PointF> a, List<PointF> b) {
if (a.size() != b.size()) return Float.MAX_VALUE;
float sum = 0;
for (int i = 0; i < a.size(); i++) {
float dx = a.get(i).x - b.get(i).x;
float dy = a.get(i).y - b.get(i).y;
sum += dx * dx + dy * dy;
}
return (float) Math.sqrt(sum);
}
阈值设定不能一刀切,不同用户的书写稳定性差异很大。建议在注册流程中让用户连续签三到五次,取它们之间距离的平均值再加缓冲作为接受边界。同时系统应当统计拒绝率,防止因为屏幕误触或手指湿润导致合法用户被挡在门外。
Android端安全集成与隐私保护
签名识别若用在支付或登录等高敏感环节,特征数据绝不能明文存放在SharedPreferences或外部存储。应优先借助Android Keystore生成非对称密钥,把特征模板加密后再落盘,或者更进一步放入StrongBox等硬件隔离区域。提取阶段也要防止被恶意悬浮窗录屏,建议在签名View上设置setSecure标志屏蔽截图。
从隐私合规角度看,签名轨迹属于个人生物特征信息,收集前必须明确告知用途并获授权。许多团队会把Signature Recognition作为多因子认证中的辅助因子,而不是唯一凭证。这样即使模板泄露,攻击者也难以仅凭签名复刻完整身份。下面的配置片段展示了在签名View上启用安全显示并限制输入来源的写法:
<com.example.SignatureView
android:layout_width="match_parent"
android:layout_height="200dp"
android:focusable="true"
android:secure="true" />
最后需要强调的是,签名识别的体验优化和算法一样重要。初次使用应提供引导动画,告诉用户用惯常速度书写而非刻意描字。后台可记录每次比对的距离分布,当某用户近期拒绝率突增时提示重新注册,既保障安全也降低投诉。把行为特征与系统级生物识别API结合,才能在易用和稳妥之间找到平衡。
AndroidSignature_Recognitionbiometric修改时间:2026-08-16 23:10:35