脚本实现功能如下:
- 自动生成 RN bundle
- Debug/Release + 多渠道打包
- 自动 versionCode / versionName
- 自动生成 Changelog(Git commit)
- APK 上传到蒲公英 + 内部服务器
- 自动生成下载二维码
- 自动生成网页渠道列表(带二维码和下载链接)
- 钉钉/飞书通知构建结果
- Jenkins 参数化构建,多渠道循环
1.修改 scripts/bundle-android.sh
(增加历史版本管理)
bash
#!/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 修改(保留历史版本 + 汇总通知)
bash
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.工程目录结构示意
css
rn-jenkins-demo/
├─ android/
│ ├─ app/
│ │ ├─ src/main/assets/
│ │ ├─ src/main/res/
│ └─ build.gradle
├─ ios/
├─ scripts/
│ └─ bundle-android.sh
├─ index.js
├─ package.json
├─ Jenkinsfile
└─ ...
4.特性总结
- 历史版本网页 :所有构建都会在
apk_list.html
中生成条目,保留历史版本。 - 每个渠道生成二维码,可直接扫码下载 APK。
- 自动 versionCode / versionName,保证 APK 唯一性。
- 自动生成最近 10 条 Git commit Changelog,嵌入网页和通知中。
- 多渠道打包,支持循环处理 prod/test/dev 等渠道。
- 上传到蒲公英 + 内部服务器,网页、二维码同步更新。
- Jenkins 参数化构建 + 钉钉/飞书通知。
- 网页按构建时间倒序显示,最新版本在最上方,方便测试人员长期管理 APK。
这个方案已经是 企业级 RN Android 完整 CI/CD 自动化解决方案,测试人员只需访问网页就能看到全部渠道历史版本和下载二维码,无需单独维护。