天天看點

swift 元件化_京東商城訂單子產品基于 Swift 的改造方案與實踐建立Swift訂單子產品Swift Objective-c混編過程中遇到的問題期望或規劃

ABI Stability & Module Stability 以及Swift優勢

2019年Swift 5釋出,标志這門語言迎來了一個重大的裡程碑。與之前的版本相比除了一些基礎文法的改變,更重要的是Swift5對Apple所有平台都是ABI(Application Binary Interface) 穩定的,即二進制接口相容;對其他平台Linux,Windows等的ABI穩定,Swift核心團隊在Swift官網上也明确表示會持續跟進。

ABI穩定帶來的好處顯而易見,使用Swift5建構的App将可以與Swift 6的标準庫對話,如下圖所示。

swift 元件化_京東商城訂單子產品基于 Swift 的改造方案與實踐建立Swift訂單子產品Swift Objective-c混編過程中遇到的問題期望或規劃

對于開發者而言,ABI穩定更直接的效果就是Swift runtime 可以和Objective-C runtime一樣被嵌入在系統OS中,不再像之前每一個App都要加入Swift的标準庫。iOS系統從12.2版本嵌入Swift runtime,即iOS 12.2及以後的版本,AppStore會自動去掉APP中的Swift标準庫。Swift标準庫如下圖所示,大緻算了一下,這些庫一共大概占到8、9M左右,這将極大的縮小Swift App的體積。

swift 元件化_京東商城訂單子產品基于 Swift 的改造方案與實踐建立Swift訂單子產品Swift Objective-c混編過程中遇到的問題期望或規劃

基于ABI stability,同一個手機不同App在run time時期可以使用不同版本的Swift,那麼compile time時期有沒有其他問題呢?答案顯然是有的。比如,一個第三方Framework是使用不同版本的Swift建構的,那麼目前的應用是無法将其導入的,在編譯時就會有如下報錯: Module compiled with Swift 4.2 cannot be imported by the Swift 5.0。要解決這一問題就需要 Module stability了。好在官方Swift 5.1 release notes中說明這一點已經得到解決。

顯然Apple對Swift在持續加大投入,可以預期會往越來越好的方向發展。從語言本身來講,相對于Objective-C,Swift在設計上更注重類型安全,擁有更快的運作效率與更現代、更簡潔的文法,等等這些,讓Swift具有了明顯的優勢。在一些代表性的技術社群,如Github,StackOverFlow,也能很明顯的感受到Swift的熱度已經遠遠超過了Objective-C。

業務的增長必然導緻APP安裝包大小的增長,京東App也不例外,Swift APP的局限也在此(需要多引入相關lib)。無論從使用者的角度,還是對技術的追求,也必然不能讓安裝包無限制的瘋長。再加上其他等等原因,過去京東APP正式版本下掉了Swift的代碼。如今iOS12.2以後Swift APP包大小可控, 有理由相信蘋果對這方面的優化會持續加大力度。(小Tip: 蘋果官方Reducing Your App’s Size一文中有說明,同一個包通過TestFlight釋出的本身會比AppStore大,是以驗證包大小時不要忽略掉這點。)

在蘋果對Swift語言的持續改進與開源社群熱度日益增加的背景下,重新開機對Swift的應用是有必要的。下文會介紹訂單子產品的改造方案以及在改造中遇到的問題。

建立Swift訂單子產品

我們期望的Swift方案是能和原有的業務完全隔離解耦,能夠具備随時內建與取消內建的能力,這樣也友善之後的落地與擴充,也鑒于商城App元件化已完成,因而選擇建立一個獨立的Swift版訂單子產品,先移植一些二、三級頁面到Swift訂單子產品。整體結構如下圖:

swift 元件化_京東商城訂單子產品基于 Swift 的改造方案與實踐建立Swift訂單子產品Swift Objective-c混編過程中遇到的問題期望或規劃

Swift Objective-c混編

早期使用過Swift的朋友可能都會有印象,在使用Cocoapods管理使用Swift的三方庫時,必須要在Podfile裡面加入指令use_frameworks!。這個指令的作用其實就是将包含Swift的三方庫作為一種動态庫來引入。但這樣會拖累啟動速度,同時目前Swift訂單子產品工程中Podfile檔案是自動生成的,無法單獨設定use_frameworks!。即使用動态庫的方案不可取。好在蘋果官方解決了這個問題,Cocoapods1.5也支援了引入Swift靜态庫。下圖是Cocoapods1.5 release的官方說明。

swift 元件化_京東商城訂單子產品基于 Swift 的改造方案與實踐建立Swift訂單子產品Swift Objective-c混編過程中遇到的問題期望或規劃

由上述官方說明可知,使用Swift靜态庫的條件已經具備。但上面同樣也提到了一個問題點,如果Swift庫依賴某Objective-C庫,那就需要為這個Objective-C庫開啟“modular header”。這就是說,要麼修改Swift訂單子產品引用的所有Objective-C的第三方庫的Podspec檔案,為其添加 ‘DEFINES_MODULE’=> ‘YES’,要麼修改Swift訂單子產品的Podfile檔案,添加use_modular_headers!或者在該Podfile檔案中為某個單獨的庫配置 :modular_headers => true。這樣Cocoapods會為涉及到的Objective-C的庫生成module map。前面已經提到過,在商城元件化過程中Podfile檔案都是自動生成的,要改動Podfile檔案的生成規則可能會影響商城的所有業務。而改動第三方的Objective-C庫,也将是巨大的工程。好在經過多方嘗試我們發現,使用Objective-C包裝一層入口即OC入口類,對外提供router路由方法調用,router方法内調用具體Swift實作,在OC入口類中引入所有需要引用的第三方Objective-C庫。在這種情況下,我們的Swift子產品調用Objective-C便沒有了問題。在蘋果官網中也找到了相對應的印證,如下圖所示。

swift 元件化_京東商城訂單子產品基于 Swift 的改造方案與實踐建立Swift訂單子產品Swift Objective-c混編過程中遇到的問題期望或規劃

過程中遇到的問題

确定了基礎方案後,剩下的就是具體的執行過程了。具體的業務按照Swift的編碼習慣來實作就好。這裡主要記錄了遇到的幾個問題。

在引入Swift庫後,Swift訂單工程可能會報錯:Could not find or use auto-linked library 'swiftObjectiveC'。連結器找不到這個library,在Library search paths 手動設定上 "$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",

"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)" 可以解決。

同時,Always Embed Swift Standard Libraries需要設定為YES,因為隻有在iOS12.2以後的版本,系統才會包含Swift的标準庫。當然即便這裡設定為YES,AppStore也會自動為包含Swift标準庫的系統做App Thinning優化

另外iOS12.2及以後系統有内置的Swift runtime,需要在 Runpath search path添加路徑 /usr/lib/swift,為動态庫運作時指定路徑。

期望或規劃

商城APP目前支援iOS9.0及以上的使用者,iOS系統使用者如下表已大多更新到12.2以上,也就是說絕大多數使用者對Swift引入的變化是無感覺的,當然我們也要兼顧低版本系統使用者的體驗。同時我們也要關注,業界已有為數不小的團隊完全在使用Swift開發,對我們來說可以預期Swift應用是可行的且必要的。

swift 元件化_京東商城訂單子產品基于 Swift 的改造方案與實踐建立Swift訂單子產品Swift Objective-c混編過程中遇到的問題期望或規劃

商城部分團隊之前也做過Swift的嘗試,但因為ABI不穩定而被各種折磨,與商城快速疊代的實際情況不契合,再加上等等其他原因,和最初的大多數體驗者一樣,最後被迫轉回OC;目前許多阻礙已不存在,可以從以下幾個方面推動:

1.工作環境、工具支援,開發、釋出、打包、內建 swift環境流程打通。

2.Swift工程架構規劃,開發Swift基礎元件,如網絡、圖檔等,搭建純Swift環境架構,同時上線切量驗證。

3.業務共建,商城已完全元件化,架構層的推進不影響業務側的儲備和應用。