最近成功搭建了fastlane自动化构建流程,做下记录。
fastlane 是用 Ruby 语言编写的一个命令行工具。
fastlane 提供了一百多个 Action,它们是 iOS 项目开发中所有自动化 *** 作的基础。Action是 fastlane 自动化流程中的最小执行单元。
fastlane的action分类:
可以根据自己项目的需要,在开发自动化 *** 作时,通过传参,将某几个action配合起来使用。
每一个自动化 *** 作或者自动化任务,在fastlane中称为一个 lane。 iOS 开发中的所有自动化 *** 作,主要通过 Lane 来封装和配置的。
所有的lane保存在fastfile文件,由git统一管理,共享给所有成员。
命令:
fastlane init
用于建立fastlane文件夹
除了Fastfile,还有Applefile,以及执行过程中生成的中间文件。
保存所有的 lane,使用lane封装常用的自动化 *** 作。
Applefile用于保存App的唯一标识符和Apple ID等信息
当fastlane执行一个action时,首先会使用传递进来的参数
没有参数时,fastlane会从applefile文件中查找并使用对应信息
一般插件从gem下载,当然github上也有插件:
https://rubygems.org/gems
下载插件命令:
gem install fastlane-plugin-xxx
安装命令:
fastlane add_plugin 插件完整名称
如果安装失败,可自己打开Pluginfile文件添加:
open ~/.fastlane/Pluginfile
写入
gem 'fastlane-plugin-xxx'
查看本地缓存的插件:
cd ~/.rvm/gems/ruby-2.7.0/gems
fastlane 切换分支的插件
https://github.com/chdzq/fastlane-plugin-git_switch_branch
生成一个不需要进行短信认证的application specific password,这个需要到 苹果开发者中心的账号管理下进行生成。注意生成后将其备份,因为页面一旦关闭将无法再次查看
执行命令 fastlane spaceauth -u [开发者账号],生成FASTLANE_SESSION,将其备份配置环境变量如下:
export FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD=[application specific password(替换为你自己的)]
export FASTLANE_SESSION=[FASTLANE_SESSION(替换为你自己的)]
执行source ~/.bash_profile使新增的环境变量生效,分别执行以下命令查看环境变量是否设置成功(成功会在控制台有打印)
echo $FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD
echo $FASTLANE_SESSION
Jenkins中的shell配置
注意:如果在Jenkins中需要执行shell,cd到某个路径,必须要在localhost:8080(端口号)下写相关命令
不可通过局域网IP:端口号方式进入Jenkins,远程配置cd命令 !!
#!/bin/bash
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
# 工程目录
cd your project path
# 环境切换命令
# 生产环境 与 开发环境 二选一
# 测试环境命令(可切换测试环境) fastlane development_env
# 生产环境命令(不可切换测试环境) fastlane product_env
fastlane development_env
# ipa分发
# development 与 开发环境 二选一
# 上传测试平台(fir) fastlane app_test
# 上传testFlight fastlane app_product
# fastlane app_product 默认会切换到生产环境🍺
fastlane app_test
开箱即食
安装 fir插件
fastlane
fastlane add_plugin firim
安装versioning插件
fastlane add_plugin versioning
以下是我们项目中用的Fastfile文件内容:
# 定义fastlane版本号
fastlane_version "2.198.1"
# 定义打包平台
default_platform :ios
#指定项目的scheme名称
scheme = "xxx"
#导出ipa模式
export_method = "development"
#fir
fir_api_token = "xxx"
pwd_path = sh("pwd")
pwd_path = "#{pwd_path}"[0...pwd_path.length - 1]
ipa_version = get_version_number_from_plist(xcodeproj: "#{scheme}.xcodeproj", # optional
target: scheme,
plist_build_setting_support: true,
build_configuration_name: 'Release')
ipa_build_base_path = "#{pwd_path}/build"
ipa_dir_base_path = "#{ipa_build_base_path}/#{ipa_version}"
# 任务脚本
platform :ios do
lane :local_noti do|options|
download_url = "请留意testFlight更新通知"
if options[:url]
download_url = options[:url]
end
puts("*************| 🐮上传ipa成功🍺 |*************")
puts("*************| #{ipa_version} build #{get_build_number()} 下载地址: |*************")
puts("\n\n\t 最新包地址 #{options[:newest_url]} \n")
puts("\n\n\t 当前包地址 #{download_url}\n")
puts("*************| 🎉🎉🎉🎉🎉🎉🎉 |*************")
# 本地通知
# notification(subtitle: "Finished upload", message: "all work done",open: download_url)
end
lane :development_env do
change_env env_state:"open"
end
lane :product_env do
change_env env_state:"close"
end
lane :change_env do|options|
sh("cd ../#{scheme} && /usr/libexec/PlistBuddy -c 'Set :EnvironmentSwitch #{options[:env_state]}' ./Info.plist")
end
lane :upload_build do
sh("cd .. && git add . && git commit -m \"change number to #{ipa_version} build #{get_build_number()}\" && git push")
end
lane :upload_fir do|options|
puts("*************| 开始上传fir... |*************")
output_name = "#{scheme}_#{export_method}_#{get_build_number()}"
ipa_path = "#{ipa_dir_base_path}/#{get_build_number()}/#{output_name}.ipa"
enterprise_ipa_path = "#{ipa_path[0...ipa_path.length-4]}_enterprise.ipa"
download_url = "xxxrelease_id="
newest_download_url = "xxx"
if options[:no_resign]
enterprise_ipa_path = ipa_path
# 从fir对应bundleId下复制下载地址
download_url = "xxx?release_id="
newest_download_url = "xxx"
end
answer = firim(firim_api_token: fir_api_token, ipa: enterprise_ipa_path)
download_url = "#{download_url}#{answer[:rows][-2][1]}"
local_noti url:download_url,newest_url:newest_download_url
end
# build递增
lane :increase_build_num do|options|
if options[:build_num] then
increment_build_number(
build_number: "#{options[:build_num]}"
)
else
increment_build_number
end
# 也可用以下方式可按照日期处理build号 例: 0222.01
# currentTime = Time.new.strftime("%m%d")
# build = get_build_number()
# if build.include?"#{currentTime}."
# # 当天版本计算迭代版本号
# lastStr = build[build.length-2..build.length-1]
# lastNum = lastStr.to_i
# lastNum = lastNum + 1
# lastStr = lastNum.to_s
# if lastNum < 10
# lastStr = lastStr.insert(0,"0")
# end
# build = "#{currentTime}.#{lastStr}"
# else
# # => 非当天版本 build 号重置
# build = "#{currentTime}.01"
# end
# puts("*************| 更新build #{build} |*************")
# # 更改项目 build 号
# increment_build_number(build_number: "#{build}")
puts("*************| 当前build号 #{get_build_number()} |*************")
end
# pod install全量更新
lane :update_project do
sh("cd ../ && git pull")
sh("if [ -e \"../Podfile.lock\" ]; then rm ../Podfile.lock; fi")
sh("if [ -d \"../Pods\" ]; then rm -rf ../Pods; fi")
cocoapods(
clean_install: true,
# 存在 Gemfile 时使用 bundle exec
use_bundle_exec: false
)
end
# 按scheme导出ipa
lane :output_ipa do|options|
if options[:export_method]
export_method = options[:export_method]
end
dir_path = "/"
if options[:dir_path]
dir_path = options[:dir_path]
end
output_directory = "#{ipa_dir_base_path}#{dir_path}#{get_build_number()}"
output_name = "#{scheme}_#{export_method}_#{get_build_number()}"
# 开始打包
gym(
scheme: scheme,
#输出的ipa名称
output_name: output_name,
# 是否清空以前的编译信息 true:是
clean:true,
# 指定打包方式,Release 或者 Debug
configuration: "Release",
# 指定打包所使用的输出方式
#目前支持app-store, package, ad-hoc, enterprise, development
export_method: export_method,
# 指定输出文件夹
output_directory: output_directory,
# 自动管理证书的时候,Xcode 9及以上没有权限获取钥匙串里面的证书,必须加上这个才能打包成功
export_xcargs: "-allowProvisioningUpdates",
include_bitcode: false,
include_symbols: true
)
end
# 企业签
lane :resign_ipa do|options|
output_name = "#{scheme}_#{export_method}_#{get_build_number()}"
ipa_path = "#{ipa_dir_base_path}/#{get_build_number()}/#{output_name}.ipa"
if options[:ipa_path]
ipa_path = options[:ipa_path]
end
enterprise_ipa_path = "#{ipa_path[0...ipa_path.length-4]}_enterprise.ipa"
sh("cp #{ipa_path} #{enterprise_ipa_path}")
puts("*************| 待重签ipa路径:#{ipa_path} |*************")
puts("*************| 开始重签 |*************")
resign(
ipa: enterprise_ipa_path,
signing_identity: "iPhone Distribution: xxx Co. Ltd.",
use_app_entitlements: true,
# 1. plugIn的bundleId前缀务必和主工程bundleId一致
# 2. 每一个plugIn的bundleId要在和主工程.mobileprovision相同账号下生成对应的 .mobileprovision
provisioning_profile: {
"com.demo.test" => "./enterprise_inhouse.mobileprovision",
"com.demo.test.boardcastupload" => "./boardcastupload.mobileprovision"
}
)
end
lane :manual_reupload_ipa do|options|
ipa_version = "#{options[:version]}"
version_path_arr = []
if ipa_version.include? ".."
version_path_arr = ipa_version.split("..")
end
if version_path_arr.length == 0 ||
version_path_arr[0].split(".").length != 3 ||
version_path_arr.length != 2
puts("\n\n\n\n\n\n")
puts("\t******| 参数有误,格式:版本号 build号 | ******")
puts("\t******| 例如:fastlane manual_reupload_ipa version:1.1.1..11 | ******")
exit(0)
else
auto_reupload_ipa version_path_arr:version_path_arr
end
end
lane :auto_reupload_ipa do|options|
if options[:scheme]
scheme = options[:scheme]
end
ipa_path = ""
version_arr = options[:version_path_arr]
if version_arr
version_path = "#{version_arr[0]}/#{version_arr[1]}"
ipa_path = "#{ipa_build_base_path}/#{version_path}/#{scheme}_#{export_method}_#{version_arr[1]}.ipa"
else
ipa_path = "#{ipa_dir_base_path}/#{get_build_number()}/#{scheme}_#{export_method}_#{get_build_number()}.ipa"
end
if FileTest::exist?(ipa_path) == false
puts("\n\n\n\n\n\n\t******| 版本#{version_arr[0]} #{version_arr[1]} 不存在!请重新打包******")
exit(0)
else
resign_ipa ipa_path:ipa_path
upload_fir
end
end
lane :upload_testFlight do|options|
output_name = "#{scheme}_#{export_method}_#{get_build_number()}"
ipa_path = "#{ipa_dir_base_path}/appstore/#{get_build_number()}/#{output_name}.ipa"
upload_to_testflight(ipa: ipa_path,username:"xxx@qq.com")
end
lane :app_test_common do|options|
if options[:export_method]
export_method = options[:export_method]
end
puts("*************| 开始打 #{export_method} ipa |*************")
puts("*************| 更换模式命令 fastlane app_test:xxx(options:app-store, package, ad-hoc, enterprise, development) |*************")
puts("*************| 命令 fastlane app_product 可输出包并上传testFlight |*************")
# 重装所有库
update_project
#更改项目build号
increase_build_num build_num:options[:build_num]
end
# 不重新安装pods,重新编译输出app-store ipa
lane :app_product_fast do|options|
product_env
output_ipa export_method:"app-store",dir_path:"/appstore/"
# 用python脚本调用transporter方式替换
# upload_testFlight dir_path:"/appstore/"
end
# 重装pods,重新编译输出app-store ipa
lane :app_product do|options|
app_test_common export_method:"app-store"
app_product_fast
upload_build
end
lane :app_test_no_resign do|options|
app_test no_resign:true
end
lane :app_test do|options|
app_test_common export_method:options[:export_method]
output_ipa export_method:export_method
if !options[:no_resign]
resign_ipa
end
upload_fir no_resign:options[:no_resign]
upload_build
end
end
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)