在Codename One中适配Android生物识别原生代码的问题咨询
Codename One迁移生物识别认证代码问题及解决
问题背景
我在Android Studio中实现了支持设备PIN/图案/密码作为备份的生物识别认证功能,在模拟器和实体设备上均可正常运行,启动应用或点击按钮时会弹出认证提示。现在需要将该功能迁移到Codename One的MyNativeImpl.java中,已导入com.codename1.impl.android.AndroidNativeUtil,尝试用AndroidNativeUtil.getContext()替换原代码中的this,用AndroidNativeUtil.getActivity()替换MainActivity.this,但构建失败。仅保留executor = ContextCompat.getMainExecutor(AndroidNativeUtil.getActivity())或executor = ContextCompat.getMainExecutor(AndroidNativeUtil.getContext())时可成功构建,问题集中在MainActivity.this的替换上。
原Android Studio工作代码
import androidx.annotation.NonNonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.biometric.BiometricPrompt; import androidx.core.content.ContextCompat; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.widget.Button; import android.widget.Toast; import java.util.concurrent.Executor; public class MainActivity extends AppCompatActivity { private Executor executor; private BiometricPrompt biometricPrompt; private BiometricPrompt.PromptInfo promptInfo; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); executor = ContextCompat.getMainExecutor(this); biometricPrompt = new BiometricPrompt(MainActivity.this, executor, new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { super.onAuthenticationError(errorCode, errString); Toast.makeText(getApplicationContext(), "Authentication error: " + errString, Toast.LENGTH_SHORT) .show(); } @Override public void onAuthenticationSucceeded( @NonNull BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); Toast.makeText(getApplicationContext(), "Authentication succeeded!", Toast.LENGTH_SHORT).show(); } @Override public void onAuthenticationFailed() { super.onAuthenticationFailed(); Toast.makeText(getApplicationContext(), "Authentication failed", Toast.LENGTH_SHORT) .show(); } }); promptInfo = new BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setAllowedAuthenticators(androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK | androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG | androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL) .build(); biometricPrompt.authenticate(promptInfo); Button biometricLoginButton = findViewById(R.id.b_launchAuth); biometricLoginButton.setOnClickListener(view -> { Log.d("b_launchAuth", "Pressed - Enter"); biometricPrompt.authenticate(promptInfo); Log.d("b_launchAuth", "Pressed - Exit"); }); } }
迁移后的Codename One代码(原错误版本)
package com.jamesco.maventestnew; import android.util.Log; import androidx.annotation.NonNonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.biometric.BiometricPrompt; import androidx.core.content.ContextCompat; import android.os.Bundle; import android.widget.Button; import android.widget.Toast; import java.util.concurrent.Executor; import com.codename1.impl.android.AndroidNativeUtil; public class MyNativeImpl { private Executor executor; private BiometricPrompt biometricPrompt; private BiometricPrompt.PromptInfo promptInfo; public boolean isSupported() { return true; } public boolean nativeAuth(){ boolean AuthOK = false; executor = ContextCompat.getMainExecutor(AndroidNativeUtil.getContext()); biometricPrompt = new BiometricPrompt(AndroidNativeUtil.getActivity(), executor, new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { super.onAuthenticationError(errorCode, errString); } @Override public void onAuthenticationSucceeded( @NonNull BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); AuthOK = true; } @Override public void onAuthenticationFailed() { super.onAuthenticationFailed(); } }); promptInfo = new BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setAllowedAuthenticators(androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK | androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG | androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL) .build(); biometricPrompt.authenticate(promptInfo); return AuthOK; } }
错误原因与修复方案
错误原因
- 类型不匹配:
BiometricPrompt的构造函数要求传入FragmentActivity或其子类(如AppCompatActivity),但AndroidNativeUtil.getActivity()返回的是Activity类型,直接传入会导致类型转换错误。 - 异步结果处理错误:
nativeAuth()方法同步返回AuthOK,但生物识别认证是异步操作,回调方法执行前就已经返回结果,导致返回值永远是false。
修复后的代码
package com.jamesco.maventestnew; import android.util.Log; import androidx.annotation.NonNonNull; import androidx.appcompat.app.AppCompatActivity; import androidx.biometric.BiometricPrompt; import androidx.core.content.ContextCompat; import java.util.concurrent.Executor; import com.codename1.impl.android.AndroidNativeUtil; // 定义回调接口处理异步认证结果 public interface AuthCallback { void onAuthSuccess(); void onAuthError(String errorMsg); void onAuthFailed(); } public class MyNativeImpl { private Executor executor; private BiometricPrompt biometricPrompt; private BiometricPrompt.PromptInfo promptInfo; private AuthCallback authCallback; public boolean isSupported() { return true; } public void nativeAuth(AuthCallback callback){ this.authCallback = callback; // 将Activity转换为AppCompatActivity AppCompatActivity activity = (AppCompatActivity) AndroidNativeUtil.getActivity(); executor = ContextCompat.getMainExecutor(activity); biometricPrompt = new BiometricPrompt(activity, executor, new BiometricPrompt.AuthenticationCallback() { @Override public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) { super.onAuthenticationError(errorCode, errString); if(authCallback != null){ authCallback.onAuthError(errString.toString()); } } @Override public void onAuthenticationSucceeded( @NonNull BiometricPrompt.AuthenticationResult result) { super.onAuthenticationSucceeded(result); if(authCallback != null){ authCallback.onAuthSuccess(); } } @Override public void onAuthenticationFailed() { super.onAuthenticationFailed(); if(authCallback != null){ authCallback.onAuthFailed(); } } }); promptInfo = new BiometricPrompt.PromptInfo.Builder() .setTitle("Biometric login for my app") .setSubtitle("Log in using your biometric credential") .setAllowedAuthenticators(androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_WEAK | androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG | androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL) .build(); biometricPrompt.authenticate(promptInfo); } }
构建配置要求
需要在Codename One项目中添加Android依赖配置:
android.gradleDep=implementation("androidx.biometric:biometric:1.1.0")
内容的提问来源于stack exchange,提问作者James N
相关产品推荐
相关产品推荐

