Cocoapod的使用(二)打包

時隔很久的交作業(yè)。。。拖延癥晚期,sorry。。。

Gitlab Runner打印Hello World

在完成這一項任務(wù)之前,我們需要先了解一個概念:鉤子
GitHub 倉庫管理中的鉤子與服務(wù)區(qū)塊是 GitHub 與外部系統(tǒng)交互最簡單的方式,另外GitLab 在項目和系統(tǒng)級別上都支持鉤子程序。 對任意級別,當(dāng)有相關(guān)事件發(fā)生時,GitLab 的服務(wù)器會執(zhí)行一個包含描述性 JSON 數(shù)據(jù)的 HTTP 請求。 這是自動化連接你的 git 版本庫和 GitLab 實例到其他的開發(fā)工具,比如 CI 服務(wù)器,聊天室,或者部署工具的一個極好方法鉤子
下面我們就通過添加鉤子來實現(xiàn)Gitlab Runner打印Hello World這一操作

1. 設(shè)置Gitlab Runner監(jiān)聽

在你項目的setting->CI/CD->get start

開始.png

之后會跳轉(zhuǎn)到
介紹頁面
在這個頁面我們可以閱讀到實際上Gitlab Runner是通過在項目中配置.gitlab-ci.yml這一文件實現(xiàn)的
reduce.png

另外我們還讀到我們需要做以下兩步:
1.在倉庫中添加.gitlab-ci.yml文件
2.創(chuàng)建一個Runner
我們一步一步來實現(xiàn)

tip

在上述圖片中我們可以看到一個名詞:continuous integration
也就是CI,持續(xù)集成,那么具體是指什么呢?
軟件集成是軟件開發(fā)過程的一個環(huán)節(jié),一般會包括以下流程:合并代碼---->安裝依賴---->編譯---->測試---->發(fā)布。而持續(xù)集成就是頻繁地(一天多次)將代碼集成到主干。集成的工作一般會比較細碎繁瑣,為了不影響開發(fā)效率,以前軟件集成這個環(huán)節(jié)一般不會經(jīng)常進行或者只會等到項目后期再進行。但是有些問題,如果等到后期才發(fā)現(xiàn),解決問題的代價很大,有可能導(dǎo)致項目延期或者失敗。因此,為了盡早發(fā)現(xiàn)集成錯誤,另外防止分支偏離主干過多,所以衍生了持續(xù)集成。它的核心措施是,代碼集成到主干之前,必須通過自動化測試。只要有一個測試用例失敗,就不能集成。

1.1 在倉庫中添加.gitlab-ci.yml文件

由上述描述可知每次提交均會觸發(fā).gitlab-ci.yml文件的默認執(zhí)行,那么我們在項目中添加該文件,具體文件內(nèi)容如下:

# 指定名稱
stages:
 - fruit
FruitJob:
 stage: fruit
# 設(shè)置可獲取分支層級深度
 variables:
  GIT_DEPTH: "3"

# 選定是哪個分支ortag有提交的時候,觸發(fā)runner
 only:
# 監(jiān)聽tag變更
 - tags
# 監(jiān)聽master分支
 - master
# 監(jiān)聽任意dev分支
 - /^.*/dev$/

# 設(shè)定執(zhí)行腳本
 script:
# curl 命令用作網(wǎng)絡(luò)數(shù)據(jù)包收發(fā),默認啟用傳輸進度條用于顯示總傳輸數(shù)據(jù)大小、傳輸速度、預(yù)計剩余傳輸時間等
# -f 禁止服務(wù)器在打開頁面失敗或腳本調(diào)用失敗時向客戶端發(fā)送錯誤說明,取而代之,curl 會返回錯誤碼 22。
# -L 當(dāng)服務(wù)器報告被請求的頁面已被移動到另一個位置時(通常返回 3XX 錯誤代碼), 允許 curl 使用新的地址重新訪問。如果跳轉(zhuǎn)鏈接指向了一個不同的主機,curl 將不向其發(fā)送用戶名和密碼。
# -o 將獲取到的數(shù)據(jù)存入文件中,而不是打印出來
# --create-dirs 建立本地目錄的目錄層次結(jié)構(gòu)
# --netrc-optional 使用 .netrc 或者 URL來覆蓋-n
# 即下載腳本文件到指定路徑
  - curl -f -L -o ./FruitCIConfig.sh https://gitlab.com/sunqy/SQYLibaryConfig/raw/master/FruitCIConfig.sh --create-dirs --netrc-optional
# 執(zhí)行路徑下的腳本
  - bash ./FruitCIConfig.sh

1.1.1 方法一

如上述文件所示,script下聲明的為默認執(zhí)行內(nèi)容,所以我們可以直接在script聲明下書寫打印代碼(將上述文件中的script下的腳本改為):

script:
- echo "HELLO WORLD!\n"
- printf "hello world" 

是現(xiàn)在我們試著來進行一次提交:
可以在項目->CI/CD->Pipelines下看到一個執(zhí)行完成的記錄:


pushResult.png

點擊查看詳情:


runResult.png

可以看到提交完成后執(zhí)行了.gitlab-ci.yml書寫的打印腳本命令

tip

此處需要注意的.gitlab-ci.yml文件有著很強的對齊要求,同一層級的元素必須對齊,子層級元素必須使用空格(tab不可以)去對齊,且短線-及冒號:后也都必須空格,我自己嘗試的時候因為這個一直檢驗不通過。。。大家可以注意一下這一點,另外可以通過項目->CI/CD->Pipelines->CI Lint


cilint.png

然后將你書寫好的.gitlab-ci.yml文件內(nèi)容貼在這里進行檢驗是否通過


lintResult.png

1.1.2 方法二

如果按照上述文件中,將執(zhí)行腳本放入一個.sh文件中,那么需要注意的是由于.gitlab-ci.yml中指定了下載腳本文件的url,所以需要我們先創(chuàng)建該文件。在我的gitlab上我創(chuàng)建了一個SQYLibaryConfig項目,將要執(zhí)行的腳本文件FruitCIConfig.sh放在了這個目錄下,拿到了該腳本文件的url,以便在.gitlab-ci.yml中使用。(此處需注意,腳本文件的url地址中使用了raw地址,raw代表純文本訪問方式,blob代表網(wǎng)頁訪問方式)

既然在項目提交時會按照.gitlab-ci.yml中尋址到FruitCIConfig.sh腳本去執(zhí)行,那么我們將打印放在FruitCIConfig.sh腳本中即可。腳本代碼如下:

#!/bin/sh
# CI_COMMIT_TAG=''
# CI_COMMIT_REF_NAME='master'
# fruit

echo 'HELLO WORLD!\n'
printf "hello world"

現(xiàn)在我們來進行一次提交,結(jié)果如下圖所示,失敗了:


腳本執(zhí)行失敗

查看圖片,提示了執(zhí)行失敗,甚至出現(xiàn)了<!DOCTYPE html> 的字眼,這是怎么回事呢?有點懵啊,請教大神后得知:gitlab是有訪問權(quán)限的。只能通過http/ssh的形式去訪問。
https訪問的話不加private_token的話是無法訪問的。然而我所創(chuàng)建的.gitlab-ci.yml中所使用的url地址為https://gitlab.com/sunqy/SQYLibaryConfig/raw/master/FruitCIConfig.sh,并沒有注明private_token,所以實際上執(zhí)行完-curl的下載語句后,下載到本地的并非是FruitCIConfig的實際腳本,而是一個gitlab的html登錄網(wǎng)頁

錯誤腳本文件

下面我們把url添加上private_token再嘗試一次提交,這次執(zhí)行結(jié)果成功了:


執(zhí)行完成

tip

可能有些同學(xué)找不到所謂private_token,這里說一下:setting->Access Tokens->可以看到填寫名稱/過期時間/選擇token權(quán)限后即可生成private_token


privateToken.png

1.2 Configure a Runner

1.2.1 淺析runner

我們首先來了解一下什么是runner:
In GitLab, Runners run the jobs that you define in .gitlab-ci.yml. A Runner
can be a virtual machine, a VPS, a bare-metal machine, a docker container or
even a cluster of containers. GitLab and the Runners communicate through an API,
so the only requirement is that the Runner's machine has network access to the
GitLab server.
A Runner can be specific to a certain project or serve multiple projects in
GitLab. If it serves all projects it's called a Shared Runner.
在GitLab中,runner執(zhí)行你在.gitlab-ci.yml中寫的命令,一個runner可能是虛擬機/VPS/一臺裸機/一個docker容器或者一群機器。GitLab和runner之間通過API進行溝通,所以我們只需要一臺能夠訪問GitLab服務(wù)器的電腦就可以把它當(dāng)作一個runner。
一個runner可以針對于一個或多個GitLab上的項目,如果他服務(wù)于多個項目那么就是共享runner。
所以簡而言之,runner就是通過配置自助幫我們執(zhí)行任何命令的服務(wù)。所以在1.1節(jié)中為什么我們只是提交了.gitlab-ci.yml文件提交代碼后就會有對應(yīng)job被執(zhí)行并顯示執(zhí)行結(jié)果呢?這是因為默認創(chuàng)建項目的時候項目的Shared Runners配置為默認開啟,你可以通過項目->Settings->CI/CD->Runner->Expand查看到目前的runner配置情況(我并未做過任何修改,只是簡單新建了一個項目,由此可見Shared Runners為默認開啟)


sharedRunner.png

當(dāng)然你可以通過點擊Disable Shared Runners關(guān)閉這一配置,


closeRunner.png

如上圖所示,是我在默認開啟和手動關(guān)閉之后提交項目代碼Pipelines的對比,如果Shared Runners存在,那么在你提交代碼時會使用Shared Runners執(zhí)行.gitlab-ci.yml文件得出結(jié)論是成功或失敗,但是手動關(guān)閉后,Shared Runners被關(guān)閉了,而你又并沒有創(chuàng)建自己的runner去支持服務(wù),那么提交任務(wù)只會達到pending狀態(tài),以等待你配置了runner,以利用runner服務(wù)去執(zhí)行。所以這一點需要注意:runner是否存在決定了服務(wù)是否會被執(zhí)行還是一直等待服務(wù)資源。

另外,runner分為兩類:Shared Runner(共享型)和Specific Runner(指定型)。Shared Runner:這種Runner是所有工程都能使用的,只有系統(tǒng)管理員能夠創(chuàng)建Shared Runner。

Specific Runner:這種Runner只能為指定的工程服務(wù),擁有該工程訪問權(quán)限的人都能夠為該工程創(chuàng)建Shared Runner。

1.2.2 構(gòu)建runner

一臉懵逼不知道從哪開始?當(dāng)然是官方文檔走起啊我的小可愛[Hey]因為本人電腦是mac,所以果斷選擇macOS版本開始一波閱讀理解[Facepalm]其實按照官方文檔執(zhí)行就好了:

// 1安裝
// 1.1下載二進制文件
sudo curl --output /usr/local/bin/gitlab-runner https://gitlab-runner-downloads.s3.amazonaws.com/latest/binaries/gitlab-runner-darwin-amd64
// 1.2授予執(zhí)行權(quán)限
sudo chmod +x /usr/local/bin/gitlab-runner

// 2注冊
// 2.1開始注冊
gitlab-runner register
// 2.2填寫gitlab url
Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com )
https://gitlab.com
// 2.3填寫token,獲取token可以通過項目->Settings->CI/CD->Runner->Expand,在Specific Runners一欄下可以獲取到這個項目針對的token
Please enter the gitlab-ci token for this runner
yourProjectSpecificRunnersToken
// 2.4填寫你對于此runner的描述
Please enter the gitlab-ci description for this runner
[hostame] my-runner
// 2.5填寫tag名稱,以逗號隔開(此tag名稱可以用來篩選.gitlab-ci.yml文件中你要執(zhí)行的多個腳本,匹配tag的腳本才會被執(zhí)行)
Please enter the gitlab-ci tags for this runner (comma separated):
my-tag,another-tag
// 2.6填寫環(huán)境部署方式(因為沒有任何多余設(shè)備所以我選擇了shell)
Please enter the executor: ssh, docker+machine, docker-ssh+machine, kubernetes, docker, parallels, virtualbox, docker-ssh, shell:
shell

// 3.初始化并開始
cd ~
gitlab-runner install
gitlab-runner start

// 4.運行(這一步就表示你開啟了runner,那么只要你控制臺開著且未執(zhí)行停止命令那么你的機器會一直開啟服務(wù)占用資源,如果想要停止,請執(zhí)行下面一步)
gitlab-runner run

// 5.停止
gitlab-runner stop
(或者使用快捷鍵control+z,再或者直接關(guān)閉控制臺)

執(zhí)行完上述命令到第2步注冊完成后,我們就可以在項目->Settings->CI/CD->Runner->Expand中查看到你創(chuàng)建的runner了:


configSuccess.png

這個時候我們進行一次提交,然后執(zhí)行3和4將runner跑起來,就可以看到這個runner處理了我們的提交操作,終于生效了,開森:


runnerLintSuccess.png

另外,因為你使用的token是針對單獨項目的,所以這個runner是針對于這一個project的Specific Runners,如果你想要創(chuàng)建shared runner你需要使用管理員權(quán)限的token。

Runner打包.framework/.a文件

從上一章節(jié)可知,其實要利用runner為我們做一些事情,重點就在于.gitlab-ci.yml文件中腳本的書寫,所以我們只要修改上述流程中
SQYLibaryConfig項目中的腳本文件FruitCIConfig.sh即可實現(xiàn)對應(yīng)功能。那么應(yīng)該怎樣書寫腳本才能實現(xiàn)打包.framework/.a文件呢?(后期我們使用ruby腳本實現(xiàn)打包,即將FruitCIConfig.sh更換為FruitCIConfig.rb,而且我們需要修改.gitlab-ci.yml文件中的腳本,請參照上文自行修改,此處不再贅述)

【1】PodItemConfig.json文件

// 用來控制包的配置(當(dāng)前僅舉例,未具體實現(xiàn),package_a代表.a包,)
{
  "SQYAlertView": {
    "type": "package_a"
  },
}

require 'JSON'

【2】PodItemModel.rb文件

// 將.podspec解析為配置模型,方便解析
class PodItemModel
attr_accessor :name
attr_accessor :version
attr_accessor :homepage
attr_accessor :source

attr_accessor :public_header_files
attr_accessor :source_files

attr_accessor :resources
attr_accessor :resource_bundles

attr_accessor :vendored_frameworks
attr_accessor :vendored_libraries

attr_accessor :dependencies

attr_accessor :type

    def initialize (json)
        
      obj = JSON.parse(json)
      self.name = obj["name"]
      self.version = obj["version"]
      self.homepage = obj["homepage"]
      self.source = obj["source"]
      
      self.public_header_files = obj["public_header_files"]
      self.source_files = obj["source_files"]
      
      self.resources = obj["resources"]
      self.resource_bundles = obj["resource_bundles"]
      
      self.vendored_frameworks = obj["vendored_frameworks"]
      self.vendored_libraries = obj["vendored_libraries"]

      self.dependencies = obj["dependencies"]

    #      self.type = json['type']
    end

end

【3】FruitCIConfig.rb文件

 // 實際執(zhí)行文件
 require './PodItemModel'
 require 'fileutils'


 class Command

#拷貝源文件至目標文件
def handle_copy_file_to_target (copy_source_file_path, copy_target_file_path)
    #如果源文件為string
    if "#{copy_source_file_path.class}".eql?("String")
        path_arr = Dir.glob(copy_source_file_path)
        path_arr.each { |path_item|
            #如果路徑是一個文件夾則跳過
            if File.directory?(path_item)
                next
            end
            FileUtils.cp_r path_item, copy_target_file_path
        }
    elsif "#{copy_source_file_path.class}".eql?("Array")
        copy_source_file_path.each { |file_item|
            path_arr = Dir.glob(file_item)
            path_arr.each { |path_item|
                if File.directory?(path_item)
                    next
                end
                FileUtils.cp_r path_item, copy_target_file_path
            }
        }
    end

    #因為podspec文件中指定的source_files可能不止包含.h文件,但我們只需要.h文件,所以拷貝完成后刪除非.h文件
    FileUtils.rm_r Dir.glob("./#{copy_target_file_path}/*.[^h]")
end

#上傳文件到固定git倉庫
def handle_library_upload (file_path,library_name,library_version)
    #檢查文件是否存在
    unless File.exist?("#{file_path}")
        raise "壓縮文件不存在,請檢查。"
    end
    
    #替換本地存放打包的倉庫
    localPodLibsGitPath = "/Users/sunqy/SQYPodLibs"
    localPodLibsGitPath_library_name = "#{localPodLibsGitPath}/#{library_name}"
    localPodLibsGitPath_library_name_version = "#{localPodLibsGitPath}/#{library_name}/#{library_version}"
    if !Dir.exist?(localPodLibsGitPath_library_name)
        FileUtils.mkdir_p localPodLibsGitPath_library_name
    end
    if !Dir.exist?(localPodLibsGitPath_library_name_version)
        FileUtils.mkdir_p localPodLibsGitPath_library_name_version
    end

    #覆蓋拷貝
    FileUtils.cp_r file_path, localPodLibsGitPath_library_name_version
    puts "---------- 拷貝文件到本地 git 倉庫,準備上傳到遠端 gitlab ./"


    gitCommand = <<-EOF
    git add .
    git commit -m "Update #{library_name} : #{library_version}"
    git push origin
    EOF
    Dir.chdir("#{localPodLibsGitPath}") do
        puts "開始上傳文件到git倉庫"
        result = system gitCommand
        unless result
            puts '上傳文件失敗'
            exit 1
        end
        puts "上傳文件成功"
    end
    
    puts "上傳完成"
    
end

#集合文件資源成為一個真正可用的庫
def handle_file_group (podspec_file_path)
    # - 項目名稱
        #     - .a/.framework
        #     - Headers
        #     - Resources
        #     - Vendored_frameworks
        #     _ Verdored_libraries

        
    #獲取項目名稱
    library_name = File.basename(podspec_file_path,".podspec")
    puts "開始整合資源,項目名稱" + "#{library_name}"  
    
    # 若本地存在podspec解析成的json文件,則先刪除
    if File.exist?("#{library_name}.json")
        FileUtils.rm_r "#{library_name}.json", :force => true
    end
    #將 podspec 文件轉(zhuǎn)化為 json 文件,并保存在 library_name.json 中
    jsonCommand = "pod ipc spec #{podspec_file_path} >> #{library_name}.json"
    system jsonCommand

    # 生成 spec_model 對象
    json = File.read("#{library_name}.json")
    puts 
    spec_model = PodItemModel.new(json)
    #生成spec_model對象后,刪除 .json 中間文件
    FileUtils.rm_r "./#{library_name}.json", :force => true

    #最終的所有文件所屬路徑
    target_file_path = "/temp/#{library_name}"
    #獲取package打包自動生成的文件夾名字
    libFileFolderName = "#{library_name}-#{spec_model.version}"

    #若整合文件路徑下存在文件則先刪除
    if Dir.exist?("./#{libFileFolderName}/temp/#{library_name}")
        FileUtils.rm_r "./#{libFileFolderName}/temp/#{library_name}", :force => true  
    end
    #重新生成整合文件路徑
    FileUtils.mkdir_p "./#{libFileFolderName}/temp/#{library_name}"

    #1.將打出來的.a包拷貝到指定目錄
    libPath = "#{libFileFolderName}/ios/lib#{library_name}.a"
    if File.exist?(libPath)
        FileUtils.cp_r libPath, "./#{libFileFolderName}/#{target_file_path}"
    else
        raise "打包生成的.a并不存在"
    end
    
    #2.獲取所有.h文件拷貝到指定目錄
    #最終的.h文件所屬路徑
    target_h_file_path = "./#{libFileFolderName}/#{target_file_path}/Headers"
    #如果podspec文件中指定了.h文件的目錄,則直接使用指定的文件
    if !spec_model.public_header_files.nil?
        FileUtils.mkdir_p target_h_file_path
        self.handle_copy_file_to_target(spec_model.public_header_files,target_h_file_path)
    else
        #如果podspec文件中未指定了.h文件的目錄,則使用source_files解析
        unless spec_model.source_files.nil?
            FileUtils.mkdir_p target_h_file_path
            self.handle_copy_file_to_target(spec_model.source_files,target_h_file_path)
        end
    end


    #3.獲取資源文件(如果存在的話)拷貝到指定目錄
    #最終的Resources文件所屬路徑
    target_r_file_path = "./#{libFileFolderName}/#{target_file_path}/Resources"
    # podspec采用resources 指定資源文件
    if !spec_model.resources.nil?
        if !Dir.exist?(target_r_file_path)
            FileUtils.mkdir_p target_r_file_path
        end

        if "#{spec_model.resources.class}".eql?("String")
            puts "---------- string spec_model.resources " + "#{spec_model.resources}"
            resources_arr = Dir.glob(spec_model.resources)
            puts "---------- resources path arr " + "#{resources_arr}"
            resources_arr.each { |resource_item|
                puts "---------- resources item " + "#{resource_item}"
                #如果路徑是文件夾形式的話可能是bundle形式,如果是bundle形式直接拷貝整個bundle
                if File.directory?(resource_item)
                    if File.extname(resource_item).eql?(".bundle")
                        FileUtils.cp_r resource_item, target_r_file_path
                    end
                    next
                end
                FileUtils.cp_r resource_item, target_r_file_path
            }
        elsif "#{spec_model.resources.class}".eql?("Array")
            puts "---------- array spec_model.resources " + "#{spec_model.resources}"
            spec_model.resources.each { |resource|
                puts "---------- resource " + "#{resource}"
                res_path_arr = Dir.glob(resource)
                puts "---------- resources path arr " + "#{res_path_arr}"
                res_path_arr.each { |res_path_item|
                    puts "---------- resources item " + "#{res_path_item}"
                    if File.directory?(res_path_item)
                        if File.extname(res_path_item).eql?(".bundle")
                            FileUtils.cp_r res_path_item, target_r_file_path
                        end
                        next
                    end
                    FileUtils.cp_r res_path_item, target_r_file_path
                }
            }
        end
    end
    # podspec 采用 resource_bundles 指定資源文件
    # 打包靜態(tài)庫后,將 resource_bundles 指定的資源按照鍵值對打包成對應(yīng)的 .bundle 文件,同樣拷貝到 ./libFileFolderName/temp/library_name/Resources 中
    # 這樣,外部引用資源,都統(tǒng)一使用 s.resources = [...] 即可
    unless spec_model.resource_bundles.nil?
        if !Dir.exist?(target_r_file_path)
            FileUtils.mkdir_p target_r_file_path
        end

        if "#{spec_model.resource_bundles.class}".eql?("Hash")
            spec_model.resource_bundles.each { |key,value|
                FileUtils.mkdir_p "./#{target_r_file_path}/#{key}.bundle" # 創(chuàng)建多層文件夾,如果某個文件夾已經(jīng)存在,則該文件夾不再創(chuàng)建
                if "#{value.class}".eql?("String")
                    resbundle_path_arr = Dir.glob(value)
                    resbundle_path_arr.each { |resbundle_path_item|
                        if File.directory?(resbundle_path_item)
                            # 如果 resource_bundles 中又引入了 bundle 資源,則終止程序并給出錯誤警告,因為此時,編譯后會在 key bundle 中再次嵌入這個 sour bundle,也就是bundle中包含bundle,這種情況往往不是我們預(yù)期的。
                        if File.extname(resbundle_path_item).eql?(".bundle")
                            raise "!!!!!!!!! resource_bundles 中,不能指定引入 bundle 文件 !> #{resbundle_path_item}" 
                        end
                            next
                        end
                        FileUtils.cp_r resbundle_path_item, "./#{target_r_file_path}/#{key}.bundle"
                    }
                elsif "#{value.class}".eql?("Array")
                    value.each { |value_item|
                        resbundle_path_arr = Dir.glob(value_item)
                        resbundle_path_arr.each { |resbundle_path_item|
                            if File.directory?(resbundle_path_item)
                                if resbundle_path_item.include?(".bundle")
                                    raise "!!!!!!!!!!! resource_bundles 中,不能指定引入 bundle 文件 !> #{resbundle_path_item}" 
                                end
                                next
                            end
                            FileUtils.cp_r resbundle_path_item, "./#{target_r_file_path}/#{key}.bundle"
                        }
                    }
                end
            }
        else
            raise "!!!!!!!!!!!! resource_bundles 不是 Hash 類型,請檢查 podspec 文件中關(guān)于 resource_bundles 的配置"
        end
    end


    #4.如果有依賴于第三方的.a/.framework文件,拷貝到最終整合文件
    #最終的依賴的第三方.framework文件所屬路徑
    target_vf_file_path = "./#{libFileFolderName}/#{target_file_path}/Vendored_frameworks"
    unless spec_model.vendored_frameworks.nil?
        FileUtils.mkdir_p target_vf_file_path
        if "#{spec_model.vendored_frameworks.class}".eql?("String")
            vendored_f_path_arr = Dir.glob(spec_model.vendored_frameworks)
            vendored_f_path_arr.each { |vendored_f_path_item|
                if File.extname(vendored_f_path_item).eql?(".framework")
                    FileUtils.cp_r vendored_f_path_item, target_vf_file_path
                end
            }
        elsif "#{spec_model.vendored_frameworks.class}".eql?("Array")
            spec_model.vendored_frameworks.each { |vendored_framework_item|
                vendored_f_path_arr = Dir.glob(vendored_framework_item)
                vendored_f_path_arr.each { |vendored_f_path_item|
                    if File.extname(vendored_f_path_item).eql?(".framework")
                        FileUtils.cp_r vendored_f_path_item, target_vf_file_path
                    end
                }
            }
        end
    end

    #最終的依賴的第三方.a文件所屬路徑
    target_vl_file_path = "./#{libFileFolderName}/#{target_file_path}/Verdored_libraries"
    unless spec_model.vendored_libraries.nil?
        FileUtils.mkdir_p target_vl_file_path
        self.handle_copy_file_to_target(spec_model.vendored_libraries,target_vl_file_path)
    end



    #4.壓縮指定目錄
    puts "---------- 更改當(dāng)前進程工作路徑到 ./temp 下,執(zhí)行壓縮命令"
    Dir.chdir("./#{libFileFolderName}/temp") do
        zip_command = "zip -r ./#{library_name}.zip ./#{library_name}"
        system zip_command
        puts "---------- 壓縮完成!"
    end
    puts "---------- 恢復(fù)到原始工作路徑 ./"

    puts "---------- 開始上傳壓縮文件到 gitlab ./"
    libZipFile = "./#{libFileFolderName}/temp/#{library_name}.zip"
    handle_library_upload(libZipFile,library_name,spec_model.version)

end

#處理打包事件
def handle_package
    #獲取并打印當(dāng)前目錄 
    current_file_path = Dir.pwd
    puts '當(dāng)前的工作目錄' + current_file_path

    #因為腳本下載應(yīng)和podspec文件處于同級目錄,所以可以根據(jù)當(dāng)前目錄和文件后綴獲取podspec文件目錄
    Dir.glob('*.podspec').each {|f|
        puts f
        puts '開始打包'

        #嘗試切換.podspec文件中的打包格式,切換打包生成.a或.framework
        is_library = 1
        #根據(jù)podspec文件設(shè)置要打包成的格式為.a還是.framework
        package_command = ''
        if is_library == 1
            package_command = "pod package #{f} --library --force --verbose"
        else
            package_command = "pod package #{f} --embedded --force --verbose"
        end

        #如果使用exec ‘shell code’的話我們無法得知命令的執(zhí)行結(jié)果是否是成功,所以此處我們選擇system命令來執(zhí)行shell腳本打包
        packet_success = system package_command
        puts "--------打包結(jié)果----" + "#{packet_success}"


        if packet_success == true
            puts '打包結(jié)束'
            #如果打包成功,且打出的包為.a包,那么我們需要將項目中的.h和資源文件與.a包合并成為一個真正可用的包
            if is_library == 1
                puts '.a打包完成,整合為可用包'
                self.handle_file_group(f)
            else
                puts 'framework打包完成'
            end
                
        else
            puts '打包失敗'
            next        
        end
    }

end

end

command = Command.new
command.handle_package

有對應(yīng)提交就會觸發(fā)runner,從而執(zhí)行yml文件去下載對應(yīng)腳本并執(zhí)行,腳本功能如上所示,另外因為上述腳本執(zhí)行完成之后打包生成的文件放在了另外一個項目地址中,所以需要對podspec文件進項相應(yīng)的修改并對應(yīng)上傳,此處請讀者自行利用腳本完成,不再贅述

tip1

友情提示:利用本地runner打包的話,需要本地安裝cocoapods-packager,

sudo gem install cocoapods-packager //安裝命令

那么可能會像我一樣遇到下列的錯誤:


installPacketFail.png

這是由于我本地的源不支持,可以利用下列命令修改cocoapods的數(shù)據(jù)源

/* 添加新的數(shù)據(jù)源*/
gem sources --add https://rubygems.org/
/* 移除舊的淘寶數(shù)據(jù)源*/
gem sources --remove https://gems.ruby-china.org/
/*查看數(shù)據(jù)源*/
gem sources -l

tip2

pod package 命令各個參數(shù)含義:


packageParame.png

--force //強制覆蓋之前已經(jīng)生成過的二進制庫

--no-mangle //表示不使用name mangling技術(shù),pod package默認是使用這個技術(shù)的。我們能在用pod package生成二進制庫的時候會看到終端有輸出Mangling symbols和Building mangled framework。表示使用了這個技術(shù)。如果你的pod庫沒有其他依賴的話,那么不使用這個命令也不會報錯。但是如果有其他依賴,不使用--no-mangle這個命令的話,那么你在工程里使用生成的二進制庫的時候就會報錯:Undefined symbols for architecture x86_64。

--embedded //生成靜態(tài).framework

--library //生成靜態(tài).a

--dynamic //生成動態(tài).framework

--bundle-identifier //動態(tài).framework是需要簽名的,所以只有生成動態(tài)庫的時候需要這個BundleId

--exclude-deps //不包含依賴的符號表,生成動態(tài)庫的時候不能包含這個命令,動態(tài)庫一定需要包含依賴的符號表。

--configuration //表示生成的庫是debug還是release,默認是release。--configuration=Debug

--subspecs //如果你的pod庫有subspec,那么加上這個命名表示只給某個或幾個subspec生成二進制庫,--subspecs=subspec1,subspec2。生成的庫的名字就是你podspec的名字,如果你想生成的庫的名字跟subspec的名字一樣,那么就需要修改podspec的名字。
這個腳本就是批量生成subspec的二進制庫,每一個subspec的庫名就是podspecName+subspecName。

--spec-sources //一些依賴的source,如果你有依賴是來自于私有庫的,那就需要加上那個私有庫的source,默認是cocoapods的Specs倉庫。--spec-sources=private,https://github.com/CocoaPods/Specs.git

tip3

所有項目關(guān)聯(lián)圖

參考文檔:1
2

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • ? 認識時間:2015-12-09 認識原因:在群里,無意看到她的,她在群中無意的把一些信息暴露在群中,我便通過支...
    莫莉姑娘閱讀 617評論 2 0
  • 故事有過去和現(xiàn)在,也許是最后把海之冬的故事回憶吧也許海之冬的故事準備消失了評我的回憶去寫吧是最難買的故事故事,在每...
    野蠻開心冬閱讀 2,143評論 0 21
  • 過去大先生和我不好,我想好好服侍他,一切順著他,將來總會好---我好比一只蝸牛,從墻底一點兒一點兒往上爬,爬的雖慢...
    劉六月閱讀 338評論 1 2
  • 今天上午圍棋班 跆拳道班 下午聲樂班
    Lily_5444閱讀 138評論 0 0
  • 一直在思考一個問題,我在別人眼中或者自己定位都是一個熱愛文學(xué)的人。而今才發(fā)現(xiàn),其實我是一個徹頭徹尾的偽文學(xué)愛好者。...
    葉樣悠閱讀 858評論 0 8

友情鏈接更多精彩內(nèi)容