Token导航 LogoToken导航TokenDH.com
研究检索需要联网github未标认证来源可访问许可证需确认审计通过

android-biometric-loginAndroid 生物识别登录

Agent Skill

android-biometric-login 用于查找、检索和筛选相关信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要根据关键词、任务场景或来源线索快速定位候选结果时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

371

周安装

15

GitHub Stars

11

下载量

116
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:android-biometric-login(Android 生物识别登录)
来源仓库:https://github.com/peterbamuhigire/skills-web-dev
仓库路径:skills/android-biometric-login
安装命令:
npx skills add https://github.com/peterbamuhigire/skills-web-dev --skill android-biometric-login
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/peterbamuhigire/skills-web-dev --skill android-biometric-login

简介

用于 Android 应用的生物识别登录功能集成与流程验证。

  • 支持指纹/面部识别的启动页集成、设置开关联动及加密存储。
  • 提供 AndroidX Biometric API 的使用示例与异常处理最佳实践。
  • 适用于需要安全身份验证但非强制要求所有用户启用的场景。
  • 安装前请确认设备生物识别硬件支持情况及密钥管理合规要求。

SKILL.md

Platform Notes

  • Optional helper plugins may help in some environments, but they must not be treated as required for this skill.

Android Biometric Login

Acknowledgement: Shared by Peter Bamuhigire, techguypeter.com, +256 784 464178.

Use When

  • Optional biometric (fingerprint/face) gate on Android app launch using AndroidX Biometric API. Covers BiometricHelper utility, splash screen integration, settings toggle with verification, EncryptedSharedPreferences storage, and graceful...
  • The task needs reusable judgment, domain constraints, or a proven workflow rather than ad hoc advice.

Do Not Use When

  • The task is unrelated to android-biometric-login or would be better handled by a more specific companion skill.
  • The request only needs a trivial answer and none of this skill's constraints or references materially help.

Required Inputs

  • Gather relevant project context, constraints, and the concrete problem to solve.
  • Confirm the desired deliverable: design, code, review, migration plan, audit, or documentation.

Workflow

  • Read this SKILL.md first, then load only the referenced deep-dive files that are necessary for the task.
  • Apply the ordered guidance, checklists, and decision rules in this skill instead of cherry-picking isolated snippets.
  • Produce the deliverable with assumptions, risks, and follow-up work made explicit when they matter.

Quality Standards

  • Keep outputs execution-oriented, concise, and aligned with the repository's baseline engineering standards.
  • Preserve compatibility with existing project conventions unless the skill explicitly requires a stronger standard.
  • Prefer deterministic, reviewable steps over vague advice or tool-specific magic.

Anti-Patterns

  • Treating examples as copy-paste truth without checking fit, constraints, or failure modes.
  • Loading every reference file by default instead of using progressive disclosure.

Outputs

  • A concrete result that fits the task: implementation guidance, review findings, architecture decisions, templates, or generated artifacts.
  • Clear assumptions, tradeoffs, or unresolved gaps when the task cannot be completed from available context alone.
  • References used, companion skills, or follow-up actions when they materially improve execution.

Evidence Produced

CategoryArtifactFormatExample
SecurityBiometric authentication test planMarkdown doc covering fingerprint / face success, fallback, lockout, and DPC policy-change scenariosdocs/android/biometric-tests.md

References

  • Use the links and companion skills already referenced in this file when deeper context is needed.

Add optional fingerprint/face authentication as a gate on app launch. Uses the AndroidX Biometric library (BIOMETRIC_STRONG — Class 3 biometrics only). The feature is opt-in: users enable it in Settings, and it triggers on every app launch from the splash screen.

Overview

Flow: App launch → Splash → Check biometric pref → Show system biometric prompt → Success (Dashboard) or Failure (Login screen).

Key principles:

  • Optional, not mandatory — users choose to enable via a Settings toggle
  • Verify before enabling — require biometric auth to turn the feature ON (prevents unauthorized enabling)
  • Graceful degradation — if device has no biometric hardware, hide the toggle entirely
  • Survive logout — biometric preference persists across logout/re-login
  • No custom UI — use the system BiometricPrompt dialog (consistent UX, handles retries)

Dependencies

# libs.versions.toml
[versions]
biometric = "1.1.0"

[libraries]
biometric = { group = "androidx.biometric", name = "biometric", version.ref = "biometric" }
// build.gradle.kts
implementation(libs.biometric)

No manifest permissions needed — BiometricPrompt API on Android 10+ (minSdk 29) handles everything.

Architecture

core/auth/
  BiometricHelper.kt    — Static utility: canAuthenticate() + authenticate()
  AuthManager.kt        — Stores biometric preference in EncryptedSharedPreferences

feature/splash/ui/
  SplashScreen.kt       — Checks pref + triggers prompt on app launch

feature/settings/ui/
  SettingsScreen.kt     — Toggle switch with verify-before-enable
  SettingsViewModel.kt  — Delegates to AuthManager

Step 1: BiometricHelper Utility

A stateless object with two functions. No DI needed — takes FragmentActivity as parameter.

package com.example.app.core.auth

import androidx.biometric.BiometricManager
import androidx.biometric.BiometricPrompt
import androidx.core.content.ContextCompat
import androidx.fragment.app.FragmentActivity

object BiometricHelper {

    /**
     * Returns true if device has enrolled Class 3 biometrics (fingerprint or face).
     */
    fun canAuthenticate(activity: FragmentActivity): Boolean {
        val bm = BiometricManager.from(activity)
        return bm.canAuthenticate(BiometricManager.Authenticators.BIOMETRIC_STRONG) ==
                BiometricManager.BIOMETRIC_SUCCESS
    }

    /**
     * Shows the system biometric prompt. Calls onSuccess or onFailure on completion.
     * onAuthenticationFailed() is intentionally not overridden — the system dialog
     * shows its own retry UI (e.g., "Try again" for bad fingerprint).
     */
    fun authenticate(
        activity: FragmentActivity,
        title: String,
        subtitle: String,
        negativeButtonText: String,
        onSuccess: () -> Unit,
        onFailure: () -> Unit
    ) {
        val executor = ContextCompat.getMainExecutor(activity)

        val callback = object : BiometricPrompt.AuthenticationCallback() {
            override fun onAuthenticationSucceeded(result: BiometricPrompt.AuthenticationResult) {
                onSuccess()
            }
            override fun onAuthenticationError(errorCode: Int, errString: CharSequence) {
                // Cancel pressed, lockout, or no biometrics enrolled
                onFailure()
            }
        }

        val prompt = BiometricPrompt(activity, executor, callback)
        val promptInfo = BiometricPrompt.PromptInfo.Builder()
            .setTitle(title)
            .setSubtitle(subtitle)
            .setNegativeButtonText(negativeButtonText)
            .build()

        prompt.authenticate(promptInfo)
    }
}

Key Decisions

  • BIOMETRIC_STRONG only — no DEVICE_CREDENTIAL fallback (PIN/pattern). The negative button sends user to the login screen instead.
  • onAuthenticationFailed not overridden — the system UI handles retry. Only onAuthenticationError (cancel/lockout) triggers onFailure.
  • FragmentActivity requiredBiometricPrompt needs a FragmentActivity. Compose activities extend ComponentActivity, which extends FragmentActivity, so this works out of the box.

Step 2: AuthManager Storage

Store the biometric preference in EncryptedSharedPreferences alongside auth tokens. The key insight: preserve biometric preference on logout. IMPORTANT: The EncryptedSharedPreferences init MUST be wrapped in try-catch with fallback to regular SharedPreferences — Samsung Knox throws KeyStoreException during MasterKey creation (see android-development security skill).

// In AuthManager.kt

companion object {
    private const val KEY_BIOMETRIC_ENABLED = "biometric_enabled"
}

fun isBiometricEnabled(): Boolean =
    securePreferences.getBoolean(KEY_BIOMETRIC_ENABLED)

fun setBiometricEnabled(enabled: Boolean) {
    securePreferences.putBoolean(KEY_BIOMETRIC_ENABLED, enabled)
}

fun clearAuth() {
    // Save preferences that survive logout
    val savedBiometric = isBiometricEnabled()
    val savedLanguage = getLanguage()
    securePreferences.clear()
    // Restore
    if (savedBiometric) securePreferences.putBoolean(KEY_BIOMETRIC_ENABLED, true)
    if (savedLanguage != null) securePreferences.putString(KEY_LANGUAGE, savedLanguage)
}

Step 3: Splash Screen Integration

The splash screen is the single integration point. Uses CompletableDeferred to bridge the callback-based BiometricPrompt into coroutine-based LaunchedEffect.

@Composable
fun SplashScreen(
    authManager: AuthManager,
    onNavigateToLogin: () -> Unit,
    onNavigateToMain: () -> Unit,
    onNavigateToChangePassword: () -> Unit
) {
    val context = LocalContext.current
    val activity = context as? FragmentActivity

    // Pre-resolve string resources outside the coroutine
    val biometricTitle = stringResource(R.string.biometric_prompt_title)
    val biometricSubtitle = stringResource(R.string.biometric_prompt_subtitle)
    val biometricCancel = stringResource(R.string.biometric_prompt_cancel)

    LaunchedEffect(Unit) {
        delay(1500) // Splash display time

        if (!authManager.isLoggedIn()) {
            onNavigateToLogin()
            return@LaunchedEffect
        }

        val biometricPref = authManager.isBiometricEnabled()
        val canAuth = activity != null && BiometricHelper.canAuthenticate(activity)

        if (biometricPref && canAuth) {
            // Bridge callback → coroutine
            val result = CompletableDeferred<Boolean>()
            BiometricHelper.authenticate(
                activity = activity!!,
                title = biometricTitle,
                subtitle = biometricSubtitle,
                negativeButtonText = biometricCancel,
                onSuccess = { result.complete(true) },
                onFailure = { result.complete(false) }
            )
            if (result.await()) {
                // Biometric passed — check force password change then go to main
                if (authManager.isForcePasswordChange()) {
                    onNavigateToChangePassword()
                } else {
                    onNavigateToMain()
                }
            } else {
                // Biometric failed/cancelled — send to login
                onNavigateToLogin()
            }
        } else {
            // No biometric — go straight through
            if (authManager.isForcePasswordChange()) {
                onNavigateToChangePassword()
            } else {
                onNavigateToMain()
            }
        }
    }

    // Splash UI (logo, brand name, etc.)
    Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
        Image(
            painter = painterResource(R.mipmap.ic_launcher_foreground),
            contentDescription = null,
            modifier = Modifier.size(150.dp)
        )
    }
}

Navigation Setup

The splash screen pops itself from the back stack when navigating:

composable(Screen.Splash.route) {
    SplashScreen(
        authManager = authManager,
        onNavigateToLogin = {
            navController.navigate(Screen.Login.route) {
                popUpTo(Screen.Splash.route) { inclusive = true }
            }
        },
        onNavigateToMain = {
            navController.navigate(Screen.Dashboard.route) {
                popUpTo(Screen.Splash.route) { inclusive = true }
            }
        },
        onNavigateToChangePassword = {
            navController.navigate(Screen.ChangePassword.route) {
                popUpTo(Screen.Splash.route) { inclusive = true }
            }
        }
    )
}

Step 4: Settings Toggle

The toggle is conditionally rendered — only shown if the device supports biometrics. Enabling requires biometric verification first.

// In SettingsScreen.kt, inside the Security section

val activity = context as? FragmentActivity
if (activity != null && BiometricHelper.canAuthenticate(activity)) {
    HorizontalDivider()

    var biometricEnabled by remember { mutableStateOf(viewModel.isBiometricEnabled()) }
    val verifyTitle = stringResource(R.string.biometric_verify_title)
    val verifySubtitle = stringResource(R.string.biometric_verify_subtitle)
    val verifyCancel = stringResource(R.string.biometric_prompt_cancel)

    ListItem(
        headlineContent = { Text(stringResource(R.string.biometric_login_title)) },
        supportingContent = { Text(stringResource(R.string.biometric_login_subtitle)) },
        leadingContent = {
            Icon(Icons.Default.Fingerprint, contentDescription = null,
                tint = MaterialTheme.colorScheme.primary)
        },
        trailingContent = {
            Switch(
                checked = biometricEnabled,
                onCheckedChange = { enabled ->
                    if (enabled) {
                        // Verify identity before enabling
                        BiometricHelper.authenticate(
                            activity = activity,
                            title = verifyTitle,
                            subtitle = verifySubtitle,
                            negativeButtonText = verifyCancel,
                            onSuccess = {
                                viewModel.setBiometricEnabled(true)
                                biometricEnabled = true
                            },
                            onFailure = { /* Verification failed — don't enable */ }
                        )
                    } else {
                        // Disabling doesn't require verification
                        viewModel.setBiometricEnabled(false)
                        biometricEnabled = false
                    }
                }
            )
        }
    )
}

Step 5: String Resources

<!-- Biometric (7 strings, translate all) -->
<string name="biometric_login_title">Biometric Login</string>
<string name="biometric_login_subtitle">Use fingerprint or face to unlock</string>
<string name="biometric_prompt_title">Biometric Login</string>
<string name="biometric_prompt_subtitle">Verify your identity to access the app</string>
<string name="biometric_prompt_cancel">Use Password</string>
<string name="biometric_verify_title">Verify Identity</string>
<string name="biometric_verify_subtitle">Authenticate to enable biometric login</string>

Flow Diagram

App Launch
  ↓
[Splash Screen] — 1.5s delay
  ↓
isLoggedIn()?
  ├─ NO → Login Screen
  └─ YES
      ↓
      isBiometricEnabled() && canAuthenticate()?
        ├─ YES → System BiometricPrompt
        │   ├─ Success → forcePasswordChange? → Dashboard / ChangePassword
        │   └─ Failure/Cancel → Login Screen
        └─ NO → forcePasswordChange? → Dashboard / ChangePassword

Patterns & Anti-Patterns

DO

  • Use BIOMETRIC_STRONG (Class 3) for security-sensitive apps
  • Require biometric verification when the user turns the feature ON
  • Preserve biometric preference across logout (clearAuth() saves + restores it)
  • Use CompletableDeferred to bridge BiometricPrompt callbacks into coroutines
  • Hide the toggle entirely on devices without biometric hardware
  • Use context as? FragmentActivity safely (never force-cast)
  • Pre-resolve string resources before entering LaunchedEffect (Compose rule)

DON'T

  • Don't add DEVICE_CREDENTIAL as a fallback — it defeats the purpose of biometric gate
  • Don't override onAuthenticationFailed() — the system handles retry UI
  • Don't store biometric data yourself — the system handles enrollment and matching
  • Don't show biometric prompt on login screen — only on splash (user is already authenticated)
  • Don't require biometric for disabling the feature — that traps users who can't authenticate
  • Don't declare manifest permissions — BiometricPrompt on API 29+ doesn't need them
  • Don't use KeyguardManager or deprecated FingerprintManager — use BiometricPrompt only

Edge Cases

ScenarioBehavior
No biometric hardwareSettings toggle hidden, splash skips biometric
Biometrics enrolled then removedcanAuthenticate() returns false, splash skips
User cancels promptonFailure() → navigate to Login
Too many failed attempts (lockout)System shows lockout message, then onFailure()
Force password change + biometricBiometric first, then redirect to ChangePassword
App killed during promptNext launch starts fresh from splash
Multiple accounts on deviceBiometric pref is per-app, not per-user

Integration with Other Skills

android-biometric-login
  ├── android-development     (project structure, Hilt, EncryptedSharedPreferences)
  ├── dual-auth-rbac          (JWT auth, AuthManager, token storage)
  └── jetpack-compose-ui      (Settings ListItem, Switch, Material 3 theming)

Key integrations:

  • dual-auth-rbac: BiometricHelper works alongside JWT auth — biometric gates app access, JWT gates API access
  • android-development: Follows MVVM pattern — ViewModel delegates to AuthManager, UI observes state
  • jetpack-compose-ui: Settings toggle uses Material 3 ListItem + Switch pattern

Checklist

  • Add androidx.biometric:biometric:1.1.0 dependency
  • Create BiometricHelper object with canAuthenticate() + authenticate()
  • Add biometric preference to AuthManager (persists across logout)
  • Integrate biometric check in Splash screen with CompletableDeferred
  • Add Settings toggle with verify-before-enable
  • Add 7 string resources (translate to all supported languages)
  • Test on device with biometrics, device without, and emulator

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

36.93%
按下载量换算43

Claude

26.25%
按下载量换算30

Cursor

17.92%
按下载量换算21

Gemini CLI

9.33%
按下载量换算11

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills