Fastlane 一鍵打包上傳Fir

Shanesun發表於2018-06-11

一、什麼是Fastlane

The easiest way to build and release mobile apps.
Fastlane是一套使用Ruby寫的自動化工具集,用於iOS和Android的自動化打包、釋出等工作,可以節省大量的時間。

50F602D2-5FDE-4AB5-B865-F67C49247027.png

1608265-f63702702cfa790f.png

fastlaneDemo.gif

Github開源地址 fastlane官網)

二、用來做什麼

iOS一鍵指令碼完成以下步驟: 1 reset_git_repo 移除git中未提交的內容 2 git pull 只拉取最新tag 3 checkout 切換到最新的tag 4 submodule update 更新子模組 5 Pod install 第三方庫管理工具 6 Archive、Sign 打包、簽名 7 upload fir 上傳Fir 8 notification 釘釘機器人

Android 可以實現一鍵多渠道打包: 1 reset_git_repo 移除git中未提交的內容 2 git pull 只拉取最新tag 3 checkout 切換到最新的tag 4 submodule update 更新子模組 5 gradle 打包 6 add_channels_to_apk 拷貝apk,修改檔名為渠道名,渠道名寫入META-INFO目錄 參考連結:Fastlane實戰(三):Fastlane在Android平臺的應用

三、安裝

  1. 安裝Fastlane sudo gem install fastlane
  2. 切換到工程目錄初始化 fastlane init
  3. 執行(lane_name為自定義lane 名字) fastlane lane_name

四、使用

  1. 構建Fastlane 打包上傳 fir
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
#     https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
#     https://docs.fastlane.tools/plugins/available-plugins
#

# Uncomment the line if you want fastlane to automatically update itself
# update_fastlane

fastlane_version "2.96.1"
default_platform(:ios)

platform :ios do
  desc "Push a new beta build to fir"
  lane :tofir do
	# Deletes the Xcode Derived Data
	clear_derived_data

 	# discarding uncommitted changes
  	reset_git_repo(
      force: true,
      skip_clean: true,
      disregard_gitignore: false
      )


  	# git pull only the tags, no commits
	git_pull(only_tags: true)

	# get recent tag
  	recentTagName = last_git_tag

  	# (fastlane-plugin-git_switch_branch為外掛)check out tag
  	git_switch_branch(branch: recentTagName)

    # submodule init and update
    git_submodule_update(
    	init: true,
    	recursive: true
    	)

  	# pod install
  	cocoapods

  	scheme = "ProCloser"
  	ipa_dir  = "./fastlane_build/"+Time.new.strftime('%Y-%m-%d')
  	ipa_name = recentTagName + "_" + Time.new.strftime('%Y%m%d%H%M')

  	# gym用來編譯 打包 簽名
  	gym(
   	 output_directory: ipa_dir,
   	 output_name: "#{ipa_name}.ipa",
	    clean: true,
	    workspace: scheme + ".xcworkspace",
	    scheme: scheme,
	    export_xcargs: "-allowProvisioningUpdates",
	    export_options: {
	      method: "ad-hoc", # 指定打包方式
	      teamID: "xxxxxxxxxxx",
	      thinning: "<none>",
	    }
    )

  	# (fastlane-plugin-firim為外掛)上傳ipa到fir.im伺服器,在fir.im獲取firim_api_token
  	firim(firim_api_token: "xxxxxxxxxxxxxxx")


	desc "Notification 釘釘機器人"
    # 釘釘機器人
  	app_patch   = ipa_dir + "/#{ipa_name}.ipa"
  	app_version = get_ipa_info_plist_value(ipa: app_patch, key: "CFBundleShortVersionString")
  	app_build_version = get_ipa_info_plist_value(ipa: app_patch, key: "CFBundleVersion")
  	app_name    = get_ipa_info_plist_value(ipa: app_patch, key: "CFBundleDisplayName")
  	app_url 	= "xxxxxxxx"
  	app_icon 	= "xxxxxxx"
  	dingTalk_url = "xxxxxxxxx"
  
  	dingMessage = 
  	{
   	 msgtype: "link", 
   	 link: {
        text: "對應git tag為: #{recentTagName}", 
        title: "iOS #{app_name} #{app_version} (#{app_build_version}) 測試版本", 
        picUrl: "#{app_icon}", 
        messageUrl: "#{app_url}"
   	 	}
	}

	uri = URI.parse(dingTalk_url)
	https = Net::HTTP.new(uri.host, uri.port)
	https.use_ssl = true

	request = Net::HTTP::Post.new(uri.request_uri)
	request.add_field('Content-Type', 'application/json')
	request.body = dingMessage.to_json

	response = https.request(request)
	puts "--------------- 釘釘機器人已經通知 ✅ ---------------"
	puts "Response #{response.code} #{response.message}: #{response.body}"

  end
end
複製程式碼
  1. 增加一鍵遠端打包指令碼

客戶端:

# 遠端到打包機,執行打包機中的shell指令碼。在打包機中配置了ssh信任所以不需要輸入密碼
ssh tiejin@tiejinios.local '/Users/tiejin/closerToFir.sh'
複製程式碼

伺服器:

# 解鎖mac中的keychain,fastlane打包命令中的證書籤名需要用到keychain中記錄的賬戶和密碼。
security unlock-keychain -p 2018 $KEYCHAIN
# 進入指定目錄
cd closer
# 設定環境變數,否則fastlane中涉及到/usr/local/bin/命令部分找不到
export PATH=/usr/local/bin/:$PATH
# 執行fastlane
fastlane tofir
複製程式碼
  1. 和 Jenkins 結合一起使用

  2. 自定義Actions 0 什麼是Action Action 是Fastlane中的最小執行單元,Action中封裝了一些shell命令。

1 建立自定義Action ,會自動生成xxx.rb檔案 fastlane new_action

2 編輯 xxx.rb 檔案,修改具體邏輯。

module Fastlane
    module Actions
        module SharedValues
            REMOVE_TAG_CUSTOM_VALUE = :REMOVE_TAG_CUSTOM_VALUE
        end
        
        class RemoveTagAction < Action
            def self.run(params)
            # 最終要執行的東西,在這裡執行
            
            # 1、獲取所有輸入的引數
            # tag 的名稱 如 0.1.0
            tageName = params[:tag]
            # 是否需要刪除本地標籤
            isRemoveLocationTag = params[:isRL]
            # 是否需要刪除遠端標籤
            isRemoveRemoteTag = params[:isRR]
            
            # 2、定義一個陣列,準備往陣列裡面新增相應的命令
            cmds = []
            
            # 刪除本地的標籤
            # git tag -d 標籤名稱
            if isRemoveLocationTag
                cmds << "git tag -d #{tageName}"
            end
            
            # 刪除遠端標籤
            # git push origin :標籤名稱
            if isRemoveRemoteTag
                cmds << "git push origin :#{tageName}"
            end
    
            # 3、執行陣列裡面的所有的命令
            result = Actions.sh(cmds.join('&'))
            UI.message("執行完畢 remove_tag的操作 ?")
            return result
   
        end
        
        #####################################################
        # @!group Documentation
        #####################################################
        
        def self.description
        "輸入標籤,刪除標籤"
    end
    
    def self.details
    # Optional:
    # this is your chance to provide a more detailed description of this action
"我們可以使用這個標籤來刪除git遠端的標籤\n 使用方式是:\n remove_tag(tag:tagName,isRL:true,isRR:true) \n或者 \nremove_tag(tag:tagName)"
end

# 接收相關的引數
def self.available_options

# Define all options your action supports.

# Below a few examples
[

# 傳入tag值的引數描述,不可以忽略<必須輸入>,字串型別,沒有預設值
FastlaneCore::ConfigItem.new(key: :tag,
                             description: "tag 號是多少",
                             optional:false,# 是不是可以省略
                             is_string: true, # true: 是不是字串
                             ),
# 是否刪除本地標籤
FastlaneCore::ConfigItem.new(key: :isRL,
                             description: "是否刪除本地標籤",
                             optional:true,# 是不是可以省略
                             is_string: false, # true: 是不是字串
                             default_value: true), # 預設值是啥

# 是否刪除遠端標籤
FastlaneCore::ConfigItem.new(key: :isRR,
                             description: "是否刪除遠端標籤",
                             optional:true,# 是不是可以省略
                             is_string: false, # true: 是不是字串
                             default_value: true) # 預設值是啥

]
end

def self.output
# Define the shared values you are going to provide
# Example

end

def self.return_value
# If your method provides a return value, you can describe here what it does
nil
end

def self.authors
# So no one will ever forget your contribution to fastlane :) You are awesome btw!
["zhangyan"]
end

# 支援平臺
def self.is_supported?(platform)
# you can do things like
#
#  true
#
#  platform == :ios
#
#  [:ios, :mac].include?(platform)
#

platform == :ios
end
end
end
end
複製程式碼

五、深入學習Fastlane

0. Fastlane基本知識

  1. Fastlane檔案結構

Gemfile 和 Bundle 是什麼: Gemfile檔案:gem包管理工具,如:管理fastlane、cocoapods Appfile檔案:從 Apple Developer Portal 獲取和專案相關的資訊 Fastlane檔案:核心檔案,主要用於 cli 呼叫和處理具體的流程 Deliverfile:從 iTunes Connect 獲取和專案相關的資訊

  1. Fastlane的Plugin機制
  • Action:對於Fastlane來說Action的收錄是非常嚴格,並且有很強的通用性才能收錄其中,即使接收了,整個釋出週期也會比較長,而且以後無論是升級還是Bug修復,都依賴Fastlane本身的發版,大大降低了靈活性。

  • Plugin: Plugin就是在Action的基礎上做了一層包裝,這個包裝巧妙的利用了RubyGems這個相當成熟的Ruby庫管理系統,所以其可以獨立於Fastlane主倉庫進行查詢,安裝,釋出和刪除。

我們甚至可以簡單的認為:Plugin就是RubyGem封裝的Action,我們可以像管理RubyGems一樣來管理Fastlane的Plugin。

安裝 fastlane add_plugin [plugin_xxx] 安裝完成後 會在fastlane資料夾下生成Pluginfile檔案實際就是一個Gemfile檔案,裡面包含了對於Plugin的引用,格式如下:

# Autogenerated by fastlane
#
# Ensure this file is checked in to source control!
# fastlane-plugin-version_from_last_tag 是外掛名字
gem 'fastlane-plugin-version_from_last_tag'
複製程式碼

使用 和Action使用一樣。

  • 釋出Plugin 1 可以作為Gem釋出到RubyGems上,這樣就可以通過fastlane search_plugins xxx 查詢,安裝。

2 可以到Github / GitLab上 或者 引用本地路徑。

gem "fastlane-plugin-version_from_last_tag", git: "https://github.com/jeeftor/fastlane-plugin-version_from_last_tag"
複製程式碼

釋出之前,為了本地除錯方便,可以將gem指向本地,在Pluginfile這樣宣告:

gem "fastlane-plugin-version_from_last_tag", path: "../fastlane-plugin-version_from_last_tag"
複製程式碼

1. Fastlane不只是移動端

  • 測試方面: 1 UI自動化測試Action: appium ,以下是appium所有引數 fastlane action appium
    401851C4-6DE4-46EC-862E-CEBAB69F1886.png

2 Android Monkey 下面我們看看Android一般執行Monkey測試的步驟:

Git Pull拉最新的程式碼 執行./gradlew clean命令清理環境 執行./gradlew assembleTest打包測試版本 執行命令安裝最新的測試版本: adb shell monkey -p com.wanmeizhensuo.zhensuo -c android.intent.category.LAUNCHER 1

每次呼叫命令: fastlane do_monkey_test times:3 project:GengmeiAndroid apk_path:./GengmeiAndroid_test.apk ... Fastlane檔案配置如下:

desc "Android monkey test"
lane :do_monkey_test do |options|
    times        = options[:times]
    project      = options[:project]
    apk_path     = options[:apk_path]
    package_name = options[:package_name]
    
    hipchat(message: "Start monkey test on #{project}")
    
    git_pull
    gradle(task: "clean")
    gradle(task: "assembleGmtest")
    (1..times.to_i).each do |i|
      adb(command: "install -r #{apk_path}")
      adb(command: "shell monkey -p #{package_name} -c android.intent.category.LAUNCHER 1")
      # 等待30秒,確保閃屏頁被Finish後,進入到主頁.
      sleep(30)
      android_monkey(package_name: "#{package_name}", count: '1000', seed: "#{10+i}")
    end
    
    hipchat(message: "Execute monkey test on project #{project} successfully")
end
複製程式碼

自定義的Action android_monkey 封裝了 Android Monkey adb

  • 理論上所有頻繁使用shell操作的,都可以利用fastlane整合,自動化處理。 Fastlane還有以下這些整合好的Actions: ssh scp cli-table cli args parser

更多Actions和Plugins查閱官網 Actions - fastlane docs Plugins - fastlane docs

2. 高階用法

  1. 前置方法 多個lane是可能包含很多共同的方法,fastlane給出的方案:
before_all do |lane, options|
  #git_pull
  #cocoapods
end
複製程式碼
  1. 後置方法 所有lane執行完時,可能都會有通知邏輯:
after_all do |lane,options|
    slack(message: "fastlane was successful", success: true)
end
複製程式碼
  1. error處理,每個lane執行時可能都會遇到錯誤,這個時候都應該有訊息通知到大家。error就是一個全域性錯誤處理方法:
error do |lane, exception|
  slack(message: exception.message, success: false)
end
複製程式碼
  1. 引用機制 遠端引用 import_from_git import_from_git - fastlane docs每次執行fastlane的命令時,首先會從git上將需要的檔案clone這個專案到本地的臨時資料夾中,然後再執行相關命令。如果某個專案中,你不想使用遠端上的某個lane,可在專案中的Fastfile中複寫這個lane即可。

  2. 更多高階用法檢視文件 Advanced - fastlane docs

0. Fastlane - iOS 和 Android 自動化構建工具 Fastlane實戰(一):移動開發自動化之道 - 簡書 Fastlane實戰(二):Action和Plugin機制 - 簡書 Fastlane實戰(三):Android平臺上的應用 - 簡書

Tips

  1. fastlane install命令在bundle update 卡住,gem ruby 源有問題,這裡建議新增國內源。

  2. ruby映象 https://gems.ruby-china.org https://ruby.taobao.org/

替換命令:

$ gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/
$ gem sources -l
*** CURRENT SOURCES ***

https://gems.ruby-china.org
# 請確保只有 gems.ruby-china.org
$ gem install rails
複製程式碼
  1. 遠端SSH到打包機執行打包 報錯:code sign 問題導致 unknown error -1=ffffffffffffffff iOS遠端自動打包問題 - 簡書

Fastlane 一鍵打包上傳Fir

相關文章