You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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;
    }
}

错误原因与修复方案

错误原因

  1. 类型不匹配:BiometricPrompt的构造函数要求传入FragmentActivity或其子类(如AppCompatActivity),但AndroidNativeUtil.getActivity()返回的是Activity类型,直接传入会导致类型转换错误。
  2. 异步结果处理错误: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:47:31