读者可以通过这篇文章了解详细的Android 与 React Native 混合工程的打包步骤及自动化脚本实现。
一、打包核心步骤
1. 生成 React Native Bundle
bash
# 在项目根目录执行,将 JS 代码和资源打包到 Android 工程
react-native bundle \
--entry-file index.js \
--platform android \
--dev false \
--bundle-output android/app/src/main/assets/index.android.bundle \
--assets-dest android/app/src/main/res/
作用:
- 将 RN 代码编译为 Android 可识别的
index.android.bundle
- 图片等资源自动复制到
res/
目录,避免运行时网络加载
2. 配置 Android 签名
步骤1:生成签名密钥(若未创建)
bash
keytool -genkey -v -keystore my-release-key.jks \
-keyalg RSA -keysize 2048 -validity 10000 \
-alias my-key-alias
步骤2:配置 gradle.properties
在 ~/.gradle/gradle.properties
或项目级 gradle.properties
添加:
properties
MYAPP_RELEASE_STORE_FILE=my-release-key.jks
MYAPP_RELEASE_KEY_ALIAS=my-key-alias
MYAPP_RELEASE_STORE_PASSWORD=your_store_password
MYAPP_RELEASE_KEY_PASSWORD=your_key_password
步骤3:修改 app/build.gradle
groovy
android {
signingConfigs {
release {
storeFile file(MYAPP_RELEASE_STORE_FILE)
storePassword MYAPP_RELEASE_STORE_PASSWORD
keyAlias MYAPP_RELEASE_KEY_ALIAS
keyPassword MYAPP_RELEASE_KEY_PASSWORD
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled true // 启用代码混淆
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
3. 执行 Gradle 打包
bash
cd android && ./gradlew clean assembleRelease
输出路径 :
android/app/build/outputs/apk/release/app-release.apk
二、自动化打包 Shell 脚本
以下是在原有打包 Shell 脚本中集成 yarn install
命令的更新版本,包含依赖安装、错误处理和构建优化:
更新后的 Shell 脚本
文件名:build_android.sh
bash
#!/bin/bash
# 配置参数
RN_ENTRY="index.js"
ANDROID_PROJECT_PATH="android"
KEYSTORE_PATH="my-release-key.jks"
APK_OUTPUT_DIR="release_apks"
# 清理旧构建文件
echo "Cleaning previous build artifacts..."
rm -rf $ANDROID_PROJECT_PATH/app/src/main/assets/index.android.bundle
rm -rf $ANDROID_PROJECT_PATH/app/src/main/res/*
# 安装依赖(严格锁定版本)
echo "Installing dependencies with yarn..."
yarn install --frozen-lockfile || { echo "yarn install 失败,请检查网络或依赖配置"; exit 1; }
# 生成 React Native Bundle
echo "Generating React Native bundle..."
react-native bundle \
--entry-file $RN_ENTRY \
--platform android \
--dev false \
--bundle-output $ANDROID_PROJECT_PATH/app/src/main/assets/index.android.bundle \
--assets-dest $ANDROID_PROJECT_PATH/app/src/main/res/ || { echo "RN Bundle 生成失败"; exit 1; }
# 创建 APK 输出目录
mkdir -p $APK_OUTPUT_DIR
# 编译 Android APK
echo "Building Android APK..."
cd $ANDROID_PROJECT_PATH && ./gradlew clean assembleRelease || { echo "Gradle 构建失败"; exit 1; }
# 移动 APK 到指定目录
echo "Moving APK to $APK_OUTPUT_DIR..."
find app/build/outputs/apk/release -name "*.apk" -exec cp {} ../$APK_OUTPUT_DIR \;
# 完成提示
echo "Build completed! APK saved in: $APK_OUTPUT_DIR"
关键优化说明
-
强制锁定依赖版本
yarn install --frozen-lockfile
严格使用yarn.lock
中的版本,避免因依赖升级导致构建失败。 -
错误处理
通过
|| { ...; exit 1; }
捕获关键步骤(如依赖安装、Bundle 生成)的失败并终止脚本,避免无效构建。 -
构建前清理
删除旧的 Bundle 和资源文件,防止残留文件干扰新构建。
-
跨版本兼容
find ... -exec
适配多 APK 输出场景(如分架构打包),自动复制所有 APK 文件。
使用说明
-
权限设置
bashchmod +x build_android.sh
-
执行构建
bash./build_android.sh
-
环境要求
- 已全局安装
yarn
和react-native-cli
ANDROID_HOME
环境变量已配置
- 已全局安装
扩展功能(按需添加)
1. 依赖缓存
在脚本开头添加缓存检查逻辑,减少重复下载时间:
bash
# 缓存检查(仅开发环境)
if [ -d "node_modules" ]; then
echo "检测到 node_modules 缓存,跳过依赖安装"
else
yarn install --frozen-lockfile
fi
2. 镜像加速
在 yarn install
前切换国内镜像源:
bash
# 使用淘宝镜像
yarn config set registry https://registry.npmmirror.com
通过上述脚本,可一站式完成 依赖安装 → RN 构建 → APK 编译,适合集成到 Jenkins/GitLab CI 等自动化流程。
使用说明:
- 赋予执行权限:
chmod +x build_android.sh
- 执行脚本:
./build_android.sh
- 输出 APK 在
release_apks
目录
功能特性:
- 自动清理旧构建 (
clean
) - 支持多 flavor 打包(需扩展 gradle 命令)
- 输出目录自动分类管理
三、高级优化方案
1. 代码混淆配置
在 proguard-rules.pro
添加 RN 专用规则:
proguard
# React Native 保留规则
-keep class com.facebook.react.** { *; }
-keep class com.facebook.hermes.** { *; }
-keep class com.facebook.jni.** { *; }
2. 拆分 CPU 架构
修改 app/build.gradle
生成多架构 APK:
groovy
android {
splits {
abi {
enable true
reset()
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
universalApk true // 生成通用包
}
}
}
3. 自动化上传(可选)
扩展脚本实现 APK 上传至 CDN/Fir:
上传蒲公英平台
以下是在现有 Shell 脚本中集成蒲公英平台上传功能的优化版代码,结合最新蒲公英 API 2.0 规范(2025 年)和搜索结果中的最佳实践:
更新后的 Shell 脚本
文件名:build_android.sh
bash
#!/bin/bash
# 配置参数
RN_ENTRY="index.js"
ANDROID_PROJECT_PATH="android"
APK_OUTPUT_DIR="release_apks"
PGY_API_KEY="your_pgy_api_key_here" # 替换为你的蒲公英API Key
# 清理旧构建文件
echo "Cleaning previous build artifacts..."
rm -rf $ANDROID_PROJECT_PATH/app/src/main/assets/index.android.bundle
rm -rf $ANDROID_PROJECT_PATH/app/src/main/res/*
# 安装依赖
echo "Installing dependencies..."
yarn install --frozen-lockfile || exit 1
# 生成 RN Bundle
echo "Generating React Native bundle..."
react-native bundle \
--entry-file $RN_ENTRY \
--platform android \
--dev false \
--bundle-output $ANDROID_PROJECT_PATH/app/src/main/assets/index.android.bundle \
--assets-dest $ANDROID_PROJECT_PATH/app/src/main/res/ || exit 1
# 编译 Android APK
echo "Building Android APK..."
cd $ANDROID_PROJECT_PATH && ./gradlew clean assembleRelease || exit 1
# 移动 APK 到输出目录
mkdir -p ../$APK_OUTPUT_DIR
find app/build/outputs/apk/release -name "*.apk" -exec cp {} ../$APK_OUTPUT_DIR/ \;
echo "APK saved to: ../$APK_OUTPUT_DIR"
# 上传蒲公英函数
upload_to_pgyer() {
local apk_path=$1
echo "Uploading $apk_path to Pgyer..."
# 使用 API 2.0 分步上传
# 1. 获取上传凭证
token_response=$(curl -s -X POST "https://api.pgyer.com/apiv2/app/getCOSToken?_api_key=$PGY_API_KEY&buildType=android")
endpoint=$(echo $token_response | jq -r '.data.endpoint')
key=$(echo $token_response | jq -r '.data.key')
signature=$(echo $token_response | jq -r '.data.params.signature')
x_cos_security_token=$(echo $token_response | jq -r '.data.params.x-cos-security-token')
# 2. 上传文件
upload_result=$(curl -X POST -F "key=$key" -F "signature=$signature" \
-F "x-cos-security-token=$x_cos_security_token" \
-F "file=@$apk_path" \
$endpoint)
if [[ $upload_result == *"success"* ]]; then
echo "✅ 上传成功!应用页面:https://www.pgyer.com/$(echo $upload_result | jq -r '.data.buildKey')"
else
echo "❌ 上传失败:$upload_result"
fi
}
# 交互式选择是否上传
latest_apk=$(ls -t $APK_OUTPUT_DIR/*.apk | head -1)
echo "检测到最新 APK:$latest_apk"
read -p "是否上传到蒲公英?[y/N] " upload_choice
case "$upload_choice" in
y|Y )
if [ -z "$PGY_API_KEY" ]; then
echo "未配置蒲公英API Key,请修改脚本中的PGY_API_KEY变量"
else
upload_to_pgyer $latest_apk
fi
;;
* )
echo "跳过上传"
;;
esac
关键功能说明
-
API 2.0 分步上传
- 先通过
/getCOSToken
接口获取临时上传凭证,避免直接暴露敏感信息 - 使用
jq
解析 JSON 响应,需确保已安装jq
工具(可通过brew install jq
安装)
- 先通过
-
安全增强
-
API Key 硬编码在脚本中,生产环境建议改为读取环境变量
bashPGY_API_KEY=${ENV_PGY_API_KEY} # 从环境变量获取
-
-
自动检测最新 APK
ls -t
按时间排序获取最新生成的 APK 文件
-
交互式确认
- 避免误上传,通过
read
命令二次确认操作
- 避免误上传,通过
使用说明
-
配置蒲公英 API Key
- 登录蒲公英后台 → 应用管理 → API 信息 → 复制 API Key
- 替换脚本中
your_pgy_api_key_here
占位符
-
安装依赖工具
bash# 安装 JSON 解析工具 brew install jq
-
执行完整流程
bashchmod +x build_android.sh ./build_android.sh
扩展功能(按需添加)
1. 上传历史记录
bash
# 在脚本尾部添加
echo "$(date '+%Y-%m-%d %H:%M') $latest_apk" >> upload_history.log
2. 邮件通知
bash
# 依赖 mailx 工具
echo "Build completed" | mailx -s "APK 已上传" [email protected]
通过该脚本可实现 打包 → 版本管理 → 分发 全流程自动化,适合集成到 Jenkins/GitLab CI 流水线。建议结合蒲公英的安装统计、版本回滚等企业级功能进一步优化交付流程 。
上传Fir平台
以下是在 Shell 脚本中集成上传至 Fir.im 平台 的完整实现方案,结合官方 API 规范及最佳实践:
一、前置准备
-
获取 Fir API Token
登录 Fir.im 后台 → 点击右上角用户头像 → 进入「API Tokens」页面 → 复制 Token(参考网页)。
-
安装依赖工具
-
jq :用于解析 JSON 响应
bashbrew install jq # macOS sudo apt-get install jq # Ubuntu
-
curl:确保已安装最新版本(网页推荐官网下载避免乱码)
-
二、Shell 脚本集成代码
bash
#!/bin/bash
# 配置参数
RN_ENTRY="index.js"
ANDROID_PROJECT_PATH="android"
APK_OUTPUT_DIR="release_apks"
FIR_API_TOKEN="your_fir_api_token_here" # 替换为你的 Fir API Token
# 清理旧构建文件
echo "清理旧构建文件..."
rm -rf $ANDROID_PROJECT_PATH/app/src/main/assets/index.android.bundle
rm -rf $ANDROID_PROJECT_PATH/app/src/main/res/*
# 安装依赖
echo "安装依赖..."
yarn install --frozen-lockfile || exit 1
# 生成 RN Bundle
echo "生成 React Native Bundle..."
react-native bundle \
--entry-file $RN_ENTRY \
--platform android \
--dev false \
--bundle-output $ANDROID_PROJECT_PATH/app/src/main/assets/index.android.bundle \
--assets-dest $ANDROID_PROJECT_PATH/app/src/main/res/ || exit 1
# 编译 Android APK
echo "编译 Android APK..."
cd $ANDROID_PROJECT_PATH && ./gradlew clean assembleRelease || exit 1
# 移动 APK 到输出目录
mkdir -p ../$APK_OUTPUT_DIR
find app/build/outputs/apk/release -name "*.apk" -exec cp {} ../$APK_OUTPUT_DIR/ \;
echo "APK 保存至: ../$APK_OUTPUT_DIR"
# 上传至 Fir.im 函数
upload_to_fir() {
local apk_path=$1
echo "开始上传至 Fir.im..."
# 步骤1: 获取上传凭证
token_response=$(curl -s -X POST "http://api.bq04.com/apps" \
-d "type=android&api_token=$FIR_API_TOKEN" \
-d "bundle_id=$(grep applicationId ../android/app/build.gradle | awk -F\' '{print $2}')")
# 解析 JSON 响应
key=$(echo $token_response | jq -r '.cert.binary.key')
upload_url=$(echo $token_response | jq -r '.cert.binary.upload_url')
token=$(echo $token_response | jq -r '.cert.binary.token')
# 步骤2: 上传 APK 文件
upload_result=$(curl -X POST \
-F "file=@$apk_path" \
-F "key=$key" \
-F "token=$token" \
-F "x:name=$(basename $apk_path)" \
"$upload_url")
# 处理结果
if [[ $(echo $upload_result | jq -r '.is_completed') == "true" ]]; then
short_url=$(echo $upload_result | jq -r '.short_url')
echo "✅ 上传成功!下载地址:https://fir.im/$short_url"
else
echo "❌ 上传失败:$upload_result"
exit 1
fi
}
# 自动选择最新 APK 并上传
latest_apk=$(ls -t $APK_OUTPUT_DIR/*.apk | head -1)
if [ -z "$latest_apk" ]; then
echo "未找到 APK 文件,请检查构建流程"
exit 1
fi
read -p "是否上传到 Fir.im?[y/N] " choice
case "$choice" in
y|Y )
if [ -z "$FIR_API_TOKEN" ]; then
echo "未配置 Fir API Token,请修改脚本中的 FIR_API_TOKEN 变量"
else
upload_to_fir "$latest_apk"
fi
;;
* )
echo "跳过上传"
;;
esac
三、关键功能说明
-
动态获取包名
通过解析
android/app/build.gradle
中的applicationId
,避免硬编码(参考网页)。 -
两阶段上传流程
- 获取凭证 :通过
http://api.bq04.com/apps
接口获取临时上传密钥 - 文件上传:使用凭证将 APK 上传至指定端点(参考官方 API 文档)
- 获取凭证 :通过
-
结果智能处理
- 使用
jq
解析 JSON 响应,提取关键字段 - 自动生成短链接,便于测试人员访问(网页方案增强)
- 使用
四、使用说明
-
替换 API Token
将脚本中的
your_fir_api_token_here
替换为实际 Token(获取方式见网页)。 -
执行脚本
bashchmod +x build_android.sh ./build_android.sh
-
交互式确认
脚本会在最后询问是否上传,输入
y
确认即可。
五、扩展功能(按需添加)
bash
# 在 upload_to_fir 函数中添加以下代码
# 版本号自动关联 Git 提交次数(参考网页)
version_suffix=$(git rev-list --count HEAD)
curl -F "x:version=${version_name}.${version_suffix}" ...
# 自动填充更新日志(网页方案)
changelog=$(git log --no-merges --pretty=format:"%s_____by__%cn<br>" -5)
curl -F "x:changelog=${changelog//$'\n'/}" ...
通过以上脚本,可实现 打包 → 版本管理 → Fir.im 分发 全流程自动化,大幅提升测试效率。建议结合 Fir.im 的 Webhooks 功能(网页)实现钉钉/Slack 通知,进一步完善交付链路。
四、常见问题解决
问题 | 解决方案 | 参考链接 |
---|---|---|
Bundle 文件未生成 | 检查 assets/ 目录权限,手动创建目录 |
|
签名密码错误 | 验证 gradle.properties 变量名是否匹配 |
|
资源文件冲突 | 清理 res/ 目录:rm -rf android/app/src/main/res/* |
|
Hermes 引擎兼容性问题 | 在 gradle.properties 添加 hermesEnabled=true |
通过以上方案,可实现混合工程的稳定高效打包。建议将脚本集成到 CI/CD 流程(如 Jenkins/GitHub Actions)实现自动化发布 。