1.什么是庫徐鹤,為什么使用庫?
庫是共享程序代碼的方式邀层,一般分為靜態(tài)庫和動態(tài)庫返敬;庫實現了iOS程序的模塊化,將某些特定的功能模塊化為庫的格式方便分享和使用寥院!
2.靜態(tài)庫和動態(tài)庫有什么特點劲赠?
異同點:
靜態(tài)庫:鏈接時完整地拷貝至可執(zhí)行文件中,被多次使用就有多份冗余拷貝秸谢。
動態(tài)庫:鏈接時不復制凛澎,程序運行時由系統(tǒng)動態(tài)加載到內存,供程序調用估蹄,系統(tǒng)只加載一次塑煎,多個程序可以共用,節(jié)省內存臭蚁。
共同點:
靜態(tài)庫和動態(tài)庫都是閉源庫最铁,只能拿來滿足某個功能的使用,不會暴露內部具體的代碼信息垮兑,而從github上下載的第三方庫大多是開源庫
3.這兩種庫都有哪些文件格式冷尉?
靜態(tài)庫:.a和.framework
動態(tài)庫:.dylib和.framework(系統(tǒng)直接提供給我們的framework都是動態(tài)庫!)
注意:1.兩種庫都有framework的格式系枪,但是它們長得一樣嗎雀哨?
2.當你創(chuàng)建一個framework文件時,系統(tǒng)“默認”是一個動態(tài)庫的格式私爷,如果想做成靜態(tài)庫震束,需要在buildSetting中將Mach-O Type選項設置為Static Library就行了!
4. .a文件和.framework文件組成的區(qū)別:
.a文件是一個純二進制文件当犯,不能直接拿來使用,需要配合頭文件割疾、資源文件一起使用嚎卫。
將靜態(tài)庫打包的時候,只能打包代碼資源宏榕,但是圖片文件拓诸、本地json文件和xib等資源文件無法打包進去,使用.a靜態(tài)庫的時候需要三個組成部分:.a文件+需要暴露的頭文件+資源文件麻昼;
.framework文件內部除了有二進制文件(如下圖黑色文件)之外還有其他的資源文件(相當于:.framwork文件=黑色二進制文件<.a文件+.h文件>+資源文件<圖片奠支、以及本地的html5,json,plist等),可以直接拿來在工程中使用。
5.制作靜態(tài)庫時需要注意的幾點:
(1)圖片資源的處理:兩種格式的靜態(tài)庫抚芦,一般都是把圖片文件單獨的放在一個.bundle文件中倍谜,一般.bundle的名字和.a或.framework的名字相同迈螟。(.bundle文件很好弄,在桌面上新建一個文件夾尔崔,把它重命名為XXX.bundle就可以了(選中文件->右鍵->顯示包內容->拖拽添加圖片資源))答毫。
(2)category是我們實際開發(fā)項目中經常用到的,把category打成靜態(tài)庫是沒有問題的季春,但是在使用這個靜態(tài)庫的工程中洗搂,調用category中的方法時,會出現找不到該方法的運行時錯誤:selector not recognized载弄,解決辦法是:在使用靜態(tài)庫的工程中配置other linkerflags的值為-ObjC耘拇。???????????????????????????????????????????????????????????????????????????????
(3)如果一個靜態(tài)庫很復雜,需要暴露的.h比較多的話宇攻,就可以在靜態(tài)庫的內部創(chuàng)建一個.h文件(一般這個.h文件的名字和靜態(tài)庫的名字相同)惫叛,然后把所有需要暴露出來的.h文件都集中放在這個.h文件中,而那些原本需要暴露的.h都不需要再暴露了尺碰,只需要把.h暴露出來就可以了挣棕。
6.framework動態(tài)庫的主要作用:
framework本來是蘋果專屬的內部提供的動態(tài)庫文件格式,但是自從2014年WWDC之后亲桥,開發(fā)者也可以自定義創(chuàng)建framework實現動態(tài)更新(繞過apple store審核洛心,從服務器發(fā)布更新版本)的功能,這與蘋果限定的上架的app必須經過apple store的審核制度是沖突的题篷,所以含有自定義的framework的app是無法在商店上架的词身,但是如果開發(fā)的是企業(yè)內部應用,就可以考慮嘗試使用動態(tài)更新技術來將多個獨立的app或者功能模塊集成在一個app上面7丁(我開發(fā)的就是企業(yè)內部使用的app法严,我們將企業(yè)官網中的板塊開發(fā)成4個獨立的app,然后將其改造為framework文件最終集成在一款平臺級的app當中進行使用葫笼,這樣就可以在一款app上面使用原本4個app的全部功能I钇 )
7.iOS 如何使用 framework 來進行動態(tài)更新!
重要參考文檔(一定要看):
http://blog.csdn.net/like7xiaoben/article/details/44081257
http://www.tuicool.com/articles/Ybq6Rf3
?(1)常見問題匯總:
NO.1:重點是利用OC的動態(tài)特性去實現framework的加載啟動路星!
注意:普通的alloc init的方法無法得到動態(tài)庫中的類溯街,必須依靠NSClassFromString
和performSelector的動態(tài)特性去程序內部查找動態(tài)庫的類并調用啟動方法!
NO.2:當framework 和 主工程中引用相同的第三方庫時:
在主工程中啟動動態(tài)庫的時候洋丐,打印臺會顯示“ClassXXX is implemented in both XXXandXXX.One of the two will be used.Which one is undefined.”
這是當 framework 工程和 主工程鏈接了相同的第三方庫或者同名的類造成的呈昔。但是可能并不影響程序的正常運行,一般的做法是在framework 的Build Settings > Other Linker Flags添加-undefined dynamic_lookup標記即可友绝!這樣操作的思想就是確保framework也從主工程中鏈接第三方庫進行使用堤尾,但是可能會存在一些隱患問題,比如:動態(tài)庫和主工程中都使用AFNetworking進行網絡請求迁客,但是定義的http請求的方法可能不同郭宝,如果讓動態(tài)庫調用主工程方法就需要確保主工程中的方法能夠滿足動態(tài)庫內部程序的使用辞槐,如果打印臺出現了上述信息卻不影響程序正常運行的時候,建議先不要做過多操作剩蟀,而是查看動態(tài)庫啟動時選擇加載的是哪里的第三方庫(經我測試催蝗,framework會加載自己工程里面的AFNetworking方法而不是主工程中的方法),然后再進行修改育特。
N0.3:出現“mmap() error 1 at address=0x100704000, size=0x00008000 segment=__TEXT”錯誤是什么原因丙号?
這個問題主要是因為動態(tài)庫打包時使用的證書和主程序調試證書不一致造成的,證書不一致時缰冤,主程序中是無法打開動態(tài)庫的HА!
NO.4:framework和主工程使用同名的類文件出現的錯誤:
嘗試過在 framework 中引用主工程中已有的文件棉浸,通過Build Settings > Header Search Paths中添加相應的目錄怀薛,Xcode 在編譯的時候可以成功(因為添加了-undefined dynamic_lookup),并且 Debug 版本是可以正常運行的迷郑,但是 Release 版本動態(tài)加載時會提示找不到符號:“Error Domain=NSCocoaErrorDomain Code=3588"The bundle “YourFramework” couldn’t be loaded."(dlopen(/var/mobile/Containers/Bundle/Application/5691FB75-408A-4D9A-9347-BC7B90D343C1/YourApp.app/YourFramework.framework”
這是因為 Debug 版本暴露了所有自定義類的符號以便于調試枝恋,因此你的 framework 可以找到相應的符號,而 Release 版本則不會嗡害。目前能想到的方法只有將相同的文件拷貝一份到 framework 工程里焚碌,并且更改類名。這一點霸妹,只要在平時開發(fā)中養(yǎng)成定義類名時添加前綴的習慣基本就能避免十电。
NO.5:怎么訪問 framework 中的資源文件?
在framework中使用 storyboard/xib創(chuàng)建的頁面叹螟,可以直接訪問framework中圖片資源鹃骂!
但是framework中通過"imageNamed:"方式加載的照片都會丟失!0照馈畏线!這是因為imageNamed的方法默認是從mainBundle中查找資源的,而framework中的照片是從framework內部加載的良价,這是的bundle并不是mainBudle寝殴,而是存在于主程序的docment文件中的framework包,圖片加載的路徑發(fā)生了變化棚壁,自然找不到圖片資源,所以需要修改加載圖片的方法U恍椤(這是一個很蛋疼的問題袖外,意味著原先工程中加載圖片的imageNamed的方法都需要更改為從指定bundle加載圖片資源的方法。我是在framework中寫了一個UIImage的category方法"imageFromBundleNamed"替換掉framework中所有的“imageNamed”的方法才實現圖片資源的加載)
NO.6主工程中加載framework可能出現彈窗顯示位置失常!
這個問題是很容易出現的魂务,因為在主工程中打開framework就向從一款App跳轉到另一款App,framwork中彈出的窗口并不受主工程的navigationController的管理曼验,這樣就極可能導致彈窗展示位置出錯泌射。
解決辦法是:1.將framework中彈窗加載的keyWindow更換為lastWindow(keyWindow是當前活躍的window,而lastWindow是最頂部的window)鬓照;2.在framwork中通過navigationController.view獲取彈窗展示的當前View(此時的View也必然是framework中最前端的頁面)熔酷,然后做相應操作!
NO.7在framework中豺裆,圖片資源不能使用xcassets進行管理拒秘!
這是因為framework中的xcassets文件打包之后會變成.cer文件,并不暴露出圖片資源臭猜,所以framework不能通過xcassets來管理圖片資源躺酒。
解決辦法是:創(chuàng)建一個資源文件夾把全部圖片文件都裝進去進行管理。
NO.8圖片命名問題:
同一個圖片包含多種適配尺寸的蔑歌,必須確保圖片名一致羹应,且以 @2x/@3x 結尾,大小寫敏感次屠。當我們調用圖片的時候只使用@符號以前的圖片名即可园匹,因為系統(tǒng)會根據手機屏幕的不同自動選擇加載該圖片名下的@2x或@3x的圖片!
NO.9架構錯誤:
錯誤描述:“dlopen(/path/to/framework,9): no suitable image found.? Didfind:/path/to/framework:mach-o, but wrong architecture”
解決辦法:打包framework的時候一定要分清是支持iphone還是iphonesimulayor劫灶,如果打包類型有誤就不能在相應設備上正常啟動framework文件裸违;當然,最好是通過lipo的合并命令講真機包和模擬器包合并一下浑此,這樣就不用擔心引起架構錯誤的問題累颂!
(1)通過終端命令查看framework包支持的架構信息:lipo -info (把framework中的黑色文件拖進來)可以查看framework的架構信息!我們打包的framework會有四種類型:
(2)合并命令:lipo -create?? xxx? xxx -output newName
“xxx”是:將模擬器包和真機包的黑色文件拖拽到終端中時產生的路徑信息凛俱;
“newName”是合并后自定義的名字紊馏,不過我一般是再拖一遍真機包的路徑來替換這個名字,這樣合并后的文件就直接包含在真機包里面蒲犬,然后拿來使用朱监。
N0.10簽名問題:
系統(tǒng)在加載動態(tài)庫時,會檢查 framework 的簽名原叮,簽名中必須包含 TeamIdentifier 并且 framework 和? 主工程 的 TeamIdentifier 必須一致赫编。
如果不一致,否則會報下面的"mmap()"錯誤:
Error loading/path/to/framework: dlopen(/path/to/framework,265): no suitable image found. Didfind:/path/to/framework:mmap() error1
NO.11:關于other linker flag的設置問題:
使用動態(tài)庫的時候極易發(fā)生鏈接錯誤奋隶,而且大多發(fā)生在加載framework中的category的情況擂送!根本原因在于Objective-C的鏈接器并不會為每個方法建立符號表,而是僅僅為類建立了符號表唯欣。這樣的話嘹吨,如果靜態(tài)庫中定義了已存在的一個類的分類,鏈接器就會以為這個類已經存在境氢,不會把分類和核心類的代碼合起來蟀拷。這樣的話碰纬,在最后的可執(zhí)行文件中,就會缺少分類里的代碼问芬,這樣函數調用就失敗了悦析。常見的設置方法就是在other linker flag中添加一個語句:-all_load,但是這樣也并不是萬能的此衅,只是在一定程度上解決了鏈接問題强戴。
關于flag標注信息:-all load和-Objc的區(qū)別請參考鏈接:http://my.oschina.net/u/728866/blog/194741
注意:當flag里面添加了注釋卻還是無法使用的時候,可能報flag與bitcode沖突的問題尤其是第三方庫可能和bitcode沖突)炕柔,這樣的話就需要將bitcode設置為NO酌泰!
bitcode的具體作用不做詳談,可參考:http://www.reibang.com/p/3e1b4e2d06c6
以下的這些問題是我拷貝原文資料的信息匕累,我在測試中并未遇到相關錯誤陵刹,權作參考:
N0.12:如果用來打包的證書是 iOS 8 發(fā)布之前生成的,則打出的包驗證的時候會沒有 TeamIdentifier 這一項欢嘿。這時在加載 framework 的時候會報下面的錯誤:
[deny-mmap]mappedfilehasno team identifierandisnotaplatformbinary:/private/var/mobile/Containers/Bundle/Application/5D8FB2F7-1083-4564-94B2-0CB7DC75C9D1/YourAppNameHere.app/Frameworks/YourFramework.framework/YourFramework
可以通過codesign命令來驗證衰琐。
codesign -dv /path/to/YourApp.app
如果證書太舊,輸出的結果如下:
Executable=/path/to/YourApp.app/YourAppIdentifier=com.company.yourappFormat=bundlewithMach-O thin (armv7)CodeDirectoryv=20100size=221748flags=0x0(none)hashes=11079+5location=embeddedSignaturesize=4321SignedTime=2015年10月21日 上午10:18:37Info.plistentries=42TeamIdentifier=notsetSealed Resourcesversion=2rules=12files=2451Internal requirementscount=1size=188
注意其中的TeamIdentifier=not set炼蹦。
采用 swift 加載 libswiftCore.dylib 這個動態(tài)庫的時候也會遇到這個問題羡宙,對此Apple 官方的解釋是:
To correct this problem, you will need to sign your app using code
signing certificates with the Subject Organizational Unit (OU) set to
your Team ID. All Enterprise and standard iOS developer certificates
that are created after iOS 8 was released have the new Team ID field in
the proper place to allow Swift language apps to run.
If you are an in-house Enterprise developer you will need to be
careful that you do not revoke a distribution certificate that was used
to sign an app any one of your Enterprise employees is still using as
any apps that were signed with that enterprise distribution certificate
will stop working immediately.
只能通過重新生成證書來解決這個問題。但是 revoke 舊的證書會使所有用戶已經安裝的掐隐,用該證書打包的 app 無法運行狗热。
等等,我們就跪在這里了嗎虑省?匿刮!
現在企業(yè)證書的有效期是三年,當證書過期時探颈,其打包的應用就不能運行熟丸,那企業(yè)應用怎么來更替證書呢?
Apple 為每個賬號提供了兩個證書伪节,這兩個證書可以同時生效光羞,這樣在正在使用的證書過期之前,可以使用另外一個證書打包發(fā)布怀大,讓用戶升級到新版本纱兑。
也就是說,可以使用另外一個證書來打包應用化借,并且可以覆蓋安裝使用舊證書打包的應用潜慎。詳情可以看Apple 文檔。