普通视图

发现新文章,点击刷新页面。
今天 — 2025年4月13日首页

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

作者 wayne214
2025年4月12日 17:52

读者可以通过这篇文章了解详细的Android 与 React Native 混合工程的打包步骤及自动化脚本实现。


一、打包核心步骤

1. 生成 React Native Bundle

# 在项目根目录执行,将 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:生成签名密钥(若未创建)

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 添加:

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

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 打包

cd android && ./gradlew clean assembleRelease

输出路径
android/app/build/outputs/apk/release/app-release.apk


二、自动化打包 Shell 脚本

以下是在原有打包 Shell 脚本中集成 yarn install 命令的更新版本,包含依赖安装、错误处理和构建优化:


更新后的 Shell 脚本

文件名:build_android.sh

#!/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. 权限设置

    chmod +x build_android.sh
    
  2. 执行构建

    ./build_android.sh
    
  3. 环境要求

    • 已全局安装 yarnreact-native-cli
    • ANDROID_HOME 环境变量已配置

扩展功能(按需添加)

1. 依赖缓存

在脚本开头添加缓存检查逻辑,减少重复下载时间:

# 缓存检查(仅开发环境)
if [ -d "node_modules" ]; then
    echo "检测到 node_modules 缓存,跳过依赖安装"
else
    yarn install --frozen-lockfile
fi

2. 镜像加速

yarn install 前切换国内镜像源:

# 使用淘宝镜像
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 专用规则:

# React Native 保留规则
-keep class com.facebook.react.** { *; }
-keep class com.facebook.hermes.** { *; }
-keep class com.facebook.jni.** { *; }

2. 拆分 CPU 架构

修改 app/build.gradle 生成多架构 APK:

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

#!/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 硬编码在脚本中,生产环境建议改为读取环境变量
      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. 安装依赖工具

    # 安装 JSON 解析工具
    brew install jq
    
  3. 执行完整流程

    chmod +x build_android.sh
    ./build_android.sh
    

扩展功能(按需添加)

1. 上传历史记录

# 在脚本尾部添加
echo "$(date '+%Y-%m-%d %H:%M') $latest_apk" >> upload_history.log

2. 邮件通知

# 依赖 mailx 工具
echo "Build completed" | mailx -s "APK 已上传" user@example.com

通过该脚本可实现 打包 → 版本管理 → 分发 全流程自动化,适合集成到 Jenkins/GitLab CI 流水线。建议结合蒲公英的安装统计、版本回滚等企业级功能进一步优化交付流程 。

上传Fir平台

以下是在 Shell 脚本中集成上传至 Fir.im 平台 的完整实现方案,结合官方 API 规范及最佳实践:


一、前置准备

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

  2. 安装依赖工具

    • jq:用于解析 JSON 响应
      brew install jq  # macOS
      sudo apt-get install jq  # Ubuntu
      
    • curl:确保已安装最新版本(网页推荐官网下载避免乱码)

二、Shell 脚本集成代码

#!/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. 执行脚本

    chmod +x build_android.sh
    ./build_android.sh
    
  3. 交互式确认
    脚本会在最后询问是否上传,输入 y 确认即可。


五、扩展功能(按需添加)

# 在 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)实现自动化发布 。

❌
❌