Using Jenkins Pipeline for Multi‑Project Android Build Automation
The team replaced numerous free‑style Jenkins jobs with a single Pipeline‑as‑code project that pulls a shared script from SCM, uses UI parameters and project‑specific configs to run a standardized Android build flow—including React Native bundle download—providing versioned, maintainable, and visualized multi‑project CI.
In daily development we often need to release builds for multiple environments (Online, Staging, Dev). Manual construction and upload are cumbersome, while continuous integration can solve the problem. Jenkins is recommended for this purpose.
Traditional free‑style Jenkins jobs work for a single project, but when many similar projects with slight differences need to be built, maintaining a separate job for each becomes unmanageable. The team faced this issue.
The team is responsible for several Android projects, each requiring a similar build flow with some variations. The typical steps include:
Clone code
Static code analysis (optional)
Unit tests (optional)
Compile and package APK or hot‑patch
Extract version code, APK hash, etc.
Code signing
Upload to test distribution platform
Archive (optional)
Trigger automated tests (optional)
Notify responsible persons
Because each project would need its own job, any change in the common flow required editing many jobs, which is error‑prone and time‑consuming. The solution is to use Jenkins Pipeline to treat the build process as code.
Pipeline Introduction
Pipeline allows flexible control of the entire build process, provides stage timing for optimization, enables quick error location via Stage View, and lets a single job manage the whole workflow.
Stage View
Using Pipeline
Create a Pipeline project and write the pipeline script (see screenshot in the original article). For a single project this works, but it has drawbacks such as duplicated scripts across projects and difficulty in version control.
Pipeline as Code
Instead of free‑style jobs, select Pipeline script from SCM so Jenkins pulls the script from a repository at job start. This enables multi‑person maintenance, code review, and versioning of the pipeline itself.
The build data now comes from three sources: job UI parameters, a common pipeline script in the repository, and project‑specific configuration.
Job UI (Parameterized Build)
Configure parameters such as repository URL, branch, and notification recipients. These parameters are often changed.
Project Configuration
Store relatively static parameters (e.g., project name) inside the project directory.
Inject Build Information
Inject properties such as APP_ENV, CI_BUILD_NUMBER, CI_BUILD_TIMESTAMP, and GIT_COMMIT_ID into gradle.properties and expose them via BuildConfig in the app.
# 应用的后端环境
APP_ENV=Beta
# CI 打包的编号,方便确定测试的版本,不通过 CI 打包,默认是 0
CI_BUILD_NUMBER=0
# CI 打包的时间,方便确定测试的版本,不通过 CI 打包,默认是 0
CI_BUILD_TIMESTAMP=0
# CI 打包的Git CommitId
GIT_COMMIT_ID=0In the app UI, display these values for QA debugging.
mCIIdtv.setText(String.format("CI 构建号:%s", BuildConfig.CI_BUILD_NUMBER));
mCITimetv.setText(String.format("CI 构建时间:%s", BuildConfig.CI_BUILD_TIMESTAMP));
mCommitIdtv.setText(String.format("Git CommitId:%s", BuildConfig.GIT_COMMIT_ID));Common Pipeline Script (in SCM)
The script abstracts the build process, using variables for project‑specific values. Example snippet:
node {
try {
stage('检出代码') {
git branch: "${BRANCH}", credentialsId: 'xxxxx-xxxx-xxxx-xxxx-xxxxxxx', url: "${REPO_URL}"
loadProjectConfig()
}
stage('编译') {
echo "项目名字 ${APP_CHINESE_NAME}"
if (Boolean.valueOf("${IS_USE_CODE_CHECK}")) {
echo "需要静态代码检查"
} else {
echo "不需要静态代码检查"
}
}
stage('存档') {
def apk = getShEchoResult("find ./lineup/build/outputs/apk -name '*.apk'")
def artifactsDir = "artifacts"
sh "mkdir ${artifactsDir}"
sh "mv ${apk} ${artifactsDir}"
archiveArtifacts "${artifactsDir}/*"
}
stage('通知负责人') {
emailext body: "构建项目:${BUILD_URL}
构建完成", subject: '构建结果通知【成功】', to: "${EMAIL}"
}
} catch (e) {
emailext body: "构建项目:${BUILD_URL}
构建失败,
错误消息:${e.toString()}", subject: '构建结果通知【失败】', to: "${EMAIL}"
} finally {
cleanWs notFailBuild: true
}
}
// Helper functions omitted for brevityHandling React Native JsBundle
When a project includes React Native, the JS bundle is built by the front‑end team and then packaged together with the native APK. To avoid unnecessary rebuilds, the bundle is archived in Meituan Storage Service (MSS) and downloaded during the native build.
Upload tool (Java) for MSS:
private static String TenantId = "mss_TenantId==";
private static AmazonS3 s3Client;
public static void main(String[] args) throws IOException {
if (args == null || args.length != 3) {
System.out.println("请依次输入:inputFile、bucketName、objectName");
return;
}
s3Client = AmazonS3ClientProvider.CreateAmazonS3Conn();
uploadObject(args[0], args[1], args[2]);
}
// uploadObject and other methods omitted for brevityGradle plugin for downloading the bundle during native build:
classpath 'com.zjiecode:rn-bundle-gradle-plugin:0.0.1'
apply plugin: 'mt-rn-bundle-download'
RNDownloadConfig {
paths = ['http://msstest-corp.sankuai.com/v1/mss_xxxx==/rn-bundle-dev/xxx/',
'http://msstest-corp.sankuai.com/v1/mss_xxxx==/rn-bundle-prod/xxx/']
version = "1"
fileName = 'xxxx.android.bundle-%s.zip'
outFile = 'xxxx/src/main/assets/JsBundle/xxxx.android.bundle.zip'
}The plugin inserts a download task before the package task, fetching the bundle if it is not already present.
All related scripts and plugins are available on GitHub: https://github.com/zjiecode/rn-bundle-gradle-plugin
Summary
Splitting the build into modular parts brings several benefits:
Only one core build process to maintain.
Facilitates multi‑person CI maintenance and avoids pipeline code overwrites.
Enables versioned pipeline scripts for easy rollback and fixes.
Provides flexible project‑specific configuration.
Visualizes the build for targeted optimization and error locating.
Drawbacks of Pipeline include less‑friendly syntax (mitigated by Jenkins Pipeline Syntax helper) and the need to test code in a Jenkins job rather than locally.
When integrating React Native, the JsBundle can be archived in MSS and dynamically downloaded during the native build.
Author Bio
Zhang Jie – Senior Android Engineer at Meituan, joined the Chengdu R&D Center in 2017, focuses on B‑side applications.
Wang Hao – Senior Android Engineer at Meituan, also joined the Chengdu R&D Center in 2017, focuses on B‑side applications.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Meituan Technology Team
Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
