npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

face-liveness-detector

v1.3.0

Published

A Capacitor plugin for iOS and Android that captures photos using the device camera at specified intervals or frame counts, and uploads them to a server API for face liveness detection. Supports multiple images and multiple action types.

Readme

face-liveness-detector

一个用于 iOS 和 Android 的 Capacitor 插件,通过 WebSocket 通信提供实时人脸活体检测功能。插件会定时捕获图像并通过 WebSocket 与后端进行实时通信,获得即时的动作验证和进度更新。

✨ 核心特性

  • 🔗 实时 WebSocket 通信:与后端进行即时双向通信
  • 📸 智能图像捕获:每 500ms 自动捕获和压缩图像
  • 🎯 动态动作管理:后端控制所有动作和验证逻辑
  • 📊 实时进度更新:从 0% 到 100% 的实时进度跟踪
  • 📱 跨平台支持:iOS 和 Android 原生实现
  • 🔄 自动动作流转:基于后端响应无缝切换动作
  • ⚡ 无倒计时延迟:立即开始检测,无等待时间
  • 🛡️ 全面错误处理:强大的错误处理和重试机制
  • 🔍 自动相机缩放:设置相机到最小缩放以获得更广视野
  • 📐 智能帧检测:向后端发送精确的帧坐标用于准确检测
  • 🎨 可自定义 UI:支持完整的 UI 主题和颜色定制

安装

npm install face-liveness-detector
npx cap sync

工作原理

插件使用基于 WebSocket 的实时通信方法:

  1. WebSocket 连接:建立与后端的持久连接
  2. 会话初始化:发送 start_session 命令开始检测
  3. 相机设置:自动将相机设置为最小缩放以获得最佳视野
  4. 连续图像捕获:每 500ms 捕获、旋转和压缩图像
  5. 帧坐标传输:随每张图像发送检测帧坐标
  6. 实时验证:后端处理图像并立即响应
  7. 动态动作流:后端控制执行哪些动作以及何时执行
  8. 实时进度更新:从 0% 到 100% 的实时进度更新
  9. action_done 完成:只有收到 action_done 事件才认为检测完成

使用方法

import { liveness } from "face-liveness-detector";

async function startWebSocketDetection() {
    // 检查相机权限
    const checkResult = await liveness.checkCameraPermission();
    if (!checkResult.granted) {
        await liveness.requestCameraPermission();
        return;
    }

    // 开始 WebSocket 活体检测
    const options = {
        token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", // 认证令牌
        host: "your-server.com:9966", // 服务器地址和端口
        wsUrl: "ws://your-server.com:9966/face-recognize?token=...", // 完整 WebSocket URL
        captureInterval: 500, // 可选:图像捕获间隔(毫秒)
        autoRotateCamera: true, // 自动旋转相机预览
        enableFaceDetectionFrame: true, // 启用人脸检测框
        nativeUI: {
            backgroundColor: "#000000",
            textColor: "#FFFFFF", 
            primaryColor: "#FF9800",  
            cameraFrameColor: "#00FF00",
            showProgressBar: true,
            showCancelButton: true,
            useNativeAnimations: true, // 启用原生动画
            customTexts: {
                lookLeft: "请向左转头",
                lookRight: "请向右转头",
                lookUp: "请向上抬头",
                lookDown: "请向下低头",
                headShake: "请左右摇头",
                nod: "请上下点头",
                cancel: "取消"
            }
        }
    };

    try {
        const result = await liveness.startSmartLivenessDetection(options);
        console.log("检测结果:", result);
        
        if (result.success && result.pass) {
            console.log("✅ 活体检测通过!");
            console.log(`进度: ${(result.progress * 100).toFixed(1)}%`);
            console.log(`耗时: ${(result.totalDuration / 1000).toFixed(2)}秒`);
            
            // 处理完成的动作
            if (result.completedActions) {
                console.log("完成的动作:", result.completedActions);
            }
            
            // 处理成功的图像
            if (result.successfulActionImages) {
                console.log("成功图像数量:", result.successfulActionImages.length);
                result.successfulActionImages.forEach(actionImage => {
                    console.log(`${actionImage.action}: ${actionImage.count}张图片`);
                });
            }
            
        } else if (result.cancelled) {
            console.log("🚫 检测被用户取消");
        } else {
            console.log("❌ 活体检测失败:", result.errorMsg);
        }
    } catch (error) {
        console.error("检测错误:", error);
    }
}

🔧 配置参数

核心参数

| 参数 | 类型 | 必需 | 默认值 | 描述 | |------|------|------|--------|------| | token | string | ✅ | - | 认证令牌 | | host | string | ✅ | - | 服务器地址和端口 | | wsUrl | string | ✅ | - | 完整的 WebSocket URL(包含令牌) | | captureInterval | number | ❌ | 500 | 图像捕获间隔(毫秒) |

相机和 UI 行为

| 参数 | 类型 | 默认值 | 描述 | |------|------|--------|------| | autoRotateCamera | boolean | true | 自动旋转相机预览以匹配设备方向 | | enableFaceDetectionFrame | boolean | true | 显示圆形人脸检测叠加层 |

UI 自定义 (nativeUI)

interface NativeUIConfig {
    backgroundColor?: string;         // 背景颜色 (hex) - 默认: "#000000"
    textColor?: string;              // 文本颜色 (hex) - 默认: "#FFFFFF"
    primaryColor?: string;           // 主要强调色 (hex) - 默认: "#FF9800"
    cameraFrameColor?: string;       // 相机框颜色 (hex) - 默认: "#00FF00"
    showProgressBar?: boolean;       // 显示进度指示器 - 默认: true
    showCancelButton?: boolean;      // 显示取消按钮 - 默认: true
    useNativeAnimations?: boolean;   // 启用原生动画 - 默认: false
    customTexts?: {                  // 自定义文本翻译
        lookLeft?: string;           // "向左看" 文本
        lookRight?: string;          // "向右看" 文本
        lookUp?: string;             // "向上看" 文本
        lookDown?: string;           // "向下看" 文本
        headShake?: string;          // "摇头" 文本
        nod?: string;                // "点头" 文本
        cancel?: string;             // 取消按钮文本
    };
}

📤 响应格式

成功响应

成功完成所有活体检测动作后,返回的结果包含详细的动作信息和图片文件列表:

{
  "success": true,
  "pass": true,
  "progress": 1,
  "content": "[{\"actionType\":\"NOD\",\"pass\":true,\"passedFiles\":[{\"id\":\"1ef3ed7b-1e8c-43a7-be1d-38873b0638ea\",\"name\":\"face_verify_e9ce8f51-fae5-4643-93bd-c41f746b7ca3.jpg\"},{\"id\":\"a616dddf-7361-4089-aa76-acc63e48e815\",\"name\":\"face_verify_42c1b23f-7f05-4b72-b32b-916636f3323a.jpg\"},{\"id\":\"be598050-952d-4852-807d-90c24c1849a5\",\"name\":\"face_verify_e6b594b5-55e6-4782-8a8c-d5be96af6ab2.jpg\"}],\"actionDescription\":\"请点点头\"},{\"actionType\":\"MOUTH\",\"pass\":true,\"passedFiles\":[{\"id\":\"3fee65c6-2bd4-4f89-b1d2-c929ecdd41d6\",\"name\":\"face_verify_7bd8f40a-5504-406d-a7e5-9a273010df70.jpg\"},{\"id\":\"6f4fdd26-7188-4ffc-ac6d-0340aae39f2e\",\"name\":\"face_verify_05aa22de-c04f-41ce-ade3-1238d30dd355.jpg\"},{\"id\":\"1503f71e-3f5e-4594-b11a-bb286d205240\",\"name\":\"face_verify_a8b12597-971b-4a2e-bffb-e9e3b5dd34cb.jpg\"}],\"actionDescription\":\"请开合嘴巴\"}]",
  "totalDuration": 19174
}

content 字段解析后的结构:

[
  {
    "actionType": "NOD",           // 动作类型:点头
    "pass": true,                  // 是否通过
    "passedFiles": [               // 通过验证的图片文件
      {
        "id": "1ef3ed7b-1e8c-43a7-be1d-38873b0638ea",
        "name": "face_verify_e9ce8f51-fae5-4643-93bd-c41f746b7ca3.jpg"
      },
      {
        "id": "a616dddf-7361-4089-aa76-acc63e48e815",
        "name": "face_verify_42c1b23f-7f05-4b72-b32b-916636f3323a.jpg"
      },
      {
        "id": "be598050-952d-4852-807d-90c24c1849a5",
        "name": "face_verify_e6b594b5-55e6-4782-8a8c-d5be96af6ab2.jpg"
      }
    ],
    "actionDescription": "请点点头"
  },
  {
    "actionType": "MOUTH",         // 动作类型:张嘴
    "pass": true,
    "passedFiles": [
      {
        "id": "3fee65c6-2bd4-4f89-b1d2-c929ecdd41d6",
        "name": "face_verify_7bd8f40a-5504-406d-a7e5-9a273010df70.jpg"
      },
      {
        "id": "6f4fdd26-7188-4ffc-ac6d-0340aae39f2e",
        "name": "face_verify_05aa22de-c04f-41ce-ade3-1238d30dd355.jpg"
      },
      {
        "id": "1503f71e-3f5e-4594-b11a-bb286d205240",
        "name": "face_verify_a8b12597-971b-4a2e-bffb-e9e3b5dd34cb.jpg"
      }
    ],
    "actionDescription": "请开合嘴巴"
  }
]

失败响应

{
  success: false,
  pass: false,
  errorMsg: "WebSocket连接失败: Connection timeout",
  progress: 0.0,
  content: "",
  totalDuration: 5000
}

取消响应

{
  success: false,
  pass: false, 
  cancelled: true,
  errorMsg: "Detection cancelled by user",
  progress: 0.3,
  totalDuration: 8000
}

关键响应字段

| 字段 | 类型 | 描述 | |------|------|------| | success | boolean | 整体操作是否成功 | | pass | boolean | 所有动作是否通过验证 |
| progress | number | 最终进度 (0.0 到 1.0) | | content | string | 后端返回的详细内容(JSON字符串格式,包含所有动作的详细信息和通过的图片文件列表) | | totalDuration | number | 总检测时间(毫秒) | | cancelled | boolean | 用户是否取消了检测 | | errorMsg | string? | 失败时的错误消息 |

Content 字段说明:

content 字段是一个 JSON 字符串,解析后包含每个动作的详细信息:

  • actionType: 动作类型(如 NOD、MOUTH、LOOK_LEFT 等)
  • pass: 该动作是否通过验证
  • passedFiles: 通过验证的图片文件数组
    • id: 文件唯一标识
    • name: 文件名称
  • actionDescription: 动作的描述文本

🔄 WebSocket 通信协议

消息流程

  1. 建立连接

    Client -> Server: WebSocket 连接到 ws://host/face-recognize?token=...
  2. 会话开始

    Client -> Server: {"cmd": "start_session"}
  3. 动作初始化

    Server -> Client: {
      "cmd": "action_init",
      "content": "[{\"action\":\"NOD\",\"actionDescription\":\"请点点头\"},{\"action\":\"MOUTH\",\"actionDescription\":\"请开合嘴巴\"}]",
      "progress": 0.0
    }
  4. 图像提交 (每 500ms 带帧坐标)

    Client -> Server: {
      "cmd": "action_input", 
      "action": "NOD",
      "images": ["base64_image_data"],
      "frameInfos": [{
        "imageWidth": 320,
        "imageHeight": 240, 
        "centerX": 160,
        "centerY": 96,
        "radius": 64
      }]
    }
  5. 动作进度更新

    Server -> Client: {
      "cmd": "action_output",
      "content": "[{\"actionType\":\"NOD\",\"pass\":false},{\"actionType\":\"MOUTH\",\"pass\":false}]",
      "progress": 0.25
    }
  6. 通知消息 (可选)

    Server -> Client: {
      "cmd": "action_notify",
      "content": "请将脸部放入框内"
    }
  7. 错误处理

    Server -> Client: {
      "cmd": "action_error", 
      "content": "Face quality check failed",
      "progress": 0.0
    }
  8. 完成 (只有收到 action_done 才认为检测完成)

    Server -> Client: {
      "cmd": "action_done",
      "content": "[{\"actionType\":\"NOD\",\"pass\":true,\"passedFiles\":[{\"id\":\"...\",\"name\":\"...jpg\"}]},{\"actionType\":\"MOUTH\",\"pass\":true,\"passedFiles\":[{\"id\":\"...\",\"name\":\"...jpg\"}]}]",
      "progress": 1.0
    }

重要提示: 插件只在收到 action_done 事件时才认为检测完成并返回结果,不会根据 progress >= 1.0 来判断完成。这确保了完整的检测流程由后端控制。

🎨 UI 主题示例

深色主题

const darkTheme = {
    backgroundColor: "#1a1a1a",
    textColor: "#ffffff", 
    primaryColor: "#007AFF",
    cameraFrameColor: "#00ff00",
    showProgressBar: true,
    showCancelButton: true,
    useNativeAnimations: true
};

浅色主题

const lightTheme = {
    backgroundColor: "#ffffff",
    textColor: "#333333",
    primaryColor: "#ff6b35", 
    cameraFrameColor: "#007AFF",
    showProgressBar: true,
    showCancelButton: true,
    useNativeAnimations: false
};

极简 UI

const minimalUI = {
    backgroundColor: "#000000",
    textColor: "#ffffff",
    cameraFrameColor: "#ffffff",
    showProgressBar: false,
    showCancelButton: false,
    useNativeAnimations: true
};

📡 后端集成指南

WebSocket 服务器要求

你的 WebSocket 服务器应该处理以下消息类型:

1. 会话开始处理器

// 接收: {"cmd": "start_session"}
// 发送动作配置和描述
{
  "cmd": "action_init",
  "content": JSON.stringify([
    {"action": "LOOK_LEFT", "actionDescription": "请向左看"},
    {"action": "LOOK_RIGHT", "actionDescription": "请向右看"}
  ]),
  "progress": 0.0
}

2. 图像处理器

// 接收: {
//   "cmd": "action_input", 
//   "action": "LOOK_LEFT", 
//   "images": ["base64..."],
//   "frameInfos": [{"imageWidth": 320, "imageHeight": 240, ...}]
// }

// 处理活体检测并响应验证结果
{
  "cmd": "action_output", 
  "content": JSON.stringify([
    {"actionType": "LOOK_LEFT", "pass": true}
  ]),
  "progress": 0.5
}

3. 可选通知

{
  "cmd": "action_notify",
  "content": "请将脸部完全放入框内"
}

4. 错误响应

{
  "cmd": "action_error",
  "content": "图像质量不足,请在光线充足的环境中使用", 
  "progress": 0.0
}

5. 完成响应

{
  "cmd": "action_done",
  "content": JSON.stringify([
    {"actionType": "LOOK_LEFT", "pass": true, "passedFiles": ["image1.jpg"]},
    {"actionType": "LOOK_RIGHT", "pass": true, "passedFiles": ["image2.jpg"]}
  ]),
  "progress": 1.0
}

🚀 主要优势

实时性能

  • 即时反馈:通过 WebSocket 获得即时验证结果
  • 优化捕获:500ms 间隔和压缩图像确保流畅检测
  • 动态流程:后端控制动作序列和时机
  • 实时通知:通过 action_notify 进行实时用户指导

增强的图像质量

  • 自动缩放:相机自动设置为最小缩放以获得更广视野
  • 智能压缩:图像调整为 320px 宽度,40% JPEG 质量
  • 帧坐标:随每张图像发送精确的检测区域坐标
  • 肖像优化:自动 -90° 旋转以获得最佳方向

简化架构

  • 后端控制:所有逻辑由服务器管理
  • 无状态客户端:插件纯粹专注于 UI 和图像捕获
  • 灵活动作:易于在服务器端添加新动作
  • 丰富消息:支持通知、错误和进度更新

增强用户体验

  • 无延迟:动作间自动进展
  • 实时进度:带通知的实时进度指示器
  • 响应式 UI:动作完成时的即时反馈
  • 可自定义:完整的 UI 主题和颜色自定义

API 参考

checkCameraPermission()

checkCameraPermission() => Promise<{ granted: boolean; message: string; }>

检查相机权限状态

返回值: Promise<{ granted: boolean; message: string; }>


requestCameraPermission()

requestCameraPermission() => Promise<{ granted: boolean; message: string; }>

向用户请求相机权限

返回值: Promise<{ granted: boolean; message: string; }>


startSmartLivenessDetection(...)

startSmartLivenessDetection(options: SmartLivenessOptions) => Promise<SmartLivenessResult>

使用 WebSocket 开始智能活体检测 - WebSocket版本 使用 WebSocket 实现实时活体检测,后端管理动作和会话

| 参数 | 类型 | | ------------- | ----------------------------------------------------------------- | | options | SmartLivenessOptions |

返回值: Promise<SmartLivenessResult>


接口

SmartLivenessOptions

智能活体检测配置 - WebSocket版本

| 属性 | 类型 | 描述 | | ------------------------------- | ------------------------------------------------------- | ----------------------------------------------- | | token | string | 认证令牌 | | host | string | 服务器地址和端口 | | wsUrl | string | WebSocket URL (包含认证token) | | captureInterval | number | 图片捕获间隔(毫秒),默认500ms | | nativeUI | NativeUIConfig | 原生UI配置(仅在原生平台生效) | | autoRotateCamera | boolean | 是否自动旋转相机预览以匹配设备方向 | | enableFaceDetectionFrame | boolean | 是否启用人脸检测框显示 |

SmartLivenessResult

智能活体检测结果 - WebSocket版本

| 属性 | 类型 | 描述 | | ------------------- | -------------------- | -------------------------------- | | success | boolean | 整体操作是否成功 | | pass | boolean | 所有动作是否都通过检测 | | errorMsg | string | 错误信息 | | progress | number | 检测进度 (0.0-1.0) | | content | string | 后端返回的内容(动作状态等) | | totalDuration | number | 总耗时(毫秒) | | cancelled | boolean | 是否被用户取消 | | completedActions | string[] | 成功完成的动作列表 | | successfulActionImages | object[] | 每个动作成功图像的统计信息 |

NativeUIConfig

原生UI配置选项

| 属性 | 类型 | 描述 | | ----------------------- | --------------------------------------------------------- | ----------------- | | backgroundColor | string | 背景颜色 (hex格式) | | textColor | string | 文字颜色 (hex格式) | | primaryColor | string | 主题颜色 (hex格式) | | cameraFrameColor | string | 相机预览框颜色 (hex格式) | | showProgressBar | boolean | 是否显示进度条 | | showCancelButton | boolean | 是否显示取消按钮 | | useNativeAnimations | boolean | 是否启用原生动画效果 | | customTexts | { lookLeft?: string; lookRight?: string; lookUp?: string; lookDown?: string; headShake?: string; nod?: string; cancel?: string; } | 自定义提示文本 |

类型别名

LivenessAction

'LOOK_LEFT' | 'LOOK_RIGHT' | 'LOOK_UP' | 'LOOK_DOWN' | 'HEAD_SHAKE' | 'NOD'

支持的活体检测动作类型(由后端动态管理)

🐛 故障排除

常见问题

  1. WebSocket 连接失败

    • 检查服务器是否运行并可访问
    • 验证 WebSocket URL 格式和令牌
    • 确保网络连接正常
  2. 相机权限被拒绝

    • 在开始检测前调用 checkCameraPermission()
    • 使用 requestCameraPermission() 请求权限
  3. 检测质量差

    • 确保光线条件良好
    • 检查人脸是否正确位于框内
    • 验证后端帧坐标处理
  4. 性能问题

    • 调整 captureInterval(较慢设备增加间隔)
    • 检查后端处理速度
    • 监控 WebSocket 消息频率

调试日志

启用调试日志以排除问题:

  • Android:按标签 LivenessDetectionActivity 过滤
  • 监控 WebSocket 消息流
  • 检查图像处理管道日志

📄 许可证

此项目采用 MIT 许可证 - 详细信息请参见 LICENSE 文件。

🤝 贡献

  1. Fork 仓库
  2. 创建你的功能分支
  3. 提交你的更改
  4. 推送到分支
  5. 创建 Pull Request

📞 支持

获取支持和问题咨询:

  • 在 GitHub 仓库中创建问题
  • 查看现有文档和示例
  • 审查 WebSocket 协议实现