竞界 — 基于 HarmonyOS ArkTS 打造的大学生职业成长 AI 平台

副标题:深度拆解一款鸿蒙原生应用的技术架构、AI 能力集成与设计哲学


在这里插入图片描述

一、导语

在中国,每年有超过一千万的大学毕业生涌入就业市场。然而,大多数学生在大学期间缺乏清晰的职业规划——他们不知道应该考什么证书、参加什么比赛、如何一步步提升自己的职场竞争力。

“竞界” 就是为了解决这个问题而生的。

“竞界"是一个基于 HarmonyOS 原生技术栈开发的大学生职业成长平台,它通过 AI 大模型能力鸿蒙系统原生能力集成丰富的证书/竞赛数据库 以及 个性化成长计划管理,帮助大学生从"躺平"到"觉醒”,找到属于自己的成长路径。

本文将从以下多个维度,深度拆解"竞界"的技术实现:

  1. 项目架构设计:MVVM 分层架构在 ArkTS 中的实践
  2. 页面与组件体系:声明式 UI 的组件化设计
  3. 数据模型层:类型安全的数据建模策略
  4. AI 服务层:DeepSeek API 集成与 SSE 流式对话全链路解析
  5. 鸿蒙生态集成:HiAI 深度求解器与智能学习助手
  6. 动画与视觉设计:沉浸式开门启动动画的设计实现
  7. 导航与路由架构:多入口导航体系的设计
  8. 用户画像系统:多维度用户建模与个性化推荐
  9. 工程化实践:项目配置、签名与构建体系

二、项目概况与技术栈

2.1 应用定位

"竞界"面向的核心用户群体是在校大学生。应用提供以下核心功能:

功能模块 描述
证书查询 12+ 主流专业认证的详细信息(CFA、CPA、PMP、HCIE 等)
竞赛推荐 20+ 全国性大学生竞赛的参赛指南
AI 答疑 基于 DeepSeek 大模型的智能问答系统
成长计划 自定义证书/竞赛备考计划,支持状态流转管理
智能学习 学习计划生成、思维导图、材料摘要、翻译等
用户画像 11维度用户档案建模,驱动个性化推荐

2.2 技术栈

平台:        HarmonyOS (API 12+ / SDK 6.0.1)
语言:        ArkTS (TypeScript 超集)
UI 框架:      ArkUI 声明式开发范式
AI 模型:      DeepSeek-Chat (通过 REST API)
鸿蒙生态:     HiAI 深度求解器、智能学习助手
网络通信:     @kit.NetworkKit (HTTP/SSE)
数据存储:     内存状态管理 + 本地 KV 存储
动画引擎:     ArkUI 内置动画系统
路由:        @ohos.router

三、项目架构:MVVM 分层设计

"竞界"采用了经典的 MVVM(Model-View-ViewModel) 分层架构。在 ArkTS 生态中,这一架构通过目录结构来体现:

entry/src/main/ets/
├── pages/          # View 层 — 页面
├── components/     # View 层 — 可复用组件
├── model/          # Model 层 — 数据模型与静态数据
├── models/         # Model 层 — 通用数据模型
├── services/       # Service 层 — 业务逻辑与 API 调用
├── viewmodels/     # ViewModel 层 — 视图状态管理
├── utils/          # 工具类
└── entryability/   # Ability 入口

3.1 分层职责

View 层(pages + components) 负责 UI 渲染与用户交互,使用 ArkUI 的 @Component@Builder 装饰器声明式构建界面。每个页面是一个独立的 struct,通过 @State@Link@Prop 等装饰器管理组件内部状态与跨组件通信。

Model 层(model) 定义数据结构和静态数据。例如 CertData.ets 定义了证书的枚举、接口和 12 条证书的完整数据;UserData.ets 定义了 11 维度的用户画像模型。

Service 层(services) 封装核心业务逻辑。AIService.ets 负责与 DeepSeek API 的通信,AISkillService.ets 负责鸿蒙原生 AI 能力的调用,SmartStudyService.ets 管理学习计划、思维导图等智能学习功能。

ViewModel 层(viewmodels) 管理页面级的状态与逻辑,例如 SearchViewModel.ets 封装了搜索相关的状态管理和过滤逻辑。

3.2 架构优势

这种分层设计带来了几个关键优势:

  • 关注点分离:页面代码只关心 UI 渲染,业务逻辑在 Service 层,数据定义在 Model 层,互不干扰
  • 可测试性:Service 层可以被独立测试,不依赖 UI 上下文
  • 复用性:Components 目录下的组件可以在多个页面中复用
  • 类型安全:所有数据结构通过 TypeScript interface 定义,编译期即可发现类型错误

四、声明式 UI:ArkTS 组件化实践

4.1 页面体系

"竞界"包含 14 个页面,覆盖了从启动到功能使用的完整用户旅程:

页面 文件 功能
SplashPage 启动页 开门动画 + 品牌展示
Index 首页 功能入口 + 热门推荐 + AI 助手
CertPage 证书列表 分类筛选 + 搜索
ContestPage 竞赛列表 分类/级别筛选 + 搜索
CertDetailPage 证书详情 考试条件、费用、备考建议
ContestDetailPage 竞赛详情 参赛信息、备赛指南
AIChatPage AI 答疑 流式对话 + 快捷提问
AIConsultPage AI 适配 个性化咨询入口
SmartStudyPage 智能学习 学习计划 + 思维导图
StudyPlanPage 学习计划 计划管理
MinePage 个人中心 用户画像编辑 + 成长统计
StatsPage 数据统计 学习数据分析
TranslationPage 翻译 多语言翻译
MaterialSummaryPage 材料摘要 AI 摘要生成

4.2 组件复用体系

"竞界"的组件设计遵循 单一职责原则,每个组件只负责一个明确的功能:

components/
├── BottomTabBar   # 底部导航栏(首页/证书/竞赛/我的)
├── TopNavBar      # 顶部导航栏(含菜单按钮)
├── SearchBar      # 搜索栏
├── FunctionCards  # 功能卡片行(横向3卡片布局)
├── FunctionCard   # 单个功能卡片
├── CertCard       # 证书列表卡片
├── ContestCard    # 竞赛列表卡片
├── MenuHeader     # 侧边栏头部
├── MenuItem       # 侧边栏菜单项
└── MenuFooter     # 侧边栏底部

BottomTabBar 为例,它通过 @Link 实现父子组件双向绑定:

@Component
export struct BottomTabBar {
  @Link currentTab: number
  onTabSelected?: (index: number) => void

  build() {
    Row() {
      this.TabItem($r('app.string.tab_home'), 0)
      this.TabItem($r('app.string.tab_cert'), 1)
      this.TabItem($r('app.string.tab_contest'), 2)
      this.TabItem($r('app.string.tab_mine'), 3)
    }
    .width('100%')
    .height(64)
    .backgroundColor($r('app.color.nav_bg'))
    .borderRadius(20)
  }

  @Builder
  TabItem(label: ResourceStr, index: number) {
    Text(label)
      .fontColor(this.currentTab === index
        ? $r('app.color.nav_text_selected')
        : $r('app.color.nav_text_unselected'))
      .backgroundColor(this.currentTab === index
        ? $r('app.color.nav_capsule_bg')
        : Color.Transparent)
      .animation({ duration: 200, curve: Curve.EaseInOut })
      .onClick(() => {
        this.currentTab = index
        if (this.onTabSelected) {
          this.onTabSelected(index)
        }
      })
  }
}

4.3 页面转场动画

每个页面都定义了进入和退出的转场动画,统一使用 pageTransition() 方法:

pageTransition() {
  PageTransitionEnter({ duration: 260, curve: Curve.FastOutSlowIn, delay: 40 })
    .opacity(0.0)
    .scale({ x: 0.95, y: 0.95 })

  PageTransitionExit({ duration: 200, curve: Curve.FastOutSlowIn })
    .opacity(0.0)
    .scale({ x: 1.03, y: 1.03 })
}

这种统一的转场设计确保了页面切换时的流畅体验:进入时从 95% 缩放 + 透明状态过渡到完整显示,退出时反向缩放并淡出。


五、数据模型层:类型安全与数据组织

5.1 枚举驱动的分类体系

"竞界"的数据模型层大量使用 TypeScript 枚举来定义分类体系,这提供了一个关键优势:类型安全。编译器可以在开发阶段捕获不存在的分类引用,避免运行时错误。

export enum CertCategory {
  MANAGEMENT = 'management',
  FINANCE = 'finance',
  ACCOUNTING = 'accounting',
  TECHNOLOGY = 'technology',
  SECURITY = 'security',
  DATA = 'data'
}

export const CATEGORY_LABELS: Record<CertCategory, string> = {
  [CertCategory.MANAGEMENT]: '管理类',
  [CertCategory.FINANCE]: '金融类',
  [CertCategory.ACCOUNTING]: '财务类',
  [CertCategory.TECHNOLOGY]: '技术类',
  [CertCategory.SECURITY]: '安全类',
  [CertCategory.DATA]: '数据类'
}

Record<CertCategory, string> 类型确保了标签映射表必须覆盖所有枚举值,如果遗漏任何一个分类,TypeScript 编译器就会报错。这是一种简单而有效的编译期校验机制。

5.2 多维度的证书数据模型

每一条证书数据包含 10+ 个字段,涵盖了从基本信息到社会认可度的全方位描述:

export interface CertificateModel {
  id: string                    // 唯一标识
  name: string                  // 证书名称
  issuer: string                // 颁发机构
  category: CertCategory        // 分类(枚举)
  rating: CertRating            // 评级(行业认可度、就业加成、能力成长)
  stars: number                 // 综合星级
  validPeriod: string           // 有效期
  tags: string[]                // 标签数组
  examCount: number             // 报考人数
  shareCount: number            // 分享次数
}

export interface CertRating {
  industryRecognition: number   // 行业认可度 (0-100)
  employmentBonus: number       // 就业加成 (0-100)
  abilityGrowth: number         // 能力成长 (0-100)
}

每条证书还有详细的 CertDetailItem[] 数组,包含分类说明、难度说明、适合人群、备考时长、详细介绍、报考条件、考试内容、通过率、费用、有效期、职业发展方向、备考建议等 12 项详细信息。

5.3 成长计划的 CRUD 操作

成长计划模块实现了一个完整的数据管理系统:

export enum PlanStatus {
  PLANNING = 'planning',
  IN_PROGRESS = 'in_progress',
  COMPLETED = 'completed'
}

export function addGrowthPlan(params: AddPlanParams): void { ... }
export function removeGrowthPlan(id: string): void { ... }
export function updatePlanStatus(id: string, status: PlanStatus): void { ... }
export function getPlansByType(type: PlanType): GrowthPlan[] { ... }
export function getPlansByStatus(status: PlanStatus): GrowthPlan[] { ... }
export function isPlanAdded(name: string, type: PlanType): boolean { ... }

这里采用 不可变数据更新模式:每次修改都创建一个新数组,而不是直接修改原数组。这种模式与 ArkUI 的状态响应式系统天然契合——当数组引用改变时,依赖该状态的 UI 会自动触发重新渲染。


六、核心亮点:AI 服务层深度解析

"竞界"的 AI 能力可以分为两条技术路线:

  1. 云端大模型:通过 HTTP REST API 调用 DeepSeek,实现智能对话和答疑
  2. 端侧 AI:通过鸿蒙系统 HiAI 框架调用设备端 AI 能力,实现深度解题和智能学习

6.1 DeepSeek API 集成

6.1.1 配置管理

AI 服务的配置采用 可持久化的单例模式

class AiConfig {
  BASE_URL: string = 'https://api.deepseek.com/v1'
  API_KEY: string = 'sk-...'
  MODEL: string = 'deepseek-chat'
  TEMPERATURE: number = 0.7
  MAX_TOKENS: number = 2048
  TIMEOUT: number = 60000
}

static async loadConfigFromStorage(): Promise<void> {
  const storedKey = await StorageService.getString(STORAGE_KEY_API_KEY, '')
  if (storedKey.length > 0) {
    AI_CONFIG.API_KEY = storedKey
  }
  // ... URL 和 Model 同理
}

API Key、Base URL 和 Model 都可以在运行时通过用户输入来修改,并自动持久化到本地存储。这种设计赋予了用户灵活切换 API 提供商的能力。

6.1.2 普通对话(非流式)

非流式请求的实现相对简单,使用 @kit.NetworkKithttp.createHttp() 发起 POST 请求:

static async chat(messages: ChatMessage[]): Promise<string> {
  const httpRequest = http.createHttp()
  try {
    const requestBody: ChatCompletionRequest = {
      model: AI_CONFIG.MODEL,
      messages: messages,
      temperature: AI_CONFIG.TEMPERATURE,
      max_tokens: AI_CONFIG.MAX_TOKENS,
      stream: false
    }

    const response = await httpRequest.request(
      `${AI_CONFIG.BASE_URL}/chat/completions`,
      {
        method: http.RequestMethod.POST,
        connectTimeout: AI_CONFIG.TIMEOUT,
        readTimeout: AI_CONFIG.TIMEOUT,
        header: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${AI_CONFIG.API_KEY}`
        },
        extraData: JSON.stringify(requestBody)
      }
    )

    if (response.responseCode === 200) {
      const result = JSON.parse(response.result as string) as ChatCompletionResponse
      return result.choices?.[0]?.message?.content ?? ''
    }
    throw new Error(`AI 请求失败: HTTP ${response.responseCode}`)
  } finally {
    httpRequest.destroy()
  }
}
6.1.3 SSE 流式对话——全链路解析

流式对话是"竞界"技术实现中最具挑战性的部分。DeepSeek API 采用 Server-Sent Events (SSE) 协议,数据以 text/event-stream 格式分块传输。实现这一功能涉及以下关键环节:

1. 流控制器设计

export interface StreamController {
  id: number
  cancel: () => void
}

每个流请求都有唯一的 ID 和 cancel() 方法,支持用户随时中断正在进行的流式回复。

2. 事件监听架构

在发起请求之前注册三个事件监听器:

  • headersReceive:确认 HTTP 响应头已到达
  • dataReceive:逐块接收 ArrayBuffer 数据
  • dataEnd:处理流结束时的缓冲区残留

3. 数据解码管道

这是整个流式系统的核心:

ArrayBuffer → Uint8Array → TextDecoder (UTF-8) → 累积缓冲区 → 按行分割 → SSE 数据行解析 → JSON 解析 → delta.content 提取 → 回调通知
httpRequest.on('dataReceive', (data: ArrayBuffer) => {
  if (cancelled) return

  const uint8Data = new Uint8Array(data)
  const text = decoder.decodeToString(uint8Data, { stream: true })
  accumulatedData += text

  const normalizedData = accumulatedData.replace(/\r\n/g, '\n')
  const lines = normalizedData.split('\n')
  accumulatedData = lines.pop() ?? ''  // 保留不完整的最后一行

  for (const line of lines) {
    const trimmed = line.trim()
    if (trimmed.length > 0) {
      parseSSERawLine(trimmed)
    }
  }
})

这里的关键技巧是 行缓冲:由于网络传输的 ArrayBuffer 可能在 SSE 数据行的中间被截断,所以不能直接对每次接收的数据做行分割。正确做法是维护一个 accumulatedData 缓冲区,每次将新数据追加到缓冲区末尾,然后按 \n 分割出完整的行,将不完整的最后一行留在缓冲区中等待下次拼接。

4. SSE 数据行解析

const parseSSERawLine = (trimmedLine: string): boolean => {
  if (trimmedLine.startsWith('data: ')) {
    const jsonStr = trimmedLine.substring(6).trim()
    if (jsonStr === '[DONE]') {
      safeOnComplete()
      return true
    }
    const parsed = JSON.parse(jsonStr) as ChatCompletionResponse
    const deltaContent = parsed.choices?.[0]?.delta?.content
    if (deltaContent) {
      safeOnChunk(deltaContent)
    }
    return true
  }
  return true
}

5. 光标闪烁动画

为了给用户提供"正在输入"的视觉反馈,"竞界"在流式输出期间会显示一个闪烁的光标:

private startCursorTimer(): void {
  this.showCursor = true
  this.cursorTimer = setInterval(() => {
    this.showCursor = !this.showCursor
  }, 500)
}

页面中在 AI 回复文本末尾追加闪烁光标:

Text(msg.content + (this.isStreaming && msg.id === this.streamingMessageId && this.showCursor ? '▍' : ''))

6. 安全状态管理

整个流式系统中大量使用 cancelled 标志位和 safeOnChunk/safeOnComplete/safeOnError 包装函数,确保在用户点击"停止"按钮或组件销毁后,不会有任何回调被执行。这是一种防御性编程策略,特别适合异步操作频繁的移动端场景。

6.2 鸿蒙原生 AI 能力集成

"竞界"深度集成了鸿蒙系统的 HiAI 框架,通过 startAbility 调用系统级 AI 服务:

static async invokeDeepSolver(
  uiContext: common.UIAbilityContext,
  userContext: string
): Promise<void> {
  const want: Want = {
    bundleName: 'com.huawei.hiai',
    abilityName: 'com.huawei.hiai.assistant.DeepSolverAbility',
    parameters: {
      'scene': 'competition_preparation',
      'userContext': userContext,
      'entrySource': 'jingjie_app'
    }
  }
  await uiContext.startAbility(want)
}

能力检测机制:在调用 AI 能力之前,通过 SDK API 版本检测来判断设备是否支持:

static detectAICapability(): boolean {
  if (deviceInfo.sdkApiVersion >= HARMONY_OS_5_API_LEVEL) {
    return true
  }
  return false
}

当设备不支持时,首页的 AI 按钮会显示"暂不可用"状态,并引导用户升级系统。这种降级方案确保了应用在不同系统版本上的兼容性。

6.3 智能学习服务

SmartStudyService 是一个综合性的智能学习服务,包含了四个核心能力:

能力 调用目标 功能
学习计划生成 SmartStudyAbility 基于目标生成分阶段学习计划
思维导图 MindMapAbility 将知识点结构化为思维导图
材料摘要 SummaryAbility AI 提取学习材料的核心要点
翻译 TranslationAbility 多语言翻译(支持 10 种语言)

此外,服务还内置了 4 套预设学习计划模板和 2 套完整的思维导图(PMP 知识体系和数学建模知识体系),即使在没有网络的情况下,用户也能获取有价值的学习资料。


七、沉浸式动画设计:开门启动动画

启动页(SplashPage)是用户对应用的第一印象。"竞界"设计了一套精彩的 “推开这扇门” 启动动画,具有极强的视觉冲击力。

7.1 动画分解

整个动画分为以下几个阶段:

时间线:
0ms        内容渐现开始
200ms      背景 Logo 显示
1200ms     "推开这扇门"按钮出现
2200ms     自动触发开门动画 → 左右门扇旋转展开
2800ms     背景主内容完全显示
4400ms     自动跳转至首页

7.2 门的 3D 旋转实现

左门和右门的旋转使用 ArkUI 的 rotate 属性配合 3D 变换:

// 左门 — 以左边缘为轴向左旋转
.rotate({
  x: 0,
  y: 1,
  z: 0,
  angle: this.doorOpenProgress * -75,
  centerX: '0%',
  centerY: '50%'
})

// 右门 — 以右边缘为轴向右旋转
.rotate({
  x: 0,
  y: 1,
  z: 0,
  angle: this.doorOpenProgress * 75,
  centerX: '100%',
  centerY: '50%'
})

doorOpenProgress 是一个 0 到 1 的值,0 表示门完全关闭,1 表示门旋转到 75 度完全打开。通过 animation({ duration: 800, curve: Curve.EaseOut }) 平滑过渡。

7.3 门的视觉结构

每扇门都设计了丰富的视觉层次:

门面板结构:
├── TopPanel (28%高度)      — 装饰线条
├── MiddlePanel (36%高度)   — 装饰图案(含圆形装饰)
└── BottomPanel (28%高度)   — 装饰线条
+ DoorFrame                  — 边框
+ DoorHandle                 — 渐变金属质感门把手

门把手使用了多层渐变来模拟金属质感:

.linearGradient({
  angle: isRight ? 180 : 0,
  colors: [
    ['#66A3FF', 0],
    ['#0066FF', 0.3],
    ['#1A75FF', 0.7],
    ['#0052CC', 1]
  ]
})
.shadow({ radius: 6, color: '#0066FF60', offsetX: 2, offsetY: 2 })

7.4 跳过机制

"竞界"提供了两种跳过启动动画的方式:

  1. 主动跳过:用户点击右上角的"跳过 N"按钮,触发 skipToHome() 方法
  2. 自动跳过:4 秒倒计时结束后自动跳转

跳过时的处理逻辑:

skipToHome(): void {
  if (this.skipTimer !== -1) {
    clearInterval(this.skipTimer)
  }
  this.doorOpenProgress = 1          // 瞬间完成开门
  this.showOpenButton = false
  setTimeout(() => {
    router.replaceUrl({ url: 'pages/Index' })
  }, 600)
}

使用 router.replaceUrl 而非 router.pushUrl 是为了替换页面栈,使用户无法通过返回操作回到启动页。


八、导航架构:多入口路由设计

"竞界"提供了三种并行的导航入口:

8.1 底部导航栏(主入口)

底部导航栏覆盖了应用的四个主要功能入口:首页、热门证书、比赛推荐、成长轨迹。使用 router.replaceUrl 进行页面切换,确保页面栈不会无限增长。

8.2 侧边抽屉菜单(辅助入口)

侧边栏提供了更详细的功能菜单,包含 7 个入口:首页、热门排行榜、AI 适配、学习助手、热门证书、比赛推荐、成长轨迹。

侧边栏的实现采用了 覆盖层 + 平移动画 的方案:

// 主内容随侧边栏展开向右平移
.translate({ x: this.showBar ? this.SIDEBAR_WIDTH : 0 })
.animation({ duration: 300, curve: Curve.Friction })

// 半透明遮罩层
Column()
  .layoutWeight(1).height('100%')
  .backgroundColor('#44000000')
  .onClick(() => { this.showBar = false })

8.3 有状态的路由导航

页面之间的导航通过 @ohos.router 实现,支持携带参数:

router.pushUrl({
  url: 'pages/CertDetailPage',
  params: { certId: '4' }
})

这种参数化路由使得详情页面可以根据传入的 ID 动态渲染不同的内容。


九、用户画像系统:11 维度个性化建模

用户画像是"竞界"实现个性化推荐的核心基础。系统定义了 11 个维度的用户属性:

export interface UserProfile {
  major: string              // 专业
  grade: string              // 年级(大一~研三)
  goal: string               // 目标方向
  schoolType: string         // 学校类型(985/211/普通本科等)
  interests: string          // 兴趣领域
  weeklyStudyTime: string    // 每周学习时长
  certBudget: string         // 考证预算
  existingCerts: string      // 已有证书
  englishLevel: string       // 英语水平(CET-4/6/IELTS/TOEFL)
  workExperience: string     // 工作经验
  learningStyle: string      // 学习风格(自学/课程/项目驱动等)
  careerTimeline: string     // 职业规划周期(短期/中期/长期)
}

9.1 上下文构建

用户画像被转换为上下文描述字符串,传递给 AI 服务以实现个性化回复:

static buildContext(profile: UserProfile): string {
  if (profile.major === DEFAULT_PROFILE.major &&
      profile.grade === DEFAULT_PROFILE.grade &&
      profile.goal === DEFAULT_PROFILE.goal) {
    return '大学生竞赛备赛'  // 默认上下文
  }

  const parts: string[] = []
  if (profile.major)  parts.push(`专业: ${profile.major}`)
  if (profile.grade)  parts.push(`年级: ${profile.grade}`)
  if (profile.goal)   parts.push(`目标方向: ${profile.goal}`)
  return parts.join(', ')
}

9.2 编辑交互

用户画像的编辑采用了 底部弹出面板(Bottom Sheet) 的设计模式,支持 8 个维度的编辑。年级、学校类型等选项使用 ArkUI 原生的 TextPickerDialog 实现下拉选择,确保了一致的系统交互体验。


十、工程化与配置体系

10.1 项目配置

应用的全局配置集中在 AppScope/app.json5

{
  "app": {
    "bundleName": "com.example.jingjie",
    "vendor": "example",
    "versionCode": 1000000,
    "versionName": "1.0.0",
    "icon": "$media:app_icon",
    "label": "$string:app_name"
  }
}

模块级配置在 entry/src/main/module.json5,定义了 Ability 入口、权限声明、设备类型等信息。

10.2 资源管理

"竞界"使用 HarmonyOS 的资源限定符系统管理资源:

  • resources/base/ — 默认资源(包含 20+ SVG 图标)
  • resources/dark/ — 暗色模式资源覆盖
  • 颜色值通过 $r('app.color.xxx') 引用,支持主题切换

10.3 构建配置

build-profile.json5 中配置了双构建模式:

"buildModeSet": [
  { "name": "debug" },
  { "name": "release" }
]

同时配置了签名信息,区分了调试签名和发布签名,为后续的真机调试和应用市场发布做好了准备。

10.4 网络权限

应用需要网络访问权限来调用 AI API,在 module.json5 中声明:

"requestPermissions": [
  {
    "name": "ohos.permission.INTERNET",
    "reason": "$string:permission_internet_reason",
    "usedScene": {
      "abilities": ["EntryAbility"],
      "when": "always"
    }
  }
]

十一、设计哲学与技术选型的思考

11.1 为什么选择 HarmonyOS?

  1. 生态优势:HarmonyOS 是华为的核心战略,拥有数亿设备基数,应用分发渠道(AppGallery)相对蓝海
  2. 原生 AI 能力:HiAI 框架提供了开箱即用的深度解题、智能学习能力,无需从零构建
  3. 声明式 UI:ArkUI 的声明式范式与现代前端开发体验一致,学习曲线平缓
  4. 性能优势:ArkTS 编译为方舟字节码,运行效率接近原生 C++

11.2 为什么集成 DeepSeek?

  1. 性价比:DeepSeek 的 API 定价极具竞争力,适合学生群体为主的用户
  2. 中文能力:DeepSeek 在中国市场的中文理解能力表现出色
  3. API 兼容性:完全兼容 OpenAI Chat Completion 格式,迁移成本低

11.3 UI 设计语言

"竞界"采用了 暗色主题 + 蓝色品牌色 的视觉方案:

  • 主色调:#165DFF(品牌蓝)
  • 背景:深色渐变(#121212#1A1A2E#16213E
  • 卡片:半透明磨砂玻璃效果(backdropBlur + 低透明度背景)
  • 排版:大标题 56px(启动页),常规标题 16-20px

11.4 性能优化策略

  1. 懒加载:AI 能力检测在 aboutToAppear 中进行,不阻塞首屏渲染
  2. 滚动优化:所有列表使用 scrollBar(BarState.Off) 隐藏滚动条,减少不必要的绘制
  3. 动画曲线:统一使用 Curve.FastOutSlowIn 曲线,确保动画流畅且符合 Material Design 的缓动标准
  4. 资源引用:全部使用 $r() 资源引用,支持运行时主题切换而不需要重新加载组件

十二、未来展望

"竞界"目前处于 V1.0 阶段,已经具备了完整的大学生职业成长辅助能力。未来可以在以下方向继续演进:

  1. 社区功能:引入用户社区,让大学生可以分享备考经验、组队参赛
  2. 智能推荐引擎:基于用户画像和行为数据,使用协同过滤算法实现更精准的证书/竞赛推荐
  3. 离线能力:利用 HarmonyOS 的分布式数据管理能力,实现关键数据的离线访问
  4. 多设备协同:利用鸿蒙的"一次开发、多端部署"能力,扩展到平板和智慧屏
  5. 端侧模型部署:当 HarmonyOS 的端侧 AI 推理框架成熟后,可以将轻量模型部署到端侧,实现零延迟的 AI 交互

十三、总结

"竞界"是一个功能完整、架构清晰的 HarmonyOS 原生应用。从技术角度看,它在以下几个方面展现了较高的工程水准:

  • 分层架构:MVVM 分层清晰,职责分明,代码可维护性强
  • AI 集成:实现了完整的 SSE 流式对话,处理了行缓冲、状态安全等关键问题
  • 鸿蒙生态:深度集成 HiAI 框架,充分利用系统能力
  • 动画设计:3D 门旋转动画提供了出色的用户第一印象
  • 类型安全:枚举驱动的数据模型 + TypeScript 类型系统确保了数据层的健壮性
  • 可配置性:AI API 配置支持运行时修改 + 持久化,灵活适应不同场景

在"唤醒亿万躺平的大学生"这一使命的驱动下,"竞界"不仅是一个技术项目,更是一个具有社会价值的创业实践。它用技术的力量,帮助中国大学生在迷茫中找到方向,在竞争中脱颖而出。


本文共计约 10500 字,涵盖了"竞界"应用的完整技术架构分析。

技术栈速览:HarmonyOS · ArkTS · ArkUI · DeepSeek API · HiAI · SSE Streaming · MVVM · TypeScript

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐