Flutter中如何检测手机是否新增指纹?
在Flutter中检测是否新增指纹/生物特征的方法
方案1:对比生物特征类型列表(基础版)
使用官方推荐的local_auth插件结合shared_preferences存储历史生物特征数据,通过对比当前与历史的生物特征类型,判断是否有新增/删除操作。
步骤:
- 添加依赖到
pubspec.yaml:
dependencies: local_auth: ^2.1.7 shared_preferences: ^2.2.2
- 实现检测逻辑:
import 'package:flutter/material.dart'; import 'package:local_auth/local_auth.dart'; import 'package:shared_preferences/shared_preferences.dart'; class BiometricChangeChecker { final _localAuth = LocalAuthentication(); final _savedBiometricsKey = 'previous_biometrics'; Future<bool> checkBiometricChanges() async { // 获取当前可用的生物特征类型 List<BiometricType> currentTypes = []; try { if (await _localAuth.canCheckBiometrics) { currentTypes = await _localAuth.getAvailableBiometrics(); } } catch (e) { print('获取生物特征失败: $e'); return false; } // 转换为字符串列表便于存储和对比 final currentTypeStrs = currentTypes.map((type) { switch (type) { case BiometricType.fingerprint: return 'fingerprint'; case BiometricType.face: return 'face'; case BiometricType.iris: return 'iris'; default: return 'unknown'; } }).toList(); // 读取历史数据 final prefs = await SharedPreferences.getInstance(); final savedTypeStrs = prefs.getStringList(_savedBiometricsKey); // 判断是否有变化 final hasChanged = !listEquals(savedTypeStrs, currentTypeStrs); // 更新历史数据 if (hasChanged) { await prefs.setStringList(_savedBiometricsKey, currentTypeStrs); } return hasChanged; } } // 使用示例 void main() async { WidgetsFlutterBinding.ensureInitialized(); final checker = BiometricChangeChecker(); final changed = await checker.checkBiometricChanges(); if (changed) { print('生物特征已变更(可能新增/删除了指纹/面容)'); // 这里可以执行重新验证用户、提示用户等逻辑 } }
方案2:检测同类型生物特征数量变化(进阶版)
如果需要检测同类型内的新增/删除(比如新增了一个指纹,而生物特征类型还是指纹),上面的方法无法实现,因为local_auth不会返回具体的指纹数量。此时需要针对Android和iOS分别处理:
- Android端:利用KeyStore创建与生物特征绑定的密钥,当用户新增/删除指纹时,该密钥会失效。可以通过尝试使用密钥签名/加密来判断是否发生变更。
- iOS端:调用
LAContext的evaluatePolicy方法时,若用户新增了指纹,首次验证可能会要求输入设备密码,或者通过监听LAErrorBiometryNotAvailable等错误来间接判断。
以下是Android端的实现示例(通过Platform Channel对接原生代码):
Flutter端代码:
import 'package:flutter/services.dart'; class BiometricTemplateChecker { static const MethodChannel _channel = MethodChannel('biometric_template_checker'); Future<bool> hasBiometricTemplatesChanged() async { try { return await _channel.invokeMethod('checkTemplateChanges'); } on PlatformException catch (e) { print('检测失败: ${e.message}'); return false; } } }
Android原生代码(MainActivity.kt):
import android.security.keystore.KeyGenParameterSpec import android.security.keystore.KeyProperties import androidx.annotation.NonNull import io.flutter.embedding.android.FlutterActivity import io.flutter.embedding.engine.FlutterEngine import io.flutter.plugin.common.MethodChannel import java.security.KeyStore import javax.crypto.Cipher import javax.crypto.KeyGenerator class MainActivity : FlutterActivity() { private val CHANNEL = "biometric_template_checker" private val KEY_NAME = "biometric_key" override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) { super.configureFlutterEngine(flutterEngine) MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler { call, result -> if (call.method == "checkTemplateChanges") { val changed = checkBiometricTemplatesChanged() result.success(changed) } else { result.notImplemented() } } } private fun checkBiometricTemplatesChanged(): Boolean { val keyStore = KeyStore.getInstance("AndroidKeyStore").apply { load(null) } val key = keyStore.getKey(KEY_NAME, null) ?: run { // 首次运行,创建密钥 val keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, "AndroidKeyStore") val spec = KeyGenParameterSpec.Builder(KEY_NAME, KeyProperties.PURPOSE_ENCRYPT or KeyProperties.PURPOSE_DECRYPT) .setBlockModes(KeyProperties.BLOCK_MODE_CBC) .setUserAuthenticationRequired(true) .setInvalidatedByBiometricEnrollment(true) // 生物特征变更时失效密钥 .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_PKCS7) .build() keyGenerator.init(spec) keyGenerator.generateKey() return false } // 尝试初始化Cipher,失败则说明密钥已失效(生物特征变更) return try { val cipher = Cipher.getInstance("${KeyProperties.KEY_ALGORITHM_AES}/${KeyProperties.BLOCK_MODE_CBC}/${KeyProperties.ENCRYPTION_PADDING_PKCS7}") cipher.init(Cipher.ENCRYPT_MODE, key) false } catch (e: Exception) { // 删除失效密钥,重新创建 keyStore.deleteEntry(KEY_NAME) true } } }
注意事项
- 方案1仅能检测生物特征类型的变化(比如从无指纹到有指纹,或从指纹到指纹+面容),无法检测同类型内的数量变化。
- 方案2可以检测同类型内的变更,但需要编写原生代码,兼容性需要针对不同Android版本和iOS版本测试。
- 无论哪种方案,都需要在应用启动时或关键操作前执行检测,确保及时发现生物特征变更。
内容的提问来源于stack exchange,提问作者Danford Kija
相关产品推荐
相关产品推荐

