Jenkins-Unity-Android/iOS打包自动化

CI(Continuous Integration,持续集成)

 * 每次提交都会触发自动化流程:编译 → 测试 → 静态检查

CD(Continuous Delivery / Continuous Deployment,持续交付/部署)

*  每次 CI 成功后,自动将构建产物(如 APK、Docker 镜像)部署到测试环境或预生产环境。

Jenkins 初始化及配置

* 配置未被占用端口及配置防火墙端口
* 插件
    + Pipeline 可视化流水线
    + Hidden Parameter 参数隐藏
    + Persistent Parameter 参数持久化
    + Active Choices
* Jenkins 权限
    * Jenkins服务中使用管理员账号密码登录并重启服务
* 参数 
    + 仅在pipelineScript中新增的参数,会在下次构建时生成,会导致构建失败,可在 ``This project is parameterized?`` 中手动增加
    + 无需更改的参数应设置为 Hidden

JenkinsFile

pipeline {
  agent any

  parameters {
      // 用户可修改的持久化参数(版本号、是否构建 APK/AAB、是否同步 Git 等)
      persistentString(name: 'VERSION_NAME', defaultValue: '1.0.0', description: '应用版本号')
      .......
      // 隐藏参数(路径、签名、Webhook 等)
      hidden(name: 'UNITY_EDITOR_PATH', defaultValue: 'C:\\Program Files\\Unity\\Editor\\Unity.exe', description: 'Unity 编辑器路径')
      ......
  }

  environment {
      BUILD_OUTPUT_PATH = "D:\\Jenkins_IIS_Server\\${JOB_BASE_NAME}\\BuildOutput\\V${VERSION_CODE}\\"
      UNITY_LOG_PATH = "D:\\Jenkins_IIS_Server\\${JOB_BASE_NAME}\\UnityLog\\V${VERSION_CODE}\\"
      JENKINS_SERVER = "http://192.168.18.222:8085/"
      IIS_SERVER = "http://192.168.18.222:8086/"
  }

  stages {

      stage('Notify Build Start') {
          steps {
              script {
                  // 打印构建参数并发送飞书通知
                  echo "构建开始,发送飞书通知..."
              }
          }
      }

      stage('Check Environment') {
          steps {
              script {
                  // 检查 Unity、Gradle、签名文件等环境依赖
                  echo "检查环境依赖..."
              }
          }
      }
     ......

  post {
      success {
          script {
              // 构建成功通知,包含耗时和可下载文件
              echo "构建成功,发送飞书通知..."
          }
      }
      failure {
          script {
              // 构建失败通知,包含耗时和控制台日志链接
              echo "构建失败,发送飞书通知..."
          }
      }
  }

UnityCode

Step1 
自动构建调用静态方法 方法直至构建结束不应有   bool goon = EditorUtility.DisplayDialog("打包平台为安卓", "输出路径为:\n" + outPutPath, "继续", "取消"); 类似阻塞逻辑
Step2
自动构建 结束应该调用 EditorApplication.Exit(0); //失败则应是 -1 或者其他不为0 的Code,参考Cmd 返回码

构建中如遇Unity编辑器重新编译(如果构建AB 生成新文件并调用AssetData.Refresh,此时异步打包方法会退出并无处调用 EditorApplication.Exit(0)),会导致Unity异步构建中断,不再会调用 EditorApplication.Exit(0); 此时需要特殊处理
超过一个小时,Jenkins 将强制打包失败 ,可通过 timeout(time: 60, unit: 'MINUTES') 进行设置timeout
建议解决方案,可控步骤都有抽成同步方法并Jenkins中配置对应stage

AndroidCode

//适配Jenkins 自动命名
def versionCodeProp = project.hasProperty('versionCode') ? project.versionCode.toInteger() : 100
def versionNameProp = project.hasProperty('versionName') ? project.versionName : '1.0.0'
versionCode versionCodeProp
versionName versionNameProp
// 自动命名:Jenkins 传入 customName 优先,否则用默认  请勿修改
def baseName = project.hasProperty('customName') ? project.cu
setProperty("archivesBaseName", baseName)

// 自动命名:Jenkins 传入 customName 优先,否则用默认  请勿修改
android.applicationVariants.all { variant ->
  variant.outputs.all { output ->
      def baseName = project.hasProperty('customName') ? project.c
      // 判断是否 AAB / APK
      def isAAB
      def isAPK
      if (project.hasProperty('customName')) {
          // customName 存在时,通过名字中是否含 "_AAB_" 判断
          isAAB = baseName.contains("_AAB_")
          isAPK = !isAAB
      } else {
          // 没有 customName 时,使用传统方法判断
          isAAB = variant.name.toLowerCase().contains("bundle")
          isAPK = variant.name.toLowerCase().contains("assemble")
      }
      // 生成输出文件名
      def fileName = ""
      if (isAAB) {
          fileName = "${baseName}.aab"
      } else if (isAPK) {
          fileName = "${baseName}.apk"
      } else {
          fileName = "${baseName}.bin" // 兜底方案
      }
      output.outputFileName = fileName
  }
}

//获取时间,添加到发布版本中
static def releaseTime() {
  return new Date().format("yyyy-MM-dd-HH-mm", TimeZone.getTimeZone("GMT+08:00"))
}

Android 构建环境

* 不同Unity版本对应 Gradle版本不同,建议创建空项目,导出确认默认Android配置

IIS 配置

- 配置未被占用端口及配置防火墙端口
- 配置目录浏览
- 配置文件可下载
- MIME类型配置支持 APK/AAB 文件下载

评论