有什么方法可以将我们自己的自定义布局添加到生物识别提示中,因为我已经看到了各种类似的线程,但似乎还没有为它提供解决方案,并且不推荐使用指纹管理器,所以我不想使用它。
1 回答
我不认为这是可能的。最新版本的 Android 的 BiometricPrompt 类旨在显示其自己的自定义活动/片段/对话。也没有 API 允许用户修改附加到 BiometricPrompt 的布局。查看托管在 Google 存储库中的源代码:https ://cs.android.com/androidx/platform/frameworks/support/+/androidx-master-dev:biometric/biometric/src/main/java/androidx/生物识别/
唯一的可能性是从头开始构建一个生物特征验证程序/类(就像谷歌所做的那样)。但那是它自己的珠穆朗玛峰。
这是运行自定义指纹对话的 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 类,我们可以看到对话框是在哪里创建的。请注意视图布局将 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>