系列文章目录
HarmonyOS Next 系列之省市区弹窗选择器实现(一)
HarmonyOS Next 系列之验证码输入组件实现(二)
HarmonyOS Next 系列之底部标签栏TabBar实现(三)
HarmonyOS Next 系列之HTTP请求封装和Token持久化存储(四)
HarmonyOS Next 系列之从手机选择图片或拍照上传功能实现(五)
HarmonyOS Next 系列之可移动悬浮按钮实现(六)
HarmonyOS Next 系列之沉浸式状态实现的多种方式(七)
HarmonyOS Next系列之Echarts图表组件(折线图、柱状图、饼图等)实现(八)
HarmonyOS Next系列之地图组件(Map Kit)使用(九)
HarmonyOS Next系列之半圆环进度条实现(十)
HarmonyOS Next 系列之列表下拉刷新和触底加载更多数据实现(十一)
HarmonyOS Next系列之实现一个左右露出中间大两边小带缩放动画的轮播图(十二)
HarmonyOS Next系列之水波纹动画特效实现(十三)
HarmonyOS Next系列之华为账号一键登录功能实现(十四)
系列文章目录2
【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器(上)
【鸿蒙】HarmonyOS NEXT开发快速入门教程之ArkTS语法装饰器(下)
【鸿蒙】HarmonyOS NEXT应用开发快速入门教程之布局篇(上)
【鸿蒙】HarmonyOS NEXT应用开发快速入门教程之布局篇(下)
【鸿蒙】HarmonyOS Next 组件或页面之间的所有通信(传参)方法总结
文章目录
- 系列文章目录
- 系列文章目录2
- 前言
- 一、开发前准备
- 1、配置Client ID
- 2、配置scope权限
- 二、功能约束
- 三、页面设计规范
- 四、组件和API讲解
- 1、一键登录按钮组件LoginWithHuaweiIDButton
- 2、修改用户协议状态
- 3、获取用户匿名手机号
- 4、一键登录错误回调处理
- 五、完整代码
前言
华为账号一键登录是指使用华为账号进行快捷登录的功能。通过一键登录,用户可以通过华为账号直接登录到指定的应用,无需输入繁琐的账号和密码。一键登录可以提供更便捷、快速、安全的登录方式,减少用户的登录烦恼和输入错误。 本文将以代码示例讲解鸿蒙next华为账号一键登录客户端实现过程和页面设计规范。
一、开发前准备
1、配置Client ID
登录AppGallery Connect平台,获取在“项目设置 > 常规 > 应用”区域获取“OAuth 2.0客户端ID(凭据)”处的Client ID。
在工程中entry模块的module.json5文件中,新增metadata,配置name为client_id,value为上一步获取的Client ID的值
2、配置scope权限
篇幅较长直接看官方教程 开启华为账号服务权限教程
二、功能约束
(1)华为账号一键登录服务当前仅限中国大陆用户可用。
(2)后端服务器必须部署在中国大陆境内。
(3)用户必须同意《华为账号用户认证协议》方可登录,同时可查看协议详细说明。
《华为账号用户认证协议》链接:https://privacy.consumer.huawei.com/legal/id/authentication-terms.htm?code=CN&language=zh-CN
系统深色模式下跳转到:
https://privacy.consumer.huawei.com/legal/id/authentication-terms.htm?code=CN&language=zh-CN&bgmode=black。
三、页面设计规范
页面设计不规范将影响审核通过,尽量按官方要求来设计
页面设计可以参考上图官方示例
登录页:
(1)首次登录必须要显示用户匿名手机号
(1)首次登录必须要显示“华为账号绑定号码”固定文字
(2)必须要显示《华为账号用户认证协议》,点击可以跳到内页查看协议详情。
(3)必须要显示华为账号一键登录按钮
(4)可选择显示应用logo或头像
(5)可选择显示其他登录方式入口
(6)可选择增加显示其他协议,比如用户协议、隐私协议等
四、组件和API讲解
客户端实现一键登录的核心提炼就是通过点击一键登录按钮将回调获取的Authorization Code数据传给服务器(后端)即可。
服务器通过调用获取用户级凭证接口和获取用户信息接口获取用户完整手机号和UnionID、OpenID完成用户关联
1、一键登录按钮组件LoginWithHuaweiIDButton
引用方式:
import { LoginWithHuaweiIDButton, loginComponentManager } from '@kit.AccountKit';
参数:
说明:
params为组件参数可以对组件样式进行设置,参考params官方文档
controller为控制器,可以设置用户协议状态(setAgreementStatus)、一键登录结果事件回调(onClickLoginWithHuaweiIDButton)等操作,参考controller官方文档
示例:
import { loginComponentManager, LoginWithHuaweiIDButton } from '@kit.AccountKit'
@Entry
@Component
struct Demo{
// 构造LoginWithHuaweiIDButton组件的控制器controller: loginComponentManager.LoginWithHuaweiIDButtonController =new loginComponentManager.LoginWithHuaweiIDButtonController()/*** 当应用使用自定义的登录页时,如果用户未同意协议,需要设置协议状态为NOT_ACCEPTED,当用户同意协议后再设置* 协议状态为ACCEPTED,才可以使用华为账号一键登录功能*/.setAgreementStatus(loginComponentManager.AgreementStatus.NOT_ACCEPTED)//执行一键登录回调.onClickLoginWithHuaweiIDButton((error: BusinessError, response: loginComponentManager.HuaweiIDCredential) => {if (error) {this.dealAllError(error);return;}if (response) {// 获取到Authorization Codeconst authorizationCode = response.authorizationCode;//底下逻辑把code通过接口发送个后端实现登录}})// 错误处理dealAllError(error: BusinessError): void {}build() {//一键登录按钮LoginWithHuaweiIDButton({controller: this.controller})}
}
2、修改用户协议状态
用户协议状态必须设置已同意《华为账号用户认证协议》才能正常执行一键登录功能,否则返回错误信息,可通过controller.setAgreementStatus(status:AgreementStatus) 设置,实际开发中初始化控制器默认设置未同意状态,等待用户勾选后再改变为已同意。
AgreementStatus枚举值
import { loginComponentManager} from '@kit.AccountKit'
//已同意
controller.setAgreementStatus(loginComponentManager.AgreementStatus.ACCEPTED)
//未同意
controller.setAgreementStatus(loginComponentManager.AgreementStatus.NOT_ACCEPTED)
3、获取用户匿名手机号
async getAnonymousPhone() {//匿名手机号let anonymousPhone: string = ''// 创建授权请求,并设置参数const authRequest = new authentication.HuaweiIDProvider().createAuthorizationWithHuaweiIDRequest();// 获取匿名手机号需传quickLoginAnonymousPhone这个scope,传参之前需要先申请“华为账号一键登录”权限authRequest.scopes = ['quickLoginAnonymousPhone'];// 用于防跨站点请求伪造authRequest.state = util.generateRandomUUID();// 一键登录场景该参数必须设置为falseauthRequest.forceAuthorization = false;const controller = new authentication.AuthenticationController();try {let response: authentication.AuthorizationWithHuaweiIDResponse = await controller.executeRequest(authRequest)anonymousPhone = response.data?.extraInfo?.quickLoginAnonymousPhone as string;} catch (error) {}return anonymousPhone}
4、一键登录错误回调处理
错误回调是BusinessError类型,错误码枚举值定义如下:
enum ErrorCode {// 账号未登录ERROR_CODE_LOGIN_OUT = 1001502001,// 该账号不支持一键登录,如儿童账号、海外账号ERROR_CODE_NOT_SUPPORTED = 1001500003,// 网络错误ERROR_CODE_NETWORK_ERROR = 1001502005,// 用户未同意用户协议ERROR_CODE_AGREEMENT_STATUS_NOT_ACCEPTED = 1005300001,// 参数错误ERROR_CODE_PARAMETER_ERROR = 401
}
处理逻辑
// 错误处理dealAllError(error: BusinessError): void {if (error.code === ErrorCode.ERROR_CODE_NETWORK_ERROR) {AlertDialog.show({message: "网络未连接,请检查网络设置。",offset: { dx: 0, dy: -12 },alignment: DialogAlignment.Bottom,autoCancel: false,confirm: {value: "知道了",action: () => {}}});} else if (error.code === ErrorCode.ERROR_CODE_AGREEMENT_STATUS_NOT_ACCEPTED) {// 未同意协议this.showToast("请阅读并同意协议");} else if (error.code === ErrorCode.ERROR_CODE_LOGIN_OUT) {// 华为账号未登录提示this.showToast("华为账号未登录,请先登录");} else if (error.code === ErrorCode.ERROR_CODE_NOT_SUPPORTED) {// 不支持该scopes或permissions提示this.showToast("该scopes或permissions不支持");} else if (error.code === ErrorCode.ERROR_CODE_PARAMETER_ERROR) {// 参数错误提示this.showToast("参数错误");} else {// 其他提示系统或服务异常this.showToast('服务或网络异常,请稍后重试');}}// Toast提示showToast(resource: string) {try {promptAction.showToast({message: resource,duration: 2000});} catch (error) {}}
五、完整代码
实现如下图所示效果:
QuickLoginDemo.ets(登录页)
import { authentication, loginComponentManager, LoginWithHuaweiIDButton } from '@kit.AccountKit'
import { promptAction, router } from '@kit.ArkUI';
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';@Entry
@Component
struct QuickLoginDemo {//是否同意隐私协议@State isAgree: boolean = false//匿名手机号@State phone: string = ''// 构造LoginWithHuaweiIDButton组件的控制器controller: loginComponentManager.LoginWithHuaweiIDButtonController =new loginComponentManager.LoginWithHuaweiIDButtonController()/*** 当应用使用自定义的登录页时,如果用户未同意协议,需要设置协议状态为NOT_ACCEPTED,当用户同意协议后再设置* 协议状态为ACCEPTED,才可以使用华为账号一键登录功能*/.setAgreementStatus(loginComponentManager.AgreementStatus.NOT_ACCEPTED).onClickLoginWithHuaweiIDButton((error: BusinessError, response: loginComponentManager.HuaweiIDCredential) => {if (error) {this.dealAllError(error);return;}if (response) {// 获取到Authorization Codeconst authorizationCode = response.authorizationCode;console.log(authorizationCode.toString(),'code')//底下写接口请求登录逻辑,code传给服务器//模拟接口setTimeout(()=>{this.showToast('登录成功!')},2000)}});// 错误处理dealAllError(error: BusinessError): void {if (error.code === ErrorCode.ERROR_CODE_NETWORK_ERROR) {AlertDialog.show({message: "网络未连接,请检查网络设置。",offset: { dx: 0, dy: -12 },alignment: DialogAlignment.Bottom,autoCancel: false,confirm: {value: "知道了",action: () => {}}});} else if (error.code === ErrorCode.ERROR_CODE_AGREEMENT_STATUS_NOT_ACCEPTED) {// 未同意协议this.showToast("请阅读并同意协议");} else if (error.code === ErrorCode.ERROR_CODE_LOGIN_OUT) {// 华为账号未登录提示this.showToast("华为账号未登录,请先登录");} else if (error.code === ErrorCode.ERROR_CODE_NOT_SUPPORTED) {// 不支持该scopes或permissions提示this.showToast("该scopes或permissions不支持");} else if (error.code === ErrorCode.ERROR_CODE_PARAMETER_ERROR) {// 参数错误提示this.showToast("参数错误");} else {// 其他提示系统或服务异常this.showToast('服务或网络异常,请稍后重试');}}// Toast提示showToast(resource: string) {try {promptAction.showToast({message: resource,duration: 2000});} catch (error) {}}//获取匿名手机号async getAnonymousPhone() {//匿名手机号let anonymousPhone: string = ''// 创建授权请求,并设置参数const authRequest = new authentication.HuaweiIDProvider().createAuthorizationWithHuaweiIDRequest();// 获取匿名手机号需传quickLoginAnonymousPhone这个scope,传参之前需要先申请“华为账号一键登录”权限authRequest.scopes = ['quickLoginAnonymousPhone'];// 用于防跨站点请求伪造authRequest.state = util.generateRandomUUID();// 一键登录场景该参数必须设置为falseauthRequest.forceAuthorization = false;const controller = new authentication.AuthenticationController();try {let response: authentication.AuthorizationWithHuaweiIDResponse = await controller.executeRequest(authRequest)anonymousPhone = response.data?.extraInfo?.quickLoginAnonymousPhone as string;} catch (error) {}return anonymousPhone}//初始化async aboutToAppear() {//获取匿名手机号this.phone = await this.getAnonymousPhone()}build() {Navigation() {Column() {// logoImage($r('app.media.logo')).width(100).height(100).borderRadius(20).margin({ top: 80 })// 匿名手机号Text(this.phone).fontSize(40).margin({ top: 60 })Text('华为账号绑定号码').fontSize(13).fontColor('#999').margin({ top: 10 })Column() {//一键登录按钮LoginWithHuaweiIDButton({params: {// LoginWithHuaweiIDButton支持的样式style: loginComponentManager.Style.BUTTON_RED,// 账号登录按钮在登录过程中展示加载态extraStyle: {buttonStyle: new loginComponentManager.ButtonStyle().loadingStyle({show: true})},// LoginWithHuaweiIDButton的边框圆角半径borderRadius: 24,// LoginWithHuaweiIDButton支持的登录类型loginType: loginComponentManager.LoginType.QUICK_LOGIN,customButtonParams: {backgroundColor: 'rgba(255,255,255,0.6)'},// LoginWithHuaweiIDButton支持按钮的样式跟随系统深浅色模式切换supportDarkMode: true,// verifyPhoneNumber:如果华为账号用户在过去90天内未进行短信验证,是否拉起Account Kit提供的短信验证码页面verifyPhoneNumber: true},controller: this.controller}).width('100%').height(48)//其他登录按钮Button('其他方式登录').margin({ top: 16 }).height(48).width('100%').backgroundColor('#F2F2F2').fontColor('#000')}.margin({ top: 50 })Blank()//隐私协议Row() {//勾选框Column() {if (this.isAgree) {Image($r('app.media.checked')).width(18)} else {Circle({ width: 18, height: 18 }).stroke('#999').fill('rgba(0,0,0,0)')}}.onClick(() => {this.isAgree = !this.isAgree//设置协议状态this.controller.setAgreementStatus(this.isAgree ? loginComponentManager.AgreementStatus.ACCEPTED :loginComponentManager.AgreementStatus.NOT_ACCEPTED);})//协议文字Flex({direction: FlexDirection.Row,alignItems: ItemAlign.Start,wrap: FlexWrap.Wrap}) {Text('已阅读并同意').custText('#999')Text('《xxxx用户协议》').custText('#000')Text('《xxxx用户协议》').custText('#000')Text('和').custText('#999')Text('《华为账号用户认证协议》').custText('#000').onClick(()=>{router.pushUrl({url:'pages/agreement'})})}.margin({ left: 8 })}.width('100%').padding({ left: 10 })}.padding(20).height('100%')}.hideTitleBar(true).hideToolBar(true).height('100%').width('100%')}
}@Extend(Text)
function custText(fontColor: ResourceColor) {.fontSize(12).fontColor(fontColor).lineHeight(18)
}enum ErrorCode {// 账号未登录ERROR_CODE_LOGIN_OUT = 1001502001,// 该账号不支持一键登录,如儿童账号、海外账号ERROR_CODE_NOT_SUPPORTED = 1001500003,// 网络错误ERROR_CODE_NETWORK_ERROR = 1001502005,// 用户未同意用户协议ERROR_CODE_AGREEMENT_STATUS_NOT_ACCEPTED = 1005300001,// 参数错误ERROR_CODE_PARAMETER_ERROR = 401
}
Agreement.ets(华为账号用户认证协议页)
/*** 华为账号用户认证协议页*/
import { webview } from '@kit.ArkWeb';@Entry
@Component
struct Agreement {@State webUrl: string = 'https://privacy.consumer.huawei.com/legal/id/authentication-terms.htm?code=CN&language=zh-CN'private controller: webview.WebviewController = new webview.WebviewController()build() {Navigation() {Web({ src: this.webUrl, controller: this.controller }).zoomAccess(false).height('100%').width('100%')}.title('华为账号用户认证协议').titleMode(NavigationTitleMode.Mini)}
}