代码仓地址,大家记得点个star
IbestKnowTeach: 百得知识库基于鸿蒙NEXT稳定版实现的一款企业级开发项目案例。 本案例涉及到多个鸿蒙相关技术知识点: 1、布局 2、配置文件 3、组件的封装和使用 4、路由的使用 5、请求响应拦截器的封装 6、位置服务 7、三方库的使用和封装 8、头像上传 9、应用软件更新等https://gitee.com/xt1314520/IbestKnowTeach
项目准备
项目介绍
“百得知识库软件”是一款专注于编程技术领域的学习资源App,旨在为开发者提供丰富的学习材料。这里涵盖了广泛的IT相关知识,无论是编程语言、软件开发,还是最新的技术趋势,都能找到详尽的资料。该软件不仅有助于开发者提升专业技能,还通过完善的社区和文档支持促进交流与合作。用户可以轻松获取解决方案,参与讨论,从而加速个人成长和技术问题的解决。
通过项目学到什么
- 华为账号授权登录
- 三方库的使用和封装
- 组件的封装和使用
- 头像上传
- 应用软件更新
- 日历组件的使用
- 地理位置定位
......
创建项目
1、点击文件,新建项目
2、选择模板
修改项目名,包名,项目名等信息
3、完成创建
4、打开模拟器,运行项目
5、修改应用名称和图标
1、在跟目录下面AppScope/resources/base/media替换app_icon图片
2、修改module.json5文件
替换成app_icon
3、修改应用名称
将label修改成百得知识库
导入静态资源
1、resources/base/element
📎color.json
📎float.json
📎string.json
2、resources/en_US/element
📎string.json
3、resources/zh_CN/element
📎string.json
4、百得知识库里面的静态图片资源
https://download.csdn.net/download/weixin_51166786/90426858
5、修改module.json5里面的startWindowIcon里面的值
"startWindowIcon": "$media:start_icon"
项目三方库依赖
三方库官方地址:
OpenHarmony三方库中心仓
1、@ohos/axios (网络请求三方库)
ohpm install @ohos/axios@2.2.0
2、@ibestservices/ibest-ui (组件三方库)
ohpm install @ibestservices/ibest-ui@2.0.3
日志的封装
在ets下面新建utils目录,然后在这个目录下面新建Logger.ets
import { hilog } from '@kit.PerformanceAnalysisKit'const DOMAIN = 0x0000
const TAG = 'wdl'
const FORMAT = '%{public}s %{public}s'export class Logger {static debug(...args: string[]) {hilog.debug(DOMAIN, TAG, FORMAT, args)}static info(...args: string[]) {hilog.info(DOMAIN, TAG, FORMAT, args)}static warn(...args: string[]) {hilog.warn(DOMAIN, TAG, FORMAT, args)}static error(...args: string[]) {hilog.error(DOMAIN, TAG, FORMAT, args)}
}
文本提示框的封装
在ets/utils目录下面新建Toast.ets
import promptAction from '@ohos.promptAction'/*** 显示toast* @param { string } message 显示的信息*/
export function showToast(message: string) {promptAction.showToast({message: message || '请求错误',duration: 2000,})
}
用户首选项的封装
在ets/utils目录下面新建PreferencesUtil.ets
import { preferences } from '@kit.ArkData'export class PreferencesUtil {/*** 保存数据到首选项* @param preferencesName* @param key* @param value*/static async savaData<T extends keyof number | number | string | boolean | Array<number> | Array<string> | Array<boolean>>(preferencesName: string,key: string, value: T) {const pre = preferences.getPreferencesSync(getContext(), { name: preferencesName })pre.putSync(key, value as preferences.ValueType)await pre.flush()}/*** 获取数据* @param preferencesName* @param key* @param defaultValue* @returns*/static getData<T extends keyof number | number | string | boolean | Array<number> | Array<string> | Array<boolean>>(preferencesName: string,key: string, defaultValue: T) {const pre = preferences.getPreferencesSync(getContext(), { name: preferencesName })return pre.getSync(key, defaultValue as preferences.ValueType) as T}/*** 删除数据* @param preferencesName* @param key*/static async delAllData(preferencesName: string, key: string) {const pre = preferences.getPreferencesSync(getContext(), { name: preferencesName })pre.deleteSync(key)await pre.flush()}
}
新建常量类
在ets/contants目录下面新建CommonConstant.ets和RouterConstant.ets
1、CommonConstant.ets
export class CommonConstant {/*** 百分百宽度*/static readonly WIDTH_FULL = '100%'/*** 百分百高度*/static readonly HEIGHT_FULL = '100%'/*** 开屏广告页面默认展示时间,单位秒*/static readonly ADVERTISING_TIME: number = 3;/*** 结束时间,单位秒*/static readonly ADVERTISING_END_TIME: number = 0;/*** 存token值的名称(token)*/static readonly TOKEN_NAME: string = 'token';/*** 用户首选项实例的名称*/static readonly PREFERENCES_NAME: string = 'preferences';/*** 存用户信息的本地存储名称*/static readonly USER_INFO: string = 'userInfo';/*** 登录错误*/static readonly DEFAULT_LOGIN_ERROR: string = '登录错误';
}
2、RouterConstant.ets
export class RouterConstant {/*** 首页*/static readonly PAGE_INDEX = 'pages/Index'/*** 登录*/static readonly PAGE_LOGIN = 'pages/LoginPage'/*** 打卡*/static readonly VIEWS_CLOCK = 'views/Learn/Clock'/*** 打卡记录*/static readonly VIEWS_CLOCK_RECORD = 'views/Learn/ClockRecord'/*** 学习目标*/static readonly VIEWS_LEARN_TARGET = 'views/Learn/LearnTarget'/*** 学习工具*/static readonly VIEWS_LEARN_TOOL = 'views/Learn/LearnTool'/*** 学习平台内容*/static readonly VIEWS_LEARN_CONTENT = 'views/Learn/LearnContent'/*** 面试平台内容*/static readonly VIEWS_INTERVIEW_CONTENT = 'views/Learn/InterviewContent'/*** home页面*/static readonly VIEWS_HOME_HOME = 'views/Home/Home'/*** 文章详情页面*/static readonly VIEWS_HOME_ARTICLE_INFO = 'views/Home/ArticleInfo'/*** home搜索页面*/static readonly VIEWS_HOME_SEARCH = 'views/Home/Search'/*** 消息列表页面*/static readonly VIEWS_MESSAGE_LIST = 'views/Message/MessageList'/*** 个人信息*/static readonly VIEWS_MINE_INFO = 'views/Mine/MineInfo'/*** 我的收藏*/static readonly VIEWS_MINE_COLLECT = 'views/Mine/MineCollect'/*** 我的点赞*/static readonly VIEWS_MINE_LIKE = 'views/Mine/MineLike'/*** 关于我们*/static readonly VIEWS_MINE_ABOUT_US = 'views/Mine/AboutUS'/*** 设置*/static readonly VIEWS_MINE_SET_UP = 'views/Mine/SetUp'/*** 隐私政策*/static readonly PAGE_PRIVACY_POLICY = 'pages/PrivacyPolicyPage'/*** 用户协议*/static readonly PAGE_USER_POLICY = 'pages/UserPolicyPage'
}
请求响应拦截器的封装
在ets下面新建request目录,然后在这个目录下面新建Request.ets和Request.type.ets
1、Request.ets
import axios, { AxiosError, AxiosResponse, InternalAxiosRequestConfig } from '@ohos/axios'
import { CODE_TYPE, BASE_HOST } from "./Request.type"
import { Logger } from '../utils/Logger';
import { showToast } from '../utils/Toast';
import { CommonConstant } from '../contants/CommonConstant';
import { PreferencesUtil } from '../utils/PreferencesUtil';
import { router } from '@kit.ArkUI';
import { RouterConstant } from '../contants/RouterConstant';/*** axios封装*/
const http = axios.create({baseURL: `http://${BASE_HOST}`,headers: {'Content-Type': 'application/json',"Channel": "B2B"}
},)/*** 添加请求拦截器*/
http.interceptors.request.use((config: InternalAxiosRequestConfig) => {// 获取数据const token: string | undefined = AppStorage.get("token")// 获取tokenif (token) {config.headers.Authorization = token}return config;
}, (error: AxiosError) => {// 对请求错误做些什么return Promise.reject(error);
});/*** 添加响应拦截器*/
http.interceptors.response.use((response: AxiosResponse) => {Logger.info("请求状态码" + response.data.code, JSON.stringify(response.data));// 判断响应状态码if (response.status === CODE_TYPE.SUCCESS) {// 请求成功if (response.data.code === CODE_TYPE.SUCCESS) {return Promise.resolve(response.data.data);} else if (response.data.code === CODE_TYPE.NO_LOGIN) {clearLoginInfoAndGoLoginPage();}}// 接口响应报错新信息showToast(response.data.message);return Promise.reject(response);
}, (error: AxiosError) => {showToast('网络错误,换个网络试试');return Promise.reject(error);
});export default http;/*** 清除用户信息并跳到登录页面*/
async function clearLoginInfoAndGoLoginPage() {// 401错误 -> 清理用户信息,跳转到登录页// 清理token,返回登录页// userInfo有订阅者删不掉,所以重新赋值空的给userInfoAppStorage.setOrCreate(CommonConstant.USER_INFO, {nickname: '',unionId: '',avatarUri: '',id: 0})AppStorage.delete(CommonConstant.TOKEN_NAME)await PreferencesUtil.delAllData(CommonConstant.PREFERENCES_NAME, CommonConstant.TOKEN_NAME)await PreferencesUtil.delAllData(CommonConstant.PREFERENCES_NAME, CommonConstant.USER_INFO)// 跳转登录页面router.pushUrl({url: RouterConstant.PAGE_LOGIN})
}
2、Request.type.ets
export enum CODE_TYPE {SUCCESS = 200,NO_LOGIN = 401
}/*** host地址*/
export const BASE_HOST = '118.31.50.145:9003'
服务端接口文档地址
api.md