当前位置: 首页 > news >正文

用 ArkTS + ArkUI 搭一个可上架的鸿蒙工程骨架

这是《鸿蒙开口练APP实战手记》的第一篇。这个系列不写"Hello World 复读",所有内容都来自一个真实项目:一款 AI 口语表达教练 App,HarmonyOS 平台,ArkTS + ArkUI,从空白工程一路做到上架。开篇先解决最基础、也最容易被糊弄过去的问题——工程骨架

很多人的第一个鸿蒙工程是 DevEco Studio 模板生成的,能跑就收工。等到要上架才发现:签名没配、版本号没规划、权限声明乱塞、构建只会点按钮。这篇文章把"可上架"倒推到第一天,逐项讲清楚。

1. 先定 SDK 基线:compile 24 / target 24 / compatible 23

鸿蒙工程的 SDK 有三个数字,对应build-profile.json5里的字段:

{ "products": [ { "name": "default", "signingConfig": "default", "targetSdkVersion": "6.1.1(24)", "compatibleSdkVersion": "6.1.0(23)", "runtimeOS": "HarmonyOS" } ] }
  • compileSdkVersion:用什么 SDK 编译,决定你能调用哪些 API。在 DevEco 里随 SDK 安装确定,选最新稳定版即可。

  • targetSdkVersion:声明"我为这个版本做过完整适配",系统按这个版本的行为对待你的应用。不要填一个你没真机验证过的版本。

  • compatibleSdkVersion:最低兼容版本。填 23 意味着 API 23 的设备也能装,代价是你用到 API 24 独有能力时必须自己做分支判断。

我们的选择是24/24/23,理由很朴素:target 跟上最新稳定版拿到完整行为,compatible 下探一级多覆盖一批存量设备,同时把"API 23 真机验证"写进验收清单,防止基线只是纸面数字。

这个决定应该在项目第一张 ADR(架构决策记录)里冻结,因为它影响后面每一个系统能力的选型——比如我们后面选 CoreSpeechKit 做离线语音识别,就是先确认了它在 API 23 上行为完整。

2. 工程全景:三个配置文件各管一件事

一个标准鸿蒙工程的根目录长这样:

SpeakLab/ ├── AppScope/ │ └── app.json5 # 应用级元数据(全局唯一一份) ├── entry/ # 主模块(entry 类型,装入口) │ └── src/main/ │ ├── module.json5 # 模块级声明(Ability、权限、页面) │ ├── ets/ # ArkTS 源码 │ └── resources/ # 资源(字符串、颜色、媒体、rawfile) ├── build-profile.json5 # 构建配置(签名、产物、构建模式) ├── oh-package.json5 # 依赖声明 └── hvigorfile.ts # 构建脚本入口

新手最容易混淆的是前三个文件的分工,一句话记法:

文件

管什么

类比

AppScope/app.json5

这个应用是谁:bundleName、vendor、版本号、图标、名称

Android 的 applicationId + versionCode

entry/src/main/module.json5

这个模块有什么:Ability、页面路由、权限声明

AndroidManifest.xml

build-profile.json5

怎么构建:签名、SDK 版本、buildMode

build.gradle

app.json5:上架信息的第一现场
{ "app": { "bundleName": "com.xiangshikeji.speaklab", "vendor": "xiangshikeji", "versionCode": 1, "versionName": "1.0.0", "icon": "$media:layered_image", "label": "$string:app_name" } }

三个纪律,都是从上架返工里学来的:

  1. bundleName 一次定终身。上架后不可改,用反域名且和主体一致,别用com.example.xxx起步。

  2. versionCode 是上架的单调轴。首发定 1,之后每次提交至少 +1;versionName 给人看,versionCode 给市场看。

  3. 名称和图标走资源引用$string:/$media:),不要硬编码。用户可见名称收敛在一个字符串资源里,后续改名字、做多语言都只动一处。

module.json5:权限和 Ability 的声明处
{ "module": { "name": "entry", "type": "entry", "mainElement": "EntryAbility", "deviceTypes": ["phone"], "abilities": [ { "name": "EntryAbility", "srcEntry": "./ets/entryability/EntryAbility.ets", "startWindowBackground": "$color:start_window_background", "exported": true, "skills": [ { "entities": ["entity.system.home"], "actions": ["ohos.want.action.home"] } ] } ], "requestPermissions": [ { "name": "ohos.permission.MICROPHONE", "reason": "$string:sl_mic_reason", "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" } }, { "name": "ohos.permission.INTERNET" } ] } }

两个要点:

  • user_grant 权限必须给 reason,且 reason 走资源ohos.permission.MICROPHONE这类用户授权权限,审核会看你声明的理由文本。reason引用字符串资源而不是写死,方便后续按审核意见调整文案。

  • 权限声明是"最小集"纪律的起点。工程第一天就要忍住"先都加上再说"的冲动——每多一个权限,上架审核就多一份解释成本。我们只有麦克风(业务必需)和 INTERNET(AI 功能必需)两个。

build-profile.json5:签名与严格模式
{ "app": { "signingConfigs": [ { "name": "default", "type": "HarmonyOS", "material": { "certpath": "/Users/xxx/.ohos/config/default_xxx.cer", "keyAlias": "debugKey", "profile": "/Users/xxx/.ohos/config/default_xxx.p7b", "signAlg": "SHA256withECDSA", "storeFile": "/Users/xxx/.ohos/config/default_xxx.p12" } } ], "products": [ { "name": "default", "signingConfig": "default", "buildOption": { "strictMode": { "caseSensitiveCheck": true, "useNormalizedOHMUrl": true } } } ] } }
  • 签名从第一天就配好。DevEco 的自动化签名会在~/.ohos/config/生成调试证书并写回这个文件。哪怕只是真机调试,鸿蒙也要求签名 HAP——先把这条链路跑通,免得"能编译不能装机"卡住节奏。注意:keyPassword/storePassword是 DevEco 托管的密文,这个文件不要提交到公开仓库。

  • strictMode 两个开关建议开caseSensitiveCheck强制 import 路径大小写敏感——macOS 文件系统默认不敏感,不开这个,代码在 CI 或同事机器上会以莫名其妙的方式挂掉;useNormalizedOHMUrl统一模块 URL 规范,避免依赖解析的隐性分叉。

3. 源码目录:第一天就分层

entry/src/main/ets/下的目录结构,决定了三个月后这个工程还能不能维护。我们的约定:

ets/ ├── entryability/ # EntryAbility(唯一入口 Ability) ├── pages/ # 页面 Destination(home / settings / report / history…) ├── sheets/ # 全局弹层(权限说明、统计、教练历史) ├── common/ │ ├── components/ # 可复用 UI 组件 │ ├── theme/ # 语义化主题 token │ ├── navigation/ # 路由与壳层 │ ├── types/ # 领域类型 │ ├── store/ # 状态管理 │ ├── lexicon/ # 领域服务:词库 │ ├── asr/ # 系统能力 port:语音识别 │ ├── ai/ # 系统能力 port:AI 调用 │ └── settings/ # 持久化 port:设置 └── spike/ # 技术验证代码(与正式代码物理隔离)

核心规则只有两条:

  1. 页面不直接碰系统 Kit。语音识别、AI 网络调用、权限申请,全部收口到common/下的 port 层,页面只依赖自己的 service 接口。这条规则让"换实现"和"写假数据"都变成只动一处的事。

  2. 命名前缀统一。类/服务统一SpeakLab前缀,资源统一sl_前缀(如$string:sl_mic_reason),日志 tag 统一SpeakLab。前缀看起来是小事,但当你要在 400 多条测试日志或整包字符串资源里grep 时,它就是救命绳。

4. 命令行构建:别只会点按钮

DevEco 的 Run 按钮很方便,但可复现的构建必须能在命令行完成——这是后续做 CI、做验收、做"干净重建"的前提。两个环境变量是关键:

export DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk export PATH="/Applications/DevEco-Studio.app/Contents/tools/hvigor/bin:\ /Applications/DevEco-Studio.app/Contents/tools/node/bin:$PATH"

注意DEVECO_SDK_HOME指向Contents/sdk这一层,不要指到里面的default/子目录——这是新手最常见的踩坑点,指错了 hvigor 会报找不到 SDK 组件。

然后一条命令打出签名包:

hvigorw --mode module \ -p product=default \ -p module=entry@default \ -p "buildMode=release" \ assembleHap --no-daemon

产物在entry/build/default/outputs/default/entry-default-signed.hap。工程里把它包一层脚本(scripts/build-entry-hap.sh),构建前先hvigorw clean、构建后打印 HAP 路径、大小和 SHA-256:

scripts/build-entry-hap.sh release # build-entry-hap: release HAP ready # build-entry-hap: path=.../entry-default-signed.hap # build-entry-hap: size=xxM sha256=f09f7a65...

为什么要打印 SHA-256?因为"验收构建"和"演示构建"必须是同一个东西。Hash 一贴,谁都没有歧义。这个小习惯在后面做独立验收时救过我们很多次。

装到真机:

hdc install -r entry/build/default/outputs/default/entry-default-signed.hap

5. 小结:骨架的检查清单

到这里,一个"朝着上架去"的鸿蒙工程骨架就齐了。按清单自查:

  • SDK 基线(compile/target/compatible)写进 ADR,最低版本有真机验证计划

  • app.json5:bundleName 定终身、versionCode 从 1 起、名称图标走资源引用

  • module.json5:权限最小集,user_grant 权限的 reason 走字符串资源

  • build-profile.json5:签名链路跑通,strictMode 两个开关打开

  • ets/分层:pages / sheets / common 各司其职,系统能力收口 port 层

  • 命名前缀统一(SpeakLab/sl_

  • 命令行能 clean 构建出签名 HAP,且打印 SHA-256

http://www.jsqmd.com/news/1252547/

相关文章:

  • 2026年最新教程:报名照片必须是JPG怎么改 亲测可用方法 - 图片处理研究员
  • 自考备考利器:10款AI工具提升3倍学习效率
  • VC++实现轻量级PDF阅读器:从解析到渲染的底层实战
  • 项目管理计划到底要解决什么问题?
  • Wireshark抓包:如何捕获并解析完整的以太网帧(含FCS)
  • AI Agent核心技术栈与工程实践解析
  • 语音交互LLM:技术原理、架构设计与Python实践指南
  • AI辅助教材编写:工具选择与查重控制实践
  • TVA时代工业视觉检测技术演进与核心解决方案
  • 从hash碰撞到ssh端口转发渗透内网:靶机练习之symfonos2
  • C++二维数组深度解析:从内存模型到实战应用
  • BQ41Z50 BMS芯片深度解析:从核心保护到智能充电与电量计量
  • C++异常处理:从原理到实践,掌握健壮代码的关键
  • 优秀项目经理的22件大事与4项核心能力:贯穿施工全流程的管理之道
  • CDU冷分配单元阀:原理、关键数据与典型应用 - 行业深度分析
  • AI元人文:欲望、客观性与自我感知的三维纠缠治理
  • 内网终端主动告警体系搭建思路,实现风险自动识别与应急处置
  • 2026毕业生必备:五大智能论文降重工具实测
  • 人事 Eva:Moka AI 的人事 AI 同事,释放 HR 的战略价值空间
  • 现代C++项目模板:CMake构建、工具链集成与跨平台开发实践
  • 基于YOLOv5的工地安全帽实时检测系统实践
  • AI写作的局限性与真人创作优势分析
  • C++日历计算器实现:从日期算法到工程实践
  • 基于LLM多智能体的AI量化交易系统设计与实践
  • C++17 std::variant:类型安全联合体的原理、应用与性能优化
  • 2026 年现阶段建德比较好的建筑外墙硬泡聚氨酯喷涂施工电话生产厂家找哪家,外墙保暖省钱秘籍:聚氨酯喷涂的真相 - 行业推荐官【认证】
  • C++ STL容器核心解析:从底层原理到性能优化实战
  • MSP430G2x53-Q1的ADC与I/O复用:低功耗数据采集系统设计指南
  • Llama2架构改进与微调实战指南
  • 专科生AI降重工具对比:千笔AI与PaperRed实测