天天看点

Fastlane-iOS(调研篇)

FastLane是一种配置iOS和Android自动化Beta部署和发布的最简单的方法之一。它可以简化一些乏味、单调、重复的工作,像截图、代码签名以及发布App。只需一条命令就可实现从 Xcode 项目到 编译\打包\构建\提交审核。

本文做以下事情:

   fastlane 环境搭建

   导入ios的xcode项目

   对xcode项目进行fastlane初始化

   FastLane目录下的主要文件说明

   安装fastlane插件

   使用fastlane测试部署

   Fastlane文件格式的具体解析

   配置发布流程

      说明:本文将 Apple Dev Center 简称为 ADC; iTunes Connect 简称为 ITC

  rvm -v                 #检查ruby是否安装正常

  rvm list known         #列出已知ruby版本

  rvm install ruby-xxxxx #安装一个最新ruby版本

  #如果报错的话   

  brew install opensslreinstall|

  install ruby-xxxxx     #注意修改xxxxxx

  $ xcode-select --install

如果未安装,终端会开始安装,如果报错误:command line tools are already installed, use "Software Update" to install updates.代表已经安装。

  $ sudo gem install -n /usr/local/bin Fastlane

  $ fastlane -v  #检查版本 Fastlane

 fastlane installation at path:

  fastlane 2.64.1

   OK,安装完成

  找到shell profile,一般在 ~/.bashrc, ~/.bash_profile or ~/.zshrc文件里,取决于你的系统,文件的末尾处添加:

  export LC_ALL=en_US.UTF-8

  export LANG=en_US.UTF-8

  终端,cd到你的工程目录,然后执行fastlane init:

  如果期间报错 Connection reset by peer - SSL_Connect,就需要执行:

  $ brew update && brew install ruby         # 重装

  # 然后重新执行

  $ fastlane init

a.期间会遇到:在 "Your Apple ID" 这一步输入苹果开发者账号,会让输入 Apple ID 账号密码(这个信息会存在钥匙串中,后续使用无需再输入密码

b.在“Please confirm the above values”这一步,是问该app是否需要在iTC和ADC中创建,输入 y会自动检测是否需要创建,然后,fastlane 会进行一系列的初始化操作,包括下载 App Store 上的元数据和截屏文件。

c.初始化执行后的结果中肯定会被创建的是Appfile和Fastfile。如果Deliverfile,screenshots和metadata目录没被创建,可以运行deliver init来创建。

d.过程中可以安心的输入密码,所有的密码都加密保存在系统的Keychain里。

a.如果上一步输入N,则没有在 ADC 和 ITC 创建相应信息,初始化完成后的fastlane目录,如下图:

该目录下没有zh-hans文件夹,当然也可以后续创建,执行如下操作即可:

$ fastlane produce init

b.若上一步输入y,则在 ADC 和 ITC 中创建了相应信息,初始化完成后的fastlane目录,如下:

1)Appfile: 存储App公共信息,存放app_identifier,apple_id和team_id用

2)Fastfile:配置管理 lane,自动化执行配置文件

3)这里有个小问题,iTC和ADC中的Team ID是不一样的,在fastlane init中只会自动在Appfile里写入ADC的team_id,所以在这个过程中会不停的问iTC的Team ID,所以在创建完Appfile后,手动在里面添加itc_team_id。

4)Deliverfile:配置应用在 ITC 中的各种信息,和 ICC 中的数据是一一对应的

5)metadata:包含应用在 ITC 中的各种信息

6)screenshots:包含截图数据需要注意的是,metadata 和 Deliverfile,都可以配置 ITC 的数据,但后者优先级高.正如下图:

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

查看所有插件:$ fastlane search_plugins

需安装以下两个插件:

1)fastlane-plugin-versioning => 用来修改build版本号和version版本号。

PS:定义Build时。直接定义成纯数字,比如100起,每次编译的时候让它自动加一。

3)安装上面的插件

$fastlane add_plugin [name]  # 安装方法

$fastlane add_plugin versioning

$fastlane add_plugin firim

构建测试应用,编辑fastfile:

lane :beta do

    gym(scheme: "MyApp",

        workspace: "MyApp.xcworkspace",

        include_bitcode: true)

end

测试运行lane(任务):

$  fastlane beta

如果顺利执行的话,将会在当前文件目录看到一个 MyApp.ipa 文件和对应 MyApp.app.dSYM 文件测试成功。

备注:选择sublime打开,把当前显示样式设置为Ruby

Appfile可以为每个lane提供不同的 app_identifier, apple_id 和 team_id,例如:这里就是为Fastfile中定义的:inhouse设置单独的信息。

app_identifier "com.xxx.xxx" # app的bundle identifier

team_id "XXXXXXXXXX" # Team ID

for_lane :inhouse do

  app_identifier "com.bbb.bbb"

  team_id "AAAAAAAAAA"

app_identifier "com.xxxx.xxxx"   # The bundle identifier of your app

Fastfile就是我们打包,发布到fir,testFlight,appstore等等操作的具体配置文件,Fastfile管理所创建的 lane,它的格式是这样的:

# 自动更新fastlane 工具              

# update_fastlane

# fastlane_version => 指定 fastlane的最小版本,在每次执行之后会检查是否有新版本,如果有会在末尾追加新版本提醒

fastlane_version "2.30.1"

# default_platform => 默认使用平台是 ios,也就是说文件可以定义多个平台

default_platform :ios

platform :ios do

  before_all do

    cocoapods

  end

# desc => 一个lane(任务)的描述,一般说明这个lane是做什么的

  desc "Runs all the tests"

  lane :test do     #一个lane就是一个任务,里面是一个个的action组成的工作流。

    scan

  desc "提交一个新的Beta版本到 Apple TestFlight"

  desc "This will also make sure the profile is up to date"

  lane :beta do

    gym(scheme: "Docment") # Build your app - more options available

    pilot

# sh "your_script.sh"

    # You can also use other beta testing services here (run `fastlane actions`)

  desc "部署一个新版本到App Store"

  lane :release do

    # match(type: "appstore")

    # snapshot

deliver(force: true)

# frameit

  # 你可以定义自己的lane

  #执行lane成功后的回调

  after_all do |lane|

    # slack(

    # message: "Successfully deployed new App Update."

    # )

  # 如果流程发生异常会走这里并终止

  error do |lane, exception|

    #   message: exception.message,

    #   success: false

可以把二进制发布到三个地方:      

发布测试版到TestFlight      

<a href="https://whlsxl.github.io/#to_app_store">发布到Apple Store</a>

用sublime打开 Fastlane 文件,将内容替换为:

# Minimum version of fastlane

<code>fastlane_version </code>"1.32.1"

<code>default_platform :ios</code>

platform<code> :ios </code>do 

<code> </code># 1. 用于描述这个 lane 的工作。一个 lane 是一个按顺序执行的工作流。

<code>  desc </code>"Creating a code signing certificate and provisioning profile"

<code> </code># 2. 执行名为 provision 的 lane。

<code>  lane :provision </code>do

<code>    </code># 3. produce 用指定的 ID、name、语言和版本号创建一个可用于 iTunes Connect 和 Developer Portal 的 app。

<code>    produce(</code>

<code>      app_name: </code>'ENTER_A_UNIQUE_APP_NAME_HERE'<code>, #将 ENTER_A_UNIQUE_APP_NAME_HERE 替换成一个唯一的 App 名字</code>

<code>      language: </code>'English'<code>,</code>

<code>      app_version: </code>'1.0'<code>,</code>

<code>      sku: </code>'123abc'

<code>    )</code>

<code>    </code># 4. cert 创建一个新的私钥和签名请求,下载、安装生成的证书并导入到钥匙串。

<code>    cert</code>

<code>    </code># 5. sigh 创建了一个 provisioning profile。force 参数为 true,则每次运行时都会创建新的 provisioning profile,这样就可以保证每次都使用正确的代码签名证书。

<code>    sigh(force: </code>true<code>)</code>

<code> </code>end

<code>  error </code>do<code> |lane, exception|</code>

<code>    </code># This block is called, if there was an error running a specific lane.

注意:sigh 默认创建的是 App Store 的发布 profile。如果想创建 ad hoc profile,需要使用 sigh(adhoc:true)。如果是开发 profile 则使用 sigh(development:true)。

此时创建了第一个 lane,保存文件,打开终端进入到项目文件夹,输入命令:

fastlane provision

这会让 fastlane 执行 provision lane。大约一分钟左右,fastlane 会问你 iTunes Connect 密码,它会保存到你的 Mac 的钥匙串里。

注意:如果看到错误,例如 “Creation of apps of this type is not available”, 则请登录 iTunes Connect,看一下是否有某些更新的协议需要你确认。

在进行下一步之前,还需要在 Xcode 中进行某些修改。打开 项目的xcode中,切换到 General 页。将 bundle identifier 修改为初始化 fastlane 时输入的 App ID。

在 Build Settings &gt; Code Signing &gt; Provisioning Profile 设为 “ &lt;新的 app ID&gt; AppStore”。然后在 Code Signing Identity 选择和这个 provisioning profile 相对应的 ID:

注意:code signing identity 应该和 provisioning profile 中的 identities 相匹配。这样,当 gym 编译 IPA 文件时会使用新创建的 provisioning profile。

登录进 iTunes Connect,此时app 已经创建好了;

打开 fastlane 文件夹下的 Snapfile 文件,将内容替换为:

# A list of devices you want to take the screenshots from

devices([

  "iPhone 4s",

  "iPhone 5",

  "iPhone 6",

  "iPhone 6 Plus"

])

# A list of supported languages

languages([

  'en-US',

  'fr-FR'

]) 

# Where should the resulting screenshots be stored?

screenshots_path "./screenshots"

# Clears previous screenshots #会清空上次创建的截屏图。

clear_previous_screenshots

# Latest version of iOS

ios_version '9.1'

保存、关闭文件。打开 Fastfile 文件,在 error do |lane, exception| 一句上面加入:

这里创建了一个新的 lane,名为 screenshot,并使用 snapshot 命令根据在 Snapfile 文件中输入的配置创建截屏图。保存文件,在终端窗口中输入:

fastlane screenshot

注意:snapshot 为了截取屏幕,需要调用 Snapfile 中列出的设备类型所对应的模拟器。如果缺少了一种或多种模拟器,你要 Xcode 中通过 Window\Devices 菜单来添加相应的模拟器。左下角的 + 号按钮就是用来添加新模拟器的。

此时,项目文件夹下面的 fastlane 目录,会看到多了一个 screenshots 子目录,还会发现一个 screenshots.html 文件。打开这个文件,可以浏览所有的屏幕截图。

打开 Fastfile,在 screenshot lane 之后添加:

desc "Create ipa" lane :build do gym end

这里创建了一个 lane 叫做 build,它使用 gym 命令创建签名的 ipa 文件。保存 Fastfile,打开终端窗口,进入 项目文件夹,输入命令:

<code>fastlane build</code>

这会执行 build lane,开始编译。一旦编译完成,打开 mZone 项目文件夹。你会看到签好名的 ipa 文件:

要上传屏幕截图、元数据和 IPA 文件到 iTunes Connect,可以使用 deliver 命令,它已经包含在 fastlane 中了。

首先,需要用 deliver 来初始化项目。在终端窗口,进入项目文件夹输入命令:

deliver init

执行完成,在 summary 栏中,你会看到 deliver 已经自动检测到 ipa 文件和屏幕截图的位置。打开 Fastfile 在 build lane 后面添加:

<code>desc "Upload to App Store" lane :upload do deliver end</code>

在终端窗口中,输入命令:

<code>fastlane upload</code>

通过这个命令,fastlane 会创建一个 html 文件,它将以 html form 表单的形式上传文件。登录你的 iTunes Connect。所有的屏幕截图、描述、版本 build 1.0 都应当上传就绪。

剩下来的事情就是点击 “Submit for Review” 按钮。 deliver 可以自动提交 app 去审核,但你需要修改 upload lane:

desc "Upload to App Store and submit for review"

lane :upload do

deliver(

submit_for_review: true

)

lane :deploy do

  # 如果你用 pod install

  cocoapods

  # 如果你没有申请adhoc证书,sigh会自动帮你申请,并且添加到Xcode里

  # 不带adhoc参数,sigh会自动生成App Store证书(公司或个人帐户)

  sigh

  # 以下两个action来自fastlane-plugin-versioning,

  # 第一个递增 Build,第二个设定Version。

  # 如果有多个target,就必须指定target的值,否则它会直接找找到的第一个plist修改

  #建议每一个打的包的Build都要不一样,这样crash了拿到日志,可以对应到ipa上

  increment_build_number_in_plist(target: [target_name])

  increment_version_number_in_plist(

    target: [target_name],

    version_number: '7.1.3'

    )

   #gym用来编译ipa,指定输出目录

  gym(

    output_directory: './build',

  # 上传所有信息到App Store

  deliver(force: true)

# You can define as many lanes as you want

desc "Deploy a new version to the App Store"

lane :release do |op|

    increment_version_number(version_number: op[:version]) #根据入参version获取app版本号

    increment_build_number(build_number: op[:build])  #将build号设置与app版本号相同

    # 设置app的info.plist文件项

    set_info_plist_value(path: "./xxx/Info.plist",  #info.plist文件目录

                        key: "UIFileSharingEnabled", 

                                              # key,将plist文件以Source Code形式打开可查询对应的key

                        value: false)   # value

    # 设置自定义plist文件项,用于给app配置不同的服务器URL

    set_info_plist_value(path: "./xxx/hostAddress.plist",

                        key: "host",

    # 更新Provisioning Profile

    # 在项目当前目录下创建provisions文件夹,并将App Store版本的.mobileprovision文件保存在里面,名称随意。

    update_project_provisioning(profile: "./provisions/appstore.mobileprovision")

    # 更新项目团队

    update_project_team(path: "xxx.xcodeproj",

                  teamid: "5JC8GZ432G")

    # 开始打包

    gym(use_legacy_build_api: true,

        output_name: "appstore",             # 输出的ipa名称

        silent: true,                                    # 隐藏没有必要的信息

        clean: true,                                   # 在构建前先clean

        configuration: "Release",                              # 配置为Release版本

        codesigning_identity: "iPhone Distribution: xxx Co.,Ltd. (5JC8GZ432G)",  # 代码签名证书

        buildlog_path: "./fastlanelog",                      # fastlane构建ipa的日志输出目录

        output_directory: "/Users/xxx/Desktop")       # ipa输出目录

desc "Build a new version use the ceshi"

lane :ceshi do |op|

    increment_version_number(version_number: op[:version])

increment_build_number(build_number: op[:build])

    set_info_plist_value(path: "./xxx/Info.plist",

                        key: "UIFileSharingEnabled",

                        value: true)

                        value: "https:/ceshiServer:xx/xxx/xxx")

    # 将Development版本的.mobileprovision文件保存在里面,名称随意。

    update_project_provisioning(profile: "./provisions/development.mobileprovision")

        output_name: "ceshi",

        silent: true,

        clean: true,

        configuration: "Debug",

        buildlog_path: "./fastlanelog",

        codesigning_identity: "iPhone Developer: xxx (xxxxxxxxxx)",

        output_directory: "/Users/xxx/Desktop"

  )

    #批量处理

desc "build all version ipa"

lane :all do |op|

              t = op[:version]

              ceshi version:t

              release version:t

    end

<code>最后,只需在终端(相关项目目录下)轻轻敲入:</code>

fastlane ceshi version:1.0.0 build:1.0.1   // 打包ceshi环境ipa,app版本号为1.0.0,build为1.0.1

fastlane release version:1.0.0 build:1.0.1 //打包App Store版本ipa,app版本号为1.0.0,build为1.0.1

fastlane all version:1.0.0 build:1.0.1   // 打包ceshi、App Store版本ipa,app版本号为1.0.0,build为1.0.1

<code>我们可以在 Fastfile 文件中添加一个函数来设置version号和build号,使得以上AppStore版本与Development版本配置使用同一函数,如下:</code>

default_platform :ios

def prepare_version(options)

    increment_version_number(

        version_number: options[:version]

    )

    increment_build_number(

        build_number: options[:build]

然后可以在一个lane中使用这个函数:

lane :appstore do |options|

   ···

    prepare_version(options)

然后执行这个lane

$ fastlane appstore version:2.4.0 build:2.0

调研ios-fastlane的安全性        

调研fastlane在其他公司的使用情况        

ios-fastlane踩坑篇        

ios-fastlane问题篇