使用fastlane工具自动打包发布App Store、fir、蒲公英

1. 前言

打包过程中为了避免重复性的工作和节省时间,以下是研究和学习Fastlane的一些记录和总结,希望可以为初学者提供一些帮助。

1.1. 依赖环境:

Xcode7 +
macOS or Linux with Ruby 2.0.0 +

2. Fastlane简介

Fastlane 是一套使用Ruby写的自动化工具集,为iOS 和 Android 开发者提供的自动化构建工具,它可以帮助开发者将 App 打包、签名、测试、发布、信息整理、提交 App Store 等工作完整的连接起来,实现完全自动化的工作流。

fastlane 强大之处就在于其提供的工具全,基本可以覆盖打包测试发布的所有流程,如下图:

image

fastlane 的每一个工具都对应一个 Ruby 脚本,用来执行某一特定的任务,而最妙的是可以通过配置文件将不同的工具灵活的结合在一起,从而形成一个完整的自动化流程,实现一键上传 ITC,从而缩短用于构建发布的时间。比如我需要完成一套发布流程:

#发布到AppStore
lane :release do
  #增加build版本号,需要先配置build setting
  increment_build_number
  #pod资源更新
  cocoapods
  #打包
  gym
  #发布到AppStore
  deliver(force: true)
  #发布testflight测试
  testflight
end

2.2. Fastlane组件

  • 测试
    • scan => 自动运行测试工具,并且可以生成漂亮的HTML报告
  • 证书,配置文件
    • cert => 自动创建管理iOS代码签名证书
    • sigh => 一声叹息啊,这么多年和Provisioning Profile战斗过无数次。总是有这样那样的问题导致配置文件过期或者失效。sigh是用来创建、更新、下载、修复Provisioning Profile的工具。
    • pem => 自动生成、更新推送配置文件
    • match => 一个新的证书和配置文件管理工具。我会另写一篇文章专门介绍这个工具。他会所有需要用到的证书传到git私有库上,任何需要配置的机器直接用match同步回来就不用管证书问题了,小团队福音啊!
  • 截图
    • snapshot => 用Xcode7推出的UI test功能实现自动化截图
    • frameit => 可以把截的图片自动套上一层外边框
  • 编译
    • shenzhen => 当年大名鼎鼎的自动编译工具,现在已经被弃用
    • gym => Fastlane家族的自动化编译工具,和其他工具配合的非常默契
  • 发布
    • produce => 如果你的产品还没在iTunes Connect(iTC)或者Apple Developer Center(ADC)建立,produce可以自动帮你完成这些工作
    • deliver => 自动上传截图,APP的元数据,二进制(ipa)文件到iTunes Connect
  • TestFlight管理
    • pilot => 管理TestFlight的测试用户,上传二进制文件
    • boarding => 建立一个添加测试用户界面,发给测试者,可自行添加邮件地址,并同步到iTC
  • 辅助工具
    • spaceship => 为pilotboardingdeliver等工具提供和 iTC 和 ADC 的交互API。spaceship本来是个独立的项目,后来被Fastlane收编进来
    • WatchBuild => 是一个独立的iTC监控工具,开启WatchBuild可以监控iTC上的文件状态,弹出MacOS自带的Notification
  • Android
    • supply => 自动上传到Google Play工具(如果有时间,我想把国内提供API的Android Store都写个插件自动上传,这个问题从10年我刚开始工作就觉得是个痛点)
    • screengrab => Android的自动截图工具

3.安装

3.1 安装正确的Ruby版本,需要2.0及以上版本:

ruby -v

3.2 检查 Xcode CLT 是否安装:

xcode-select --install
##如果已经安装,出现command line tools are already installed, use "Software Update" to install updates.出现command line tools are already installed, use "Software Update" to install updates.

3.3 安装 fastlane:

sudo gem install fastlane

执行命令时,输入用户密码

3.4 检查版本 fastlane:

fastlane --version

3.5 初始化配置-----进入工程开干(first)

$ cd 项目目录
$ fastlane init

Peter-2:~ Peter$ cd desktop
Peter-2:desktop Peter$ cd Popo/
Peter-2:Popo Peter$ fastlane init
[⠋] 🚀 /Users/peter/.rvm/rubies/ruby-2.4.1/lib/ruby/gems/2.4.0/gems/tty-screen-0.6.4/lib/tty/version.rb:3: warning: already initialized constant TTY::Screen::VERSION
/Users/peter/.rvm/gems/ruby-2.4.1@global/gems/tty-screen-0.6.4/lib/tty/version.rb:3: warning: previous definition of VERSION was here
[✔] 🚀 
[✔] Looking for iOS and Android projects in current directory...
[17:08:01]: Created new folder './fastlane'.
[17:08:01]: Detected an iOS/macOS project in the current directory: 'Popo.xcodeproj'
[17:08:01]: -----------------------------
[17:08:01]: --- Welcome to fastlane 🚀 ---
[17:08:01]: -----------------------------
[17:08:01]: fastlane can help you with all kinds of automation for your mobile app
[17:08:01]: We recommend automating one task first, and then gradually automating more over time
[17:08:01]: What would you like to use fastlane for?
1. 📸  Automate screenshots
2. 👩‍✈️  Automate beta distribution to TestFlight
3. 🚀  Automate App Store distribution
4. 🛠  Manual setup - manually setup your project to automate your tasks
?  

写在当前:

1、代表app市场图片素材;
2、发布到TestFlight进行测试;
3、发布到App Store;
4、自定义

在初始化```fastlane```的过程中,可能会出现要输入苹果开发者账号,
在 "Your Apple ID" 这一步输入苹果开发者账号。
在“Please confirm the above values”这一步,确认信息,没问题输入 y。
然后,```fastlane ```会进行一系列的初始化操作,包括下载 App Store 上的元数据和截屏文件。

在这里,我们选择序号 4 ,来手动去设置自定义的打包内容,在这一步完成后,工程目录下就多了一个 fastlane目录,其内容如下:

image.png
  • 期间会让你输入 Apple ID 账号密码(这个信息会存在钥匙串中,后续使用无需再输入密码)
  • 会检测当前的 app identifier 是否在 ADC 中
  • 会检测当前 app 是否在 ITC 中
  • 如果已经在 ADC 和 ITC 中创建相应的信息,那么过程会很顺利

接下来会问你这个app是否需要在iTC和ADC中创建(上一步中如果选择y会自动检测是否需要创建),fastlane会调用produce进行初始化,如果现在还不想创建,也可以之后再运行fastlane produce init进行这个流程。如果不执行produce的流程,deliver的流程也会被掠过,当然之后也可以fastlane deliver init运行完全一样的流程。

3.6 Fastlane 初始化完成后,工程目录下会自动生成 fastlane 文件夹,如下所示:

fastlane
├── Appfile
├── Deliverfile
├── Fastfile
├── metadata
│   ├── copyright.txt
│   ├── en-US
│   │   ├── description.txt
│   │   ├── keywords.txt
│   │   ├── marketing_url.txt
│   │   ├── name.txt
│   │   ├── privacy_url.txt
│   │   ├── release_notes.txt
│   │   └── support_url.txt
│   ├── primary_category.txt
│   ├── primary_first_sub_category.txt
│   ├── primary_second_sub_category.txt
│   ├── secondary_category.txt
│   ├── secondary_first_sub_category.txt
│   ├── secondary_second_sub_category.txt
│   └── zh-Hans
│       ├── description.txt
│       ├── keywords.txt
│       ├── marketing_url.txt
│       ├── name.txt
│       ├── privacy_url.txt
│       ├── release_notes.txt
│       └── support_url.txt
└── screenshots
    ├── README.txt
    ├── en-US
    │   ├── 一堆png图片

其他:

  1. 这里肯定会被创建的是AppfileFastfile。如果Deliverfilescreenshotsmetadata目录没被创建,可以运行deliver init重新初始化,在执行deliver init的过程中,会同步iTC中的所有语言的元数据和截图。

  2. fastlane的配置会要求输入开发者账号密码,所有的密码都加密保存在系统的Keychain里

  3. Matchfile: match 这个action的配置文件,fastlane match init 自动生成,存放git地址等

推荐使用Sublime Text工具打开

cd fastlane
open -a /Applications/Sublime\ Text.app/ Appfile Deliverfile Fastfile

操作步骤:在Sublime Text 工作窗口,点击右下角Plain Text区域,出现的下拉菜单中选择Ruby,或者在sublime的菜单中,找到View——>Syntax中选择ruby,即可高亮代码。

4. fastlane 文件配置

fastlane 的各文件解释如下:

  • Appfile:用于指定 app_identifier, apple_id, team_id
  • Fastfile:配置管理 lane
  • Deliverfile:配置应用在 ITC 中的各种信息,和 ICC 中的数据是一一对应的
  • metadata:包含应用在 ITC 中的各种信息
  • screenshots:包含截图数据
4.1 配置 Fastfile
default_platform(:ios)

platform :ios do
  desc "上传到 App Store"
  lane :release do
    build_app(workspace: ENV['SCHEME_workspace'], scheme: ENV['SCHEME_NAME'])
    upload_to_app_store(
          skip_screenshots:true,# 不上传屏幕截图
          skip_metadata:true,# 不上传元数据
      )
  end


desc "打包到fir"
  lane :to_firim do
      # 如果你用 pod install
      cocoapods
      # 如果你没有申请adhoc证书,sigh会自动帮你申请,并且添加到Xcode里
      sigh(adhoc: true)
      # 以下两个action来自fastlane-plugin-versioning,
      # 第一个递增 Build,第二个设定Version。
      # 如果你有多个target,就必须指定target的值,否则它会直接找找到的第一个plist修改
      # 在这里我建议每一个打的包的Build都要不一样,这样crash了拿到日志,可以对应到ipa上
      increment_build_number_in_plist(target:ENV['SCHEME_NAME'])
      increment_version_number_in_plist(
        target:ENV['SCHEME_NAME'],
        version_number: ENV['APP_VERSION_RELEASE']
        )
      # gym用来编译ipa
      gym(
        output_directory: './firim',
        export_options: {
          method: "ad-hoc",#打包类型app-store, ad-hoc, enterprise(企业账号打包), development
          thinning: "<none>"
        },
        scheme: ENV['SCHEME_NAME']
        )
      # 上传ipa到fir.im服务器,在fir.im获取firim_api_token
      firim(firim_api_token:ENV['Firim_Api_Token'])
    end


end

如果想创建 ad hoc 配置文件,需要指定sigh(adhoc: true).更多的信息参见:

4.2 配置 metadata 文件夹---如果不想配置可跳过到 5. 插件

需要注意的是,metadata 和 Deliverfile,都可以配置 ITC 的数据,但后者优先级高
下文先在 metadata 文件夹中进行配置用于演示,在文末会删除 metadata 中的配置文本,全部配置在 Deliverfile 中.

  1. 在 metadata 文件夹中创建分级文件:itunes_rating_config.json,这个和 ICC 中的分级是对应的.
{"CARTOON_FANTASY_VIOLENCE": 0,
"REALISTIC_VIOLENCE": 0, 
"PROLONGED_GRAPHIC_SADISTIC_REALISTIC_VIOLENCE": 0,
"PROFANITY_CRUDE_HUMOR": 0,
"MATURE_SUGGESTIVE": 0, 
"HORROR": 2,
"MEDICAL_TREATMENT_INFO": 0,
"ALCOHOL_TOBACCO_DRUGS": 0, 
"GAMBLING": 0, 
"SEXUAL_CONTENT_NUDITY": 0,
"GRAPHIC_SEXUAL_CONTENT_NUDITY": 0, 
"UNRESTRICTED_WEB_ACCESS": 0,
"GAMBLING_CONTESTS": 0
}

此处配置参见官方文档

  1. 将 App 图标添加至文件夹中
4.3 Snapshot 截图和 XCTest

命令行输入:

fastlane snapshot init

生成名为Snapfile的文件,修改内容为:

# A list of devices you want to take the screenshots from
devices([
  "iPhone 5",
  "iPhone 6",
  "iPhone 6 Plus"
])
# A list of supported languages
languages([
  'en-US',
  'fr-FR'
])
# Where should the resulting screenshots be stored?
output_directory "./fastlane/screenshots"
# Clears previous screenshots
clear_previous_screenshots true
# Latest version of iOS
ios_version '10.1'

然后打开 Xcode 工程,添加截图设置(需要增加 UITest, 因为截图是在 UITest 时截取的):

\\ 1)在项目添加UI测试,已经添加略过
\\ 2)将./fastlane/SnapshotHelper.swift 添加到UI测试中
\\ 3)打开 XXXUITests.swift ,删除setUp和tearDown方法,然后在其中添加以下代码testExample:

  let app = XCUIApplication()
  setupSnapshot(app)
  app.launch()

  app.buttons["next"].tap()
  snapshot("01firstPage") // 此处截图

  app.buttons["back"].tap()
  snapshot("02secondPage") // 此处截图

4.3 配置 Deliverfile

其实上传 ITC 最主要的文件是 Deliverfile,配置好 Deliverfile 后,可以删除 metadata 文件夹中的文本配置.最终配置如下图:

15698.png

以下是主要的配置,更多更详细的请戳文件,里面有详细的注释,拿来即可使用

# 1 app_identifier
app_identifier "com.3code.ADDemo"

# 2 用户名,Apple ID电子邮件地址
username "Apple ID电子邮件地址"  

# 3 支持语言
supportedLanguages = {
  "cmn-Hans" => "zh-Hans"
}

# 4 app 名称
name({
'zh-Hans' => "ADDemo"
})

# 5 描述
description({
  'zh-Hans' => "简体中文版"
})

# 6 提交审核信息
submission_information({    
    export_compliance_encryption_updated: false,
    export_compliance_uses_encryption: false,
    content_rights_contains_third_party_content: false,
    add_id_info_uses_idfa: false
})

# 7 应用审核小组的联系信息 app 审核信息
app_review_information(
  first_name: "name",
  last_name: "name",
  phone_number: "手机号",
  email_address: "email",
  demo_user: "测试账号用户名",
  demo_password: "测试账号密码",
  notes: "noting"
)

# 8 copyright 
copyright "#{Time.now.year} 3code"

# 

5. 插件

Fastlane的插件是一个或者一组action的打包,单独发布在fastlane之外。Fastlane Plugin 指南

#查看所有插件
fastlane search_plugins
# 安装方法
fastlane add_plugin [name] 

#常用插件
#版本号
fastlane add_plugin versioning
#fir
fastlane add_plugin firim
#蒲公英
fastlane add_plugin pgyer

  • 使用 Fastlane 上传 App 到蒲公英(https://www.pgyer.com/doc/view/fastlane)

  • fastlane-plugin-versioning: 用来修改build版本号和version版本号。Fastlane内嵌的actionincrement_build_number使用的是苹果提供的agvtoolagvtool在更改Build的时候会改变所有target的版本号。这时如果你在一个工程里有多个产品的话,每次编译,所有的Build都要加1,最后就不知道高到哪里去了。
    有了fastlane-plugin-versioning不仅可以指定target增加Build,当然也可以直接设定Version。

6. 环境变量Environment Variables

有时候我们希望把账号信息、更新描述和版本号等信息单独放在一个配置文件。在这里Fastlane给我们提供了相应的解决方案。

我们可以在工程目录下创建一个名为 .env 的文件,自定义所需的临时变量,然后Fastlane的三个配置文件(AppfileDeliverfileFastfile)分别从.env文件中读取配置信息。

关于ENV用法可参考以下链接:
https://docs.fastlane.tools/advanced/#environment-variables
https://github.com/bkeepers/dotenv

.env 文件为影藏文件,可使用如下命令查看:
Finder 默认不显示隐藏文件,创建 .env 文件后,若需查看,需要执行两条命令来开启隐藏文件的显示:

$ defaults write com.apple.finder AppleShowAllFiles -boolean true;
$ killall Finder

ls -a

下面给出的 .env 文件配置可做参考:

#APP唯一标识符
APP_IDENTIFIER = "xxx.xxx.TestGitProject"

#发布版本号
APP_VERSION_RELEASE = "1.1.0"

#新版本修改记录
RELEASE_NOTES = "1) 升级测试第一行\n2) 升级测试第二行"

#蒲公英 更新描述
PGY_UPDATE_DESCRIPTION = "fastlane自动打包上传测试"

#自动提交审核
SUBMIT_FOR_REVIEW = false

#审核通过后立刻发布
AUTOMATIC_RELEASE = false

#苹果开发者账号
APPLE_ID = "xxx@xxx.xxx"

#苹果开发者帐号密码
FASTLANE_PASSWORD = "xxxxxx"

#套装ID
TEAM_ID = "94xxxxx02"

#应用名称
SCHEME_NAME = "TestGitProject"

#APP元数据及截图存放路径
METADATA_PATH = "./metadata/TestGitProject"
SCREENSHOTS_PATH = "./screenshots/TestGitProject"

#APP元数据及截图下载时,直接覆盖原有数据,不询问
DELIVER_FORCE_OVERWRITE = true

AppfileDeliverfileFastfile配置文件修改如下:
Appfile

app_identifier ENV['APP_IDENTIFIER'] # The bundle identifier of your app

apple_id ENV['APPLE_ID'] # Your Apple email address

team_id ENV['TEAM_ID'] # Developer Portal Team ID

Deliverfile :

app_identifier ENV['APP_IDENTIFIER'] # The bundle identifier of your app

username ENV['APPLE_ID'] # your Apple ID user

Fastfile :
上传到 App Store

desc "上传到 App Store"
  lane :release do
    build_app(workspace: ENV['SCHEME_workspace'], scheme: ENV['SCHEME_NAME'])
    upload_to_app_store(
          skip_screenshots:true,# 不上传屏幕截图
          skip_metadata:true,# 不上传元数据
      )
  end

skip_screenshots:true,# 不上传屏幕截图,要上传就传false
skip_metadata:true,# 不上传元数据,要上传就传false

打包到fir

desc "打包到fir"
  lane :to_firim do
      # 如果你用 pod install
      cocoapods
      # 如果你没有申请adhoc证书,sigh会自动帮你申请,并且添加到Xcode里
      sigh(adhoc: true)
      # 以下两个action来自fastlane-plugin-versioning,
      # 第一个递增 Build,第二个设定Version。
      # 如果你有多个target,就必须指定target的值,否则它会直接找找到的第一个plist修改
      # 在这里我建议每一个打的包的Build都要不一样,这样crash了拿到日志,可以对应到ipa上
      increment_build_number_in_plist(target:ENV['SCHEME_NAME'])
      increment_version_number_in_plist(
        target:ENV['SCHEME_NAME'],
        version_number: ENV['APP_VERSION_RELEASE']
        )
      # gym用来编译ipa
      gym(
        output_directory: './firim',
        export_options: {
          method: "ad-hoc", # 这可以不指定
          thinning: "<none>"
        },
        scheme: ENV['SCHEME_NAME']
        )
      # 上传ipa到fir.im服务器,在fir.im获取firim_api_token
      firim(firim_api_token:ENV['Firim_Api_Token'])
    end
  desc "发布 测试版本 到 蒲公英"
  lane :beta_pgy do    
    gym(scheme: ENV['SCHEME_NAME'], 
      export_method: "ad-hoc",
      silent: true,  # 隐藏没有必要的信息
      clean: true  # 在构建前先clean
      )

    pgyer(api_key: ENV['PGY_API_KEY'], 
      user_key: ENV['PGY_USER_KEY'], 
      update_description: ENV['PGY_UPDATE_DESCRIPTION'], 
      password: "123456", 
      install_type: "2")
  end

上传到App store,在终端cd到目录,执行如下就可以了

$ fastlane release

完成后,上传到fir,在终端cd到目录,执行如下就可以了

$ fastlane to_firim

如果提示


image.png

说明工程使用了cocoapod,需要在Gemfile中添加gem 'cocoapods'

source "https://rubygems.org"

gem "fastlane"
gem 'cocoapods'

plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)

image.png

上传到蒲公英,在终端cd到目录,执行如下就可以了

$ fastlane beta_pgy

参考链接:

  1. Hailong's Blog- Fastlane带来的全自动化发布
  2. AD_Fastlane
  3. iOS持续集成Fastlane + 蒲公英自动打包发布
  4. Fastlane 实现多 Target 自动化打包发布
  5. iOS Fastlane 自动打包发布技术
  6. fastlane使用说明书
  7. [Fastlane使用总结(一)]
    (https://www.jianshu.com/p/04b83b335d53)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,117评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,328评论 1 293
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,839评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,007评论 0 206
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,384评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,629评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,880评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,593评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,313评论 1 243
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,575评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,066评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,392评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,052评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,082评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,844评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,662评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,575评论 2 270

推荐阅读更多精彩内容