1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        CocoaPods對三方庫的管理探究

        共 9820字,需瀏覽 20分鐘

         ·

        2020-11-23 22:31

        4dc606ae788572e3a74225438f3c25db.webp

        CocoaPods是iOS開發(fā)中經(jīng)常被用到的第三方庫管理工具,我們有必要深入了解一下它對項(xiàng)目產(chǎn)生了什么影響,以及它是如何管理這些庫的。

        使用pod安裝三方庫

        我們新建一個(gè)不帶測試模塊的名為FFDemo的Swift項(xiàng)目,它的目錄結(jié)構(gòu)是這樣的

        ├──?FFDemo
        │???├──?AppDelegate.swift
        │???├──?Assets.xcassets
        │???├──?Base.lproj
        │???├──?Info.plist
        │???├──?SceneDelegate.swift
        │???└──?ViewController.swift
        └──?FFDemo.xcodeproj
        ????├──?project.pbxproj
        ????├──?project.xcworkspace
        ????└──?xcuserdata

        然后我們執(zhí)行pod init創(chuàng)建一個(gè)Podfile模板,在里面引入這兩個(gè)三方庫:

        target?'FFDemo'?do
        ??#?Comment?the?next?line?if?you?don't?want?to?use?dynamic?frameworks
        ??use_frameworks!

        ??#?Pods?for?FFDemo
        ??pod?'MJRefresh',?'~>?3.5.0'
        ??pod?'Moya'

        end

        成功執(zhí)行pod install之后我們就將這兩個(gè)庫引入到了項(xiàng)目,這時(shí)項(xiàng)目目錄變成了這樣:

        ├──?FFDemo
        │???├──?AppDelegate.swift
        │???├──?Assets.xcassets
        │???├──?Base.lproj
        │???├──?Info.plist
        │???├──?SceneDelegate.swift
        │???└──?ViewController.swift
        ├──?FFDemo.xcodeproj
        │???├──?project.pbxproj
        │???├──?project.xcworkspace
        │???└──?xcuserdata
        ├──?FFDemo.xcworkspace
        │???└──?contents.xcworkspacedata
        ├──?Podfile
        ├──?Podfile.lock
        └──?Pods
        ????├──?Alamofire
        ????├──?Headers
        ????├──?Local\?Podspecs
        ????├──?MJRefresh
        ????├──?Manifest.lock
        ????├──?Moya
        ????├──?Pods.xcodeproj
        ????└──?Target\?Support\?Files

        從目錄看,除了pod init引入了Podfile,其余三部分內(nèi)容:FFDemo.xcworkspace、Podfile.lock、Pods目錄都是由pod install之后生成的。我們下面重點(diǎn)講下這三部分內(nèi)容。

        CocoaPods安裝的內(nèi)容

        xcworkspace文件

        該文件下包含一個(gè)叫contents.xcworkspacedata的文件,它的內(nèi)容是這樣的:


        <Workspace
        ???version?=?"1.0">

        ???<FileRef
        ??????location?=?"group:FFDemo.xcodeproj">

        ???FileRef>
        ???<FileRef
        ??????location?=?"group:Pods/Pods.xcodeproj">

        ???FileRef>
        Workspace>

        使用xml格式將依賴包含在標(biāo)簽內(nèi)。

        xcworkspace是一個(gè)項(xiàng)目容器,當(dāng)有多個(gè)project需要相互依賴時(shí)可以用xcworkspace將它們組織起來。pod在首次安裝三方庫時(shí)會生成一個(gè)叫Pods.xcodeproj的project管理三方庫,然后將該project和主項(xiàng)目的project通過workspace進(jìn)行關(guān)聯(lián)。這樣我們就可以在主工程里引入三方庫了,而且三方庫由Pods.xcodeproj統(tǒng)一管理,不會對我們原項(xiàng)目產(chǎn)生任何干擾。

        Podfile.lock

        Podfile.lock文件的內(nèi)容是這樣的:

        PODS:
        ??-?Alamofire?(5.3.0)
        ??-?MJRefresh?(3.5.0)
        ??-?Moya?(14.0.0):
        ????-?Moya/Core?(=?14.0.0)
        ??-?Moya/Core?(14.0.0):
        ????-?Alamofire?(~>?5.0)

        DEPENDENCIES:
        ??-?MJRefresh?(~>?3.5.0)
        ??-?Moya

        SPEC?REPOS:
        ??trunk:
        ????-?Alamofire
        ????-?MJRefresh
        ????-?Moya

        SPEC?CHECKSUMS:
        ??Alamofire:?2c792affbdc2f18016e08fdbcacd60aebe1ba593
        ??MJRefresh:?6afc955813966afb08305477dd7a0d9ad5e79a16
        ??Moya:?5b45dacb75adb009f97fde91c204c1e565d31916

        PODFILE?CHECKSUM:?073f3d6d9f03e6a76838ca3719df48ae6cc01450

        COCOAPODS:?1.9.3

        因?yàn)镻odfile文件里可以不指定版本號,而版本信息又很重要,于是就有了Podfile.lock,它里面記錄完整的版本信息和依賴關(guān)系。它的內(nèi)容包含以下幾大塊

        PODS

        PODS是指當(dāng)前引用庫的具體版本號,可以發(fā)現(xiàn)我們并沒有引入Alamofire,但在PODS里確有它。這是因?yàn)镸oya中依賴了它,Moya里定義了一個(gè)subspec叫Core,這是Moya/Core寫法的由來。pod是通過各個(gè)庫的podspec文件找到對應(yīng)依賴的,這里可以簡單看下Moya的部分podspeec文件內(nèi)容Moya.podspec:

        Pod::Spec.new?do?|s|
        ??s.default_subspecs?=?"Core"

        ??s.subspec?"Core"?do?|ss|
        ????ss.source_files??=?"Sources/Moya/",?"Sources/Moya/Plugins/"
        ????ss.dependency?"Alamofire",?"~>?5.0"
        ????ss.framework??=?"Foundation"
        ??end
        end

        DEPENDENCIES

        DEPENDENCIES為pod庫的描述信息,這里內(nèi)容是同Podfile里的寫法。因?yàn)槲覀冎付薓JRefresh的版本號,并沒有指定Moya的版本號,所以這里內(nèi)容也是一樣的。

        SPEC REPOS

        這里描述的是倉庫信息,即安裝了哪些三方庫,他們來自于哪個(gè)倉庫。

        trunk是共有倉庫的名稱,它的地址是https://github.com/CocoaPods/Specs.git,外部使用的三方庫大都來自于這里。通常我們還會依賴一些公司內(nèi)部的私有庫,私有庫的信息也會顯示在這里。

        SPEC CHECKSUM

        這里描述的是各個(gè)三方庫的校驗(yàn)和,校驗(yàn)和的算法是對當(dāng)前安裝版本的三方庫的podspec文件求SHA1。比如MJRefresh的校驗(yàn)和:6afc955813966afb08305477dd7a0d9ad5e79a16。我們安裝的MJRefresh的版本為3.5.0,它在本地的podspec文件路徑為:~/.cocoapods/repos/trunk/Specs/0/f/b/MJRefresh/3.5.0/MJRefresh.podspec.json。

        這個(gè)路徑可以通過在安裝庫時(shí)增加--verbose參數(shù)在輸出日志里查看。我們對該文件內(nèi)容通過openssl求sha1摘要:

        $?pod?ipc?spec?~/.cocoapods/repos/trunk/Specs/0/f/b/MJRefresh/3.5.0/MJRefresh.podspec.json?|?openssl?sha1
        $?6afc955813966afb08305477dd7a0d9ad5e79a16

        因?yàn)槭菍odspec.json內(nèi)容求sha1,所以只要內(nèi)容發(fā)生一點(diǎn)變化,得出的校驗(yàn)和就將大不相同,而這也是校驗(yàn)和設(shè)計(jì)的目的:podspec文件發(fā)生變化意味著版本信息發(fā)生了變化,就需要重新同步代碼。

        大家可能注意到了,我們通常制作私有pod,控制配置信息的文件是podspec格式的,為什么本地文件變成了json格式?

        這是因?yàn)閖son格式兼容性更高也更容易批量處理,官方Spec倉庫的所有庫配置文件都是被轉(zhuǎn)成json格式的。在我們制作私有庫的時(shí)候是可以直接以podspec的格式推到遠(yuǎn)程倉庫的,但后續(xù)解析文件時(shí)pod內(nèi)部檢索還是會把它轉(zhuǎn)成json格式。上面的命令是包含了podsepc轉(zhuǎn)json的命令的,轉(zhuǎn)json命令如下:

        $?pod?ipc?spec?ModuleName.podspec

        PODFILE CHECKSUM

        這個(gè)校驗(yàn)和是針對Podfile內(nèi)容的校驗(yàn)和,如果Podfile內(nèi)容改變了,該值也會跟著改變。計(jì)算方法為:

        $?openssl?sha1?filePath/Podfile

        COCOAPODS: 1.9.3

        這個(gè)代表當(dāng)前使用的CocoaPod版本號,遠(yuǎn)程版本管理應(yīng)該要保證大家使用的pod版本號一致。

        Pods

        Manifest.lock

        Manifest.lock是Podfile.lock的副本,它是在Pods目錄里面。它的作用是這樣的,我們通常是不把Pods文件放到版本管理里面,而把Podfile.lock放到版本管理里面。這時(shí)對于拉取代碼之后是否需要更新pod,就可以通過對比本地的Manifest.lock和遠(yuǎn)程Podfile.lock是否相同即可。

        Targets Support Files

        Pods安裝的依賴是這樣的組織形式

        f8929f4ea9d5bd1c554b8add773754b2.webp

        一個(gè)Pods的Project下面有三個(gè)Targets,其中三個(gè)是安裝的依賴庫,最后一個(gè)Pods-FFDemo是關(guān)聯(lián)三個(gè)庫的Framework,也即是Pods這個(gè)Project的Targets。

        Pods-Demo Framework

        先看這個(gè)Demo的Framework,它會被用于工程項(xiàng)目的引用依賴

        573faa2d18beb09ac65dc61e5a630979.webp

        這個(gè)庫不會被打進(jìn)包里,因?yàn)?code style="font-size:14px;color:rgb(30,107,184);background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;">Do Not Embed代表并不是包含的關(guān)系。

        這個(gè)工程下的配置文件有這些:

        65fd185984b50951041df9708aacb159.webp

        許可協(xié)議文件兩個(gè)以acknowledgements命名的文件是用于管理pod庫的許可協(xié)議,即三方庫必須帶有的LICENSE文件,這也是為什么我們在制作pod時(shí)會要求我們指定軟件協(xié)議。

        Framework文件這里還包含了用于管理Module的modulemap和umbrella.h文件。modulemap是對Module的聲明文件,制作Framework我們總是需要該文件,它的內(nèi)容如下:

        framework?module?Pods_FFDemo?{
        ??umbrella?header?"Pods-FFDemo-umbrella.h"

        ??export?*
        ??module?*?{?export?*?}
        }

        其指向了一個(gè)umbrella的頭文件,這是制作Framework必須的頭文件,modulemap和umbrella.h會在創(chuàng)建Module時(shí)自動(dòng)生成,不建議手動(dòng)修改其關(guān)系。

        dummy.m文件

        這其實(shí)是一個(gè)空的.m文件

        #import 
        @interface PodsDummy_Pods_FFDemo : NSObject
        @end
        @implementation PodsDummy_Pods_FFDemo
        @end

        那為什么要有這個(gè)東西呢,包括所有的三方庫的包里也會包含一個(gè)dummy文件。我在stackoverflow[1]找到了一個(gè)解釋:Xcode的編譯是依賴.m文件的,如果一個(gè)庫里沒有.m文件,將不會被編譯,為了防止這種情況就會在每個(gè)庫里增加一個(gè)空的.m文件。

        xcconfig文件

        xcconfig文件是Build Setting配置項(xiàng)的文件形式,它的優(yōu)先級大于Xcode內(nèi)的Build Setting??匆粋€(gè)pod生成的debug模式下的xcconfig文件。

        ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES?=?YES
        FRAMEWORK_SEARCH_PATHS?=?$(inherited)?"${PODS_CONFIGURATION_BUILD_DIR}/Alamofire"?"${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh"?"${PODS_CONFIGURATION_BUILD_DIR}/Moya"
        GCC_PREPROCESSOR_DEFINITIONS?=?$(inherited)?COCOAPODS=1
        HEADER_SEARCH_PATHS?=?$(inherited)?"${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers"?"${PODS_CONFIGURATION_BUILD_DIR}/MJRefresh/MJRefresh.framework/Headers"?"${PODS_CONFIGURATION_BUILD_DIR}/Moya/Moya.framework/Headers"
        LD_RUNPATH_SEARCH_PATHS?=?$(inherited)?'@executable_path/Frameworks'?'@loader_path/Frameworks'
        OTHER_LDFLAGS?=?$(inherited)?-framework?"Alamofire"?-framework?"CFNetwork"?-framework?"Foundation"?-framework?"MJRefresh"?-framework?"Moya"
        OTHER_SWIFT_FLAGS?=?$(inherited)?-D?COCOAPODS
        PODS_BUILD_DIR?=?${BUILD_DIR}
        PODS_CONFIGURATION_BUILD_DIR?=?${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
        PODS_PODFILE_DIR_PATH?=?${SRCROOT}/.
        PODS_ROOT?=?${SRCROOT}/Pods
        USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES?=?YES

        xcconfig還有個(gè)作用是設(shè)置參數(shù),比如我們比較熟悉的PODS_ROOT=${SRCROOT}/PODS,它代表項(xiàng)目根目錄下的PODS文件目錄。另外兩項(xiàng)用于幫助我們在項(xiàng)目中查找三方庫的FRAMEWORK_SEARCH_PATHSHEADER_SEARCH_PATHS也是在該文件內(nèi)部定義的,這些配置會體現(xiàn)到Build Settings里面:

        dd598bba062c9ea8855987130c381e52.webp
        三方庫的Framework

        各個(gè)三方庫也都有一些配置文件,他們文件格式基本一致,文件作用跟上面介紹的類似,下圖是Moya的配置文件,Xcode中Pods > Pods > Moya > Support Files對應(yīng)的文件就是該內(nèi)容。

        7efc00c278caee4d0c4d77a2d27011bc.webpimage-20201114150517801

        我們可以想一個(gè)問題,當(dāng)安裝的第三方庫需要依賴于別的庫時(shí)它是如何去找這個(gè)庫的呢?Moya是需要使用Alamofire的API的,會有import Alamofire的操作。憑借上面的內(nèi)容,可以得知Framework的引用是需要在Build Setting里提前該Target,有哪些引用項(xiàng)的。所以這也是Framework里xcconfig文件的作用,可以在Moya的xcconfig文件里找到這個(gè):

        FRAMEWORK_SEARCH_PATHS?=?$(inherited)?"${PODS_CONFIGURATION_BUILD_DIR}/Alamofire"

        而且引用的是跟主項(xiàng)目同一個(gè)Alamofire的路徑。

        Build Phases

        9933ec919dc1bf7c35c51553384ecaf2.webp

        這里是設(shè)置編譯階段配置的地方,當(dāng)首次pod install成功之后,這里會多幾個(gè)[CP]開頭的配置項(xiàng)(CP即CocoaPods縮寫),它們都是由CocoPods添加的腳本內(nèi)容,執(zhí)行順序從上到下。

        New System Build

        在講編譯腳本之前簡單說下New Build System。

        New Build System是Xcode10之后蘋果推出的新的構(gòu)建系統(tǒng),新的構(gòu)建系統(tǒng)對編譯流程的優(yōu)化[2]做了很多工作,雖然到Xcode12仍兼容舊版的Legacy Build System,但其已經(jīng)被標(biāo)記為移除,我們的項(xiàng)目和庫都應(yīng)該使用新版的構(gòu)建系統(tǒng)進(jìn)行構(gòu)建。和新的構(gòu)建系統(tǒng)隨之而來的是在運(yùn)行腳本時(shí)增加的輸入輸出列表。

        8800a731a70dd13566afe9d00b562e55.webp

        這是為了控制是否每次編譯都需要執(zhí)行對應(yīng)腳本,input和output文件可以是單個(gè)文件形式,如果文件過多可以放到格式為xcfilelist的文件列表里。

        如果沒有提供input和output,則每次構(gòu)建都會運(yùn)行該腳本。如果提供了,則會在以前從未運(yùn)行過、某個(gè)輸入文件被更改或某個(gè)輸出文件丟失的情況下再次運(yùn)行。

        注意這些是構(gòu)建腳本的默認(rèn)邏輯,Xcode還提供了Run Scripts的自定義行為,默認(rèn)勾選項(xiàng):Based on dependency analysis,即代表上述邏輯。如果提供了輸入輸出還需要每次運(yùn)行,關(guān)閉該選項(xiàng)即可。

        [CP] Check Pods Manifest.lock

        該腳本位于較上方,如果沒有Dependencies,開始編譯就會執(zhí)行該腳本,它的內(nèi)容如下:

        diff?"${PODS_PODFILE_DIR_PATH}/Podfile.lock"?"${PODS_ROOT}/Manifest.lock"?>?/dev/null
        if?[?$??!=?0?]?;?then
        ????#?print?error?to?STDERR
        ????echo?"error:?The?sandbox?is?not?in?sync?with?the?Podfile.lock.?Run?'pod?install'?or?update?your?CocoaPods?installation."?>&2
        ????exit?1
        fi
        #?This?output?is?used?by?Xcode?'outputs'?to?avoid?re-running?this?script?phase.
        echo?"SUCCESS"?>?"${SCRIPT_OUTPUT_FILE_0}"

        作用是比較Podfile.lockManifest.lock文件是否相同,如果不同就輸出錯(cuò)誤信息:error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.,并執(zhí)行退出,這會導(dǎo)致后續(xù)項(xiàng)目報(bào)錯(cuò),無法繼續(xù)編譯。

        該錯(cuò)誤較常見,出現(xiàn)于拉取遠(yuǎn)端代碼,遠(yuǎn)端pod依賴于本地不一致的情況。這時(shí)我們可以根據(jù)提示,執(zhí)行pod install命令,根據(jù)Podfile及遠(yuǎn)端Podfile.lock生成新的Manifest.lock文件。

        [CP] Copy Pods Resources

        這個(gè)一般在以靜態(tài)庫引入的三方庫切里面包含資源的話會添加該腳本,其作用是將三方庫的資源文件拷貝至項(xiàng)目中。

        它的完成是通過運(yùn)行以下腳本進(jìn)行的:

        "${PODS_ROOT}/Target?Support?Files/Pods-FFDemo/Pods-FFDemo-resources.sh"

        Pods-FFDemo-resources.sh文件在Pods目錄內(nèi),該腳本內(nèi)有個(gè)關(guān)鍵函數(shù)install_resource

        install_resource()
        {
        ??if?[[?"$1"?=?/*?]]?;?then
        ????RESOURCE_PATH="$1"
        ??else
        ????RESOURCE_PATH="${PODS_ROOT}/$1"
        ??fi
        ??if?[[?!?-e?"$RESOURCE_PATH"?]]?;?then
        ????cat?<error:?Resource?"$RESOURCE_PATH"?not?found.?Run?'pod?install'?to?update?the?copy?resources?script.
        EOM
        ????exit?1
        ??fi
        ??case?$RESOURCE_PATH?in
        ????*.storyboard)
        ??????ibtool?--reference-external-strings-file?--errors?--warnings?--notices?--minimum-deployment-target?${!DEPLOYMENT_TARGET_SETTING_NAME}?--output-format?human-readable-text?--compile?"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename?\"$RESOURCE_PATH\"?.storyboard`.storyboardc"?"$RESOURCE_PATH"?--sdk?"${SDKROOT}"?${TARGET_DEVICE_ARGS}
        ??????;;
        ????*.xib)
        ??????ibtool?--reference-external-strings-file?--errors?--warnings?--notices?--minimum-deployment-target?${!DEPLOYMENT_TARGET_SETTING_NAME}?--output-format?human-readable-text?--compile?"${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/`basename?\"$RESOURCE_PATH\"?.xib`.nib"?"$RESOURCE_PATH"?--sdk?"${SDKROOT}"?${TARGET_DEVICE_ARGS}
        ??????;;
        ????*.framework)
        ??????echo?"mkdir?-p?${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"?||?true
        ??????mkdir?-p?"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
        ??????echo?"rsync?--delete?-av?"${RSYNC_PROTECT_TMP_FILES[@]}"?$RESOURCE_PATH?${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"?||?true
        ??????rsync?--delete?-av?"${RSYNC_PROTECT_TMP_FILES[@]}"?"$RESOURCE_PATH"?"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
        ??????;;
        ????*.xcassets)
        ??????ABSOLUTE_XCASSET_FILE="$RESOURCE_PATH"
        ??????XCASSET_FILES+=("$ABSOLUTE_XCASSET_FILE")
        ??????;;
        ????*)
        ??????echo?"$RESOURCE_PATH"?||?true
        ??????echo?"$RESOURCE_PATH"?>>?"$RESOURCES_TO_COPY"
        ??????;;
        ??esac
        }

        刪除了一部分日志內(nèi)容,其內(nèi)部主要是一個(gè)switch語句,根據(jù)資源文件的類型進(jìn)行不同的同步操作。這里重點(diǎn)說下幾種重要格式文件的處理方式。

        storyboard和xib格式

        這兩項(xiàng)資源文件是需要編譯處理的,利用ibtool命令分別轉(zhuǎn)成sotryboardc和nib格式。

        xcassets格式

        這里的圖片最終會被打包到Assets.car供程序使用,需要使用actool。

        Bundle、plist、png等資源

        其他類的資源是會走到switch語句最后出口,進(jìn)行資源路徑賦值給$RESOURCES_TO_COPY,在后面的代碼中通過rsync命令,將資源同步到構(gòu)建包的目錄。

        該腳本會打印很多日志,在使用CocoaPods時(shí)如果遇到資源相關(guān)的問題都可以遵循錯(cuò)誤日志來這里推測定位錯(cuò)誤原因。

        [CP] Embed Pods Frameworks

        該處腳本是直接運(yùn)行Pods-FFDemo-frameworks.sh

        "${PODS_ROOT}/Target?Support?Files/Pods-FFDemo/Pods-FFDemo-frameworks.sh"

        可能你還記得上面說的pod會把多個(gè)庫的依賴做成一個(gè)合并的庫,但該庫是以依賴的形式引入主工程,但是程序的運(yùn)行時(shí)需要這些庫,我們打包時(shí)就需要將各個(gè)庫Embed到項(xiàng)目里,而做這個(gè)工作的就是該腳本。

        #?Copies?and?strips?a?vendored?framework
        install_framework()
        {
        ??rsync?--delete?-av?"${RSYNC_PROTECT_TMP_FILES[@]}"?--links?--filter?"-?CVS/"?--filter?"-?.svn/"?--filter?"-?.git/"?--filter?"-?.hg/"?--filter?"-?Headers"?--filter?"-?PrivateHeaders"?--filter?"-?Modules"?"${source}"?"${destination}"

        ??#
        ?other?code...

        ??#
        ?Strip?invalid?architectures?so?"fat"?simulator?/?device?frameworks?work?on?device
        ??if?[[?"$(file?"$binary")"?==?*"dynamically?linked?shared?library"*?]];?then
        ????strip_invalid_archs?"$binary"
        ??fi

        ??#
        ?Resign?the?code?if?required?by?the?build?settings?to?avoid?unstable?apps
        ??code_sign_if_enabled?"${destination}/$(basename?"$1")"
        }

        腳本內(nèi)容主要是調(diào)用install_framework函數(shù),將framework內(nèi)容同步到構(gòu)建包里。在該函數(shù)里還有幾個(gè)關(guān)鍵方法,strip_invalid_archs用于去除無用架構(gòu),code_sign_if_enabled用于framwork簽名。

        參考資料

        [1]

        Why do cocoapod create a dummy class for every pod?: https://stackoverflow.com/questions/39160655/why-do-cocoapod-create-a-dummy-class-for-every-pod

        [2]

        Speeding up your custom Xcode build scripts: https://nathanwong.co.uk/post/xcode-buildphases/


        瀏覽 71
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            日韩欧美手机在线 | 久久国产免费视频 | 男人插女人的下面 | 影音先锋国产乱伦 | 水蜜桃成人网 | 日韩精品久久久肉伦网站 | 把护士的批日出水120分钟 | asian艳丽小少妇pics | 丰满人妻一区二区三区 | 久久人妻嫩草无码AV专区动漫 |