iOS使用fastlane持续集成实现


声明:本文转载自https://my.oschina.net/FEEDFACF/blog/1608824,转载目的在于传递更多信息,仅供学习交流之用。如有侵权行为,请联系我,我会及时删除。

iOS使用fastlane持续集成实现

前言

最近公司有打渠道包的需求,领导说使用fastlane来做持续集成,发了点时间研究了下,所有有了这篇文章

本文主要涉及到以下几个主题:

  • fastlane是什么和为什么使用fastlane
  • fastlane安装和设置
  • fastlane项目集成

是什么和为什么

fastlane是一款使用ruby实现的跨平台的持续集成工具,支持安卓和iOS平台项目的持续集成实践,fastlane处理提供基本的但是很强大的包含了:初始设置、屏幕截图、打包、上传到测试平台、部署等功能。此外还有大量的第三方插件可以使用,比如fir插件支持上传beta版本到fir测试平台,appicon插件支持自定义某个子版本的应用图标,还有很多不胜枚举。
因为项目的配置、打包、上传等一系列操作是耗时且没有技术含量的工作,所以有了fastlane可以为我们节省大量的没有什么价值的时间花费,以提高我们的工作效率。

fastlane安装和设置

安装

支持三种方式安装

  • 使用brew安装
brew cask install fastlane 
  • 使用gem安装
sudo gem install fastlane -NV 
  • 下载安装包安装

fastlane下载,下载完了之后打开install脚本即可安装

安装完成之后命令行输入fastlane -v,可以看到fastlane的版本信息说明安装成功了,接下来可以继续设置步骤

➜  PlushGame fastlane -v fastlane installation at path: /Users/aron/.rvm/gems/ruby-2.3.0@global/gems/fastlane-2.62.0/bin/fastlane ----------------------------- fastlane 2.62.0 

设置

进入到项目目录执行fastlane init命令,会有一系列的设置,包含了登录apple账号,确认fastlane检测到的项目信息确认,登录iTunesConnect和从iTunesConnect拉取项目已存在的信息

➜  PlushGame fastlane init [20:37:45]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile [20:37:48]: Detected iOS/Mac project in current directory... ... # 根据提示输入项目的Apple ID和对应的密码,会自动登录到苹果开发者后台,拉取开发者账号对应的信息完成设置 [20:37:52]: Your Apple ID (e.g. fastlane@krausefx.com): XXXXXX@126.com [20:37:55]: Verifying that app is available on the Apple Developer Portal and iTunes Connect... [20:37:55]: Starting login with user 'XXXXXX@126.com' ------------------------------------------------------------------------------------- Please provide your Apple Developer Program account credentials The login information you enter will be stored in your macOS Keychain You can also pass the password using the `FASTLANE_PASSWORD` environment variable More information about it on GitHub: https://github.com/fastlane/fastlane/tree/master/credentials_manager -------------------------------------------------------------------------------------  # 输入Apple ID 对应的密码 Password (for XXXXXX@126.com): **************  +----------------+------------------------------------------------------+ |                            Detected Values                            | +----------------+------------------------------------------------------+ | Apple ID       | XXXXXX@126.com                                 | | App Name       | PlushGame                                            | | App Identifier | com.xxxx.xxxx                                | | Workspace      | /Users/aron/PuTaoWorkSpace/project/PlushGame/PlushG  | |                | ame.xcworkspace                                      | +----------------+------------------------------------------------------+   # 检测到的项目信息要求确认,按y即可 [20:38:50]: Please confirm the above values (y/n) y [20:39:03]: Created new file './fastlane/Appfile'. Edit it to manage your preferred app metadata information. [20:39:03]: Loading up 'deliver', this might take a few seconds [20:39:03]: Login to iTunes Connect (XXXXXXX@126.com) [20:39:16]: Login successful  +--------------------------------------+------------------------+ |                    deliver 2.62.0 Summary                     | +--------------------------------------+------------------------+ | run_precheck_before_submit           | false                  | | screenshots_path                     | ./fastlane/screenshots | | metadata_path                        | ./fastlane/metadata    | | username                             | XXXXXX@126.com   | | app_identifier                       | com.xxxx.xxxxx  | | edit_live                            | false                  | | platform                             | ios                    | | skip_binary_upload                   | false                  | | skip_screenshots                     | false                  | | skip_metadata                        | false                  | | skip_app_version_update              | false                  | | force                                | false                  | | submit_for_review                    | false                  | | automatic_release                    | false                  | | dev_portal_team_id                   | JN55YSQ744             | | overwrite_screenshots                | false                  | | precheck_default_rule_level          | warn                   | | ignore_language_directory_validation | false                  | +--------------------------------------+------------------------+   # 从ituneconnect拉取已存在的元数据,这里只有截屏的信息 [20:39:34]: Downloading all existing screenshots... [20:39:37]: Downloading existing screenshot '1_iphone58_1.X1_1.jpg' for language 'zh-Hans' [20:39:42]: Downloading existing screenshot '2_iphone58_2.X2_1.jpg' for language 'zh-Hans' [20:40:22]: Downloading existing screenshot '3_iphone58_3.X3_1.jpg' for language 'zh-Hans' [20:40:49]: Downloading existing screenshot '4_iphone58_4.X5_1.jpg' for language 'zh-Hans' .... 

初始化设置之后再项目文件夹下多出了一个fastlane文件夹,主要有以下的一些的信息

➜  fastlane tree . ├── Appfile ├── Deliverfile ├── Fastfile ├── metadata │   ├── app_icon.jpg │   ├── copyright.txt │   └── zh-Hans │       ├── description.txt │       ├── keywords.txt │       ├── marketing_url.txt │       ├── name.txt │       ├── privacy_url.txt │       ├── promotional_text.txt │       ├── release_notes.txt │       ├── subtitle.txt │       └── support_url.txt └── screenshots     ├── README.txt     └── zh-Hans         ├── 1_iphone58_1.X1_1.jpg         ├── 1_iphone6Plus_1.1.png         ├── 2_iphone58_2.X2_1.jpg         ├── 2_iphone6Plus_2.2.png         ├── 3_iphone58_3.X3_1.jpg         ├── 3_iphone6Plus_3.3.png         ├── 4_iphone58_4.X5_1.jpg         ├── 4_iphone6Plus_4.4.png         └── 5_iphone6Plus_5.5.png  8 directories, 62 files 

最重要的是Appfile文件、Fastfile文件和Deliverfile文件

  • Appfile文件保存了项目信息,包含项目使用的apple账号信息、项目的team_id信息、项目identifier信息
app_identifier "com.xxxx.xxxx" # The bundle identifier of your app apple_id "XXXXXX@126.com" # Your Apple email address  team_id "XXXXXSQ744" # Developer Portal Team ID 
  • Fastfile文件保存了apple账号信息和teamid信息,该文件的信息用于上传appStore使用
app_identifier "com.sanshuai.FunCatch" # The bundle identifier of your app username "sanshuai2017@126.com" # your Apple ID user 
  • Fastfile文件定义了一些列的action,包含了项目打包设置、项目打包、项目截图、项目上传测试平台、项目发布、项目打包完成后期的一些操作

初始的Fastfile大致如下,可以看到 lane :release 包含了
snapshot action用于截屏
gym action用于打包
deliver action用于上传到App Store
frameit action用于给截屏添加边框
after_all 块中的slack action 则是负责打包成功之后发送信息到slack

fastlane_version "2.62.0"  default_platform :ios  platform :ios do    desc "Deploy a new version to the App Store"   lane :release do     # match(type: "appstore")     # snapshot     gym(scheme: "PlushGame") # Build your app - more options available     deliver(force: true)     # frameit   end    # You can define as many lanes as you want    after_all do |lane|     # This block is called, only if the executed lane was successful      # slack(     #   message: "Successfully deployed new App Update."     # )   end end 

接下来是为我们自己的项目编写符合业务需求的Fastfile了

fastlane项目集成

fastlane 详细介绍

该部分会详细的介绍fastlane中的块操作和lane的用途,以及fastlane中预定义的常用的action

fastlane 中的块和lane

fastlane 包含了预定义块有:
before_all 块用于项目打包之前的操作,比如可以使用cocopods命令更新pod库(如果使用的是pod项目)
after_all 块用于项目打包完成之后的操作,比如通知用户打包完成
error 块用于项目打包失败之后的操作,比如通知用户打包失败
lane 定义一个打包操作的具体流程,预设的有 lane :release定义了打包并且发布到App Store,lane :beta 打包并且发布到testflight测试平台。

fastlane 常用的action以及参数

fastlane中最主要的操作就是调用action,fastlane预定义了很多很有用的action,如果不够还可以使用第三发提供的插件调用第三发的action。下面介绍几个fastlane中预定的action
gym 是打包action,是 build_ios_app action的别名,他有以下常用的参数:

key描述
workspace如果项目是一个workspace,则是该项目的workspace路径
project项目的project路径
scheme项目的scheme,注意指定的scheme需要被指定为shared,/->Manage Schemes->Shared复选框需要打钩
output_directory打包保存路径
output_name打包保存的文件名
export_method相当于配置 Archives->Export->mehtod 可选:[app-store, ad-hoc, package, enterprise, development(默认), developer-id]
configuration相当于配置Scheme->Build Configuration:[Release, Debug],Release会生成dsym文件,而Debug不会

set_info_plist_value是设置修改info.plist文件的 action,一次调用该action只能设置一个值,可以多次调用该命令来设置多个值,他有以下常用的参数:

key描述
pathinfo.plist文件路径
keyinfo.plist文件中的key
valuekey对应的值

pilot 是上传到TestFlight的 action,是 upload_to_testflight action的别名,没有特殊需求可以不指定参数

deliver 是上传到App Store的 action,是 upload_to_app_store action的别名,没有特殊需求可以不指定参数,会从Deliverfile文件读取账号信息登录到ITunesConnect从./fastlane/metadata ./fastlane/screenshots 文件夹中读取配置的App信息元数据然后上传

fastlane其他操作

fastlane是一个ruby的脚本,可以在里面执行自定义的脚本文件,比如添加 sh "your_script.sh" 语句可以执行自定义的脚本命令,也可以添加 'pwd' (这里使用的是反引号)执行一个shell命令或者添加 exec("pwd") 执行一个shell命令

Fastfile文件基本的编写

下面以一个真实的业务场景为例,该业务场景要求多渠道打包,并且不同渠道对应的配置有差异(info.plist文件配置不同和图标不同),打包支持上传到fir测试平台,不同渠道打包的命名方式是【时间+渠道+名称.ipa】格式,最后还需要把对应的dsym文件和ipa文件压缩归档为一个zip包文件。

# Customise this file, documentation can be found here: # https://docs.fastlane.tools/actions/ # All available actions: https://docs.fastlane.tools/actions # can also be listed using the `fastlane actions` command  # Change the syntax highlighting to Ruby # All lines starting with a # are ignored when running `fastlane`  # If you want to automatically update fastlane if a new version is available: # update_fastlane  # This is the minimum version number required. # Update this, if you use features of a newer version fastlane_version "2.62.0"  default_platform :ios  platform :ios do   before_all do     # ENV["SLACK_URL"] = "https://hooks.slack.com/services/..."     # cocoapods     # carthage   end    desc "Runs all the tests"   lane :test do     scan   end    # 定义全局参数:项目名称   projName = "Plush"   # 定义全局参数:Assets路径   projAssetsPath = "../#{projName}/Resources/Assets.xcassets"   # 定义全局参数:Info.plist路径   plistPath = "./#{projName}/Resources/Info.plist"   # 定义全局参数:包名(接收之后压缩使用)   pkgName = ""   # 定义全局参数:基本包名   basePkgName = "Plush"   # 定义全局参数:输出目录,对应output_directory配置   outputBaseDir = "output"      desc "自定义的渠道打包"   desc "使用方式:苹果助手:`bundle exec fastlane customChannelBeta ch:pgzs shouldUp:0`"   desc "使用方式:91助手:`bundle exec fastlane customChannelBeta ch:91zs shouldUp:0`"   desc "op 支持参数: ch:渠道类型[pgzs, 91zs, AppStore(默认)]"   desc "op 支持参数: shouldUp:是否需要上传[0, 1]"   desc "op 支持参数: up:上传类型[testflight, fir]"   desc "op 支持参数: exportMethod: export_method 配置[app-store, ad-hoc, package, enterprise, development(默认), developer-id] ** up为testflight需要制定为app-store **"   desc "op 支持参数: version:版本(可选)"   desc "op 支持参数: build:构建版本(可选,testflight和appstore这个参数需要制定一个不重复的)"   lane :customChannelBeta do |op|          # 渠道     channel = op[:ch]     if channel.nil? || channel.empty?       channel = "AppStore"     end      # 打包名字     time = Time.new     dateTimeStr = "#{time.year}-#{time.month}-#{time.day}_#{time.hour}-#{time.min}"     pkgName = "#{dateTimeStr}_#{channel}_#{basePkgName}.ipa"      # match(type: "appstore") # more information: https://codesigning.guide     #设置plist,此处传入plist路径,可以用来做环境配置     set_info_plist_value(path: plistPath, key: "pt_channel", value: channel)       # # 设置AppIcon     # iconPath = op[:iconPath]     # if iconPath.nil? || iconPath.empty?     #   iconPath = "channel_config/#{channel}/icon1024.png"     #   iconPath = "channel_config/91zs/icon1024.png"     # end     # puts "iconPath = #{iconPath}"     # appicon(appicon_image_file: iconPath,     # appicon_devices: [:ipad, :iphone, :ios_marketing, :watch, :watch_marketing])      # 拷贝AppIcon.appiconset替换图标     iconAssetPath = op[:iconPath]     if iconAssetPath.nil? || iconAssetPath.empty?       iconAssetPath = "../channel_config/#{channel}/AppIcon.appiconset"     end     cpCmd = "cp -fRv #{iconAssetPath} #{projAssetsPath}"     `#{cpCmd}`     puts "cpCmd = #{cpCmd}"      # 设置显示版本和构建版本     version = op[:version]     build = op[:build]     if version.nil? || version.empty?     else       increment_version_number(version_number: version)     end     if build.nil? || build.empty?     else       increment_build_number(build_number: build)     end      exportMethod = op[:exportMethod]     if exportMethod.nil? || exportMethod.empty?       exportMethod = "development"     end      puts "exportMethod = #{exportMethod}  pkgName = #{pkgName}  outputBaseDir = #{outputBaseDir}"      # build_ios_app 参数配置     gym(       export_method: exportMethod, # 相当于配置 Archives->Export->mehtod:[app-store, ad-hoc, package, enterprise, development(默认), developer-id]       output_name: pkgName,       configuration: "Release", # 相当于配置Scheme->Build Configuration:[Release, Debug],Release会生成dsym文件,而Debug不会       output_directory: outputBaseDir,       scheme: "Plush",     )       # 是否需要上传配置,默认不上传     shouldUp = op[:shouldUp]     if shouldUp == "1"       # 上传测试包到测试平台类型,默认上传到fir,可以支持多种测试平台使用逗号分隔       # testflight, fir       upType = op[:up]       if upType.nil? || upType.empty?         upType = "fir"       end       if upType.include? "testflight"         pilot # 上传到testflight       elsif upType.include? "fir"         firim(firim_api_token: "xxxxxxxx")#上传fir,如果是新项目,fir会自动创建       end     end   end    desc "上传到 App Store"   lane :release do     # match(type: "appstore")     # snapshot     gym(       export_method: "app-store", # 相当于配置 Archives->Export->mehtod:[app-store, ad-hoc, package, enterprise, development, developer-id]       output_name: pkgName,       configuration: "Release", # 相当于配置Scheme->Build Configuration:[Release, Debug],Release会生成dsym文件,而Debug不会       output_directory: outputBaseDir,       scheme: "Plush",     )     deliver(force: true)     # frameit   end    # You can define as many lanes as you want    after_all do |lane, op|     # This block is called, only if the executed lane was successful      # slack(     #   message: "Successfully deployed new App Update."     # )      if !pkgName.empty?       fileName = pkgName.gsub(".ipa", "")       dsymName = "#{fileName}.app.dSYM.zip"       zipFileName = "#{fileName}.zip"        # 使用zip命令压缩       zipCmd = "zip ../#{outputBaseDir}/#{zipFileName} ../#{outputBaseDir}/#{dsymName} ../#{outputBaseDir}/#{pkgName}"       puts "begin zip #{zipCmd}"       `#{zipCmd}`     end    end    error do |lane, exception|     # slack(     #   message: exception.message,     #   success: false     # )   end end 

使用方式:

#打91助手渠道的包不上传 bundle exec fastlane customChannelBeta ch:91zs shouldUp:0  # 91助手渠道打包并且上传到fir bundle exec fastlane customChannelBeta ch:91zs shouldUp:1 up:fir  # testflight 打包上传 bundle exec fastlane customChannelBeta shouldUp:1 up:testflight exportMethod:app-store  # AppStore 打包上传 bundle exec fastlane release 

执行打包的命令会在项目目录下生成一个output目录,内容如下

➜  output tree . ├── 2018-1-17_11-53_pgzs_Plush.app.dSYM.zip ├── 2018-1-17_11-53_pgzs_Plush.ipa └── 2018-1-17_11-53_pgzs_Plush.zip 

添加第三方插件

fastlane有很多的第三方扩展插件,下面以添加firim插件为例

使用fastlane search_plugins查找插件

➜  output fastlane search_plugins fir ... +----------+-------------------------------------+-----------+ |                   fastlane plugins 'fir'                   | +----------+-------------------------------------+-----------+ | Name     | Description                         | Downloads | +----------+-------------------------------------+-----------+ | firebase | Unofficial tool to access Firebase  | 1393      | |          | project settings                    |           | | firim    | firim                               | 1142      | | fir      | Upload a new build to fir.im        | 807       | +----------+-------------------------------------+-----------+ 

使用fastlane add_plugin安装插件

fastlane add_plugin firim 

使用fastlane action查找某个action的使用方法和参数,下面是查找firim action的使用方法和参数的例子

➜  Plush.app fastlane action firim [23:50:31]: fastlane detected a Gemfile in the current directory [23:50:31]: however it seems like you don't use `bundle exec` [23:50:31]: to launch fastlane faster, please use [23:50:31]:  [23:50:31]: $ bundle exec fastlane action firim [23:50:31]:  [23:50:31]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile +-------------------------+---------+-------------------------+ |                        Used plugins                         | +-------------------------+---------+-------------------------+ | Plugin                  | Version | Action                  | +-------------------------+---------+-------------------------+ | fastlane-plugin-firim   | 0.1.0   | firim                   | | fastlane-plugin-appicon | 0.11.0  | android_appicon appicon | +-------------------------+---------+-------------------------+  Loading documentation for firim:  +------------------------------------+ |               firim                | +------------------------------------+ | Uses firim to upload ipa to fir.im | |                                    | | Created by whlsxl                  | +------------------------------------+  +------------------------+--------------------------+------------------+---------+ |                                 firim Options                                  | +------------------------+--------------------------+------------------+---------+ | Key                    | Description              | Env Var          | Default | +------------------------+--------------------------+------------------+---------+ | firim_api_token        | fir.im user api token    |                  |         | | firim_username         | fir.im username, a sign  |                  |         | |                        | for identify different   |                  |         | |                        | token                    |                  |         | | ipa                    | Path to your ipa file    | DELIVER_IPA_PATH |         | | icon                   | Path to the app icon,    |                  |         | |                        | MUST BE jpg              |                  |         | | app_identifier         | The app's identifier     |                  |         | | app_name               | The app's name           |                  |         | | app_desc               | The app's desc           |                  |         | | app_short              | The app's short URL      |                  |         | | app_is_opened          | APP's download link      |                  |         | |                        | whether opened           |                  |         | | app_is_show_plaza      | Whether the app show in  |                  |         | |                        | plaza                    |                  |         | | app_passwd             | The app's download page  |                  |         | |                        | password                 |                  |         | | app_store_link_visible | Whether show store link  |                  |         | |                        | in download page         |                  |         | | app_version            | The app's version        |                  |         | | app_build_version      | The app's build version  |                  |         | | app_release_type       | The app's release type   |                  |         | |                        | (Adhoc, Inhouse)         |                  |         | | app_changelog          | The app's changelog      |                  |         | | app_info_to_file_path  | Append all [app's name]  |                  |         | |                        | : [URL] to this file     |                  |         | +------------------------+--------------------------+------------------+---------+  More information can be found on https://docs.fastlane.tools/actions 

在Fastfile中添加firim action,把包上传到fir,token可以到fir后台点击右上角的设置获取即可

firim(firim_api_token: "xxxxxx")#上传fir,如果是新项目,fir会自动创建 

结束

以上就是fastlane在项目中的实战演练,需要能够帮助到需要得人

本文发表于2018年01月18日 08:32
(c)注:本文转载自https://my.oschina.net/FEEDFACF/blog/1608824,转载目的在于传递更多信息,并不代表本网赞同其观点和对其真实性负责。如有侵权行为,请联系我们,我们会及时删除.

阅读 2212 讨论 0 喜欢 0

抢先体验

扫码体验
趣味小程序
文字表情生成器

闪念胶囊

你要过得好哇,这样我才能恨你啊,你要是过得不好,我都不知道该恨你还是拥抱你啊。

直抵黄龙府,与诸君痛饮尔。

那时陪伴我的人啊,你们如今在何方。

不出意外的话,我们再也不会见了,祝你前程似锦。

这世界真好,吃野东西也要留出这条命来看看

快捷链接
网站地图
提交友链
Copyright © 2016 - 2021 Cion.
All Rights Reserved.
京ICP备2021004668号-1