在鸿蒙(HarmonyOS)系统中开通认证服务 如何使用自己设计的UI界面和修改个人信息(例:上传头像)的步骤如下:
2025-06-29 10:36:14
209次阅读
0个评论
1. 准备工作
1. 注册华为开发者账号
- 访问华为开发者联盟官网并注册账号。
- 完成实名认证(个人或企业开发者),需提供身份证或企业资质信息。
2. 登录AppGallery Connect (AGC)
- 使用华为开发者账号登录AGC控制台。
- 创建或选择已有项目。
3. 开通认证服务
- 在项目设置中,点击左侧菜单的 “认证服务”。
- 选择需要开通的认证方式(如手机验证码、邮箱、生物识别等)并启用。
4. 配置端侧项目
- 添加依赖:在oh-package.json5中引入相关SDK,如:
"dependencies": {
  "@hw-agconnect/cloud": "^1.0.0",
  "@hw-agconnect/hmcore": "^1.0.0"
}
- 开通网络权限:在module.json5中申请INTERNET权限。
- 更新agconnect-services.json:从AGC下载最新配置文件并集成到项目中。
5. 登录页面实现 (MyLogin.ets)
5.1 基础界面代码
@Entry
@Component
struct MyLogin {
  // 状态变量声明
  @State phoneNumber: string = '';  //手机号
  @State verifyCode: string = '';   //验证码
  build() {
    Column({space:10}){
      Text('登录').fontSize(24)
      Divider()
      Row(){
        TextInput({ placeholder: '请输入手机号' })
          .width(160)
          .onChange((val) => { 
            this.phoneNumber = val // 绑定手机号输入
          }) 
      }
      Row(){
        TextInput({placeholder:'请输入验证码'})
          .width(150)
          .onChange((val)=>{
            this.verifyCode = val // 绑定验证码输入
          }) 
        Button('获取验证码').onClick(async ()=>{ 
          /* 调用5.2逻辑 */
        })
      }
      Button('登录').onClick(async () => {
        /* 调用5.3逻辑 */
      })
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
  }
}
说明:
- 使用ArkUI声明式语法构建登录界面,包含手机号和验证码输入框
- 通过@State实现数据响应式绑定,输入内容实时更新状态变量
5.2 验证码功能实现
        Button('获取验证码')
          .onClick(async ()=>{
            try {
              await cloud.auth().requestVerifyCode({
                verifyCodeType: {
                  kind: 'phone',
                  phoneNumber: this.phoneNumber,  // 获取用户输入的手机号
                  countryCode: '86'
                },
                action: VerifyCodeAction.REGISTER_LOGIN,
                lang: 'zh_CN',
                sendInterval: 60
              })
              promptAction.showToast({ message: '验证码已发送' })
            } catch (error) {
              promptAction.showToast({ message: `发送失败: ${error.message}` })
            }
          })
说明:
- requestVerifyCode方法向指定手机号发送验证码
- sendInterval参数防止频繁发送,提升安全性
5.3 登录功能实现
  @State verifyCode:string = ''  // 验证码
  @StorageLink('user')user:AuthUser | null= null //使用 AppStorage 保存当前登录的用户信息
  
      
      Button('登录')
        .onClick(async () => {
          try {
            const  result = await cloud.auth().signIn({
              credentialInfo: {
                kind: 'phone',
                countryCode: '86',
                phoneNumber: this.phoneNumber, // 获取用户输入的手机号
                verifyCode: this.verifyCode  // 获取用户输入的验证码
              }
            })
            const user = result.getUser() // 用户信息
            AppStorage.setOrCreate('user',user) // 保存用户信息
            router.replaceUrl({url:'pages/MyInfo'})
            promptAction.showToast({ message: '登录成功' })
          } catch (error) {
            console.error('登录失败:', error)
            promptAction.showToast({ message: '登录失败' })
          }
        })
说明:
- signIn方法通过手机号+验证码完成登录验证
- AppStorage实现用户信息跨页面持久化
5.4处理异常退出后无法登录
  async aboutToAppear(): Promise<void> {
    // 防止异常退出应用无法登录
    try {
      const user = await cloud.auth().getCurrentUser()
      if (user != null) {
        AppStorage.setOrCreate('user',user)
        router.replaceUrl({url:'pages/MyInfo'})
      }
    }catch (e){
    }
  }
6. 用户信息页面 (MyInfo.ets)
6.1 基础界面
@State username: string = '';
@State photoUrl: string = '';
@State uris: Array<string> = []; // 新增:图片URI数组
@StorageLink('user') user: AuthUser | null = null;
build() {
  Column({space:10}){
    Image(this.photoUrl == undefined?$r('app.media.user_dark'):this.photoUrl)
      .width(70)
      .onClick(()=>{
        this.getFileAssetsFromType()  // 调用6.3逻辑
      }) 
    Row(){
      Text('昵称:')
      TextInput({placeholder:`${this.username}`})
        .onChange((val)=>{ 
          this.username = val
        })
    }
    Button('保存').onClick(async () => {
      /* 调用6.4逻辑 */ 
    })
    Button('退出登录').onClick(async ()=>{
      /* 调用6.5逻辑 */
    })
  }
  .height('100%')
  .width('100%')
}
说明:
- 通过条件渲染显示用户头像或默认占位图
- 点击头像触发文件选择器
6.2 用户信息获取
  @State username: string = '';  //用户昵称
  @State photoUrl : string = '' //用户头像
  @StorageLink('user')user:AuthUser | null= null // 登录的用户信息
    aboutToAppear(): void {
    // 1.
    cloud.auth().getCurrentUser()  // 方法一直接获取当前登录的用户信息
  
    // 2.AppStorage               使用上一个登录页面的 AppStorage 保存当前登录的用户信息
    this.photoUrl = this.user?.getPhotoUrl() as string
    this.username = this.user?.getDisplayName() as string
  }
说明:
- aboutToAppear生命周期钩子在页面显示前初始化数据
- 优先从AppStorage获取用户信息,减少网络请求
6.3 头像上传功能
  /**
   *  图片上传
   */
  getFileAssetsFromType(){
    //  获取图片选择对象实例
    const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions()
    //  定义当前图片选择器选择图片的最大数量
    photoSelectOptions.maxSelectNumber = 1
    //  定义选择数据的类型
    photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE
    //  创建图库选择器实例
    const photoviewPicker = new photoAccessHelper.PhotoViewPicker()
    photoviewPicker.select(photoSelectOptions)
      .then((value)=>{
        // 获取到选择图片的路径,数组类型数据
        this.uris = value.photoUris
        this.photoCount = this.uris.length
        this.photoUrl = this.uris[0]
      }).catch((err:BusinessError)=>{
      console.error('err',JSON.stringify(err))
      return
    })
  }
       Image(this.photoUrl == undefined?$r('app.media.user_dark'):this.photoUrl)  // 设置默认头像
        .width(70)
        .onClick(()=>{
          this.getFileAssetsFromType()  // 调用上传头像方法
        })
说明:
- 使用系统相册选择器获取本地图片URI
6.4 数据保存功能
      Button('保存')
        .onClick(async () => {
          if (!this.user) {
            promptAction.showToast({ message: '用户未登录' });
            return;
          }
          try {
            await this.user.updateProfile({
              displayName: this.username, // 获取修改后的用户名
              photoUrl: this.photoUrl   // 获取修改后的头像
            });
            promptAction.showToast({ message: '保存成功' });
          } catch (e) {
            console.error(e); // 打印错误信息到控制台
            promptAction.showToast({ message: '保存失败: ' + e.message });
          }
        })
说明:
- 保存前校验用户登录状态
- updateProfile需配合云存储使用
6.5 退出登录
Button('退出登录')
  .onClick(async ()=>{
    try {
      await cloud.auth().signOut();
      this.user = null; // 清空本地用户状态
      router.back(); // 返回上一页
    } catch (error) {
      console.error('退出失败:', error);
    }
  })
说明:
- signOut清除本地认证令牌
- 同步更新全局存储中的用户状态
补充说明:
- 状态管理: 
  - @State用于组件内响应式数据,- @StorageLink实现跨组件数据共享
- 复杂场景建议使用全局状态管理(如Redux模式)
 
- 调试建议: 
  - 真机测试需确保AGC项目配置正确的OAuth 2.0回调地址
- 使用console.log打印用户对象结构,验证数据获取
 
- 结合华为云服务实现端云一体化认证。
如需更详细的代码示例或高级配置(如生物识别认证),可参考华为官方文档或相关教程。
完整代码和模拟器演示:
1.登录页面实现 (MyLogin.ets)
import cloud, { AuthUser, VerifyCodeAction } from '@hw-agconnect/cloud'
import { promptAction, router } from '@kit.ArkUI'
@Entry
@Component
struct MyLogin {
  @State phoneNumber:string = ''
  @State verifyCode:string = ''
  @StorageLink('user')user:AuthUser | null= null
  async aboutToAppear(): Promise<void> {
    // 防止异常退出应用无法登录
    try {
      const user = await cloud.auth().getCurrentUser()
      if (user != null) {
        AppStorage.setOrCreate('user',user)
        router.replaceUrl({url:'pages/MyInfo'})
      }
    }catch (e){
    }
  }
  build() {
    Column({space:10}){
      Text('登录')
        .fontSize(24)
      Divider()
      Row(){
        TextInput({placeholder:'请输入手机号'})
          .width(260)
          .onChange((val)=>{
            this.phoneNumber = val
          })
      }
      Row(){
        TextInput({placeholder:'请输入验证码'})
          .width(150)
          .onChange((val)=>{
            this.verifyCode = val
          })
        Button('获取验证码')
          .onClick(async ()=>{
            try {
              await cloud.auth().requestVerifyCode({
                verifyCodeType: {
                  kind: 'phone',
                  phoneNumber: this.phoneNumber,
                  countryCode: '86'
                },
                action: VerifyCodeAction.REGISTER_LOGIN,
                lang: 'zh_CN',
                sendInterval: 60
              })
              promptAction.showToast({ message: '验证码已发送' })
            } catch (error) {
              promptAction.showToast({ message: `发送失败: ${error.message}` })
            }
          })
      }
      Button('登录')
        .onClick(async () => {
          try {
            const  result = await cloud.auth().signIn({
              credentialInfo: {
                kind: 'phone',
                countryCode: '86',
                phoneNumber: this.phoneNumber,
                verifyCode: this.verifyCode
              }
            })
            const user = result.getUser() // 用户信息
            AppStorage.setOrCreate('user',user) // 保存用户信息
            router.replaceUrl({url:'pages/MyInfo'})
            promptAction.showToast({ message: '登录成功' })
          } catch (error) {
            console.error('登录失败:', error)
            promptAction.showToast({ message: '登录失败' })
          }
        })
    }
    .justifyContent(FlexAlign.Center)
    .height('100%')
    .width('100%')
  }
}
/**
 * user.getuid()  //获取用户唯一标识
 *user.getPhone()  //获取手机号
 *user.getEmail()  // 获取邮箱
 *user.getUserExtra() //获取用户创建时间 和 最近一次的登录时间
 * user.getPhotoUrl()  // 头像
 * user.getDisplayName()  //昵称
 */
2.用户信息页面 (MyInfo.ets)
import cloud, { AuthUser } from '@hw-agconnect/cloud';
import { promptAction, router } from '@kit.ArkUI';
import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { error } from '@hw-agconnect/hmcore/src/main/ets/error/CoreErrorCode';
@Entry
@Component
struct MyInfo {
  @State username: string = '';  //用户昵称
  @State photoUrl : string = '' //用户头像
  @StorageLink('user')user:AuthUser | null= null // 登录的用户信息
  @State uris:Array<string> = [] // 从图库获取的图片路径组
  @State photoCount:number = 0
  aboutToAppear(): void {
    // 1.
    cloud.auth().getCurrentUser()
    // 2.AppStorage
    this.photoUrl = this.user?.getPhotoUrl() as string
    console.log('useruser',`${this.photoUrl}`);
    this.username = this.user?.getDisplayName() as string
    console.log('useruser',JSON.stringify(this.user?.getDisplayName()));
    console.log('useruser',`${this.username}`);
  }
  /**
   *  图片上传
   */
  getFileAssetsFromType(){
    //  获取图片选择对象实例
    const photoSelectOptions = new photoAccessHelper.PhotoSelectOptions()
    //  定义当前图片选择器选择图片的最大数量
    photoSelectOptions.maxSelectNumber = 1
    //  定义选择数据的类型
    photoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE
    //  创建图库选择器实例
    const photoviewPicker = new photoAccessHelper.PhotoViewPicker()
    photoviewPicker.select(photoSelectOptions)
      .then((value)=>{
        // 获取到选择图片的路径,数组类型数据
        this.uris = value.photoUris
        this.photoCount = this.uris.length
        this.photoUrl = this.uris[0]
      }).catch((err:BusinessError)=>{
      console.error('err',JSON.stringify(err))
      return
    })
  }
  build() {
    Column({space:10}){
      Image(this.photoUrl == undefined?$r('app.media.user_dark'):this.photoUrl)
        .width(70)
        .onClick(()=>{
          this.getFileAssetsFromType()
          this.photoUrl = this.uris[0]
        })
      Row(){
        Text('昵称:')
        TextInput({placeholder:`${this.username}`})
          .onChange((val)=>{
            this.username = val
          })
      }
      Button('保存')
        .onClick(async () => {
          if (!this.user) {
            promptAction.showToast({ message: '用户未登录' });
            return;
          }
          try {
            await this.user.updateProfile({
              displayName: this.username,
              photoUrl: this.photoUrl
            });
            promptAction.showToast({ message: '保存成功' });
          } catch (e) {
            console.error(e); // 打印错误信息到控制台
            promptAction.showToast({ message: '保存失败: ' + e.message });
          }
        })
      Button('退出登录')
        .onClick(async ()=>{
          try {
            await cloud.auth().signOut() // 退出登录
            router.replaceUrl({ url: 'pages/Index' })
            promptAction.showToast({ message: '保存成功' })
          }catch (e) {
          }
        })
    }
    .height('100%')
    .width('100%')
  }
}
3.演示效果
00
- 0回答
- 0粉丝
- 0关注
相关话题
- 在鸿蒙(HarmonyOS 5)系统中开通认证服务的步骤如下(Login()组件):
- 《仿盒马》app开发技术分享-- 个人信息页(23)
- Uniapp在鸿蒙中的使用 二
- HarmonyNext技术探索:ArkTS在鸿蒙系统中的高级动画与交互设计
- 鸿蒙5.0如何快速接入端云一体化的认证服务
- 【HarmonyOS】模仿个人中心头像图片,调用系统相机拍照,从系统相册选择图片和圆形裁剪显示 (一)
- 【HarmonyOS】模仿个人中心头像图片,调用系统相机拍照,从系统相册选择图片和圆形裁剪显示 (二)
- 【HarmonyOS 5】鸿蒙中如何使用MQTT
- 【HarmonyOS 5】鸿蒙中如何使用MQTT
- HarmonyOS NEXT 头像制作项目系列教程之 --- 头像上传功能实现
- HarmonyNext深度解析:ArkTS在鸿蒙系统中的高级应用与实践
- HarmonyNext技术解析:ArkTS在鸿蒙系统中的高效性能优化实践
- OpenHarmony 设计模式-单例模式
- 如何通过系统相机拍照和录像
- HarmonyNext:深入探索鸿蒙内核与ArkTS在系统开发中的实践

