HarmonyOS鸿蒙Next中CSDN17年老兵之我与华为的十年之约【鸿蒙极客新势力申请】
HarmonyOS鸿蒙Next中CSDN17年老兵之我与华为的十年之约【鸿蒙极客新势力申请】 #我要成为鸿蒙极客#
CSDN17年老兵之我与华为的十年之约【鸿蒙极客新势力申请】
1. 概述
首先,欢迎大家百无聊赖的打开这篇帖子。我要首先申明,我不是标题党。这篇帖子的缘由,本身是为了加入鸿蒙极客为初衷,顺便和大家分享分享我的一些新路历程和牢骚。关于标题的内容呢,我接下来会为大家一一讲解。
2. 个人经历
- 缘起:那年,拿着JAVA的我,满心欢喜的对着初恋说,我以后要走这条路。没想到,那时的我还没精通JAVA,确投入了C的怀抱。多年后,早已对JAVA熟悉的我,确看着那个熟悉的QQ头像,不敢点开。是的,这就是我的起点,一个桌面端开发者。也和很多人一样,心中有一个爱而不得的初恋。经历过C和汇编的洗礼以后,慢慢沉浸在C#的开发中。其中,也在github上开源了几个项目,或许项目受众太小,也没什么人关注。最多Star的一个也才21个。

- 缘中:由于工作关系,也为了那个每个男孩子的电子梦。接触了电路,电子。也使得我的工作点开始转移到嵌入式开发。接触过嵌入式的人都知道,每天的工作都是枯燥、乏味的。所以每天下班都喜欢倒腾新的玩意,这个时候起,就开始了安卓的开发和小程序的开发。由于都是公司应用和未上架的私下流通应用。这里就不放出贴图了。现在的很多人都很喜欢说自己开发了多少多少IOS应用,也有人问我:你会不会开发IOS啊。每到此时,我都会回答,IOS我一点都不会,也不想去了解。或许,自己心里一直有一个芥蒂,IOS比较一直都是国外的,所以一直不愿意去接触他。
- 十年之约:某天,百无聊赖的刷着新闻的时候,突然出现的一句话:国产编程语言,仓颉。那一刻,我心里仿佛有什么东西被触动了。就是想学仓颉,想用仓颉。可是,现实,你们懂的,不管多么期待,这一等,就等了很多年。这期间,没事就登录华为看看,不知不觉,热爱IDC的我,在华为的服务器,也达成了一群IDC佬喜欢说的十年之约。
- 17年老兵:经过时间的洗礼,岁月的磨砺。打开自己的CSDN一看,原来,我已经在CSDN待了17年,
这期间还有很多很多曾经喜欢的论坛,讨论过,开源过,吵架过的论坛也在时间的洗礼中,逐一走向了关闭的命运。而自己,也因为不爱惜自己,在春节后的某一天,也住进了糖尿病科室的病床。看着手机,想想自己。也想为自己或者身边的病友做点什么。经过讨论,糖人助手。这个APP概念就开始萌生了。
3. 前期准备
- 看着全家都用的华为,和新升级的鸿蒙纯血系统。这一次,别和我谈什么IOS,什么小程序。拿出我的十年之约的华为服务器就是干,我就是要全部用华为来干。
- 开发语言: ArkTS
- UI 框架: ArkUI
- 目标平台: HarmonyOS 5
4. 过程中遇到的问题(新手向)
- 前期准备工作一定要考虑好应用的方向和特点,不然现在的审核状态,你很难通过审核的。
- 多看开发文档,多看开发文档,多看开发文档,重要的事情说三遍。我来给你举个活生生的例子,下面是我最初的华为账号登录代码:
import { authentication, loginComponentManager } from '[@kit](/user/kit).AccountKit';
@Entry
@Component
struct NewLoginPage {
private loginController: loginComponentManager.LoginWithHuaweiIDButtonController =
new loginComponentManager.LoginWithHuaweiIDButtonController();
aboutToAppear(): void {
// 配置华为登录控制器
this.loginController.onClickLoginWithHuaweiIDButton = () => {
this.startHuaweiLogin();
};
// 页面加载时自动检测华为账号
this.tryHuaweiSilentSignIn();
}
private async tryHuaweiSilentSignIn(): Promise<void> {
try {
// 获取当前系统中已登录的华为账号
const accountInfo = await HuaweiAccountService.getCurrentHuaweiAccount();
if (accountInfo) {
this.huaweiAccount = this.maskAccount(accountInfo.account);
}
} catch (error) {
console.info('华为账号检测:' + JSON.stringify(error));
}
}
// 账号脱敏处理
private maskAccount(account: string): string {
if (account.length <= 5) return account;
const prefix: string = account.substring(0, 3);
const suffix: string = account.substring(account.length - 2);
const maskLength: number = account.length - 5;
let mask: string = '';
for (let i = 0; i < maskLength; i++) { mask += '米'; }
return prefix + mask + suffix;
}
build() {
Column() {
// 华为官方登录按钮组件
LoginWithHuaweiIDButton({
params: {
style: loginComponentManager.Style.BUTTON_RED,
borderRadius: 24,
loginType: loginComponentManager.LoginType.QUICK_LOGIN
},
controller: this.loginController
})
.width('100%').height(48)
}
}
}
结果你猜怎么找?我只看了登录实现,没看这个权限我能不能用,个人开发者不能这么一键登录,我瞬间,啊???? 还好,华为是为大家考虑的,还准备了其他方案,下面是我后面的华为登录方案实现:
import { authentication } from '[@kit](/user/kit).AccountKit';
// 使用 authentication.HuaweiIDProvider 和 AuthenticationController
const authRequest: authentication.HuaweiIDProvider = new authentication.HuaweiIDProvider();
const request: authentication.AuthorizationWithHuaweiIDRequest =
authRequest.createAuthorizationWithHuaweiIDRequest();
request.scopes = ['openid', 'profile'];
request.permissions = ['idtoken'];
const controller: authentication.AuthenticationController =
new authentication.AuthenticationController(getContext(this));
controller.executeRequest(request).then((response) => {
// 获取 authorizationCode, openID, unionID, idToken
});
诸如此类事件,比比皆是,所以,大家多看清楚一点文档,绝对不是坏事。
- 还有一点,如果你有条件的话,例如你有什么交流群之类的话,多和前辈交流,沟通,询问,如果你真的是一个好学的人的话,很多人,其实都会毫不吝啬的告诉你的,现在交流的生态圈,大家都还是很融洽的。
- ArkTS 对代码有严格的类型检查要求,以下是给大家踩过的坑:
4.1. 类型注解规范
// ❌ 错误:隐式类型
const count = 5;
let items = [];
// ✅ 正确:显式类型注解
const count: number = 5;
let items: FoodItem[] = [];
4.2. 禁止使用 any 类型
// ❌ 错误
const deletePromises: Promise<any>[] = [];
Promise.all(promises).then((res: any) => {});
// ✅ 正确:定义具体接口类型
interface RemoveFavoriteResponse {
success: boolean;
message?: string;
data?: FoodFavoriteItem;
}
const deletePromises: Promise<RemoveFavoriteResponse>[] = [];
Promise.all(promises).then((responses: RemoveFavoriteResponse[]): void => {
// 处理响应
});
4.3. 禁止使用解构语法
// ❌ 错误
const [source, idStr] = key.split(':');
const { name, age } = user;
// ✅ 正确
const parts: string[] = key.split(':');
const source: string = parts[0];
const idStr: string = parts[1];
const name: string = user.name;
const age: number = user.age;
4.4. 循环语法规范
// ❌ 避免使用 forEach 和 for...of
items.forEach(item => { /* ... */ });
for (const item of items) { /* ... */ }
// ✅ 推荐使用传统 for 循环
for (let i = 0; i < items.length; i++) {
const item: ItemType = items[i];
// 处理逻辑
}
4.5. Promise 回调类型
// ❌ 错误:缺少类型注解
.then((res) => {})
.catch((err) => {})
// ✅ 正确:显式声明参数和返回类型
.then((responses: ApiResponse[]): void => {
// 处理逻辑
})
.catch((error: Error | string): void => {
const message: string = this.extractErrorMessage(error);
});
5. 个人在应用中使用的代码分享,希望对各位有帮助。
5.1.ArkData Kit (@kit.ArkData) - 数据持久化
使用 Preferences 存储用户配置、主题设置等轻量级数据。
import { preferences } from '[@kit](/user/kit).ArkData';
class ThemeService {
private static readonly PREFERENCES_NAME: string = 'theme_preferences';
private static readonly KEY_THEME_MODE: string = 'theme_mode';
static async saveThemeMode(context: Context, mode: ThemeMode): Promise<void> {
const prefs: preferences.Preferences = await preferences.getPreferences(
context,
ThemeService.PREFERENCES_NAME
);
await prefs.put(ThemeService.KEY_THEME_MODE, mode);
await prefs.flush();
}
static async getThemeMode(context: Context): Promise<ThemeMode> {
const prefs: preferences.Preferences = await preferences.getPreferences(
context,
ThemeService.PREFERENCES_NAME
);
const mode: string = await prefs.get(
ThemeService.KEY_THEME_MODE,
'system'
) as string;
return mode as ThemeMode;
}
}
5.2. NetworkKit (@kit.NetworkKit) - 网络通信
封装统一的 HTTP 请求服务,支持自动故障转移。
import { http } from '[@kit](/user/kit).NetworkKit';
class DatabaseService {
private static readonly BASE_URL: string = 'http://129.204.27.11:1516';
static async request<T>(
endpoint: string,
method: http.RequestMethod,
data?: object
): Promise<ApiResponse<T>> {
const httpRequest: http.HttpRequest = http.createHttp();
try {
const response: http.HttpResponse = await httpRequest.request(
`${this.BASE_URL}${endpoint}`,
{
method: method,
header: {
'Content-Type': 'application/json'
},
extraData: data ? JSON.stringify(data) : undefined,
connectTimeout: 10000,
readTimeout: 30000
}
);
if (response.responseCode === 200) {
const result: string = response.result as string;
return JSON.parse(result) as ApiResponse<T>;
} else {
return { success: false, message: `HTTP ${response.responseCode}` };
}
} finally {
httpRequest.destroy();
}
}
}
5.3. CoreFileKit (@kit.CoreFileKit) - 文件操作
用于图片处理、数据备份恢复等场景。
import { fileIo, fileUri } from '[@kit](/user/kit).CoreFileKit';
class BackupService {
static async exportData(context: Context, data: string): Promise<string> {
const fileName: string = `backup_${Date.now()}.json`;
const filePath: string = `${context.filesDir}/${fileName}`;
const file: fileIo.File = await fileIo.open(
filePath,
fileIo.OpenMode.CREATE | fileIo.OpenMode.WRITE_ONLY
);
await fileIo.write(file.fd, data);
await fileIo.close(file);
return fileUri.getUriFromPath(filePath);
}
}
5.4. 图片选择与处理
import { photoAccessHelper } from '[@kit](/user/kit).MediaLibraryKit';
import { image } from '[@kit](/user/kit).ImageKit';
class ImagePickerService {
static async selectAndProcessImage(context: Context): Promise<string> {
// 创建图片选择器
const photoPicker: photoAccessHelper.PhotoViewPicker =
new photoAccessHelper.PhotoViewPicker();
const result: photoAccessHelper.PhotoSelectResult = await photoPicker.select({
MIMEType: photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE,
maxSelectNumber: 1
});
if (result.photoUris.length === 0) {
throw new Error('未选择图片');
}
const uri: string = result.photoUris[0];
// 读取并压缩图片
const imageSource: image.ImageSource = image.createImageSource(uri);
const pixelMap: image.PixelMap = await imageSource.createPixelMap();
// 转换为 Base64
const packer: image.ImagePacker = image.createImagePacker();
const buffer: ArrayBuffer = await packer.packing(pixelMap, {
format: 'image/jpeg',
quality: 80
});
return ArrayBufferToBase64(buffer);
}
}
5.5. 主题服务实现
// ThemeService.ets
import { preferences } from '[@kit](/user/kit).ArkData';
type ThemeChangeCallback = (colors: ThemeColors) => void;
class ThemeService {
private static instance: ThemeService | null = null;
private currentMode: ThemeMode = 'system';
private listeners: ThemeChangeCallback[] = [];
static getInstance(): ThemeService {
if (!ThemeService.instance) {
ThemeService.instance = new ThemeService();
}
return ThemeService.instance;
}
async initialize(context: Context): Promise<void> {
const prefs: preferences.Preferences = await preferences.getPreferences(
context, 'theme_prefs'
);
this.currentMode = await prefs.get('mode', 'system') as ThemeMode;
}
getCurrentColors(): ThemeColors {
switch (this.currentMode) {
case 'light':
return LIGHT_THEME_COLORS;
case 'dark':
return DARK_THEME_COLORS;
case 'system':
return this.getSystemThemeColors();
}
}
private getSystemThemeColors(): ThemeColors {
// 获取系统当前主题设置
const isDark: boolean = this.isSystemDarkMode();
return isDark ? DARK_THEME_COLORS : LIGHT_THEME_COLORS;
}
async setThemeMode(context: Context, mode: ThemeMode): Promise<void> {
this.currentMode = mode;
// 持久化
const prefs: preferences.Preferences = await preferences.getPreferences(
context, 'theme_prefs'
);
await prefs.put('mode', mode);
await prefs.flush();
// 通知所有监听者
const colors: ThemeColors = this.getCurrentColors();
for (let i = 0; i < this.listeners.length; i++) {
this.listeners[i](colors);
}
}
addListener(callback: ThemeChangeCallback): void {
this.listeners.push(callback);
}
removeListener(callback: ThemeChangeCallback): void {
const index: number = this.listeners.indexOf(callback);
if (index > -1) {
this.listeners.splice(index, 1);
}
}
}
5.6. 页面中应用主题
@Entry
@Component
struct SettingsPage {
@State themeColors: ThemeColors = LIGHT_THEME_COLORS;
@State currentThemeMode: ThemeMode = 'system';
private themeService: ThemeService = ThemeService.getInstance();
private themeCallback: (colors: ThemeColors) => void =
(colors: ThemeColors) => { this.themeColors = colors; };
aboutToAppear(): void {
this.themeColors = this.themeService.getCurrentColors();
this.themeService.addListener(this.themeCallback);
}
aboutToDisappear(): void {
this.themeService.removeListener(this.themeCallback);
}
build() {
Column() {
// 主题选择
Row() {
Text('主题模式').fontSize(16)
Blank()
Select([
{ value: '跟随系统' },
{ value: '浅色模式' },
{ value: '深色模式' }
])
.selected(this.getThemeIndex())
.onSelect((index: number) => this.onThemeSelect(index))
}
.padding(16)
.backgroundColor(this.themeColors.surface)
}
.backgroundColor(this.themeColors.background)
}
private onThemeSelect(index: number): void {
const modes: ThemeMode[] = ['system', 'light', 'dark'];
this.themeService.setThemeMode(getContext(this), modes[index]);
}
}
5.7. 收藏数据管理
interface FoodFavoriteItem {
id: number;
user_id: number;
food_id: number;
food_source: FoodSource;
food_name: string;
created_at: string;
// 关联的食物详情
food_detail?: FoodDetail;
}
type FoodSource = 'food_database' | 'shiwuyingyang';
class FoodFavoriteService {
// 添加收藏
static async addFavorite(
userId: number,
更多关于HarmonyOS鸿蒙Next中CSDN17年老兵之我与华为的十年之约【鸿蒙极客新势力申请】的实战教程也可以访问 https://www.itying.com/category-93-b0.html
可以,老兵,我也是CSDN老兵。
更多关于HarmonyOS鸿蒙Next中CSDN17年老兵之我与华为的十年之约【鸿蒙极客新势力申请】的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html
老兵好,
HarmonyOS鸿蒙Next是华为推出的新一代操作系统,旨在构建全场景智慧生态。CSDN老兵与华为的十年之约体现了开发者对鸿蒙生态的长期关注与支持。鸿蒙Next采用分布式架构和ArkTS语言,支持一次开发、多端部署,提升开发效率。该申请属于鸿蒙极客新势力计划,旨在汇聚开发者力量,共同推动鸿蒙生态发展。
感谢您分享如此详尽的HarmonyOS Next开发经历和宝贵经验。作为一名拥有17年开发经验的资深技术人,您从桌面端到嵌入式,再到鸿蒙原生应用开发的转型之路,以及对国产技术的执着,令人敬佩。
您分享的“糖人助手”开发实践和代码片段,为HarmonyOS Next的开发者提供了极具价值的参考。特别是以下几点,对社区开发者很有帮助:
-
权限与API适配:您提到的
LoginWithHuaweiIDButton与authentication.HuaweiIDProvider的区别,是典型的开发初期易踩的坑。这提醒所有开发者,在调用Kit API前,务必在官方文档中确认其使用条件和权限要求,尤其是对于个人开发者账号。 -
ArkTS编码规范:您总结的类型注解、禁用
any、循环语法等规范,正是HarmonyOS Next应用通过方舟编译器进行静态检查和高性能运行的关键。遵循这些规范能有效避免运行时错误,并优化应用性能。 -
Kit的工程化使用:您对
@kit.ArkData(数据持久化)、@kit.NetworkKit(网络通信)、@kit.CoreFileKit(文件操作)等核心Kit的封装示例,展示了如何构建可维护、可测试的服务层。特别是主题服务的实现,清晰地演示了如何利用Preferences进行状态管理和跨页面同步。 -
问题排查思路:您“多看开发文档”的建议和与社区交流的经验,是高效解决问题的核心路径。HarmonyOS开发者社区和官方论坛是获取支持、交流心得的重要平台。
您将个人健康管理的需求转化为开发动力,并成功上架应用,是“技术服务于人”的完美体现。您分享的不仅是代码,更是一位老兵对技术生态的贡献和热忱。
期待您未来更多的技术分享。祝“糖人助手”项目持续迭代,帮助更多用户,也祝您在鸿蒙生态中继续开拓,收获更多成果。

