你是不是也在想——“鸿蒙这么火,我能不能学会?”
答案是:当然可以!
这个专栏专为零基础小白设计,不需要编程基础,也不需要懂原理、背术语。我们会用最通俗易懂的语言、最贴近生活的案例,手把手带你从安装开发工具开始,一步步学会开发自己的鸿蒙应用。
不管你是学生、上班族、打算转行,还是单纯对技术感兴趣,只要你愿意花一点时间,就能在这里搞懂鸿蒙开发,并做出属于自己的App!
📌 关注本专栏《零基础学鸿蒙开发》,一起变强!
每一节内容我都会持续更新,配图+代码+解释全都有,欢迎点个关注,不走丢,我是小白酷爱学习,我们一起上路 🚀

前言

先问个扎心的:每次提测前,你是不是还在 DevEco Studio 里点来点去,“Clean→Build→Sign→装到测试机→截包发群”?这活儿别说优雅了,连可靠都谈不上。今天我把鸿蒙(HarmonyOS/OpenHarmony)应用从“代码提交”到“可分发产物”的持续集成(CI)与自动化构建完整方案摊开讲:规范→触发→拉依赖→编译→测试→签名→制品→发布→回滚,配上GitHub Actions / GitLab CI / Jenkins 三版脚本示例,顺手把缓存、并行、版本号、环境隔离这些坑一并填了。看完这篇,你可以把“点点点”打包方式永远按下葫芦。😎

目录快览

  • 前言:为啥CI必须现在上
  • 架构蓝图:从提交到产物的一条龙
  • 工程规范:分支、版本、包型、签名物料
  • 关键环节:依赖、构建、测试、签名、制品、质量门禁
  • 三套CI脚本:Actions / GitLab / Jenkins
  • 环境与缓存优化:分钟级出包不是梦
  • 发布与回滚:灰度开关与渠道打通
  • 清单与常见坑

一、前言:没有自动化,交付就是玄学

移动端构建链条长、变量多:ohpm 依赖偶尔抽风、hvigor 任务一多就“谁先谁后”难以复现、签名Profile/证书 一换就“今天又打不出来了”。CI的意义是把“个人经验”固化为“可重复流程”:同一提交,任何机器、任何时间都能稳定产出同样的HAP/APP包,并附上测试与质量证明

二、流水线蓝图(心中要有图)

Push/MR/Tag
   │
   ├─ ① 代码规范检查(lint / format / commit-msg)
   ├─ ② 依赖安装(ohpm)+ 缓存
   ├─ ③ 编译(hvigor)→ 生成 HAP/HAR/APP
   ├─ ④ 测试(单测:Hypium;UIUI测试/集成)
   ├─ ⑤ 质量门禁(阈值:覆盖率/包体积/敏感API)
   ├─ ⑥ 签名(hap-sign)→ 产出可安装包
   ├─ ⑦ 产物归档(Artifacts / 制品库)
   ├─ ⑧ 渠道分发(内测/灰度/商店API)
   └─ ⑨ 回滚与基线(版本锁/Release Notes/镜像)

关键原则:可声明、可缓存、可并行、可追溯、可回滚

三、工程规范先立起来(不立规矩,后面都白搭)

3.1 分支与触发策略(推荐)

  • main:受保护分支,仅允许通过PR合并;
  • develop:日常集成,触发快照构建
  • release/x.y:预发分支,触发签名+灰度
  • hotfix/x.y.z:紧急修复;
  • feat/*, fix/*:功能/缺陷分支,触发快速构建+单测

3.2 版本号与制品命名

  • 语义化版本:MAJOR.MINOR.PATCH
  • 自动打标签:v1.4.0+build.2025.1111.shaabcdef;
  • 制品名:app-${flavor}-${arch}-${buildType}-${version}.hap

3.3 包型与构建任务

  • HAP:应用包(常用);HAR:库;APP:多HAP打包的发布产物;

  • 常见 hvigor 目标(示意):

    • hvigor assembleHap(编译HAP)
    • hvigor bundleApp(打APP包)
    • hvigor --profile release(切换构建Profile)

具体任务名以你的工程脚手架/hvigor版本为准,下面脚本用占位任务名,你替换成项目里真实的。

3.4 签名物料与机密管理

  • 证书/密钥/发行Profile 放入CI的SecretJenkins Credentials
  • 运行时下发到工作目录,用后立即清理
  • 永远不要把.p12/.cer/.profile 放仓库。

四、关键环节详解与代码片段

4.1 依赖与缓存(ohpm)

# 安装依赖(根目录与各module都可能有oh-package.json)
ohpm install
# 若有子模块:
for d in */ ; do [ -f "$d/oh-package.json" ] && (cd "$d" && ohpm install); done

缓存要点

  • 缓存 ~/.ohpm~/.hvigornode_modules(若使用ESLint/工具链);
  • 缓存Key包含:os + lockfile hash + hvigor version,防止脏缓存。

4.2 编译(hvigor)

# Debug/Release 多矩阵
hvigor assembleHap --mode debug
hvigor assembleHap --mode release
# 如需多产品形态:
hvigor assembleHap -Pproduct=phone
hvigor assembleHap -Pproduct=car
# 打APP(多hap合并分发)
hvigor bundleApp --mode release

4.3 单元测试(Hypium/ArkTS 示例)

// test/Example.test.ets —— Hypium风格极简示例
import { describe, it, expect } from '@ohos/hypium';

describe('calc', () => {
  it('add', () => {
    const sum = 1 + 2;
    expect(sum).assertEqual(3);
  });
});

CI中执行(示意,按工程实际命令替换):

hvigor test --module app
# 或指定test profile/报告输出目录
hvigor test --report-dir build/reports/tests

4.4 代码质量(ESLint+API敏感扫描)

// .eslintrc.json
{
  "env": { "es2022": true },
  "extends": ["eslint:recommended"],
  "parserOptions": { "ecmaVersion": "latest", "sourceType": "module" },
  "rules": {
    "no-unused-vars": "warn",
    "complexity": ["warn", 15]
  }
}

CI片段:

npx eslint --max-warnings=0 ./entry/src ./feature-*/src

敏感API/权限审计(思路)

  • 解析 module.json5/oh-package.json 与签名Profile,校对权限白名单;
  • 探测 @ohos.net.http、文件系统等调用集中度,超阈值报警。

4.5 签名与制品

你需要在CI里解密证书与profile,然后调用签名工具(示例命令名仅作参考,按你的签名工具链替换):

# 假设CI中把证书与profile写入工作目录
export SIGN_CERT=cert.p12
export SIGN_CERT_PASS=$SIGN_PASS
export PROFILE=release.profile

# 构建产物目录(示意)
ART=./build/outputs/hap/release/app-release.hap

# 签名(示意)
hap-sign-tool sign \
  --in $ART \
  --out ./dist/app-release-signed.hap \
  --cert $SIGN_CERT --cert-pass $SIGN_CERT_PASS \
  --profile $PROFILE

4.6 质量门禁与阈值

  • 单测覆盖率 < 60% → 失败;
  • 包体积 > 目标上限(比如 50MB)→ 失败;
  • 关键 lint 规则违反 → 失败;
  • 可选:启动时长、包体敏感文件检查 作为门禁。

五、三套CI脚本给你(拿走即用,按需替换任务名)

5.1 GitHub Actions

name: Harmony CI

on:
  push:
    branches: [ develop, release/**, hotfix/** ]
  pull_request:
    branches: [ develop, main ]
  workflow_dispatch:

jobs:
  build-test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        mode: [debug, release]
        product: [phone]
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node (for tooling)
        uses: actions/setup-node@v4
        with: { node-version: '20' }

      - name: Cache ohpm
        uses: actions/cache@v4
        with:
          path: |
            ~/.ohpm
            ~/.hvigor
            **/node_modules
          key: ${{ runner.os }}-ohpm-${{ hashFiles('**/oh-package-lock.json','**/package-lock.json') }}-hv${{ env.HVIGOR_VER }}
          restore-keys: |
            ${{ runner.os }}-ohpm-

      - name: Install tool deps
        run: |
          npm ci || npm i

      - name: Install ohpm deps
        run: |
          ohpm install || echo "ohpm fallback"
          for d in */ ; do [ -f "$d/oh-package.json" ] && (cd "$d" && ohpm install || true); done

      - name: Lint
        run: npx eslint --max-warnings=0 ./entry/src

      - name: Build
        run: |
          hvigor assembleHap --mode ${{ matrix.mode }} -Pproduct=${{ matrix.product }}

      - name: Unit Test
        run: |
          hvigor test --module app || true
          [ -d build/reports ] && tar -czf test-reports.tgz build/reports || true
      - name: Upload Test Reports
        uses: actions/upload-artifact@v4
        with:
          name: test-reports-${{ matrix.mode }}
          path: test-reports.tgz
          if-no-files-found: ignore

      - name: Sign (release only)
        if: matrix.mode == 'release'
        env:
          SIGN_PASS: ${{ secrets.SIGN_PASS }}
        run: |
          echo "${{ secrets.SIGN_CERT_BASE64 }}" | base64 -d > cert.p12
          echo "${{ secrets.PROFILE_BASE64 }}" | base64 -d > release.profile
          ART=$(ls build/outputs/hap/release/*.hap | head -n1)
          hap-sign-tool sign --in "$ART" --out "dist/app-${{ matrix.product }}-${{ matrix.mode }}-signed.hap" \
            --cert cert.p12 --cert-pass "$SIGN_PASS" --profile release.profile

      - name: Upload Artifacts
        uses: actions/upload-artifact@v4
        with:
          name: hap-${{ matrix.product }}-${{ matrix.mode }}
          path: |
            build/outputs/hap/${{ matrix.mode }}/*.hap
            dist/*.hap

5.2 GitLab CI

stages: [lint, build, test, sign, deploy]

variables:
  NODE_ENV: production

cache:
  key: "${CI_COMMIT_REF_SLUG}"
  paths:
    - .ohpm/
    - .hvigor/
    - node_modules/

lint:
  stage: lint
  image: node:20
  script:
    - npm ci || npm i
    - npx eslint --max-warnings=0 ./entry/src
  only: [merge_requests, branches]

build:
  stage: build
  image: node:20
  script:
    - ohpm install || true
    - hvigor assembleHap --mode release
  artifacts:
    paths:
      - build/outputs/hap/**/*
    expire_in: 7 days
  only: [branches, tags]

test:
  stage: test
  image: node:20
  script:
    - hvigor test --module app || true
  artifacts:
    when: always
    paths:
      - build/reports/**/*
    expire_in: 7 days

sign:
  stage: sign
  image: alpine:3.20
  dependencies: [build]
  script:
    - echo "$SIGN_CERT_BASE64" | base64 -d > cert.p12
    - echo "$PROFILE_BASE64" | base64 -d > release.profile
    - ART=$(ls build/outputs/hap/release/*.hap | head -n1)
    - hap-sign-tool sign --in "$ART" --out "dist/app-release-signed.hap" \
        --cert cert.p12 --cert-pass "$SIGN_PASS" --profile release.profile
  artifacts:
    paths:
      - dist/app-release-signed.hap
    expire_in: 14 days
  only: [tags, /^release\/.*$/]

deploy:
  stage: deploy
  script:
    - echo "Upload to internal store or test hub..."
  when: manual
  only: [tags]

5.3 Jenkins(Declarative Pipeline)

pipeline {
  agent any
  options { timestamps() }

  environment {
    SIGN_PASS = credentials('sign-pass')
    // 证书、profile建议用 "Secret file" 方式注入
  }

  stages {
    stage('Checkout') { steps { checkout scm } }
    stage('Install') {
      steps {
        sh 'npm ci || npm i'
        sh 'ohpm install || true'
      }
    }
    stage('Lint') { steps { sh 'npx eslint --max-warnings=0 ./entry/src' } }
    stage('Build Debug') { steps { sh 'hvigor assembleHap --mode debug' } }
    stage('Build Release') { steps { sh 'hvigor assembleHap --mode release' } }
    stage('Test') {
      steps {
        sh 'hvigor test --module app || true'
        junit 'build/reports/tests/**/*.xml'
      }
    }
    stage('Sign') {
      when { branch 'release/*' }
      steps {
        withCredentials([file(credentialsId: 'sign-cert', variable: 'CERT'),
                         file(credentialsId: 'release-profile', variable: 'PROFILE')]) {
          sh '''
            ART=$(ls build/outputs/hap/release/*.hap | head -n1)
            hap-sign-tool sign --in "$ART" --out "dist/app-release-signed.hap" \
              --cert "$CERT" --cert-pass "$SIGN_PASS" --profile "$PROFILE"
          '''
        }
      }
    }
  }
  post {
    always {
      archiveArtifacts artifacts: 'build/outputs/hap/**,dist/*.hap', fingerprint: true
    }
  }
}

六、环境与速度优化(把“十几分钟”打到“几分钟”)

  • Runner镜像预装 hvigor/ohpm/Node:避免每次下载;
  • 缓存分层ohpmnode_modules 分开缓存;
  • 并行矩阵mode × product × arch 并行跑;
  • 跳过无关任务:仅前端变更不跑Native构建,仅文档变更跳过全流程;
  • 制品复用:库(HAR)项目单独CI出产物,上层应用引用固定版本,减少重复编译。

七、发布与回滚(稳住阵脚的关键)

  • 分发层

    • 内部:上传到制品库(如Nexus/OSS)或企业分发平台;
    • 外部:接入商店API(若有),走草稿→审核→灰度流程;
  • 灰度开关:版本开关与远程配置绑定(开关一关,某功能即刻软回滚);

  • 回滚release/x.y出问题→从上一个标签 vX.Y.Z-1 自动重构并分发;

  • Release Notes 自动生成:基于 Conventional Commits,feat/fix 自动聚合到变更日志。


八、质量门禁模板(开箱即用的阈值)

  • Lint 0 Error;
  • 单测覆盖率 ≥ 60%(核心模块 ≥ 80%);
  • 包体积 ≤ 目标阈值;
  • 敏感权限变更需人工审批;
  • 关键启动用例(仪表测试)持续通过。

九、落地清单(Checklist)

  • 规范化分支与触发策略(main/develop/release/hotfix)
  • 缓存 ohpm/hvigor/node_modules(含Key策略)
  • hvigor 任务与产品形态矩阵构建
  • Hypium 单测与测试报告上传
  • ESLint + 权限/敏感API审计
  • 签名证书与Profile放入CI机密,运行态注入
  • 产物归档(Artifacts/制品库)与指纹追踪
  • 自动版本与Release Notes
  • 灰度/手动门禁/回滚通道
  • 失败可复现(日志齐全、环境可重跑)

十、常见大坑(都是血与泪)

  • 证书泄露:切记只在 Runner 临时目录解密,完事删;PR 不要跑签名步骤。
  • 脏缓存:ohpm锁文件变了没更新缓存Key,构建“成功但不完整”。
  • 任务串行:明明可并行非要串着来,时间都浪费在排队上。
  • 无门禁:测试红了还继续往下签名发包,事故都是这么来的。
  • 环境漂移:Runner系统更新导致 hvigor 版本不兼容;固定镜像版本最稳妥。

结语:自动化不是花活,是团队的“交付契约” 📦

把这套CI流水线落下去,你会发现两件好事同时发生:出包更快质量更稳。更重要的是,“人肉经验”被固化为“团队契约”——任何人、任何时候、在任何机器上,都能生成同样可验收的包。

❤️ 如果本文帮到了你…

  • 请点个赞,让我知道你还在坚持阅读技术长文!
  • 请收藏本文,因为你以后一定还会用上!
  • 如果你在学习过程中遇到bug,请留言,我帮你踩坑!
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐