让你的app高大上,自定义对话框实现安卓原生指纹功能

2,151 阅读4分钟
原文链接: www.apkbus.com

安卓6后,开始官方支持指纹识别的api。主要用到的类是FingerprintManager。但是该类在低于6的安卓环境上运行会崩溃。因此有了衍生的FingerprintManagerCompatFingerprintManagerCompat23。其中23这个版本包含了对23之后的api的特殊处理,而FingerprintManagerCompat内部对api进行了判断,我们只需要直接调用它就好。

static {
        if (Build.VERSION.SDK_INT >= 23) {
            IMPL = new Api23FingerprintManagerCompatImpl();
        } else {
            IMPL = new LegacyFingerprintManagerCompatImpl();
        }
    }

这里我教大家如何入门的使用这个官方的指纹api。有人就要问,为什么叫入门。是因为
图片描述
这个方法里面的第一个参数 FingerprintManagerCompat.CryptoObject。这个参数才是指纹识别的关键。比较复杂,有兴趣的童鞋可以度娘一下用法。我在demo里面没有涉及到它,只是简单的实现指纹别的基础功能,写了一个辅助类:

public class FingerPrintHelper {
    static final String PREFERENCE_FINGER_PRINT_CONFIG_NAME = "fingerPrint";
    static final String PREFERENCE_KEY_IS_SUPPORT_FINGER_PRINT = "isSupportFingerPrint";
    static final String PREFERENCE_KEY_HAS_EVER_CHECKED = "hasEverCheckedSupportFingerPrint";

    static final String TAG = "fingerPrint";

    public static SharedPreferences getConfig() {
        return ContextUtil.getContext().getSharedPreferences(PREFERENCE_FINGER_PRINT_CONFIG_NAME, Context.MODE_PRIVATE);
    }

    public static void clearConfig() {
        getConfig().edit().clear().commit();
    }

    private static void setSupportFingerPrint(boolean isSupport) {
        SharedPreferences.Editor editor = getConfig().edit();
        editor.putBoolean(PREFERENCE_KEY_IS_SUPPORT_FINGER_PRINT, isSupport);
        editor.commit();
    }

    /**
     * 判断当前手机支不支持指纹识别
     * 这种方法仅限于api低于安卓6.0但是手机厂家有会支持的手机。如小米,VIVO的一些机型。
     * 可取性不是很好。
     *
     * @return
     */
    public static boolean isSupportFingerPrint() {
        boolean res = false;
        if (!hasEverCheckedFingerPrintSupport()) {
            res = checkSupportFingerPrint();
            setSupportFingerPrint(res);
            setHasEverCheckedFingerPrintSupport(true);
        } else {
            res = getConfig().getBoolean(PREFERENCE_KEY_IS_SUPPORT_FINGER_PRINT, false);
        }
        return res;
    }

    private static boolean hasEverCheckedFingerPrintSupport() {
        return getConfig().getBoolean(PREFERENCE_KEY_HAS_EVER_CHECKED, false);
    }

    private static void setHasEverCheckedFingerPrintSupport(boolean hasEver) {
        SharedPreferences.Editor editor = getConfig().edit();
        editor.putBoolean(PREFERENCE_KEY_HAS_EVER_CHECKED, hasEver);
        editor.commit();
    }

    /**
     * 检测当前的手机支不支持指纹识别,实际上就是判断一下当前的手机API有没有{@link android.hardware.fingerprint.FingerprintManager}这个类
     *
     * @return
     */
    private static boolean checkSupportFingerPrint() {
        boolean result = false;
        try {
            Class.forName("android.hardware.fingerprint.FingerprintManager"); // 通过反射判断是否存在该类
            result = true;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 开始进行指纹识别
     * @param context
     * @param cancellationSignal 指纹识别取消的控制器
     * @param callback 指纹识别回调函数
     */
    public static void doFingerPrint(Context context, android.support.v4.os.CancellationSignal cancellationSignal, FingerprintManagerCompat.AuthenticationCallback callback) {
        FingerprintManagerCompat managerCompat = FingerprintManagerCompat.from(context);
        managerCompat.authenticate(null, 0, cancellationSignal, callback, null);
    }

    /**
     * 官方写法,用于判断是否支持指纹识别
     *
     * @param context
     * @return
     */
    public static boolean isHardWareDetected(Context context) {
        return FingerprintManagerCompat.from(context).isHardwareDetected();
    }

    /**
     * 官方写法,当前手机是否设置过指纹
     *
     * @param context
     * @return
     */
    public static boolean hasEnrolledFingerPrint(Context context) {
        return FingerprintManagerCompat.from(context).hasEnrolledFingerprints();
    }
}

然后再自定义对话框,实现这个功能:

public class FingerPrintDialog extends AbstractDialogFragment implements View.OnClickListener{
    private Button btn_cancel;
    private ImageView iv_back;
    private ImageView iv_icon_finger;
    private TextView tv_title;
    private TextView tv_desc;
    private ProgressBar mProgressBar;

    private boolean enableVibrator=true;//是否开启震动
    private Vibrator mVibrator;

    private CancellationSignal mCancellationSignal;//指纹识别取消控制器

    private static final int COLOR_ERROR= R.color.colorAccent;
    private static final int COLOR_WARN=R.color.orange;
    private static final int COLOR_SUCCESS=R.color.green;

    private boolean isSuccess;//指纹识别是否成功

    private OnDismissListener mOnDismissListener;

    public void setOnDismissListener(OnDismissListener onDismissListener) {
        mOnDismissListener = onDismissListener;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mVibrator= (Vibrator) context.getSystemService(Service.VIBRATOR_SERVICE);
    }

    public static FingerPrintDialog showDialog(FragmentActivity activity, boolean cancelable, String tag, OnDismissListener onDismissListener){
        FingerPrintDialog dialog=new FingerPrintDialog();
        dialog.setCancelable(cancelable);
        dialog.setOnDismissListener(onDismissListener);
        dialog.show(activity.getSupportFragmentManager(),tag);
        dialog.startFingerPrint();
        return dialog;
    }

    public static FingerPrintDialog showDialog(FragmentActivity activity, OnDismissListener onDismissListener){
        return showDialog(activity,true,"",onDismissListener);
    }

    @Override
    protected int setLayoutId() {
        return R.layout.dialog_finger_print;
    }

    @Override
    protected void bindView(View convertView, Bundle savedInstanceState) {
        btn_cancel=findViewByIdAuto(R.id.btn_cancel);
        iv_back=findViewByIdAuto(R.id.iv_back);
        tv_title=findViewByIdAuto(R.id.tv_title);
        tv_desc=findViewByIdAuto(R.id.tv_desc);
        iv_icon_finger=findViewByIdAuto(R.id.iv_icon_finger);
        mProgressBar=findViewByIdAuto(R.id.progress);
    }

    @Override
    protected void bindEvents(View convertView, Bundle savedInstanceState) {
        Bundle data=getArguments();
        iv_back.setOnClickListener(this);
        btn_cancel.setOnClickListener(this);
        setStyle(getString(R.string.finger_print_default),STYLE_DEFAULT);
    }

    @Override
    public void onClick(View v) {
        if(v==btn_cancel){
            dismissAllowingStateLoss();
        }else if(v==iv_back){
            dismissAllowingStateLoss();
        }
    }

    @Override
    public void onDismiss(DialogInterface dialog) {
        if(mCancellationSignal!=null){
            mCancellationSignal.cancel();
            mCancellationSignal=null;
        }
        if(mOnDismissListener!=null){
            mOnDismissListener.onDismiss(isSuccess);
        }
        super.onDismiss(dialog);
    }

    @Override
    protected int setWindowWidth() {
        return (int) (super.setWindowWidth()*0.8);
    }

    private void startFingerPrint(){
        mCancellationSignal=new CancellationSignal();
        FingerPrintHelper.doFingerPrint(ContextUtil.getContext(), mCancellationSignal,new FingerprintManagerCompat.AuthenticationCallback() {
            @Override
            public void onAuthenticationError(int errMsgId, CharSequence errString) {
                super.onAuthenticationError(errMsgId, errString);
                setStyle(errString.toString(),STYLE_ERROR);
                startVibrate();
            }

            @Override
            public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
                super.onAuthenticationHelp(helpMsgId, helpString);
                setStyle(helpString.toString(),STYLE_WARN);
                startVibrate();
            }

            @Override
            public void onAuthenticationSucceeded(FingerprintManagerCompat.AuthenticationResult result) {
                super.onAuthenticationSucceeded(result);
                setStyle(getString(R.string.finger_print_success),STYLE_SUCCESS);
                startVibrate();
                isSuccess=true;
                (new Handler()).postDelayed(new Runnable() {
                    @Override
                    public void run() {
                        dismissAllowingStateLoss();
                    }
                },1000);
            }

            @Override
            public void onAuthenticationFailed() {
                super.onAuthenticationFailed();
                setStyle(getString(R.string.finger_print_failed),STYLE_ERROR);
                startVibrate();
            }
        });
    }

    public void startVibrate(){
        if(enableVibrator && mVibrator!=null){
            mVibrator.vibrate(200);
        }
    }

    private static final int STYLE_DEFAULT=0;
    private static final int STYLE_SUCCESS=1;
    private static final int STYLE_ERROR=-1;
    private static final int STYLE_WARN=2;

    private void setStyle(String msg, int style){
        tv_desc.setText(msg);
        mProgressBar.setVisibility(View.VISIBLE);
        switch (style){
            case STYLE_ERROR:
                tv_desc.setTextColor(ColorKit.getColorSrc(COLOR_ERROR));
                DrawableKit.setDrawableTintColor(iv_icon_finger.getDrawable(),COLOR_ERROR);
                break;
            case STYLE_WARN:
                tv_desc.setTextColor(ColorKit.getColorSrc(COLOR_WARN));
                DrawableKit.removeDrawableTintColor(iv_icon_finger.getDrawable());
                break;
            case STYLE_SUCCESS:
                tv_desc.setTextColor(ColorKit.getColorSrc(COLOR_SUCCESS));
                DrawableKit.setDrawableTintColor(iv_icon_finger.getDrawable(),COLOR_SUCCESS);
                mProgressBar.setVisibility(View.GONE);
                break;
            default:
                tv_desc.setTextColor(ColorKit.getColorSrc(R.color.white_gray));
                DrawableKit.removeDrawableTintColor(iv_icon_finger.getDrawable());
                break;

        }
    }

    /**
     * 描述:对话框消失的时候的监听器
     *
     * <br>作者: cjs
     * <br>创建时间: 2017/11/8 0008 15:26
     * <br>邮箱: chenjunsen@outlook.com
     * @version 1.0
     */
    public interface OnDismissListener{
        /**
         * 对话框消失的时候
         * @param isSuccess 验证是否成功
         */
        void onDismiss(boolean isSuccess);
    }
}

用法在此:

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(FingerPrintHelper.isHardWareDetected(this) && FingerPrintHelper.hasEnrolledFingerPrint(this)){
            FingerPrintDialog.showDialog(this, false, "fingerPrint", new FingerPrintDialog.OnDismissListener() {
                @Override
                public void onDismiss(boolean isSuccess) {
                    if(isSuccess){
                        setContentView(R.layout.activity_main);
                    }else{
                        finish();
                        System.exit(0);
                    }
                }
            });
        }else{
            Toast.makeText(this,"当前机型不支持安卓原生指纹系统或者你还没有设置指纹密码",Toast.LENGTH_LONG).show();
            setContentView(R.layout.activity_main);
        }
    }
}

PS:目前我用三星S8 plus测试通过,其余机型,有兴趣的童鞋可以下载自测。