企业级 RN Android 完整 CI/CD 自动化解决方案

脚本实现功能如下:

  • 自动生成 RN bundle

  • Debug/Release + 多渠道打包

  • 自动 versionCode / versionName

  • 自动生成 Changelog(Git commit)

  • APK 上传到蒲公英 + 内部服务器

  • 自动生成下载二维码

  • 自动生成网页渠道列表(带二维码和下载链接)

  • 钉钉/飞书通知构建结果

  • Jenkins 参数化构建,多渠道循环


1.修改 scripts/bundle-android.sh(增加历史版本管理)

#!/bin/bash
# ===============================
# RN Android 多渠道 bundle & APK 自动打包 + Changelog + QR + 网页历史版本
# ===============================

set -e

ROOT_DIR=$(cd "$(dirname "$0")/.." && pwd)
cd $ROOT_DIR

BUILD_TYPE=${1:-Release}   # Release 或 Debug
FLAVOR=${2:-prod}          # 默认 prod 渠道

BUILD_TIME=$(date "+%Y-%m-%d %H:%M")
echo "Build Type: $BUILD_TYPE, Flavor: $FLAVOR, Build Time: $BUILD_TIME"

# RN 版本
RN_VERSION=$(npx react-native --version)
echo "React Native version: $RN_VERSION"

# 清理旧 bundle
rm -rf android/app/src/main/assets/index.android.bundle
rm -rf android/app/src/main/res/*

# 安装依赖 & 打包 bundle
npm install
npm run bundle-android

# 自动 versionCode / versionName
VERSION_CODE=$(date +%Y%m%d%H%M)
VERSION_NAME=$(date +%Y.%m.%d.%H%M)
sed -i "" "s/versionCode .*/versionCode $VERSION_CODE/" android/app/build.gradle
sed -i "" "s/versionName \".*\"/versionName \"$VERSION_NAME\"/" android/app/build.gradle

# 生成 Changelog
CHANGELOG=$(git log --pretty=format:"%h %s" --no-merges -n 10)
echo "$CHANGELOG" > build_changelog.txt

# 编译 APK
cd android
if [ "$BUILD_TYPE" == "Debug" ]; then
    ./gradlew clean assemble${FLAVOR^}Debug
else
    ./gradlew clean assemble${FLAVOR^}Release
fi

APK_PATH=$(ls app/build/outputs/apk/${FLAVOR}/${BUILD_TYPE,,}/*.apk)
echo $APK_PATH > ../last_apk_path.txt

# 生成二维码
APK_URL="http://your.server/path/to/apk/$(basename $APK_PATH)"
QR_FILE="$ROOT_DIR/qr_${FLAVOR}_${VERSION_CODE}.png"
python3 - <<EOF
import qrcode
img = qrcode.make("$APK_URL")
img.save("$QR_FILE")
EOF

# 更新网页历史版本列表
HTML_FILE="$ROOT_DIR/apk_list.html"

# 创建 HTML 文件头
if [ ! -f "$HTML_FILE" ]; then
cat <<EOT > "$HTML_FILE"
<html>
<head>
<title>Android APK 历史版本</title>
<meta charset="utf-8">
</head>
<body>
<h2>Android APK 下载历史版本</h2>
<ul id="apk-list">
</ul>
</body>
</html>
EOT
fi

# 生成单条 HTML
ENTRY="<li><b>${BUILD_TIME} ${FLAVOR} (${BUILD_TYPE}) v${VERSION_NAME}</b><br>"
ENTRY+="<a href='${APK_URL}'>下载 APK</a><br>"
ENTRY+="<img src='qr_${FLAVOR}_${VERSION_CODE}.png' width='150'/><br>"
ENTRY+="<pre>${CHANGELOG}</pre></li>"

# 使用 sed 插入到 <ul id="apk-list"> 内
sed -i "" "/<ul id=\"apk-list\">/a\\
$ENTRY
" "$HTML_FILE"

echo "✅ Build finished: ${BUILD_TYPE}-${FLAVOR}, APK: $APK_PATH"

2. Jenkinsfile 修改(保留历史版本 + 汇总通知)

pipeline {
    agent any

    parameters {
        choice(name: 'BUILD_TYPE', choices: ['Debug','Release'], description: '选择构建类型')
        string(name: 'FLAVORS', defaultValue: 'prod,test,dev', description: '选择要打的渠道,多渠道用逗号分隔')
    }

    environment {
        NODE_HOME = "/usr/local/bin/node"
        NPM_HOME  = "/usr/local/bin/npm"
        JAVA_HOME = "/usr/lib/jvm/java-11-openjdk"
        ANDROID_HOME = "/usr/local/android-sdk"
        PATH = "${env.ANDROID_HOME}/tools:${env.ANDROID_HOME}/platform-tools:${env.NODE_HOME}:${env.NPM_HOME}:${env.PATH}"

        UPLOAD_PGY = "https://www.pgyer.com/apiv2/app/upload"
        PGY_API_KEY = "your_pgy_api_key"

        INTERNAL_SERVER = "user@your.server:/path/to/apk"
        NOTIFY_WEBHOOK = "https://oapi.dingtalk.com/robot/send?access_token=your_token"
    }

    stages {
        stage('Checkout') { steps { checkout scm } }
        stage('Install Dependencies') { steps { sh 'npm install' } }

        stage('Build & Upload APKs') {
            steps {
                script {
                    def flavorList = params.FLAVORS.split(',')
                    for (flavor in flavorList) {
                        flavor = flavor.trim()
                        echo "------------------ Building ${params.BUILD_TYPE}-${flavor} ------------------"
                        sh "./scripts/bundle-android.sh ${params.BUILD_TYPE} ${flavor}"

                        def apkPath = readFile('last_apk_path.txt').trim()
                        def qrFile = "qr_${flavor}_*.png"

                        // 上传 APK + QR 到服务器
                        sh "scp ${apkPath} ${INTERNAL_SERVER}"
                        sh "scp ${qrFile} ${INTERNAL_SERVER}"

                        // 上传蒲公英
                        sh """
                        curl -F "file=@${apkPath}" -F "_api_key=${PGY_API_KEY}" ${UPLOAD_PGY}
                        """
                    }

                    // 上传网页历史版本列表
                    sh "scp apk_list.html ${INTERNAL_SERVER}"
                }
            }
        }
    }

    post {
        success {
            echo "✅ All builds finished successfully!"
            // 发送 HTML 消息到钉钉/飞书,通知包含网页历史版本链接
            sh """
            curl ${NOTIFY_WEBHOOK} -H 'Content-Type: application/json' -d '{
                "msgtype": "text",
                "text": {"content": "✅ Android ${params.BUILD_TYPE} 构建成功,历史版本页面: http://your.server/path/to/apk_list.html"}
            }'
            """
        }
        failure {
            echo "❌ Build failed!"
            sh """
            curl ${NOTIFY_WEBHOOK} -H 'Content-Type: application/json' -d '{
                "msgtype": "text",
                "text": {"content": "❌ Android ${params.BUILD_TYPE} 构建失败,请检查 Jenkins 日志!"}
            }'
            """
        }
    }
}

3.工程目录结构示意

rn-jenkins-demo/
├─ android/
│  ├─ app/
│  │  ├─ src/main/assets/
│  │  ├─ src/main/res/
│  └─ build.gradle
├─ ios/
├─ scripts/
│  └─ bundle-android.sh
├─ index.js
├─ package.json
├─ Jenkinsfile
└─ ...

4.特性总结

  1. 历史版本网页:所有构建都会在 apk_list.html 中生成条目,保留历史版本。
  2. 每个渠道生成二维码,可直接扫码下载 APK。
  3. 自动 versionCode / versionName,保证 APK 唯一性。
  4. 自动生成最近 10 条 Git commit Changelog,嵌入网页和通知中。
  5. 多渠道打包,支持循环处理 prod/test/dev 等渠道。
  6. 上传到蒲公英 + 内部服务器,网页、二维码同步更新。
  7. Jenkins 参数化构建 + 钉钉/飞书通知。
  8. 网页按构建时间倒序显示,最新版本在最上方,方便测试人员长期管理 APK。

这个方案已经是 企业级 RN Android 完整 CI/CD 自动化解决方案,测试人员只需访问网页就能看到全部渠道历史版本和下载二维码,无需单独维护。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值