iOS使用fastlane實現(xiàn)持續(xù)集成的方法教程
前言
最近公司有打渠道包的需求,領(lǐng)導(dǎo)說使用fastlane來做持續(xù)集成,發(fā)了點時間研究了下,所有有了這篇文章
本文主要涉及到以下幾個主題:
- fastlane是什么和為什么使用fastlane
- fastlane安裝和設(shè)置
- 在項目中集成fastlane
是什么和為什么
fastlane是一款使用ruby實現(xiàn)的跨平臺的持續(xù)集成工具,支持安卓和iOS平臺項目的持續(xù)集成實踐,fastlane處理提供基本的但是很強大的包含了:初始設(shè)置、屏幕截圖、打包、上傳到測試平臺、部署等功能。此外還有大量的第三方插件可以使用,比如fir插件支持上傳beta版本到fir測試平臺,appicon插件支持自定義某個子版本的應(yīng)用圖標,還有很多不勝枚舉。
因為項目的配置、打包、上傳等一系列操作是耗時且沒有技術(shù)含量的工作,所以有了fastlane可以為我們節(jié)省大量的沒有什么價值的時間花費,以提高我們的工作效率。
fastlane安裝和設(shè)置
安裝
支持三種方式安裝
使用brew安裝
brew cask install fastlane
使用gem安裝
sudo gem install fastlane -NV
下載安裝包安裝
fastlane下載,下載完了之后打開install腳本即可安裝
安裝完成之后命令行輸入fastlane -v,可以看到fastlane的版本信息說明安裝成功了,接下來可以繼續(xù)設(shè)置步驟
➜ 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
設(shè)置
進入到項目目錄執(zhí)行fastlane init命令,會有一系列的設(shè)置,包含了登錄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... ... # 根據(jù)提示輸入項目的Apple ID和對應(yīng)的密碼,會自動登錄到蘋果開發(fā)者后臺,拉取開發(fā)者賬號對應(yīng)的信息完成設(shè)置 [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 對應(yīng)的密碼 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拉取已存在的元數(shù)據(jù),這里只有截屏的信息 [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' ....
初始化設(shè)置之后再項目文件夾下多出了一個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,包含了項目打包設(shè)置、項目打包、項目截圖、項目上傳測試平臺、項目發(fā)布、項目打包完成后期的一些操作
初始的Fastfile大致如下,可以看到 lane :release 包含了
snapshot action用于截屏
gym action用于打包
deliver action用于上傳到App Store
frameit action用于給截屏添加邊框
after_all 塊中的slack action 則是負責(zé)打包成功之后發(fā)送信息到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
接下來是為我們自己的項目編寫符合業(yè)務(wù)需求的Fastfile了
fastlane項目集成
fastlane 詳細介紹
該部分會詳細的介紹fastlane中的塊操作和lane的用途,以及fastlane中預(yù)定義的常用的action
fastlane 中的塊和lane
fastlane 包含了預(yù)定義塊有:
before_all 塊用于項目打包之前的操作,比如可以使用cocopods命令更新pod庫(如果使用的是pod項目)
after_all 塊用于項目打包完成之后的操作,比如通知用戶打包完成
error 塊用于項目打包失敗之后的操作,比如通知用戶打包失敗
lane 定義一個打包操作的具體流程,預(yù)設(shè)的有 lane :release定義了打包并且發(fā)布到App Store,lane :beta 打包并且發(fā)布到testflight測試平臺。
fastlane 常用的action以及參數(shù)
fastlane中最主要的操作就是調(diào)用action,fastlane預(yù)定義了很多很有用的action,如果不夠還可以使用第三發(fā)提供的插件調(diào)用第三發(fā)的action。下面介紹幾個fastlane中預(yù)定的action
gym 是打包action,是 build_ios_app action的別名,他有以下常用的參數(shù):
| key | 描述 |
|---|---|
| workspace | 如果項目是一個workspace,則是該項目的workspace路徑 |
| project | 項目的project路徑 |
| scheme | 項目的scheme,注意指定的scheme需要被指定為shared,/->Manage Schemes->Shared復(fù)選框需要打鉤 |
| output_directory | 打包保存路徑 |
| output_name | 打包保存的文件名 |
| export_method | 相當(dāng)于配置 Archives->Export->mehtod 可選:[app-store, ad-hoc, package, enterprise, development(默認), developer-id] |
| configuration | 相當(dāng)于配置Scheme->Build Configuration:[Release, Debug],Release會生成dsym文件,而Debug不會 |
set_info_plist_value是設(shè)置修改info.plist文件的 action,一次調(diào)用該action只能設(shè)置一個值,可以多次調(diào)用該命令來設(shè)置多個值,他有以下常用的參數(shù):
| key | 描述 |
|---|---|
| path | info.plist文件路徑 |
| key | info.plist文件中的key |
| value | key對應(yīng)的值 |
pilot 是上傳到TestFlight的 action,是 upload_to_testflight action的別名,沒有特殊需求可以不指定參數(shù)
deliver 是上傳到App Store的 action,是 upload_to_app_store action的別名,沒有特殊需求可以不指定參數(shù),會從Deliverfile文件讀取賬號信息登錄到ITunesConnect從./fastlane/metadata ./fastlane/screenshots 文件夾中讀取配置的App信息元數(shù)據(jù)然后上傳
fastlane其他操作
fastlane是一個ruby的腳本,可以在里面執(zhí)行自定義的腳本文件,比如添加 sh "your_script.sh" 語句可以執(zhí)行自定義的腳本命令,也可以添加 'pwd' (這里使用的是反引號)執(zhí)行一個shell命令或者添加 exec("pwd") 執(zhí)行一個shell命令
Fastfile文件基本的編寫
下面以一個真實的業(yè)務(wù)場景為例,該業(yè)務(wù)場景要求多渠道打包,并且不同渠道對應(yīng)的配置有差異(info.plist文件配置不同和圖標不同),打包支持上傳到fir測試平臺,不同渠道打包的命名方式是【時間+渠道+名稱.ipa】格式,最后還需要把對應(yīng)的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
# 定義全局參數(shù):項目名稱
projName = "Plush"
# 定義全局參數(shù):Assets路徑
projAssetsPath = "../#{projName}/Resources/Assets.xcassets"
# 定義全局參數(shù):Info.plist路徑
plistPath = "./#{projName}/Resources/Info.plist"
# 定義全局參數(shù):包名(接收之后壓縮使用)
pkgName = ""
# 定義全局參數(shù):基本包名
basePkgName = "Plush"
# 定義全局參數(shù):輸出目錄,對應(yīng)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 支持參數(shù): ch:渠道類型[pgzs, 91zs, AppStore(默認)]"
desc "op 支持參數(shù): shouldUp:是否需要上傳[0, 1]"
desc "op 支持參數(shù): up:上傳類型[testflight, fir]"
desc "op 支持參數(shù): exportMethod: export_method 配置[app-store, ad-hoc, package, enterprise, development(默認), developer-id] ** up為testflight需要制定為app-store **"
desc "op 支持參數(shù): version:版本(可選)"
desc "op 支持參數(shù): build:構(gòu)建版本(可選,testflight和appstore這個參數(shù)需要制定一個不重復(fù)的)"
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
#設(shè)置plist,此處傳入plist路徑,可以用來做環(huán)境配置
set_info_plist_value(path: plistPath, key: "pt_channel", value: channel)
# # 設(shè)置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}"
# 設(shè)置顯示版本和構(gòu)建版本
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 參數(shù)配置
gym(
export_method: exportMethod, # 相當(dāng)于配置 Archives->Export->mehtod:[app-store, ad-hoc, package, enterprise, development(默認), developer-id]
output_name: pkgName,
configuration: "Release", # 相當(dāng)于配置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會自動創(chuàng)建
end
end
end
desc "上傳到 App Store"
lane :release do
# match(type: "appstore")
# snapshot
gym(
export_method: "app-store", # 相當(dāng)于配置 Archives->Export->mehtod:[app-store, ad-hoc, package, enterprise, development, developer-id]
output_name: pkgName,
configuration: "Release", # 相當(dāng)于配置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
執(zhí)行打包的命令會在項目目錄下生成一個output目錄,內(nèi)容如下
➜ 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 安裝firim插件 ➜ PlushGame fastlane add_plugin firim # 添加 `bundle exec` 使用本地的插件,加快速度 ➜ PlushGame bundle exec fastlane add_plugin firim [15:08:48]: Plugin 'fastlane-plugin-firim' was added to './fastlane/Pluginfile' [15:08:48]: Make sure to commit your Gemfile, Gemfile.lock and Pluginfile to version control Installing plugin dependencies... Successfully installed plugins
添加成功之后再 fastlane 目錄下多出了一個 Pluginfile 文件,描述添加的插件的信息
# Autogenerated by fastlane # # Ensure this file is checked in to source control! gem 'fastlane-plugin-firim'
插件使用方法
使用fastlane action查找某個action的使用方法和參數(shù),下面是查找firim action的使用方法和參數(shù)的例子
➜ 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后臺點擊右上角的設(shè)置獲取即可
firim(firim_api_token: "xxxxxx")#上傳fir,如果是新項目,fir會自動創(chuàng)建
結(jié)束
以上就是fastlane在項目中的實戰(zhàn)演練,需要能夠幫助到需要得人
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,謝謝大家對腳本之家的支持。
相關(guān)文章
iOS開發(fā)實現(xiàn)UIImageView的分類
這篇文章主要為大家詳細介紹了iOS開發(fā)實現(xiàn)UIImageView的分類,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-01-01
iOS中的UITextView文字輸入光標使用技巧小結(jié)
UITextView在用戶體驗方面有著十分明顯的作用,包括鍵盤的呼出及文字的選擇等,接下來就來整理給出一份iOS中的UITextView文字輸入光標使用技巧小結(jié),需要的朋友可以參考下2016-05-05
詳解iOS通過ASIHTTPRequest提交JSON數(shù)據(jù)
這篇文章主要介紹了詳解iOS通過ASIHTTPRequest提交JSON數(shù)據(jù),對代碼進行了詳細的講解,具有一定的參考價值,感興趣的小伙伴們可以參考一下。2016-12-12
iOS應(yīng)用開發(fā)中矢量圖的使用及修改矢量圖顏色的方法
這篇文章主要介紹了iOS應(yīng)用開發(fā)中矢量圖的使用及修改矢量圖顏色的方法,文中的方法是在Adobe Illustrator中繪制矢量圖然后導(dǎo)入Xcode中使用,需要的朋友可以參考下2016-03-03

