內容來源:2017 年 12 月 3 日,科大訊飛應用研發經理程坤在「IAS2017互聯網架構峯會」進行《訊飛輸入法Android架構演進與實踐》演講分享。IT 大咖說(微信id:itdakashuo)做爲獨家視頻合做方,經主辦方和講者審閱受權發佈。java
閱讀字數:3031 | 8分鐘閱讀git
本次演講將分享訊飛輸入法Android版從最初開發到逐步發展成熟的過程當中所面臨的各類挑戰以及經驗,還有架構的逐步演進過程。最後提到了團隊在組件化架構中的一些實踐。安全
訊飛輸入法初期採用的是簡單MVC,2012年3月份進行了分層重構,2014年12月份作了多進程的架構,最後2015年12月份開始嘗試組件化相關的工做。微信
當架構與業務發展不匹配的時候就須要考慮改變當前架構,讓架構去適應業務。不管是組織架構仍是軟件架構都須要面對業務問題,而如何解決這一問題是架構的核心目標。架構
軟件架構也要與組織架構相匹配,它們之間應該是一一映射的關係,也就是說系統設計的架構所對應的設計結構和組織結構是相等的。框架
架構的演進的關鍵在於平衡性,架構設計人員常常會追求完美,好比設計很是好的擴展性,追求極致的架構,一股腦的將最新最酷的技術放到架構中。這些作法是否是業務所需求的其實並不必定 ,因此架構的可靠性、擴展性包括安全性等是要作必定平衡的,考慮時間和成本上的問題。工具
訊飛輸入法的項目於2010年7月份啓動,當時的開發人員僅有兩人。在2010年10月份的語音雲發佈會上訊飛輸入法要做爲演示型產品展現,所以對產品的要求是很是高的。能夠看到開發的時間其實只有短短的三個多月,並且當時不少功能都是獨創並沒有產考。組件化
基於產品初期的這些挑戰,咱們在開發的時候實際上是沒有使用架構,而是優先考慮如何快速穩定的實現功能。下圖展現的是開發前的設計圖,上面是展示層,包含各類功能模塊,右邊是業務邏輯,中間是拼音手寫和語音輸入的引擎,最下面是數據存儲。性能
根據項目開發過程當中的經驗來看,當你不能判斷產品發佈出去後是否能存活或者可否達到預期的狀況下,不要花太多的精力去作一個很是好架構,如何快速穩定的發佈產品纔是核心目的,所以咱們的建議是儘可能複用。測試
在產品的快速發展時期咱們的主要工做就是補齊功能、優化效果,這時的開發人員也由原來的2人增長到了4人。開發過程當中也出現了一些問題,因爲當時都是各寫各的代碼,致使代碼的重用性不好,新功能開發成本高,維護起來困難。
基於這方面的問題咱們向產品人員提出了放慢產品發佈節奏的要求,所以有了三個月的時間進行產品的重構。
此次重構對產品進行了抽象分層,主要目的是爲了複用。下面兩層與業務無關,工具層包含經常使用的工具類,框架封裝的是業務無關的通用業務能力。服務層和業務層則是和業務相關的,好比服務層的日誌應用了框架層日誌的能力,並融合了業務上的策略。
分層架構後開發效率得到極大的提高,將原先比較差或很差維護的模塊從新進行了梳理和優化,同時還封裝了不少了公共初始模塊。
產品通過迭代後功能愈來愈多,代碼也愈來愈複雜,這時傳統的分層架構已沒法知足需求。所以咱們將現有的10人團隊,分紅了業務組和架構組,架構組主要負責性能和穩定性上的優化。
在架構組進行優化的過程當中,咱們將原先的架構調整成多進程架構。原先的輸入法只有一個進程,啓動的速度很是緩慢,進程崩了輸入法就沒法使用。所以咱們將輸入法分紅5個進程,將用戶不經常使用的功能放在單獨的進程中,用完後馬上殺掉,也就是即用即走。另外一點就是隔離,把原前後臺的一些功能,好比日誌、下載、推送等單獨剝離出來獨立成一個進程,那麼當這部分出現問題的時候就不會影響到主進程。
多進程的調用是很是麻煩的,所以咱們摒棄了原先的單例模式,簡化了調用。
產品發展後期團隊已經達到了20多人,管理起來很不方面,所以整個團隊被分紅了4個業務團隊,4個架構團隊。這時須要考慮的是什麼樣架構才能匹配各個團隊的例行開發,同時還要支持更快的產品迭代。
爲了保證快速迭代的過程當中的產品穩定性,咱們開始往組件化的架構上發展。
目前開源的組件化框架很是多,要想實現這樣的框架其實沒有什麼成本。當時咱們的關注點在並行開發上,作到團隊之間是隔離的,開發人員開發完功能後能夠自行上線、測試、驗證。另外一個關注點是動態更新,保證上線的時候框架支持動態更新能力。
這個過程咱們發現組件化架構坑實在是太多了,尚未或者準備作這方面的人員要想清楚是否必定要使用組件化架構。這裏有兩個概念,一個是並行開發,一個是並行發佈,能夠根據自身的狀況選擇作到哪一點爲止。並行開發相對來講比較容易的,可是並行發佈難度就不同了,它涉及的不只是客戶端,還有服務端、大數據、版本的管理和兼容等各方面的問題。
較早的組件化框架有Atlas/ACDD、DynamicLoadApk、DynamicApk、Small,最近又出了兩個新的框架VirtualAPK、Replugin。雖然考察了衆多的框架,可是咱們綜合考慮後仍是決定本身動手實現,這是因爲輸入法業務有其獨特性。輸入法不一樣於普通的App,它在鍵盤方面有着很是高的要求,而這偏偏是其餘開源框架沒法知足的。
因爲安卓系統的碎片化問題兼容性上的處理很是麻煩,好比會出現手機在切換到橫屏狀態時輸入法顯示一半的狀況,後來發現是由於屏幕切換的時候資源沒有刷新,獲取到的仍是原來的屏幕寬度,因而咱們在ActivityThread內作了Hook。Hook自己的機制就是利用java的反射機制將API固有的實現替換成咱們本身的。
啓動性能的問題主要出如今鍵盤啓動變慢,空間不足致使崩潰上。框架的啓動相比於原先作的事情更多了,花費的時間也更多。另外老用戶在進行升級的時候,組件啓動過程當中會有一個配置文件,列出組件清單配置組件啓動的優先級,而後對它進行解壓再壓縮最後拷貝到相應的地方。能夠看到由於要騰出另外的空間將組件提取出來進行解壓優化,這樣對於老款的ROM空間不夠的手機就很不友好。
基於以上的問題咱們將原先的清單文件改爲class文件,將應用啓動相關的部分歸爲一個Dex,不相關的歸爲另外的Dex,這樣啓動速度就能獲得提高,由於在安裝時Dex就作了優化。
咱們在進程的相互調用間添加了封裝層,像使用本地能力同樣使用跨進程的能力,包括遠程接口轉本地接口、遠程拉起、重連和狀態恢復。另外爲了保證各組件能力可以正常運行,讓組件自適應選擇進程。
這裏的殼工程無任何代碼,僅有腳本及配置文件,且只有惟一分支,通常不作修改。另外殼工程僅集成打包、集成調試時使用,不使用repo、git submodule。
業務組件中的Bundle可獨立編譯調試,打包產物有:測試apk、組件apk和aar,這些產物都會被上傳到Nexus私服。