biometric
Face ID / Touch ID 验证。
Face ID / Touch ID 本机身份确认,支持设备密码回退。
边界:只证明当前设备用户通过了系统认证,不能替代服务器登录。敏感数据仍用 keychain 保存,不要放进 storage。认证必须由用户动作触发,不要在 body() 里调用。
#模块概览
| 项 | 说明 |
|---|---|
| 导入 | import biometric |
| 适合做什么 | 打开安全笔记、API Key 页、隐私设置前的二次确认 |
| 调用时机 | 放在按钮回调;用户取消后不要循环弹窗 |
| 推荐顺序 | is_available() → authenticate_with_passcode(reason) → 检查 result["success"] |
| 结果判断 | 看 result.get("success"),不要把整个 dict 当 bool |
#快速开始
下面脚本检查设备能力并尝试解锁:
已复制
import biometric
print("类型:", biometric.biometric_type()) # face_id / touch_id / none
print("可用:", biometric.is_available())
if biometric.is_available():
result = biometric.authenticate_with_passcode("解锁安全笔记")
if result.get("success"):
print("已解锁")
else:
print("失败:", result.get("error", "用户取消"))
else:
print("当前设备不可用生物认证")
#AppUI 示例
认证由按钮触发;成功、取消、失败都写回界面,不打印敏感内容。
已复制
import appui
import biometric
TYPE_LABELS = {
"face_id": "Face ID",
"touch_id": "Touch ID",
"none": "不可用",
}
state = appui.State(
status="未验证",
bio_type=TYPE_LABELS.get(biometric.biometric_type(), "未知"),
available="是" if biometric.is_available() else "否",
message="点击按钮开始验证",
)
def unlock_biometric_only():
if not biometric.is_available():
state.message = "生物认证不可用,请检查系统设置"
return
result = biometric.authenticate("验证身份以继续")
_apply_result(result, "仅生物认证")
def unlock_with_passcode():
if not biometric.is_available():
state.message = "生物认证不可用,请检查系统设置"
return
result = biometric.authenticate_with_passcode("验证身份以继续")
_apply_result(result, "生物认证或设备密码")
def _apply_result(result, mode):
if result.get("success"):
state.batch_update(
status="已解锁",
message=f"{mode} · 认证成功",
)
else:
state.batch_update(
status="未解锁",
message=result.get("error", "用户取消或认证失败"),
)
def body():
return appui.NavigationStack(
appui.Form([
appui.Section("设备", [
appui.LabeledContent("类型", value=state.bio_type),
appui.LabeledContent("可用", value=state.available),
]),
appui.Section("验证", [
appui.Button("Face ID / Touch ID 解锁", action=unlock_biometric_only)
.button_style("bordered_prominent"),
appui.Button("允许设备密码回退", action=unlock_with_passcode),
]),
appui.Section("状态", [
appui.LabeledContent("结果", value=state.status),
appui.Text(state.message).foreground_color("secondaryLabel"),
]),
]).navigation_title("生物认证")
)
appui.run(body, state=state)
#API 参考
#速查
| API | 作用 |
|---|---|
biometric_type() | 返回 face_id / touch_id / none |
is_available() | 设备与系统设置是否可用 |
authenticate(reason) | 仅 Face ID / Touch ID |
authenticate_with_passcode(reason) | 生物认证 + 设备密码回退 |
#设备能力
biometric_type() — 当前支持的生物认证类型。
is_available() — 能否发起认证(硬件 + 系统设置均就绪)。
已复制
import biometric
bio = biometric.biometric_type()
if biometric.is_available():
...
#认证
authenticate(reason) — 只使用 Face ID / Touch ID,无密码回退。
authenticate_with_passcode(reason) — 推荐用于解锁流程;生物失败时可输入设备密码。
已复制
result = biometric.authenticate_with_passcode("打开安全笔记")
if result.get("success"):
# 继续读取 keychain 等操作
...
else:
print(result.get("error"))
返回字典常见字段:
| 字段 | 说明 |
|---|---|
success | 认证是否通过 |
error | 失败或取消时的原因 |
注意:reason 会显示在系统弹窗中,用简短中文说明用途,如「验证身份以查看 API Key」。
#常见错误
| 错误写法 | 后果 | 修正 |
|---|---|---|
在 body() 里 authenticate() | 刷新时反复弹窗 | 放进按钮回调 |
if biometric.authenticate(...): | dict 恒为真值 | 检查 result.get("success") |
| 认证成功打印 token | 敏感信息进日志 | 只显示「已解锁」 |
| 用户取消后反复弹窗 | 体验差 | 保持锁定并提示原因 |
#相关文档
| 文档 | 用途 |
|---|---|
| keychain | 认证通过后读取 token |
| permission | 统一权限查询 |
| 原生能力入口 | MiniApp 场景配方 |
#预期效果
运行示例后,界面应出现文档描述的目标结果;若与预期不符,先看「失败路径」并按返回值或日志排查。