首页
/ fastlane 内置 Actions 目录解析:自动检测机制与自定义 Action 创建指南

fastlane 内置 Actions 目录解析:自动检测机制与自定义 Action 创建指南

2026-09-05 17:19:43作者:蔡怀权

fastlane 的核心扩展能力建立在 “action” 这一最小执行单元之上:每一个 .rb 文件对应一个可复用的自动化步骤,从构建签名(gym、match)到上传发布(deliver、pilot)都由 action 编排完成。本文以 fastlane/lib/fastlane/actions/README.md 为主线,深入解析内置 actions 目录的组织约定、fastlane 如何自动检测并加载该目录下的文件、fastlane new_action 命令的完整生成流程,以及一个 Action 类需要实现哪些接口才能被 fastlane 正确识别、执行和生成文档。

内置 Actions 目录:fastlane 集成的事实中心

actions/README.md 说明了该目录的定位:

All built-in integrations are available in this directory. Use the fastlane new_action command to create a new action.

fastlane will automatically detect the files in this folder

也就是说,fastlane/lib/fastlane/actions/ 目录是 fastlane 全部内置集成的存放地,且 fastlane 会自动检测该目录下的文件,开发者无需手动注册。当前仓库中该目录包含数百个 action 文件,例如:

值得注意的是,许多 action 文件内部通过 require 复用更底层的实现,例如 gym.rb 首行即 require 'fastlane/actions/build_app'pilot.rb 复用 upload_to_testflight。从源码结构看,目录内存在两层内容:直接面向用户调用的 action供其他 action 内部 require 的共享实现(如 upload_to_app_store.rbdeliverappstore 共同依赖),这也是阅读该目录时需要区分的关键点。

该目录下还有一个 docs/ 子目录,存放特定 action 的补充文档(如 run_tests.mdupload_to_app_store.md.erbupload_to_testflight.md),供文档生成流程合并进各 action 的说明页。

自动检测机制:fastlane 如何“发现”一个 Action

README 中“自动检测”的说法对应 actions_helper.rb 中的三个关键方法:

1. 加载内置 actions:load_default_actions

def self.load_default_actions
  Dir[File.expand_path('*.rb', File.dirname(__FILE__))].each do |file|
    require file
  end
end

实现非常直接:对 actions/ 目录下所有 *.rb 文件逐一 require。这就是“自动检测”的全部含义——文件名即注册信息,只要文件内定义了符合命名约定的 Action 子类,加载后即可通过名字调用。

2. 官方 action 清单:get_all_official_actions

def self.get_all_official_actions
  Dir[File.expand_path('*.rb', File.dirname(__FILE__))].collect do |file|
    File.basename(file).gsub('.rb', '').to_sym
  end
end

同样的目录扫描被用来生成官方 action 名称列表(如 :gym:scan),供插件系统区分内置与插件 action。action_collector.rb 中的 determine_version 也依赖这一约定:带插件前缀(fastlane-plugin-)的名字解析为插件版本,否则统一归为内置 action 并返回 Fastlane::VERSION

3. 按名字反查类:action_class_ref

def self.action_class_ref(action_name)
  class_name = action_name.to_s.fastlane_class + 'Action'
  # ...
  class_ref = Fastlane::Actions.const_get(class_name)
end

调用方只写小写名字(如 gym),fastlane 将其转换为驼峰类名并追加 Action 后缀(GymAction),再到 Fastlane::Actions 命名空间下查找。这一约定与 action.rb 中的 action_name 互为逆操作:

# instead of "AddGitAction", this will return "add_git" to print it to the user
def self.action_name
  self.name.split('::').last.gsub(/Action$/, '').fastlane_underscore
end

因此文件名必须与 action 名字一致、类名必须以 Action 结尾,否则加载器 load_external_actions 会明确报错:

Could not find '<ClassName>' class defined.
Action '<file_name>' is damaged!

该错误处理同时出现在 actions_helper.rbload_external_actions 中,它负责加载项目本地 fastlane/actions/ 目录下的自定义 action:对每个文件做 require,捕获 SyntaxError 并高亮出错行,再校验类存在且实现了 run 方法。

使用 fastlane new_action 创建新 Action

README 推荐的创建方式是 fastlane new_action 命令。该命令在 commands_generator.rb 中注册,语法为 fastlane new_action,支持传入可选的名字参数,最终调用 new_action.rb 中的 Fastlane::NewAction.run

命名校验规则

如果不带参数运行,命令会进入交互式输入;无论哪种方式,名字都必须通过同一个校验:

def self.name_valid?(name)
  name =~ /^[a-z0-9_]+$/
end

只能包含小写字母、数字和下划线,交互提示中也给出了示例:'testflight''upload_to_s3'。不符合规则会提示 "Name is invalid. Please ensure the name is all lowercase, free of spaces and without special characters!" 并要求重新输入。

模板渲染与文件落盘

generate_action 从内置模板生成 action 文件:

def self.generate_action(name)
  template = File.read("#{Fastlane::ROOT}/lib/assets/custom_action_template.rb")
  template.gsub!('[[NAME]]', name)
  template.gsub!('[[NAME_UP]]', name.upcase)
  template.gsub!('[[NAME_CLASS]]', name.fastlane_class + 'Action')

  actions_path = File.join((FastlaneCore::FastlaneFolder.path || Dir.pwd), 'actions')
  FileUtils.mkdir_p(actions_path) unless File.directory?(actions_path)

  path = File.join(actions_path, "#{name}.rb")
  File.write(path, template)
  UI.success("Created new action file '#{path}'. Edit it to implement your custom action.")
end

三个模板占位符分别被替换为:

占位符 替换值 示例(name = upload_to_s3
[[NAME]] 原样名字 upload_to_s3
[[NAME_UP]] 大写化(用于 SharedValues 常量、环境变量前缀) UPLOAD_TO_S3
[[NAME_CLASS]] 驼峰化 + Action 后缀 UploadToS3Action

注意生成位置:优先写入项目的 fastlane/ 目录下的 actions/ 子目录(FastlaneCore::FastlaneFolder.path),找不到 fastlane 文件夹时回退到当前工作目录。这正好对接前述 load_external_actions 的加载路径——生成在项目的 fastlane/actions/ 里,运行时被自动加载,形成完整闭环。

拆解 Action 模板:一个合法 Action 的最小接口

生成文件的内容来自 custom_action_template.rb,它完整展示了一个 Action 需要(或建议)实现的所有静态方法,也是理解内置 action 源码的通用钥匙。以模板为例:

module Fastlane
  module Actions
    module SharedValues
      UPLOAD_TO_S3_CUSTOM_VALUE = :UPLOAD_TO_S3_CUSTOM_VALUE
    end

    class UploadToS3Action < Action
      def self.run(params)
        # fastlane will take care of reading in the parameter and
        # fetching the environment variable:
        UI.message("Parameter API Token: #{params[:api_token]}")

        # sh "shellcommand ./path"
        # Actions.lane_context[SharedValues::UPLOAD_TO_S3_CUSTOM_VALUE] = "my_val"
      end

      def self.description
        'A short description with <= 80 characters of what this action does'
      end

      def self.available_options
        [
          FastlaneCore::ConfigItem.new(key: :api_token,
                                       env_name: 'FL_UPLOAD_TO_S3_API_TOKEN',
                                       description: 'API Token',
                                       verify_block: proc do |value|
                                         unless value && !value.empty?
                                           UI.user_error!("No API token given")
                                         end
                                       end),
          FastlaneCore::ConfigItem.new(key: :development,
                                       env_name: 'FL_UPLOAD_TO_S3_DEVELOPMENT',
                                       description: 'Create a development certificate',
                                       is_string: false,
                                       default_value: false)
        ]
      end

      def self.output
        [['UPLOAD_TO_S3_CUSTOM_VALUE', 'A description of what this value contains']]
      end

      def self.is_supported?(platform)
        platform == :ios
      end
    end
  end
end

对照基类 action.rb 可以逐条确认各方法的职责与缺省行为:

方法 作用 基类缺省行为
run(params) 实际逻辑入口,params 中同时包含 Fastfile 传参与环境变量解析结果 空实现(子类必须覆写)
description 文档中的一行简短描述 返回红色警告 "No description provided"(action.rb
details 可选的长描述,可含 markdown nil
available_options 声明所有参数,每项是 FastlaneCore::ConfigItem nil
output 声明 action 写入共享区(lane_context)的键值 nil
return_value / return_type 描述返回值;return_type 取值受限于 RETURN_TYPES:string:array_of_strings:hash:bool:int 等,见 action.rb nil
authors 作者署名 nil
is_supported?(platform) 声明支持的平台(:ios:mac:androidtrue 直接 UI.crash!,即必须实现action.rb
category 文档分类,取值来自 AVAILABLE_CATEGORIEStestingbuildingcode_signingnotifications 等,deprecated 必须最后) :undefined
deprecated_notes 标记废弃 action 时给用户的迁移说明 nil

几个模板中的细节值得展开:

  • ConfigItemenv_name 约定:参数会同时从 Fastfile 调用参数和环境变量两处读取,模板推荐用 FL_<ACTION_NAME_UPPER> 作为环境变量前缀(如 FL_UPLOAD_TO_S3_API_TOKEN),避免与系统变量冲突。
  • verify_block 是参数校验钩子:在值被使用前执行,可直接 UI.user_error! 终止并给出带使用示例的提示。
  • is_string: false 表示参数接受非字符串值(如布尔),default_value 提供缺省值。
  • lane_context 是 action 之间的共享数据区output 中声明的键在运行时写入 Actions.lane_context,下游 action 可直接读取。基类中 Action.lane_context 只是对 Actions.lane_context 的转发(action.rb),底层是一个支持敏感值隐藏的特殊 Hash 实现 LaneContextValuesactions_helper.rb),用于存放 token 之类不宜明文打印的数据。
  • 在 action 内部调用其他 action:模板注释中提示 other_action.xxx。这是由基类的 method_missing 兜底逻辑保证的——若直接裸调 xxx,会触发 UI.user_error!("To call another action from an action use \other_action.#{method_sym}` instead")`(action.rb)。
  • sh 一行即用:基类通过 def_delegator(Actions, :sh_control_output, :sh)sh 委托给 Actions 助手,使自定义 action 可以直接执行 shell 命令;当项目存在 Gemfile 时 shell out 会自动尝试使用 bundle execshell_out_should_use_bundle_exec?action.rb)。

运行时的执行与追踪

action 被调用时会经过 actions_helper.rb 中的 execute_action 包装:打印 Step: <step_name> 标题、计时、捕获异常,并在 executed_actions 中记录每一步的名字、耗时与错误堆栈。这份记录同时服务于终端输出与 JUnit 报告生成,因此自定义 action 即使不实现 step_text(缺省返回 action_name),也会出现在执行报告中。此外 Actions.alias_actionsactions_helper.rb)会收集所有声明了 aliases 的 action,支持为 action 提供别名调用。

文档生成与文档站

actions/README.md 最后一段说明所有 action 会在文档站集中列出并逐一生成文档页。结合仓库实现来看,文档内容的数据来源正是上表中的各个静态方法:descriptiondetailsavailable_optionsoutputexample_codesample_return_value 等。基类为此还扩展了 String 的 markdown 辅助方法(markdown_samplemarkdown_details 等,action.rb),用于把 details/example_code 中返回的 heredoc 字符串规范化为文档页格式;assets 等 ERB 模板则负责最终渲染。因此写好 description(建议 ≤80 字符)与 details 本身就是 action 交付物的一部分,这也是模板注释反复强调的原因。

小结

回到 actions/README.md 的三句话,本文给出了完整的源码级印证:

  1. 内置集成集中在 fastlane/lib/fastlane/actions/,文件即注册,通过 load_default_actions / get_all_official_actions 的目录扫描被自动发现;
  2. 创建新 action 使用 fastlane new_action,命名只允许 [a-z0-9_],文件由 custom_action_template.rb 渲染后写入项目的 fastlane/actions/,再由 load_external_actions 自动加载并校验 run 方法的存在;
  3. 一个可被文档化、可执行的 action,需要继承 Fastlane::Action、实现 runis_supported?,并通过 ConfigItem 声明参数、通过 output 声明共享值——模板 custom_action_template.rb 已把这些骨架全部备齐,开发者只需填充 run 内的实际逻辑。
登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384