天天看點

iOS 利用 framework 進行動态更新

目前 ios 上的動态更新方案主要有以下 4 種:

html 5

lua(wax)hotpatch

react native

framework

前面三種都是通過在應用内搭建一個運作環境來實作動态更新(html 5 是原生支援),在使用者體驗、與系統互動上有一定的限制,對開發者的要求也更高(至少得熟悉 lua 或者 js)。

使用 framework 的方式來更新可以不依賴第三方庫,使用原生的 oc/swift 來開發,體驗更好,開發成本也更低。

由于 apple 不希望開發者繞過 app store 來更新 app,是以隻有對于不需要上架的應用,才能以 framework 的方式實作 app 的更新。

将 app 中的某個子產品(比如一個 tab)的内容獨立成一個 framework 的形式動态加載,在 app 的 main bundle 中,當 app 啟動時從伺服器上下載下傳新版本的 framework 并加載即可達到動态更新的目的。代碼放在了這裡。

建立一個普通工程 dynamicupdatedemo,其包含一個 framework 子工程 module。也可以将 module 建立為獨立的工程,建立工程的過程不再贅述。

在主工程的 build phases > target dependencies 中添加 module,并且添加一個 new copy files phase。

iOS 利用 framework 進行動态更新

這樣,打包時會将生成的 module.framework 添加到 main bundle 的根目錄下。

主要的代碼如下:

代碼先嘗試在 document 目錄下尋找更新後的 framework,如果沒有找到,再在 main bundle 中尋找預設的 framework。

其中的關鍵是利用 oc 的動态特性 <code>nsclassfromstring</code> 和 <code>performselector</code> 加載 framework 的類并且執行其方法。

這是當 framework 工程和 host 工程連結了相同的第三方庫或者類造成的。

為了讓打出的 framework 中不包含 host 工程中已包含的三方庫(如 cocoapods 工程編譯出的 .a 檔案),可以這樣:

删除 <code>build phases &gt; link binary with libraries</code> 中的内容(如有)。此時編譯會提示三方庫中包含的符号找不到。

在 framework 的 <code>build settings &gt; other linker flags</code> 添加 <code>-undefined dynamic_lookup</code>。必須保證 host 工程編譯出的二進制檔案中包含這些符号。

嘗試過在 framework 中引用 host 工程中已有的檔案,通過 <code>build settings &gt; header search paths</code> 中添加相應的目錄,xcode 在編譯的時候可以成功(因為添加了 <code>-undefined dynamic_lookup</code>),并且 debug 版本是可以正常運作的,但是 release 版本動态加載時會提示找不到符号:

因為 debug 版本暴露了所有自定義類的符号以便于調試,是以你的 framework 可以找到相應的符号,而 release 版本則不會。

目前能想到的方法隻有将相同的檔案拷貝一份到 framework 工程裡,并且更改類名。

在 storyboard/xib 中可以直接通路圖檔,代碼中通路的方法如下:

注意:使用代碼方式通路的圖檔不可以放在 xcassets 中,否則得到的将是 nil。并且檔案名必須以 @2x/@3x 結尾,大小寫敏感。因為 <code>imagenamed:</code> 預設在 main bundle 中查找圖檔。

這是說 framework 不支援目前機器的架構。

通過

可以檢視 framework 支援的 cpu 架構。

碰到這種錯誤,一般是因為編譯 framework 的時候,scheme 選擇的是模拟器,應該選擇ios device。

此外,如果沒有選擇ios device,編譯完成後,products 目錄下的 .framework 檔案名會一直是紅色,隻有在 derived data 目錄下才能找到編譯生成的 .framework 檔案。

系統在加載動态庫時,會檢查 framework 的簽名,簽名中必須包含 teamidentifier 并且 framework 和 host app 的 teamidentifier 必須一緻。

如果不一緻,否則會報下面的錯誤:

此外,如果用來打包的證書是 ios 8 釋出之前生成的,則打出的包驗證的時候會沒有 teamidentifier 這一項。這時在加載 framework 的時候會報下面的錯誤:

可以通過 <code>codesign</code> 指令來驗證。

如果證書太舊,輸出的結果如下:

注意其中的 <code>teamidentifier=not set</code>。

采用 swift 加載 libswiftcore.dylib 這個動态庫的時候也會遇到這個問題,對此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 無法運作。

等等,我們就跪在這裡了嗎?!

現在企業證書的有效期是三年,當證書過期時,其打包的應用就不能運作,那企業應用怎麼來更替證書呢?

apple 為每個賬号提供了兩個證書,這兩個證書可以同時生效,這樣在正在使用的證書過期之前,可以使用另外一個證書打包釋出,讓使用者更新到新版本。

也就是說,可以使用另外一個證書來打包應用,并且可以覆寫安裝使用舊證書打包的應用。詳情可以看 apple 文檔。

you are responsible for managing your team’s certificates and provisioning profiles. apple developer enterprise program certificates expire after three years and provisioning profiles expire after one year. before a distribution certificate expires, create an additional distribution certificate, described in creating additional enterprise distribution certificates. you cannot renew an expired certificate. instead, replace the expired certificate with the new certificate, described in replacing expired certificates. if a distribution provisioning profile expires, verify that you have a valid distribution certificate and renew the provisioning profile, described in renewing expired provisioning profiles.

http://devguo.com/blog/2015/06/16/iosdong-tai-geng-xin-frameworkshi-xian/

http://stackoverflow.com/questions/25909870/xcode-6-and-embedded-frameworks-only-supported-in-ios8

http://blog.csdn.net/like7xiaoben/article/details/44081257

https://www.apperian.com/mam-blog/impact-ios-8-app-wrapping/

http://stackoverflow.com/questions/9216485/how-to-manage-enterprise-distribution-certificate-expiration

繼續閱讀