业务场景介绍

目前电商等各类应用中,大多数应用存在账号登录系统。对于现在的网络环境,安全问题,是开发者和用户都看重的问题。

华为帐号服务(HUAWEI Account Kit)可以为您提供了简单、安全的登录授权功能,方便用户快捷登录。用户不必输入帐号、密码和繁琐验证,就可以通过"华为帐号登录"快速登录,即刻使用您的App。
安全检测服务可为您提供多种安全检测接口,其虚假用户检测,可以帮助您的App防范批量注册、撞库攻击、活动"薅羊毛"、内容爬虫等行为。
线上快速身份验证服务为应用提供安全可信的本地生物特征认证和安全便捷的线上快速身份验证能力。用户可使用指纹、人脸快捷登录手机上的个人应用,应用登录更安全便捷。

您将建立什么

在这个Codelab中,您将实现通过华为帐号服务,安全检测服务,线上快速身份验证服务实现:

您将会学到什么

您需要什么

硬件要求

软件要求

集成HUAWEI HMS Core能力,需要完成以下准备工作

具体操作,请按照《HUAWEI HMS Core集成准备》中详细说明来完成。

华为帐号服务可以通过如下方式一开通,Safety Detect和FIDO服务可以通过如下两种方式开通,具体开通实现如下:

方式一

华为开发者联盟 AppGallery Connect中选择"我的项目",在项目列表中选择创建的应用,在"项目设置"页面中选择"API管理"。

打开Account KitSafety DetectFIDO服务。

方式二

华为开发者联盟控制台中,在页面侧边栏,选择"HMS API服务"->"API库",并选择对应项目。

安全检测服务

在"API总量"卡片列表中点击"安全检测服务" 卡片

进入卡片中,点击"启用"按钮,即可开通服务。

启用服务后,显示如下图所示:

线上快速身份验证服务

在"API总量"卡片列表中点击"线上快速身份验证服务" 卡片。

进入卡片中,点击"启用"按钮,开通服务。

启用服务后,显示如下图所示:

获取配置文件

打开华为开发者联盟AppGallery Connect选择"我的项目",在项目列表中选择创建的应用,在"项目设置"页面中选择"常规",并在项目数据存储位置点击设置按钮。

根据应用实际情况,设置对应数据存储位置,然后点击确认按钮。

下载应用中的"agconnect-services.json"文件。

将 "agconnect-services.json"文件移至Android Studio开发工程应用模块的根目录。

配置HMS Core SDK依赖

打开应用级的build.gradle文件。

在"dependencies"中添加AccountSafety DetectFIDO SDK依赖

dependencies { // HMS Core - Account Kit implementation 'com.huawei.hms:hwid:{version}' // HMS Core - Safety Detect implementation 'com.huawei.hms:safetydetect:{version}' // HMS Core - FIDO BioAuthn implementation 'com.huawei.hms:fido-bioauthn-androidx:{version}' }

点击Sync Now 同步工程。

配置混淆脚本

  1. 打开Android Studio工程的混淆配置文件proguard-rules.pro
  2. 加入混淆配置。
    -ignorewarnings -keepattributes *Annotation* -keepattributes Exceptions -keepattributes InnerClasses -keepattributes Signature -keepattributes SourceFile,LineNumberTable -keep class com.huawei.hianalytics.**{*;} -keep class com.huawei.updatesdk.**{*;} -keep class com.huawei.hms.**{*;}
  3. 如果开发者使用了AndResGuard,需要在混淆配置文件中加入AndResGuard允许清单。
    "R.string.hms*", "R.string.connect_server_fail_prompt_toast", "R.string.getting_message_fail_prompt_toast", "R.string.no_available_network_prompt_toast", "R.string.third_app_*", "R.string.upsdk_*", "R.layout.hms*", "R.layout.upsdk_*", "R.drawable.upsdk*", "R.color.upsdk*", "R.dimen.upsdk*", "R.style.upsdk*", "R.string.agc*"

UserDetect API说明

调用UserDetect API分为三步骤:

步骤1 初始化安全检测;

步骤2 客户端发起检测请求:调用UserDetect API的userDetection()方法以发起虚假用户检测请求,API会返回一个responseToken

步骤3 服务端获取检测结果:使用步骤2获取response token调用接口获取检测结果。

初始化安全检测

在登录页面初始化虚假用户检测功能。UserDetect提供了行为检测能力,如果您希望您的虚假用户检测功能具备该能力,可以通过调用initUserDetect()接口初始化虚假用户检测。

Java代码

/** * init safety detect */ private void initSafetyDetect() { // init SafetyDetect SafetyDetectClient client = SafetyDetect.getClient(this); client.initUserDetect().addOnSuccessListener(new OnSuccessListener<Void>() { @Override public void onSuccess(Void aVoid) { // init success } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // init fail } }); }

Kotlin代码

/** * init safety detect */ private fun initSafetyDetect() { // init SafetyDetect val client = SafetyDetect.getClient(this) client.initUserDetect().addOnSuccessListener { // init success }.addOnFailureListener { // init fail } }

客户端发起检测请求

点击登录按钮,首先通过调用userDetection发起检测,传入您申请的app_id作为该方法的参数。

分别添加OnSuccessListenerOnFailureListener实例作为监听器。

Java代码

String app_Id = AGConnectServicesConfig.fromContext(this).getString("client/app_id"); SafetyDetectClient client = SafetyDetect.getClient(this); client.userDetection(app_Id).addOnSuccessListener(new OnSuccessListener<UserDetectResponse>() { @Override public void onSuccess(UserDetectResponse userDetectResponse) { // String responseToken = userDetectResponse.getResponseToken(); // if (!responseToken.isEmpty()) { // Send the response token to your app server, and call the cloud API of // HMS Core on your server to obtain the fake user detection result. // } } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { Log.e(TAG, "user detect fail"); } });

Kotlin代码

val appId = AGConnectServicesConfig.fromContext(this).getString("client/app_id") val client = SafetyDetect.getClient(this) client.userDetection(appId).addOnSuccessListener { // String responseToken = userDetectResponse.getResponseToken(); // if (!responseToken.isEmpty()) { // Send the response token to your app server, and call the cloud API of // HMS Core on your server to obtain the fake user detection result. // } }.addOnFailureListener { Log.e(TAG, "user detect fail") }

调用userDetection,会进行人机智能验证检测,弹出需要确认页面

服务端获取检测结果

使用客户端检测结果的responseToken,调用云端获取检测结果:中国大陆地区调用nocaptcha云侧接口获取检测结果,海外地区通过verify云侧接口获取检测结果。

服务端主要分为两步:

步骤1 获取accessToken,详细请参见开放平台鉴权相关内容描述

步骤2 调用云侧API获取检测结果。

消息请求示例如下所示:

POST https://hirms.cloud.huawei.com/rms/v1/userRisks/verify?appId=123456 HTTP/1.1 Content-Type: application/json;charset=utf-8
{ "accessToken":"AAWWHI94sgUR2RU5_P1ZptUiwLq7W8XWJO2LxaAPuXw4_HOJFXnBlN-q5_3bwlxVW_SHeDPx_s5bWW-9DjtWZsvcm9CwXe1FHJg0u-D2pcQPcb3sTxDTJeiwEb9WBPl_9w", "response":"1_55d74c04eab36a0a018bb7a879a6f49f072b023690cba936" }

进入登录页面,添加华为帐号登录按钮。

<com.huawei.hms.support.hwid.ui.HuaweiIdAuthButton android:id="@+id/login_huaweiAccount" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_gravity="center_horizontal" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/login_otherLogin" app:layout_constraintVertical_bias="0.2" tools:ignore="MissingConstraints" />

登录页面如图显示。

华为帐号登录按钮添加点帐号登录逻辑。
Java代码

/** * HUAWEI Account Login in */ private void onHuaweiAccountLogin() { AccountAuthParams authParams = new AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM) .setIdToken().createParams(); AccountAuthService mAuthService = AccountAuthManager.getService(this, authParams); startActivityForResult(mAuthService.getSignInIntent(), REQUEST_CODE); }

Kotlin代码

/** * HUAWEI Account Login in */ private fun onHuaweiAccountLogin() { val authParams: AccountAuthParams = AccountAuthParamsHelper(AccountAuthParams.DEFAULT_AUTH_REQUEST_PARAM) .setIdToken().createParams() val mAuthService: AccountAuthService = AccountAuthManager.getService(this, authParams) startActivityForResult(mAuthService.signInIntent, REQUEST_CODE) }

登录授权页面

授权成功后处理。
Java代码

@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_CODE) { Task<AuthAccount> authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data); if (authAccountTask.isSuccessful()) { //login success AuthAccount authAccount = authAccountTask.getResult(); onHuaweiIdLoginSuccess(authAccount); } else { Log.e(TAG, "sign in failed : " + ((ApiException) authAccountTask.getException()).getStatusCode()); } } }

Kotlin代码

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (requestCode == REQUEST_CODE) { val authAccountTask = AccountAuthManager.parseAuthResultFromIntent(data) if (authAccountTask.isSuccessful) { //login success val authAccount = authAccountTask.result onHuaweiIdLoginSuccess(authAccount) } else { Log.e(TAG, "sign in failed : " + (authAccountTask.exception as ApiException).statusCode) } } }

授权登录成功后处理华为帐号信息。

Java代码

/** * HUAWEI Account Login success */ private void onHuaweiIdLoginSuccess(AuthAccount authAccount) { String openId = authAccount.getOpenId(); Log.i(TAG, "OpenId : " + openId); SPUtil.put(this, SPConstants.KEY_OPENID, openId); // save user info UserBean userBean = UserUtil.getLocalUser(this, openId); if (userBean == null) { userBean = new UserBean(); userBean.setAvatar(authAccount.getAvatarUriString()); userBean.setDisplayName(authAccount.getDisplayName()); String localStr = new Gson().toJson(userBean); SPUtil.put(this, openId, localStr); } startActivity(new Intent(this, HomeAct.class)); finish(); }

Kotlin代码

/** * HUAWEI Account Login success */ private fun onHuaweiIdLoginSuccess(authAccount: AuthAccount) { val openId = authAccount.openId Log.i(TAG, "OpenId : $openId") // is login SPUtil.put(this, SPConstants.KEY_OPENID, openId) var userBean: UserBean? = UserUtil.getLocalUser(this, openId) if (userBean == null) { userBean = UserBean(authAccount.displayName, authAccount.avatarUriString) val localStr = Gson().toJson(userBean) SPUtil.put(this, openId, localStr) } startActivity(Intent(this, HomeAct::class.java)) finish() }

登录成功后,用户信息展示。

通过指纹认证能力,完成应用使用指纹登录功能,应用主要完成如下步骤。

  1. 应用登录;
  2. 校验是否支持指纹;
  3. 开通指纹登录,并保存华为帐号登录的openId
  4. 指纹登录,通过指纹解密获取openId,并通过openId获取用户信息

具体步骤实现

1. 应用登录

用户使用华为帐号登录,并通过openId保存用户信息。

2. 校验是否支持指纹

校验是否支持指纹认证,如果支持,可以进行下一步骤集成,校验方式:
Java代码

// check fingerprint is support BioAuthnManager bioAuthnManager = new BioAuthnManager(this); int errorCode = bioAuthnManager.canAuth(); if (errorCode != 0) { // not support SPUtil.put(HomeAct.this, SPConstants.FINGER_PRINT_LOGIN_SWITCH, true); return; }

Kotlin代码

// check fingerprint is support val bioAuthnManager = BioAuthnManager(this@HomeAct) val errorCode = bioAuthnManager.canAuth() if (errorCode != 0) { // not support return }

3. 开通指纹登录

步骤1 添加控件,控制指纹认证和登录。

在页面添加一个SwitchCompat控件,来开通指纹登录能力,在未开通前,控件处于关闭状态。

<androidx.appcompat.widget.SwitchCompat android:id="@+id/setting_fingerprint" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="@dimen/dimen_10" android:checked="false" android:thumb="@drawable/switch_circle_bg" app:track="@drawable/switch_bg" />

对添加的开通指纹登录SwitchCompat控件,添加事件监听。

Java代码

mSwitchCompat.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (mSwitchCompat.isChecked()) { // open fingerprint onFingerprintOpenCheck(); } else { // close fingerprint onFingerprintCloseCheck(); } } });

Kotlin代码

home_fingerprint.setOnClickListener { if (home_fingerprint.isChecked) { // open fingerprint onFingerprintOpenCheck(); } else { // close fingerprint onFingerprintCloseCheck(); } }

步骤2 生成加密Cipher。

根据加密的Key(加密Key可根据对称或者非对称加密方式生成),生成对应的Cipher实体。

Java代码

/** * get Encrypt Cipher */ public Cipher getEncryptCipher() { Cipher cipher = null; try { cipher = Cipher.getInstance(JAVA_TRANSFORMATION); cipher.init(Cipher.ENCRYPT_MODE, getKey()); } catch (Exception e) { e.printStackTrace(); } return cipher; }

Kotlin代码

/** * get Encrypt Cipher */ fun getEncryptCipher(): Cipher? { var cipher: Cipher? = null try { cipher = Cipher.getInstance(KOTLIN_TRANSFORMATION) cipher.init(Cipher.ENCRYPT_MODE, getKey()) } catch (e: java.lang.Exception) { e.printStackTrace() } return cipher }

步骤3 生成CryptoObject。

获取com.huawei.hms.support.api.fido.bioauthn.CryptoObject实体。

Java代码

// get cryptoObject CryptoObject cryptoObject = new CryptoObject(KeyHelper.getInstance().getEncryptCipher()); bioAuthnPrompt.auth(info, cryptoObject);

Kotlin代码

// get cryptoObject val cryptoObject = KeyHelper.getInstance().getEncryptCipher()?.let { CryptoObject(it) } if (cryptoObject != null) { bioAuthnPrompt.auth(info, cryptoObject) }

步骤4 调用指纹认证。

Java代码

/** * open fingerprint */ private void onFingerprintOpen() { BioAuthnPrompt bioAuthnPrompt = new BioAuthnPrompt(this, ContextCompat.getMainExecutor(this), authCallback); BioAuthnPrompt.PromptInfo.Builder builder = new BioAuthnPrompt.PromptInfo.Builder() .setTitle("This is the title.") .setSubtitle("This is the subtitle") .setDescription("This is the description"); builder.setNegativeButtonText("This is the 'Cancel' button."); BioAuthnPrompt.PromptInfo info = builder.build(); // get cryptoObject CryptoObject cryptoObject = new CryptoObject(KeyHelper.getInstance().getEncryptCipher()); bioAuthnPrompt.auth(info, cryptoObject); }

Kotlin代码

/** * open fingerprint */ private fun onFingerprintOpen() { val bioAuthnPrompt = BioAuthnPrompt(this, ContextCompat.getMainExecutor(this), authCallback) val builder = BioAuthnPrompt.PromptInfo.Builder() .setTitle("This is the title.") .setSubtitle("This is the subtitle") .setDescription("This is the description") builder.setNegativeButtonText("This is the 'Cancel' button.") val info = builder.build() // get cryptoObject val cryptoObject = KeyHelper.getInstance().getEncryptCipher()?.let { CryptoObject(it) } if (cryptoObject != null) { bioAuthnPrompt.auth(info, cryptoObject) } }

调用成功会显示一个刷指纹的Dialog。

在您成功刷了指纹后,程序用通过authCallback回调,并在回调成功方法onAuthSucceeded(@NotNull BioAuthnResult result)保存OpenId。

Java代码

// call back BioAuthnCallback authCallback = new BioAuthnCallback() { @Override public void onAuthError(int errMsgId, @NonNull CharSequence errString) { Log.e(TAG, "auth error : " + errString); onFingerprintOpenResult(false); } @Override public void onAuthSucceeded(@NonNull BioAuthnResult result) { // Auth Success try { CryptoObject cryptoObject = result.getCryptoObject(); if (null == cryptoObject) { Log.e(TAG, "auth success cryptoObject is null"); onFingerprintOpenResult(false); return; } Cipher cipher = result.getCryptoObject().getCipher(); if (null == cipher) { Log.e(TAG, "auth success cipher is null"); onFingerprintOpenResult(false); return; } String openId = (String) SPUtil.get(HomeAct.this, SPConstants.KEY_OPENID, ""); byte[] bytes = cipher.doFinal(openId.getBytes()); // save Encode FingerprintHelper.put(HomeAct.this, SPConstants.KEY_SAVE_ENCODE, Base64.encodeToString(bytes, Base64.URL_SAFE)); // save IV byte[] iv = cipher.getIV(); FingerprintHelper.put(HomeAct.this, SPConstants.KEY_SAVE_IV, Base64.encodeToString(iv, Base64.URL_SAFE)); Log.i(TAG, "auth success"); onFingerprintOpenResult(true); } catch (Exception e) { e.printStackTrace(); } } @Override public void onAuthFailed() { Log.e(TAG, "auth failed"); onFingerprintOpenResult(false); } };

Kotlin代码

// call back private var authCallback: BioAuthnCallback = object : BioAuthnCallback() { override fun onAuthError(errMsgId: Int, errString: CharSequence) { Log.e("authCallback", "auth error : $errString") onFingerprintOpenResult(false); } override fun onAuthSucceeded(result: BioAuthnResult) { // Auth Success try { val cryptoObject = result.cryptoObject if (null == cryptoObject) { Log.e("authCallback", "auth success cryptoObject is null") onFingerprintOpenResult(false); return } val cipher = result.cryptoObject!!.cipher if (null == cipher) { Log.e("authCallback", "auth success cipher is null") onFingerprintOpenResult(false); return } val openId = SPUtil[this@HomeAct, SPConstants.KEY_OPENID, ""] as String val bytes = cipher.doFinal(openId.toByteArray()) // save Encode FingerprintHelper.put(this@HomeAct, SPConstants.KEY_SAVE_ENCODE, Base64.encodeToString(bytes, Base64.URL_SAFE)) // save IV val iv = cipher.iv FingerprintHelper.put(this@HomeAct, SPConstants.KEY_SAVE_IV, Base64.encodeToString(iv, Base64.URL_SAFE)) Log.i("authCallback", "auth success") onFingerprintOpenResult(true); } catch (e: Exception) { e.printStackTrace() } } override fun onAuthFailed() { Log.e("authCallback", "auth failed") onFingerprintOpenResult(false); } }

4. 指纹登录

步骤1 在登录页,添加指纹登录按钮:

<androidx.appcompat.widget.AppCompatTextView android:id="@+id/login_fingerprint" android:layout_width="200dp" android:layout_height="36dp" android:layout_gravity="center_vertical" android:background="@drawable/bg_fingerprint" android:drawableStart="@drawable/fingerprint" android:drawablePadding="@dimen/dimen_8" android:gravity="center_vertical" android:paddingStart="@dimen/dimen_40" android:text="@string/fingerprint" android:textColor="@color/white" android:textSize="@dimen/text_16" android:visibility="gone" app:flow_horizontalAlign="start" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/login_huaweiAccount" app:layout_constraintStart_toStartOf="@+id/login_huaweiAccount" app:layout_constraintTop_toBottomOf="@+id/login_huaweiAccount" app:layout_constraintVertical_bias="0.1" tools:ignore="MissingConstraints,RtlSymmetry" />

步骤2 调用指纹登录。

调用登录方法。

Java代码

/** * Fingerprint login */ private void onFingerprintLogin() { BioAuthnPrompt bioAuthnPrompt = new BioAuthnPrompt(this, ContextCompat.getMainExecutor(this), loginCallback); BioAuthnPrompt.PromptInfo.Builder builder = new BioAuthnPrompt.PromptInfo.Builder().setTitle("This is the title.") .setSubtitle("This is the subtitle") .setDescription("This is the description"); builder.setNegativeButtonText("This is the 'Cancel' button."); BioAuthnPrompt.PromptInfo info = builder.build(); // save IV String ivStr = FingerprintHelper.get(this, SPConstants.KEY_SAVE_IV); byte[] iv = Base64.decode(ivStr, Base64.URL_SAFE); CryptoObject cryptoObject = new CryptoObject(KeyHelper.getInstance().getDecryptCipher(iv)); bioAuthnPrompt.auth(info, cryptoObject); }

Kotlin代码

/** * Fingerprint login */ private fun onFingerprintLogin() { val bioAuthnPrompt = BioAuthnPrompt(this, ContextCompat.getMainExecutor(this), loginCallback) val builder = BioAuthnPrompt.PromptInfo.Builder().setTitle("This is the title.") .setSubtitle("This is the subtitle") .setDescription("This is the description") builder.setNegativeButtonText("This is the 'Cancel' button.") val info = builder.build() // save IV val ivStr = FingerprintHelper[this, SPConstants.KEY_SAVE_IV] val iv = Base64.decode(ivStr, Base64.URL_SAFE) val cryptoObject = CryptoObject(getInstance().getDecryptCipher(iv)!!) bioAuthnPrompt.auth(info, cryptoObject) }

获取解密的Cipher。

Java代码

/** * get decrypt cipher */ public Cipher getDecryptCipher(byte[] initializeVector) { Cipher cipher = null; try { cipher = Cipher.getInstance(JAVA_TRANSFORMATION); IvParameterSpec ivParameterSpec = new IvParameterSpec(initializeVector); cipher.init(Cipher.DECRYPT_MODE, getKey(), ivParameterSpec); } catch (Exception e) { e.printStackTrace(); } return cipher; }

Kotlin代码

/** * get decrypt cipher */ fun getDecryptCipher(initializeVector: ByteArray?): Cipher? { var cipher: Cipher? = null try { cipher = Cipher.getInstance(KOTLIN_TRANSFORMATION) val ivParameterSpec = IvParameterSpec(initializeVector) cipher.init(Cipher.DECRYPT_MODE, getKey(), ivParameterSpec) } catch (e: Exception) { e.printStackTrace() } return cipher }

调用成功会显示一个刷指纹的Dialog。

在您成功刷了指纹后,程序通过loginCallback回调,

在回调成功方法onAuthSucceeded(@NotNull BioAuthnResult result)中获取OpenId。

Java代码

// call back BioAuthnCallback loginCallback = new BioAuthnCallback() { @Override public void onAuthError(int errMsgId, @NonNull CharSequence errString) { // TODO Login Auth Error Log.e("loginCallback", "login auth error : " + errString); } @Override public void onAuthSucceeded(@NonNull BioAuthnResult result) { try { CryptoObject cryptoObject = result.getCryptoObject(); if (null == cryptoObject) { Log.e(TAG, "auth success cryptoObject is null"); return; } Cipher cipher = result.getCryptoObject().getCipher(); if (null == cipher) { Log.e(TAG, "cipher is null"); return; } String saveEncode = FingerprintHelper.get(LoginAct.this, SPConstants.KEY_SAVE_ENCODE); byte[] input = Base64.decode(saveEncode, Base64.URL_SAFE); byte[] bytes = cipher.doFinal(input); String saveString = new String(bytes); Log.i(TAG, "auth success openId:" + saveString); onFingerprintLoginSuccess(saveString); } catch (Exception e) { e.printStackTrace(); } } @Override public void onAuthFailed() { // TODO Auth Failed Log.e(TAG, "auth failed"); } };

Kotlin代码

// call back private var loginCallback: BioAuthnCallback = object : BioAuthnCallback() { override fun onAuthError(errMsgId: Int, errString: CharSequence) { // TODO Login Auth Error Log.e("loginCallback", "login auth error : $errString") } override fun onAuthSucceeded(result: BioAuthnResult) { try { val cryptoObject = result.cryptoObject if (null == cryptoObject) { Log.e("loginCallback", "auth success cryptoObject is null") return } val cipher = result.cryptoObject!!.cipher if (null == cipher) { Log.e(TAG, "cipher is null") return } val saveEncode = FingerprintHelper[this@LoginAct, SPConstants.KEY_SAVE_ENCODE] val input = Base64.decode(saveEncode, Base64.URL_SAFE) val bytes = cipher.doFinal(input) val saveString = String(bytes) Log.i(TAG, "auth success save openId:$saveString") onFingerprintLoginSuccess(saveString) } catch (e: Exception) { e.printStackTrace() } } override fun onAuthFailed() { // TODO Auth Failed Log.e("loginCallback", "auth failed") } }

步骤3 登录,进入首页:

Java代码

/** * fingerprint login success */ private void onFingerprintLoginSuccess(String openId) { SPUtil.put(this, SPConstants.KEY_OPENID, openId); startActivity(new Intent(this, HomeAct.class)); }

Kotlin代码

/** * fingerprint login success */ private fun onFingerprintLoginSuccess(openId: String) { SPUtil.put(this, SPConstants.KEY_OPENID, openId) startActivity(Intent(this, HomeAct::class.java)) }

指纹登录成功后,用户信息展示。

干得好,您已经成功完成了Codelab并学到了:

您可以阅读下面链接,了解更多相关的信息。

您可以点击下方按钮下载源码。

源码下载

已复制代码