android - 将自定义布局添加到生物识别提示

标签 android android-fingerprint-api android-biometric-prompt android-biometric

有什么方法可以将我们自己的自定义布局添加到生物识别提示中,因为我已经看到了各种类似的线程,但似乎还没有为它提供解决方案,并且不推荐使用指纹管理器,所以我不想使用它。

最佳答案

我不认为这是可能的。最新版本的 Android 的 BiometricPrompt 类旨在显示其自己的自定义 Activity/fragment/对话。也没有 API 允许用户修改附加到 BiometricPrompt 的布局。查看托管在 Google 存储库中的源代码:https://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:biometric/biometric/src/main/java/androidx/biometric/
唯一的可能性是从头开始构建一个生物特征验证程序/类(就像谷歌所做的那样)。但那是它自己的珠穆朗玛峰。
这是运行自定义指纹对话的 Google 代码。请注意,它创建了一个 BiometricFragment 对象:

    /**
     * Shows the biometric prompt to the user and begins authentication.
     *
     * @param info A {@link PromptInfo} object describing the appearance and behavior of the prompt.
     * @param crypto A crypto object to be associated with this authentication.
     */
    private void authenticateInternal(@NonNull PromptInfo info, @Nullable CryptoObject crypto) {
        if (mClientFragmentManager == null) {
            Log.e(TAG, "Unable to start authentication. Client fragment manager was null.");
            return;
        }
        if (mClientFragmentManager.isStateSaved()) {
            Log.e(TAG, "Unable to start authentication. Called after onSaveInstanceState().");
            return;
        }

        final BiometricFragment biometricFragment =
                findOrAddBiometricFragment(mClientFragmentManager);
        biometricFragment.authenticate(info, crypto);
    }
转到 BiometricFragment 的代码,我们可以看到 FingerprintDialogFragment 对话对象在最后的 dialog.show(...) 中向用户显示的位置:
    /**
     * Shows the fingerprint dialog UI to the user and begins authentication.
     */
    @SuppressWarnings("deprecation")
    private void showFingerprintDialogForAuthentication() {
        final Context context = requireContext();
        androidx.core.hardware.fingerprint.FingerprintManagerCompat fingerprintManagerCompat =
                androidx.core.hardware.fingerprint.FingerprintManagerCompat.from(context);
        final int errorCode = checkForFingerprintPreAuthenticationErrors(fingerprintManagerCompat);
        if (errorCode != 0) {
            sendErrorAndDismiss(
                    errorCode, ErrorUtils.getFingerprintErrorString(getContext(), errorCode));
            return;
        }

        if (isAdded()) {
            final boolean shouldHideFingerprintDialog =
                    DeviceUtils.shouldHideFingerprintDialog(context, Build.MODEL);
            if (mViewModel.isFingerprintDialogDismissedInstantly() != shouldHideFingerprintDialog) {
                mHandler.postDelayed(
                        new Runnable() {
                            @Override
                            public void run() {
                                mViewModel.setFingerprintDialogDismissedInstantly(
                                        shouldHideFingerprintDialog);
                            }
                        },
                        DISMISS_INSTANTLY_DELAY_MS);
            }

            if (!shouldHideFingerprintDialog) {
                final FingerprintDialogFragment dialog = FingerprintDialogFragment.newInstance();
                dialog.show(getParentFragmentManager(), FINGERPRINT_DIALOG_FRAGMENT_TAG);
            }

            mViewModel.setCanceledFrom(CANCELED_FROM_NONE);
            fingerprintManagerCompat.authenticate(
                    CryptoObjectUtils.wrapForFingerprintManager(mViewModel.getCryptoObject()),
                    0 /* flags */,
                    mViewModel.getCancellationSignalProvider().getFingerprintCancellationSignal(),
                    mViewModel.getAuthenticationCallbackProvider().getFingerprintCallback(),
                    null /* handler */);
        }
    }
转到 Google 的 FingerprintDialogFrament 类,我们可以看到对话框是在哪里创建的。请注意 View 布局将 R.layout.fingerprint_dialog_layout 向顶部膨胀的位置,这是显示指纹对话框的内置布局:
     @Override
    @NonNull
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        final AlertDialog.Builder builder = new AlertDialog.Builder(requireContext());
        builder.setTitle(mViewModel.getTitle());

        // We have to use builder.getContext() instead of the usual getContext() in order to get
        // the appropriately themed context for this dialog.
        final View layout = LayoutInflater.from(builder.getContext())
                .inflate(R.layout.fingerprint_dialog_layout, null);

        final TextView subtitleView = layout.findViewById(R.id.fingerprint_subtitle);
        final TextView descriptionView = layout.findViewById(R.id.fingerprint_description);

        final CharSequence subtitle = mViewModel.getSubtitle();
        if (TextUtils.isEmpty(subtitle)) {
            subtitleView.setVisibility(View.GONE);
        } else {
            subtitleView.setVisibility(View.VISIBLE);
            subtitleView.setText(subtitle);
        }

        final CharSequence description = mViewModel.getDescription();
        if (TextUtils.isEmpty(description)) {
            descriptionView.setVisibility(View.GONE);
        } else {
            descriptionView.setVisibility(View.VISIBLE);
            descriptionView.setText(description);
        }

        mFingerprintIcon = layout.findViewById(R.id.fingerprint_icon);
        mHelpMessageView = layout.findViewById(R.id.fingerprint_error);

        final CharSequence negativeButtonText =
                mViewModel.isDeviceCredentialAllowed()
                        ? getString(R.string.confirm_device_credential_password)
                        : mViewModel.getNegativeButtonText();
        builder.setNegativeButton(negativeButtonText, new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                mViewModel.setNegativeButtonPressPending(true);
            }
        });

        builder.setView(layout);
        Dialog dialog = builder.create();
        dialog.setCanceledOnTouchOutside(false);
        return dialog;
    }
这是内置指纹对话框 R.layout.fingerprint_dialog_layout 的代码:
<?xml version="1.0" encoding="utf-8"?>
<!--
  ~ Copyright 2018 The Android Open Source Project
  ~
  ~ Licensed under the Apache License, Version 2.0 (the "License");
  ~ you may not use this file except in compliance with the License.
  ~ You may obtain a copy of the License at
  ~
  ~      http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  -->

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <LinearLayout android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:orientation="vertical">

        <TextView
            android:id="@+id/fingerprint_subtitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="24dp"
            android:layout_marginStart="24dp"
            android:textColor="?android:attr/textColorSecondary"
            android:textSize="16sp"
            android:singleLine="true"
            android:ellipsize="marquee"
            android:marqueeRepeatLimit="marquee_forever"/>

        <TextView
            android:id="@+id/fingerprint_description"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="0dp"
            android:layout_marginEnd="24dp"
            android:layout_marginStart="24dp"
            android:textColor="?android:attr/textColorSecondary"
            android:textSize="16sp"
            android:maxLines="4"/>

        <ImageView
            android:id="@+id/fingerprint_icon"
            android:layout_width="@dimen/fingerprint_icon_size"
            android:layout_height="@dimen/fingerprint_icon_size"
            android:layout_gravity="center_horizontal"
            android:layout_marginTop="32dp"
            android:scaleType="fitXY" />

        <TextView
            android:id="@+id/fingerprint_error"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginEnd="24dp"
            android:layout_marginStart="24dp"
            android:paddingTop="16dp"
            android:paddingBottom="24dp"
            android:textSize="14sp"
            android:gravity="center_horizontal"
            android:accessibilityLiveRegion="polite"
            android:text="@string/fingerprint_dialog_touch_sensor"
            android:textColor="?android:attr/textColorSecondary" />

    </LinearLayout>

</ScrollView>

关于android - 将自定义布局添加到生物识别提示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62228113/

相关文章:

android - 在 Android 应用程序中实现蜂鸣声

android - 操作栏空指针异常

android - Android Fingerprint 是否提供指纹名称或指纹的任何唯一标识?

android - BiometricPrompt 虹膜和面部提示不适用于加密对象身份验证。 #AndroidX

java - 如何将 Dokka 添加到 Android 项目而不需要在依赖项部分添加额外的类路径?

java - 与 Smack 4.2 重新连接后发送离线消息时,经过身份验证的监听器出现异常

Android - 如何从指纹认证中获取唯一 key ?

android - Android P 上的 Fingerprint BiometricPrompt 从 View

Android BiometricPrompt DeviceCredentialHandler : onCreate: Executor and/or callback was null