Android与React Native混合开发打包全攻略:从零搭建自动化CI/CD流水线

读者可以通过这篇文章了解详细的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"

关键优化说明

  1. 强制锁定依赖版本
    yarn install --frozen-lockfile 严格使用 yarn.lock 中的版本,避免因依赖升级导致构建失败。

  2. 错误处理

    通过 || { ...; exit 1; } 捕获关键步骤(如依赖安装、Bundle 生成)的失败并终止脚本,避免无效构建。

  3. 构建前清理

    删除旧的 Bundle 和资源文件,防止残留文件干扰新构建。

  4. 跨版本兼容
    find ... -exec 适配多 APK 输出场景(如分架构打包),自动复制所有 APK 文件。


使用说明

  1. 权限设置

    bash 复制代码
    chmod +x build_android.sh
  2. 执行构建

    bash 复制代码
    ./build_android.sh
  3. 环境要求

    • 已全局安装 yarnreact-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 等自动化流程。

使用说明

  1. 赋予执行权限:chmod +x build_android.sh
  2. 执行脚本:./build_android.sh
  3. 输出 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

关键功能说明

  1. API 2.0 分步上传

    • 先通过 /getCOSToken 接口获取临时上传凭证,避免直接暴露敏感信息
    • 使用 jq 解析 JSON 响应,需确保已安装 jq 工具(可通过 brew install jq 安装)
  2. 安全增强

    • API Key 硬编码在脚本中,生产环境建议改为读取环境变量

      bash 复制代码
      PGY_API_KEY=${ENV_PGY_API_KEY}  # 从环境变量获取
  3. 自动检测最新 APK

    • ls -t 按时间排序获取最新生成的 APK 文件
  4. 交互式确认

    • 避免误上传,通过 read 命令二次确认操作

使用说明

  1. 配置蒲公英 API Key

    • 登录蒲公英后台 → 应用管理 → API 信息 → 复制 API Key
    • 替换脚本中 your_pgy_api_key_here 占位符
  2. 安装依赖工具

    bash 复制代码
    # 安装 JSON 解析工具
    brew install jq
  3. 执行完整流程

    bash 复制代码
    chmod +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 规范及最佳实践:


一、前置准备

  1. 获取 Fir API Token

    登录 Fir.im 后台 → 点击右上角用户头像 → 进入「API Tokens」页面 → 复制 Token(参考网页)。

  2. 安装依赖工具

    • jq :用于解析 JSON 响应

      bash 复制代码
      brew 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

三、关键功能说明

  1. 动态获取包名

    通过解析 android/app/build.gradle 中的 applicationId,避免硬编码(参考网页)。

  2. 两阶段上传流程

    • 获取凭证 :通过 http://api.bq04.com/apps 接口获取临时上传密钥
    • 文件上传:使用凭证将 APK 上传至指定端点(参考官方 API 文档)
  3. 结果智能处理

    • 使用 jq 解析 JSON 响应,提取关键字段
    • 自动生成短链接,便于测试人员访问(网页方案增强)

四、使用说明

  1. 替换 API Token

    将脚本中的 your_fir_api_token_here 替换为实际 Token(获取方式见网页)。

  2. 执行脚本

    bash 复制代码
    chmod +x build_android.sh
    ./build_android.sh
  3. 交互式确认

    脚本会在最后询问是否上传,输入 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)实现自动化发布 。

相关推荐
小妖怪的夏天2 天前
React Native 动态切换主题
javascript·react native·react.js
zhangguo20023 天前
react native和react在跨端架构上有什么区别?
javascript·react native·react.js
阿珊和她的猫3 天前
React Native 开发环境搭建:从零开始
javascript·react native·react.js
渔舟唱晚@3 天前
React Native 从零开始完整教程(环境配置 → 国内镜像加速 → 运行项目)
javascript·react native·react.js
小纛3 天前
React Native 太慢:kotlin-gradle-plugin-2.0.21-gradle76.jar 下载太慢
react native·kotlin·jar
爱笑的眼睛115 天前
React Native 入门 jsx tsx 基础语法
javascript·react native·react.js
西楚曹长卿5 天前
RN 获取视频封面,获取视频第一帧
android·react native·音视频·react
流星雨在线5 天前
解决 RN Switch 组件在安卓端样式很丑的问题
react native
ylineyline5 天前
React-Native Android 多行被截断
android·react native·react.js·截断·多行·cut off
爱笑的眼睛116 天前
React Navigation 使用指南
javascript·react native·react.js