HarmonyOS《柚兔学伴》项目实战20-华为一键登录与数据备份
第20篇:华为一键登录与数据备份
在移动应用中,用户身份认证和数据备份是提升用户体验和数据安全的关键能力。HarmonyOS 提供了华为账号一键登录和端云数据备份机制,"柚兔学伴"项目通过 backup_air 第三方库将两者整合,实现了无缝的登录流程和自动化的数据备份恢复。本篇详细讲解其实现方式。

1. backup_air 库概述
backup_air 是项目使用的第三方库,封装了华为账号登录、云端备份恢复和用户信息管理能力。主要提供以下核心类:
| 类名 | 职责 |
|---|---|
BackupManager |
备份恢复管理,含登录、备份、恢复操作 |
BackupDir |
备份目录配置 |
BackupConfig |
备份配置读取 |
UserInfoManager |
用户信息管理(登录状态、Token、用户资料) |
2. BackupManager 初始化
2.1 BackupManagerService 单例
项目通过 BackupManagerService 单例封装 BackupManager 的初始化和状态管理:
import { BackupDir, BackupManager } from 'backup_air';
import { DbUtil } from '../util/Dbutil';
export class BackupManagerService {
private static instance: BackupManagerService;
private isInitialized: boolean = false;
private isLoggedIn: boolean = false;
private userInfo: string = '未登录';
private constructor() {}
public static getInstance(): BackupManagerService {
if (!BackupManagerService.instance) {
BackupManagerService.instance = new BackupManagerService();
}
return BackupManagerService.instance;
}
public isBackupManagerInitialized(): boolean {
return this.isInitialized;
}
public getLoginState(): boolean {
return this.isLoggedIn;
}
public getUserInfo(): string {
return this.userInfo;
}
private updateLoginState() {
this.isLoggedIn = true;
this.userInfo = '已登录';
}
}
2.2 初始化配置
initializeBackupManager() 是核心初始化方法,配置了备份恢复的所有参数:
public async initializeBackupManager(): Promise<void> {
try {
const backupManager = BackupManager.getInstance();
let store = (await DbUtil.getInstance(getContext().getApplicationContext())).store;
if (!store) {
throw new Error('未初始化数据库');
}
backupManager.init({
onCompleteBackup: () => {
console.log('自定义回调- 备份完成');
},
onCompleteRestore: () => {
console.log('自定义回调- 恢复完成');
},
updateDbVersion: (cloudDbVersion) => {
console.log("自定义回调- 更新数据库版本 云端数据库版本" + cloudDbVersion);
},
cloudDir: `testUser`,
cloudDbName: 'Partner.db',
storeConfig: DbUtil.STORE_CONFIG,
backupDirs: [new BackupDir("testDir", "testCloud.zip")],
cloudStorageType: 'sdk',
bucketName: "partner-xhmds",
productId: '461323198430304163',
client_id: '1766045115320685696',
client_secret: '34E13149AF818215E17E6192F0059E95B7517DB143C524D29EC8044699497C5E',
oauth_client_id: "6917583027092394696",
oauth_client_secret: "91089c76b37141672901fe606ad38de79bf51138544988765d3cbd4ccd1ff435",
}, store);
this.isInitialized = true;
this.updateLoginState();
console.log('BackupManager初始化成功');
} catch (error) {
console.error('BackupManager初始化失败:', error);
promptAction.showToast({ message: 'BackupManager初始化失败' });
this.isInitialized = false;
this.isLoggedIn = false;
this.userInfo = '初始化失败,未登录';
}
}
2.3 配置参数详解
| 参数 | 说明 |
|---|---|
onCompleteBackup |
备份完成回调,可在其中刷新 UI |
onCompleteRestore |
恢复完成回调,通常需要重新加载数据 |
updateDbVersion |
云端数据库版本变更回调,用于处理数据迁移 |
cloudDir |
用户在云存储中的目录,不同用户应使用不同目录 |
cloudDbName |
云端存储的数据库文件名,这里是 Partner.db |
storeConfig |
本地 RDB 数据库配置,备份恢复的数据载体 |
backupDirs |
需要备份的文件目录列表,BackupDir(本地目录, 云端压缩包名) |
cloudStorageType |
'sdk' 需要登录认证,'http' 不需要登录 |
bucketName |
云存储桶名称 |
productId |
AGC 项目 ID |
client_id / client_secret |
ServerSDK API 凭证 |
oauth_client_id / oauth_client_secret |
OAuth2 凭证,用于 Token 刷新 |
cloudStorageType 选择:
'sdk':使用云存储 SDK 模式,需要用户登录华为账号,安全性更高'http':使用 HTTP 模式,不需要登录,适合公开数据的备份
3. 华为一键登录
3.1 登录流程
在 MineView 中,用户点击头像触发登录:
login() {
const backupManager = BackupManager.getInstance();
if (!BackupManagerService.getInstance().isBackupManagerInitialized()) {
promptAction.showToast({ message: '等待初始化完成' });
return;
}
this.isLoggedIn = UserInfoManager.isLoggedIn();
if (this.isLoggedIn) {
return
}
try {
backupManager.login();
setTimeout(() => {
this.updateLoginState();
if (this.isLoggedIn) {
// 登录成功处理
} else {
// 登录失败处理
}
}, 1000);
} catch (error) {
console.error('登录失败:', error);
}
}
登录流程时序:
用户点击头像
→ 检查 BackupManager 是否初始化
→ 检查是否已登录
→ backupManager.login() 弹出华为账号授权页
→ 用户授权后华为返回 Token
→ UserInfoManager 自动存储用户信息
→ setTimeout 延迟后读取登录状态
→ 更新 UI
3.2 登录状态更新
private updateLoginState() {
this.isLoggedIn = UserInfoManager.isLoggedIn();
if (this.isLoggedIn) {
const userInfoData = UserInfoManager.getUserInfo();
this.userInfo = `${userInfoData?.nickName || '未登录'}`;
this.avatar = userInfoData?.avatarUri || $r('app.media.ic_avatar')
} else {
this.userInfo = '未登录';
this.avatar = $r('app.media.ic_avatar')
}
}
3.3 UserInfoManager API
UserInfoManager 提供了完整的用户信息管理接口:
| 方法 | 返回值 | 说明 |
|---|---|---|
isLoggedIn() |
boolean |
是否已登录 |
getUserInfo() |
UserInfo | undefined |
获取用户信息 |
getAccessToken() |
string |
获取访问令牌 |
getRefreshToken() |
string |
获取刷新令牌 |
isAccessTokenExpired() |
boolean |
AccessToken 是否过期 |
isRefreshTokenExpired() |
boolean |
RefreshToken 是否过期 |
updateTokens(token, expire) |
void |
更新 Token |
clearUserInfo() |
void |
清除用户信息(登出) |
用户信息对象包含以下字段:
UserInfo {
openID: string // 用户唯一标识
nickName: string // 昵称
avatarUri: string // 头像 URI
unionID: string // 跨应用唯一标识
}
4. 登录拦截:CustomTabBar
应用首页底部导航栏实现了登录拦截——非首页的 Tab 切换需要用户先登录:
@Component
export struct CustomTabBar {
@State isLoggedIn: boolean = false
@Prop @Require currentIndex: number;
tabBarChange: (index: number) => void = (index: number) => {};
@Builder
TabItemBuilder(tabBar: TabBarData) {
Column() {
SymbolGlyph(tabBar.icon)
.fontSize($r('sys.float.Title_M'))
.fontColor(tabBar.id === this.currentIndex ? [$r('app.color.app_primary')] :
[$r('sys.color.font_tertiary')])
Text(tabBar.title)
.fontSize($r('sys.float.Caption_M'))
.margin({ top: $r('sys.float.padding_level1') })
.fontWeight(FontWeight.Medium)
}
.onClick(() => {
this.isLoggedIn = UserInfoManager.isLoggedIn();
if (!this.isLoggedIn && tabBar.id !== 0) {
this.login()
} else {
if (this.currentIndex !== tabBar.id) {
this.tabBarChange(tabBar.id);
}
}
})
}
}
拦截逻辑:
- 每次点击 Tab 时检查
UserInfoManager.isLoggedIn() - 未登录且点击的不是首页(
tabBar.id !== 0),触发登录流程 - 已登录或点击首页,正常切换 Tab
4.1 TabBar 中的登录调用
login() {
const backupManager = BackupManager.getInstance();
if (!BackupManagerService.getInstance().isBackupManagerInitialized()) {
promptAction.showToast({ message: '等待初始化完成' });
return;
}
this.isLoggedIn = UserInfoManager.isLoggedIn();
if (this.isLoggedIn) {
return
}
try {
backupManager.login();
setTimeout(() => {
if (this.isLoggedIn) {
// 登录成功
} else {
// 登录失败
}
}, 1000);
} catch (error) {
console.error('登录失败:', error);
}
}
5. 用户界面展示
5.1 MineView 个人中心
个人中心页面展示用户头像、昵称和功能菜单:
@Component
export struct MineView {
@State isInitialized: boolean = false;
@State isLoggedIn: boolean = false;
@State userInfo: string = '未登录';
@State userNickname: string = '柚兔';
@State avatar: Resource | string = $r('app.media.ic_avatar');
aboutToAppear(): void {
this.updateLoginState()
}
build() {
Column() {
Row({ space: 10 }) {
Image(this.avatar).width(48)
.clip(true)
.borderRadius(30)
.onClick(() => {
if (!this.isLoggedIn) {
this.login()
}
})
Column({ space: 8 }) {
Text(this.userInfo).fontSize(16).fontWeight(FontWeight.Bold)
Text('书山有路勤为径').fontColor($r('app.color.color_sub_text')).fontSize(12)
}.layoutWeight(1).alignItems(HorizontalAlign.Start)
Image($r('app.media.ic_setting')).width(32)
.onClick(() => {
this.pageContext.openPage({
routerName: 'SettingPage',
onReturn: async (data) => {
this.updateLoginState()
}
}, true);
})
}
.width('100%')
.padding(12)
.borderRadius(5)
.backgroundColor($r('app.color.color_card'))
}
}
}
UI 状态映射:
| 登录状态 | 头像 | 昵称文本 |
|---|---|---|
| 未登录 | 默认头像 ic_avatar |
“未登录” |
| 已登录 | 用户华为头像 avatarUri |
用户昵称 |
5.2 未登录头像点击
头像区域是一个隐式的登录入口——未登录时点击头像触发 login() 方法,已登录时不响应。这种设计比专门的登录按钮更加自然。
6. 登出流程
通过 UserInfoManager.clearUserInfo() 清除用户信息实现登出:
// 在需要登出的地方调用
UserInfoManager.clearUserInfo()
登出后所有依赖登录状态的功能都会自动降级:
- 云存储:
MyAuthProvider检测到未登录返回空 Token - 云数据库:查询中
unionID为空,无法获取用户数据 - TabBar 拦截:非首页 Tab 被拦截,引导用户重新登录
7. 备份恢复机制
7.1 备份触发
BackupManager 初始化后,备份和恢复通常在以下时机触发:
- 备份:用户数据变更后、应用切换到后台、用户手动触发
- 恢复:应用首次安装、用户在新设备登录
7.2 备份内容
根据配置,备份涉及两类数据:
- 数据库文件:
cloudDbName: 'Partner.db',将本地 RDB 数据库备份到云端 - 文件目录:
backupDirs: [new BackupDir("testDir", "testCloud.zip")],将指定目录打包为 zip 上传
7.3 版本管理
updateDbVersion 回调在云端数据库版本与本地不一致时触发,用于处理数据迁移:
updateDbVersion: (cloudDbVersion) => {
console.log("云端数据库版本:" + cloudDbVersion);
// 执行数据迁移逻辑
}
8. 安全性考量
8.1 凭证管理
项目中凭证直接写在代码中,实际生产环境建议:
- 将
client_id、client_secret等凭证移至服务端 - 客户端通过自有服务获取临时凭证
- 使用环境变量或配置文件区分开发/生产环境
8.2 Token 刷新
Token 刷新机制确保长期登录态:
AccessToken 过期
→ MyAuthProvider 检测过期
→ refreshAuthToken() 使用 RefreshToken 刷新
→ RefreshToken 也过期
→ 提示用户重新登录
→ clearUserInfo() 清除本地状态
小结
本篇围绕华为一键登录和数据备份展开讲解:
- 初始化配置:
BackupManager.init()配置回调、云端目录、存储类型和 API 凭证 - 一键登录:
backupManager.login()弹出华为账号授权页,授权后UserInfoManager自动管理状态 - 用户信息:
UserInfoManager.isLoggedIn()检查状态,getUserInfo()获取昵称、头像和 unionID - 登录拦截:CustomTabBar 在非首页 Tab 切换时检查登录态,未登录则触发授权
- 状态展示:MineView 根据登录状态动态切换头像和昵称
- 数据备份:配置
cloudDbName和backupDirs指定备份内容,回调处理完成和版本更新 - 安全机制:Token 自动刷新,过期引导重新登录
华为一键登录和数据备份为"柚兔学伴"提供了零门槛的身份认证和跨设备数据同步能力,让用户的学习进度和偏好设置在多设备间无缝流转。
更多推荐

所有评论(0)