Unity游戏多渠道打包自动化:基于Jenkins与Fastlane的CI/CD实战方案
2026/8/1 17:26:40 网站建设 项目流程

1. 项目概述与核心价值

如果你是一个Unity游戏团队的开发者或技术负责人,每次临近版本发布,面对iOS、Android、华为、小米、TapTap等多个渠道的打包需求,是不是感觉头大?手动配置SDK、切换平台、处理证书、上传商店,一套流程下来,半天时间就没了,还容易出错。这正是“Unity游戏多渠道打包自动化”要解决的核心痛点。这个项目不是简单的脚本堆砌,而是一套将Unity构建、各平台SDK集成、证书管理、应用商店上传等环节串联起来的完整CI/CD(持续集成/持续部署)流水线。它的核心价值在于,将重复、繁琐、易错的手工操作,转变为一次提交、自动触发、全流程无人值守的标准化产出。对于追求快速迭代、多版本并行测试的现代游戏开发团队而言,这不仅是效率工具,更是质量保障的基石。

我经历过从纯手工到半自动,再到如今基于Jenkins和Fastlane的全自动流水线,踩过的坑不计其数。这套方案的核心思路是:以Jenkins作为调度和任务管理中心,用Fastlane作为各平台(尤其是移动端)的“自动化瑞士军刀”,再通过精心设计的脚本和配置,将Unity的构建命令与各渠道SDK的集成无缝衔接起来。最终实现的效果是,开发者在GitLab或GitHub上打一个标签,或者合并代码到特定分支,Jenkins就会自动拉取代码,按预设流程为所有目标渠道生成安装包,并上传到内测分发平台或应用商店后台。下面,我就把这套经过实战检验的自动化方案拆解开来,从设计思路到实操细节,毫无保留地分享给你。

2. 整体架构设计与工具选型考量

在动手搭建之前,理清整体架构和为什么选择这些工具至关重要。一个健壮的自动化系统,其稳定性、可维护性和扩展性都源于最初的设计。

2.1 核心组件角色解析

我们的自动化流水线主要由三个核心部分组成,它们各司其职,协同工作:

  1. Jenkins (CI/CD 引擎与任务调度器)

    • 角色: 它是整个流水线的大脑和指挥官。负责监听代码仓库的变动(如Git推送),触发构建任务。它管理着构建环境(例如在一台专用的Mac Mini或强大的Linux服务器上),按顺序执行我们定义好的构建步骤(如下载依赖、调用Unity打包、执行Fastlane脚本等)。
    • 为什么是Jenkins?在游戏开发领域,Jenkins的普及率极高,插件生态丰富,与Git、Shell脚本、各种编译工具的集成非常成熟。它的Pipeline脚本(Jenkinsfile)允许我们将整个构建流程以代码的形式进行版本管理,这是实现“流水线即代码”理念的关键,使得构建过程的变更可追溯、可回滚。
  2. Fastlane (多平台部署自动化工具)

    • 角色: 它是针对iOS和Android平台部署的“自动化专家”。对于iOS,它可以自动处理证书(Code Signing)和描述文件(Provisioning Profile)的更新、打包(gym)、上传TestFlight或App Store(deliver)。对于Android,它可以构建APK/AAB(gradle)、对齐和签名(sign)、上传到Google Play Console(supply)或国内各大商店。
    • 为什么是Fastlane?手动管理iOS证书和描述文件是噩梦,Fastlane的match工具可以将其同步到Git仓库,实现团队共享和自动更新,彻底解决了“在我机器上能打包,在你机器上不行”的问题。对于国内渠道,虽然Fastlane没有官方插件,但其灵活的Ruby脚本能力和丰富的Action库,让我们可以轻松编写自定义脚本来模拟上传操作。
  3. Unity (游戏内容构建器)

    • 角色: 它是内容生产的核心。我们通过Jenkins调用Unity的命令行接口(-batchmode -quit -executeMethod),执行一个我们预先编写好的C#编辑器脚本,在这个脚本中,我们会设置构建目标(iOS/Android)、应用版本号、Bundle Identifier、导入不同的渠道SDK包,并最终执行BuildPipeline.BuildPlayer
    • 关键点: Unity的命令行构建是稳定且可脚本化的,这是实现自动化的基础。我们需要将渠道SDK的差异(如不同的AppKey、配置文件)通过脚本或配置文件进行管理。

2.2 架构工作流图解

整个流程是一个清晰的单向流水线:

代码提交 (Git) -> Jenkins触发 -> 拉取代码 -> 执行Unity构建脚本 -> 生成原始包 -> 调用Fastlane处理平台相关任务 -> 输出最终包 -> 上传分发

这个过程中,Jenkins是总控,它依次调用不同的“工人”(Unity命令行、Fastlane命令)来完成工作。所有环节的配置(如Jenkins的Pipeline脚本、Fastlane的Fastfile、Unity的编辑器脚本)都应纳入代码仓库管理。

2.3 工具选型背后的“为什么”

  • 为什么不只用Jenkins脚本?Jenkins的Shell脚本能力足以调用Unity打包,但处理iOS证书、描述文件以及与应用商店API交互非常复杂且容易出错。Fastlane是专门为此而生的,它封装了这些复杂操作,提供了更简洁、更稳定的接口。让专业的人(工具)做专业的事。
  • 为什么选择Pipeline而不是自由风格项目?Jenkins的Pipeline(尤其是声明式Pipeline)将构建流程定义为Jenkinsfile,并存储在项目根目录。这样做的好处是,构建流程的修改需要经过代码评审,与项目代码一同演进,避免了在Jenkins网页界面上进行容易遗忘或难以复现的配置操作。
  • 如何处理国内Android渠道?国内渠道(如华为、小米、OPPO、vivo、TapTap)没有统一的官方上传API。我们的策略是:Unity构建出“母包”(一个包含所有渠道公共资源的APK),然后通过各渠道提供的后处理工具(通常是Python或Java脚本)进行“渠道包”的生成(注入渠道标识文件)。这一步可以集成在Jenkins的Pipeline中,在Fastlane完成签名后执行,或者编写自定义的Fastlane Action来处理。

3. 环境准备与核心配置详解

工欲善其事,必先利其器。搭建环境是第一步,也是最容易踩坑的一步。这里我会详细说明在macOS(兼顾iOS打包)或Linux服务器上,如何一步步配置好这个自动化战场。

3.1 Jenkins的安装与基础配置

首先,我们需要一台作为构建服务器的机器。对于包含iOS打包的需求,这台机器必须是macOS系统(可以是Mac Mini、Mac Studio或虚拟机,但必须拥有有效的Apple开发者账号)。如果只打包Android,则Linux服务器是更经济稳定的选择。

安装Jenkins: 推荐使用Docker安装,这能保证环境隔离和易于迁移。但对于需要调用Xcode和iOS模拟器的macOS环境,直接安装Java并运行Jenkins war包更为方便。

# macOS 使用Homebrew安装 brew install jenkins-lts brew services start jenkins-lts # 或者下载通用Java包 java -jar jenkins.war --httpPort=8080

安装后,通过浏览器访问http://服务器IP:8080,按照指引完成初始化,安装推荐的插件,特别是Git pluginPipelineBlue Ocean(可视化流水线)等。

关键配置点

  1. 全局工具配置: 在“系统管理” -> “全局工具配置”中,指定JDK、Git的路径。如果使用Docker agent,还需要配置Docker。
  2. 凭据配置: 这是安全的核心。你需要在这里添加:
    • Git仓库凭据: SSH私钥或用户名/密码,用于拉取代码。
    • Apple Developer Account凭据: 用于Fastlane自动管理证书。
    • 各应用商店的API Key: 如Google Play的Service Account JSON文件,苹果的App Store Connect API Key。
  3. 节点管理: 如果构建任务繁重,可以设置多个“节点”(Agent),将任务分发到不同的机器上执行。对于Unity构建这种CPU/内存密集型任务,独立的构建节点非常有必要。

3.2 Unity项目与命令行构建准备

Unity命令行构建是整个流程的基石。你需要准备一个专门的构建脚本。

  1. 创建编辑器构建脚本: 在你的Unity项目Assets目录下,创建Editor/BuildScript.cs

    using UnityEditor; using System.Collections.Generic; using System.IO; public static class BuildScript { public static void PerformBuild() { // 从命令行参数读取构建目标和输出路径 // 例如:-executeMethod BuildScript.PerformBuild -buildTarget Android -outputPath ./Builds string[] args = System.Environment.GetCommandLineArgs(); string outputPath = "./Builds"; // 默认值 BuildTarget buildTarget = BuildTarget.Android; // 默认值 // 解析参数(此处简化,实际需要更健壮的解析逻辑) for (int i = 0; i < args.Length; i++) { if (args[i] == "-outputPath" && i + 1 < args.Length) { outputPath = args[i + 1]; } if (args[i] == "-buildTarget" && i + 1 < args.Length) { buildTarget = (BuildTarget)System.Enum.Parse(typeof(BuildTarget), args[i + 1]); } } // 定义场景路径 List<string> scenes = new List<string>(); foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes) { if (scene.enabled) scenes.Add(scene.path); } // 关键:根据渠道或平台,动态调整PlayerSettings // 例如,从外部配置文件读取Bundle Identifier、Version等 PlayerSettings.applicationIdentifier = GetBundleIdForChannel(); PlayerSettings.bundleVersion = GetVersionFromCI(); // 从Jenkins环境变量获取 // 执行构建 BuildPipeline.BuildPlayer(scenes.ToArray(), outputPath, buildTarget, BuildOptions.None); } private static string GetBundleIdForChannel() { // 这里可以根据环境变量或配置文件决定使用哪个BundleId // 例如:Jenkins会设置一个 CHANNEL 变量 string channel = System.Environment.GetEnvironmentVariable("CHANNEL"); switch (channel) { case "huawei": return "com.yourcompany.game.huawei"; case "xiaomi": return "com.yourcompany.game.xiaomi"; default: return "com.yourcompany.game"; } } }
  2. 准备Unity安装: 在构建服务器上,需要安装与项目版本匹配的Unity Editor。可以从Unity Hub命令行工具安装,或者直接下载安装包。务必记住安装路径,因为Jenkins需要调用这个路径下的Unity可执行文件。

3.3 Fastlane的安装与初始化

Fastlane是基于Ruby的,所以需要先确保Ruby环境。

# 安装Ruby (macOS通常自带,Linux需安装) # 使用RVM或rbenv管理Ruby版本是更好的选择,这里以系统Ruby为例 sudo gem install fastlane -NV

在项目根目录(或iOS/Android子项目目录)初始化Fastlane:

# 对于iOS项目,进入ios目录(如果Unity导出的Xcode工程在此) cd ./Builds/iOS fastlane init # 按照指引输入Apple ID等信息,会生成Appfile和Fastfile # 对于Android项目,进入android目录(Unity导出的Gradle工程) cd ./Builds/Android fastlane init

初始化过程会引导你连接App Store Connect或Google Play,并生成关键的配置文件。一个重要的建议:将Fastlane的配置(fastlane/目录)也纳入你的主项目代码仓库管理,这样任何机器拉取代码后都能拥有一致的部署配置。

3.4 各平台SDK的预集成策略

多渠道打包的复杂性主要来源于各平台SDK的差异。我们不能在Unity编辑器里手动切换SDK,必须实现脚本化。

  1. 目录结构规划: 在Unity项目的Assets目录下,创建一个如Plugins/ChannelSDKs/的目录。每个渠道的SDK放在独立的子文件夹内,例如huawei/,xiaomi/,tapTap/。同时,每个渠道SDK可能包含平台特定的原生代码(.aar,.jar,.framework),需要按Android/,iOS/子目录存放。
  2. 使用Unity的Define Symbols和条件编译: 在Player Settings中为不同渠道定义编译符号,如CHANNEL_HUAWEI,CHANNEL_XIAOMI。在代码中,可以使用#if CHANNEL_HUAWEI来编写渠道特定的初始化逻辑。
  3. 使用ScriptableObject管理配置: 创建一个ChannelConfig的ScriptableObject,包含AppKey、AppSecret等字段。为每个渠道创建一个该资源的实例(如ChannelConfig_Huawei.asset)。构建时,根据目标渠道,通过编辑器脚本动态地将对应的Asset文件复制到Resources目录下,或直接加载其内容并写入到最终的配置文件中。
  4. 依赖管理: 对于通过Unity Package Manager (UPM) 或第三方包管理器(如OpenUPM)引入的SDK,需要在构建脚本中通过UnityEditor.PackageManager.Client的API来确保特定版本的包被正确添加。对于.aar等文件,确保其放置在正确的Plugins/Android目录结构下。

实操心得: SDK的预集成是最大的“脏活”。强烈建议建立一个“渠道SDK管理仓库”,使用Git Submodule或简单的文件同步脚本,将各渠道的SDK原始文件统一管理。在Jenkins构建开始时,先从这个管理仓库将所需渠道的SDK文件拷贝到Unity项目指定位置。这样可以避免将巨大的SDK二进制文件都塞进主游戏代码仓库。

4. Jenkins Pipeline流水线核心实现

Jenkins Pipeline是我们自动化流程的“总剧本”。我们将使用声明式Pipeline,因为它结构更清晰,可读性更强。这个Pipeline脚本(Jenkinsfile)会放在项目根目录。

4.1 Pipeline脚本结构剖析

下面是一个高度概括但结构完整的Jenkinsfile示例:

pipeline { agent any // 可以指定具体的agent标签,如 `agent { label 'macos-unity' }` environment { // 定义全局环境变量 UNITY_PATH = '/Applications/Unity/Hub/Editor/2022.3.20f1/Unity.app/Contents/MacOS/Unity' PROJECT_PATH = "${WORKSPACE}" BUILD_TARGET = params.BUILD_TARGET // 从构建参数获取 CHANNEL = params.CHANNEL VERSION = sh(script: 'git describe --tags --always --dirty', returnStdout: true).trim() } parameters { // 定义构建参数,允许手动触发时选择 choice(name: 'BUILD_TARGET', choices: ['Android', 'iOS'], description: '选择构建平台') choice(name: 'CHANNEL', choices: ['official', 'huawei', 'xiaomi', 'tapTap'], description: '选择发布渠道') booleanParam(name: 'UPLOAD_TO_STORE', defaultValue: false, description: '是否上传到应用商店') } stages { stage('代码与依赖准备') { steps { checkout scm // 拉取代码 script { // 根据CHANNEL参数,从SDK管理仓库同步对应渠道的SDK文件到项目目录 sh "python3 ./Scripts/fetch_sdk.py --channel ${env.CHANNEL}" } } } stage('Unity构建') { steps { script { // 调用Unity命令行进行构建 sh """ "${UNITY_PATH}" -batchmode -quit -nographics \ -projectPath "${PROJECT_PATH}" \ -executeMethod BuildScript.PerformBuild \ -buildTarget ${BUILD_TARGET} \ -outputPath "${WORKSPACE}/Builds/${BUILD_TARGET}" \ -logFile "${WORKSPACE}/unity_build.log" """ } } post { always { // 无论成功失败,都存档Unity的日志,便于排查 archiveArtifacts artifacts: 'unity_build.log' } } } stage('平台后处理与打包') { steps { script { // 根据不同平台,进入不同目录执行Fastlane dir("${WORKSPACE}/Builds/${BUILD_TARGET}") { if (env.BUILD_TARGET == 'iOS') { sh "fastlane ios build" } else if (env.BUILD_TARGET == 'Android') { sh "fastlane android build" // 如果是国内渠道,额外执行渠道包生成脚本 if (env.CHANNEL != 'official') { sh "python3 ./generate_channel_package.py --channel ${env.CHANNEL}" } } } } } } stage('上传与分发') { when { expression { params.UPLOAD_TO_STORE == true } } steps { script { dir("${WORKSPACE}/Builds/${BUILD_TARGET}") { if (env.BUILD_TARGET == 'iOS') { sh "fastlane ios upload" } else if (env.BUILD_TARGET == 'Android') { sh "fastlane android upload" // 国内渠道可能需要调用自定义脚本上传到各自的后台 if (env.CHANNEL != 'official') { sh "python3 ./upload_to_channel.py --channel ${env.CHANNEL}" } } } } } } stage('归档与通知') { steps { // 将最终生成的ipa/apk文件归档到Jenkins服务器 archiveArtifacts artifacts: "Builds/${BUILD_TARGET}/**/*.ipa, Builds/${BUILD_TARGET}/**/*.apk" // 发送构建结果通知到钉钉/飞书/企业微信等 dingTalk( robot: 'jenkins-robot', type: 'MARKDOWN', title: "构建完成: ${env.JOB_NAME}", text: "项目: ${env.JOB_NAME}\\n版本: ${env.VERSION}\\n渠道: ${env.CHANNEL}\\n状态: ${currentBuild.currentResult}\\n详情: ${env.BUILD_URL}" ) } } } }

4.2 关键阶段详解与避坑指南

  • 代码与依赖准备阶段

    • checkout scm是Pipeline内置步骤,用于拉取触发此次构建的对应分支/标签代码。
    • fetch_sdk.py是一个自定义脚本,它的职责是根据CHANNEL参数,将对应的SDK文件(可能来自另一个Git仓库、网络存储或本地目录)复制或链接到当前Unity项目的Assets/Plugins/目录下。这是实现“一次构建,多种输出”的关键
  • Unity构建阶段

    • -batchmode让Unity以无界面的批处理模式运行。
    • -quit构建完成后自动退出Unity进程。
    • -nographics在无图形界面的服务器上构建时使用,可以节省资源。
    • -logFile指定日志文件路径至关重要。Unity命令行构建的错误信息都输出在这里,必须存档以供排查。
    • 避坑点1: Unity命令行构建对路径中的空格和特殊字符非常敏感。确保UNITY_PATHPROJECT_PATH用双引号包裹。
    • 避坑点2: Unity的激活问题。在构建服务器上,你需要预先使用序列号或Unity账号激活Unity。可以通过命令行-serial XX -username YY -password ZZ来激活,但更安全的做法是使用离线激活文件(Unity_v2022.x.ulf)。
  • 平台后处理与打包阶段

    • 这个阶段的核心是执行Fastlane。我们进入Unity构建输出的平台工程目录(Xcode或Gradle工程),运行对应的Fastlane任务(lane)。
    • 对于Android渠道包,generate_channel_package.py脚本会利用各渠道提供的工具(如华为的appgallery-connector, 小米的misdk-tools),向基础APK中注入渠道标识文件(如channel_)。这个过程通常在签名之后进行。

5. Fastlane配置与多平台部署实战

Fastlane的配置集中在fastlane/Fastfile中。这里我们定义不同的lane(任务)来执行构建、打包、上传等操作。

5.1 iOS平台的Fastlane配置

以下是iOS平台一个典型的Fastfile示例,包含两个lane:buildupload

# fastlane/Fastfile (iOS) default_platform(:ios) platform :ios do # 构建lane:负责证书、编译、打包 desc "Build the iOS application" lane :build do # 1. 自动同步证书和描述文件(团队协作最佳实践) match( type: "appstore", # 或 "development", "adhoc" app_identifier: ["com.yourcompany.game"], readonly: true # 建议设置为true,避免误操作修改证书仓库 ) # 2. 增加构建号(可以从环境变量获取,如Jenkins的BUILD_NUMBER) increment_build_number( build_number: ENV["BUILD_NUMBER"] || Time.now.strftime("%Y%m%d%H%M") ) # 3. 编译并打包ipa gym( scheme: "Unity-iPhone", # Xcode工程的scheme名,Unity导出的一般是这个 export_method: "app-store", # 导出方式:app-store, ad-hoc, enterprise, development output_directory: "./fastlane_builds", clean: true ) end # 上传lane:负责上传到TestFlight或App Store desc "Upload the IPA to App Store Connect" lane :upload do # 上传到TestFlight pilot( skip_submission: true, # 只上传,不提交审核 changelog: "Automated build from Jenkins #{ENV['BUILD_ID']}" ) # 如果需要直接提交到App Store审核,使用deliver # deliver( # skip_binary_upload: false, # submit_for_review: false, # force: true # ) end end

关键点解析

  • match:这是Fastlane的证书管理神器。它将你的证书和描述文件加密后存储在一个私有的Git仓库中。团队所有成员和CI服务器都从这个仓库同步,保证了环境的一致性。首次设置需要一些功夫,但一劳永逸。
  • gym: 封装了xcodebuildxcrun,负责编译和打包。export_method必须与match使用的类型匹配。
  • pilot/deliver: 用于与App Store Connect交互。需要预先在App Store Connect中创建API Key,并在Fastlane的Appfile中配置。

5.2 Android平台的Fastlane配置

Android的配置相对简单,因为签名和构建主要由Gradle管理。

# fastlane/Fastfile (Android) default_platform(:android) platform :android do # 构建lane desc "Build the Android APK/AAB" lane :build do # 1. 可选:动态更新版本信息(在gradle.properties或build.gradle中) # android_update_version_code(...) # android_update_version_name(...) # 2. 调用Gradle任务进行构建 gradle( task: "bundle", # 或 "assembleRelease" 生成APK。'bundle'生成AAB (Android App Bundle) build_type: "Release", properties: { "android.injected.signing.store.file" => ENV["ANDROID_KEYSTORE_PATH"], "android.injected.signing.store.password" => ENV["ANDROID_KEYSTORE_PASSWORD"], "android.injected.signing.key.alias" => ENV["ANDROID_KEY_ALIAS"], "android.injected.signing.key.password" => ENV["ANDROID_KEY_PASSWORD"] } ) end # 上传lane (以Google Play为例) desc "Upload the AAB to Google Play Internal Track" lane :upload do upload_to_play_store( track: 'internal', # 发布轨道:internal, alpha, beta, production aab: lane_context[SharedValues::GRADLE_AAB_OUTPUT_PATH] || './app/build/outputs/bundle/release/app-release.aab', # 使用服务账号的JSON密钥文件进行身份验证 json_key: File.read(ENV['GCLOUD_SERVICE_ACCOUNT_JSON_PATH']) ) end end

关键点解析

  • gradle: 执行Gradle构建。我们将签名信息通过properties参数注入,避免了在代码仓库中硬编码敏感信息。这些密码应存储在Jenkins的“凭据”中,并通过ENV变量传递。
  • upload_to_play_store: 需要先在Google Play Console创建服务账号并下载JSON密钥文件。将该文件路径存入Jenkins凭据,再通过环境变量传入。

5.3 处理国内Android渠道包

国内渠道没有统一的Fastlane插件,我们需要自己写脚本。假设我们已经有一个签好名的APK(app-release.apk),和一个Python脚本generate_channel_package.py

# generate_channel_package.py 示例框架 import argparse import subprocess import os import zipfile def inject_channel_android(original_apk_path, channel, output_dir): """ 向APK中注入渠道信息。 原理:在APK的META-INF目录下放入一个以渠道名命名的空文件(如 `channel_xiaomi`)。 运行时,App通过读取这个文件来识别渠道。 """ # 1. 复制原APK new_apk_name = f"app_{channel}.apk" new_apk_path = os.path.join(output_dir, new_apk_name) subprocess.run(['cp', original_apk_path, new_apk_path]) # 2. 使用zip命令向APK中添加渠道标识文件 # 注意:不能直接用zipfile模块,会破坏APK签名。需要使用jar或apktool等不破坏签名的方式。 # 这里以使用V1签名允许的添加空文件方式为例(需安装zip) channel_file = f"META-INF/channel_{channel}" subprocess.run(['zip', '-q', new_apk_path, channel_file], input=b'', capture_output=True) # 更稳健的做法是使用各渠道官方提供的命令行工具,如华为的AGC工具。 print(f"Channel package generated: {new_apk_path}") return new_apk_path if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument('--channel', required=True) args = parser.parse_args() original_apk = "./app/build/outputs/apk/release/app-release.apk" # Fastlane构建输出的APK路径 output_dir = "./channel_packages" os.makedirs(output_dir, exist_ok=True) inject_channel_android(original_apk, args.channel, output_dir)

然后在Jenkinsfile的Android后处理阶段调用这个脚本。对于需要特定SDK或复杂操作的渠道(如华为需要集成HMS Core SDK),则需要在Unity构建阶段就通过fetch_sdk.py将对应的SDK集成进去。

6. 常见问题排查与实战经验录

自动化流程搭建过程中,你会遇到各种各样的问题。这里记录了一些高频问题和解决思路。

6.1 Unity构建失败排查

  • 问题: Jenkins控制台输出Unity license is not activated.
    • 排查: 构建服务器上的Unity未激活。确保已使用有效许可证激活。对于无图形界面的服务器,使用离线激活是最可靠的方式。在图形界面机器上激活后,将生成的.ulf文件拷贝到服务器Unity的许可目录下。
  • 问题: 构建成功,但生成的包在手机上崩溃,日志显示ClassNotFoundExceptionSo not found
    • 排查: 这通常是SDK集成问题。检查构建日志,确认所有需要的.aar.jar.so文件都被正确打包进APK。可以使用apkanalyzer(Android SDK工具) 或直接解压APK查看lib目录。确保渠道SDK的放置路径符合Unity的规范(如Android的.aar放在Assets/Plugins/Android下)。
  • 问题: iOS构建成功,但上传到App Store Connect时提示Invalid BundleMissing Icon
    • 排查: Xcode工程配置问题。检查Unity导出的Xcode工程中,Info.plist、图标文件、启动图等资源是否完整。有时Unity版本与Xcode版本不兼容会导致资源拷贝失败。可以在Jenkins的Unity构建步骤后,添加一个脚本步骤,检查Xcode工程的关键文件是否存在。

6.2 Fastlane与证书管理问题

  • 问题match执行失败,提示No matching provisioning profiles found
    • 排查
      1. 确认match类型(appstore,adhoc)与gymexport_method是否一致。
      2. 确认Appfile中配置的app_identifier与Apple开发者后台的App ID完全匹配。
      3. 如果是首次使用match,需要先运行fastlane match init初始化证书仓库,然后运行fastlane match [type]来生成并上传证书。
      4. 确保Jenkins服务器运行的机器有权限访问存放证书的Git仓库(配置了SSH Key)。
  • 问题: 上传到TestFlight时,pilot长时间卡住或报网络错误。
    • 排查
      1. App Store Connect API有时不稳定。可以尝试增加超时时间pilot(... , api_timeout: 300)
      2. 检查使用的API Key是否还有权限,是否在App Store Connect中正确配置了“用户与访问”。
      3. 对于中国大陆的服务器,网络连接可能是问题。考虑使用代理或重试机制。

6.3 Jenkins Pipeline流程优化

  • 问题: 构建时间过长,尤其是Unity构建阶段。
    • 优化
      1. 使用缓存: 利用Jenkins的stashunstash步骤,缓存Library文件夹。Unity在非代码改变的重建时,可以复用大部分缓存数据,极大缩短构建时间。
      2. 并行构建: 如果有多台构建机(Agent),可以在Pipeline的parallel块中同时进行iOS和Android的构建。
      3. 增量构建脚本: 编写更智能的Unity构建脚本,只构建发生变化的资源包(AssetBundle)。
  • 问题: 构建脚本复杂,维护困难。
    • 优化
      1. 模块化: 将复杂的Shell脚本、Python脚本拆分成独立的、可复用的文件。
      2. 使用共享库: Jenkins支持Pipeline共享库,可以将通用的函数(如Unity构建、版本号生成)提取到共享库中,供多个项目使用。
      3. 文档化: 在Jenkinsfile和脚本中添加清晰的注释,说明每个步骤的目的和关键参数。

6.4 安全与敏感信息管理

这是自动化流水线的生命线。绝对不要将任何密码、密钥、API Token硬编码在脚本或代码中。

  1. Jenkins Credentials: 将所有敏感信息(Git SSH Key、Apple ID密码、Google Play JSON密钥、各渠道AppSecret)存入Jenkins的“凭据”系统。在Pipeline中通过withCredentials绑定到环境变量使用。
    stage('构建') { environment { // 通过凭证ID引用 APPLE_ID_PASSWORD = credentials('apple-id-password') } steps { sh 'echo $APPLE_ID_PASSWORD' // 密码会被掩码 } }
  2. Fastlane Match: 将iOS证书和描述文件存入加密的Git仓库,通过密码访问。这个密码同样存入Jenkins Credentials。
  3. 环境变量文件: 对于非Jenkins管理的变量,可以使用.env文件,但务必将其加入.gitignore,并通过Jenkins在构建时注入。

搭建这样一套系统初期投入不小,但一旦稳定运行,它带来的效率提升和错误减少是巨大的。它让开发团队能更专注于游戏内容本身,而不是重复的打包和上传操作。从每次发布前的手忙脚乱,到喝着咖啡看Jenkins自动完成所有工作,这种体验的提升,对于团队士气和开发节奏的优化,是实实在在的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询