当前位置: 首页 > article >正文

HarmonyOS Next系列之华为账号一键登录功能实现(十四)

系列文章目录

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 Code
          const 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();
    // 一键登录场景该参数必须设置为false
    authRequest.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 Code
          const 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();
    // 一键登录场景该参数必须设置为false
    authRequest.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() {
        // logo
        Image($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)
  }
}

http://www.kler.cn/a/474205.html

相关文章:

  • 数据结构:包装类和泛型
  • 联邦学习中的LoRA:FedLoRA
  • 使用免费内网穿透(p2p)网络环境搭建小型文件管理服务器(简单操作)
  • Python学习笔记:显示进度条
  • 性能测试01|性能测试理论
  • C语言 数组编程练习
  • 【MySQL】九、表的内外连接
  • C# 实现 gRPC 进程间通讯:两台设备的数据交换之道
  • 前端笔记:获取leetcode题目
  • 【复杂网络演化博弈_01】理论部分+代码应用
  • [Unity]MacOS下开发Unity
  • TCP通信原理学习
  • sql 查询尾差(去尾0后小数点的位数)
  • maven如何从外部导包
  • liunx后台运行jar包
  • 2025 西电软工数据结构机考 Tip (By Felix)
  • npm run 运行项目报错:Cannot resolve the ‘pnmp‘ package manager
  • Centos7使用yum工具出现 Could not resolve host: mirrorlist.centos.org
  • 高级 SQL 技巧:提升数据查询与分析能力
  • 202305 青少年软件编程等级考试C/C++ 一级真题答案及解析(电子学会)
  • 消息队列架构、选型、专有名词解释
  • 更改Endnote在word中的字体输出样式、段落格式问题等
  • git自用指南
  • 比较procfs 、 sysctl和Netlink
  • 202312 青少年软件编程等级考试C/C++ 一级真题答案及解析(电子学会)
  • 免费网站源码下载指南:如何安全获取并降低开发成本