看到有網友看到Shadow的開源公告和Github主頁的README以後,以爲都是報喜不報憂的介紹。咱們也多少贊成這個見解。若是開源一個項目,並不期望其餘人能真正使用,也不期待收穫網友們回饋的代碼貢獻,那麼報喜不報憂問題不大。可是Shadow開源的目的不是單純的吹噓本身的技術多厲害,給你們隨便看看代碼片斷。咱們是真的但願你們能用起來,將來咱們的業務和你們的業務用的Shadow是同樣的,沒有任何區別。這樣你們能在插件技術上直接得到通過咱們業務大量實踐的高質量SDK,咱們也有機會直接得到你們貢獻的代碼,減輕咱們維護Shadow的負擔。所以,咱們好好談談Shadow的缺點。git
Shadow採用了用一個殼子代理轉調插件組件的技術手段實現組件生命週期。好比Activity的各類生命週期都須要殼子代理Activity收到系統調用後轉調插件的Activity。同時,反過來插件Activity想調用的父類方法,好比getIntent()
方法,也須要經過中間件層ShadowActivity
轉調回殼子Activity。所以理論上,ShadowActivity
就應該完整複製系統Activity
類的全部方法,大約有200個左右吧。github
不像其餘插件框架沒有插件框架自己動態化的設計,Shadow的插件框架實現代碼也是插件包的一部分,是能夠動態更新的。好比ShadowActivity
這個類處於runtime
模塊,也屬於插件框架自己實現,咱們的業務假設當前沒有使用getIntent()
方法,則同這個業務當前版本一塊兒發佈的Shadow實現就不用實現getIntent()
方法。當下一個版本的業務須要用這個方法時,插件框架實現也能夠補充這個方法的實現,隨業務插件的新版本一同發佈。框架
基於上述緣由,Shadow的功能實現很不完整,只知足了咱們自身業務的需求。不過請放心的是,咱們的業務也比較複雜了,大部分經常使用的功能咱們已經實現了,相似的沒有實現的方法,大部分也只須要簡單轉調便可,很是容易實現。咱們之因此沒有真的去實現,主要緣由是咱們的業務不須要這些方法,因此咱們實現了也不能保證質量。ide
目前Shadow開源的代碼中全部的功能應該只有ContentProvider是咱們業務中沒有用到的。確切的說,只使用了宿主的FileProvider獲取照相文件,插件自身沒有提供任何ContentProvider。ContentProvider的實現確實是爲了讓Shadow的功能對齊其餘插件框架而實現的。測試
Fragment的具體實現方案和緣由在這裏先不講,老是咱們因爲堅持不使用任何Hack手段實現,包括在編譯期也堅持不Hack官方的構建流程,致使咱們最後只能選擇將插件中本來的Fragment類名更名爲在本來名字後面加一個下劃線。好比業務插件裏有一個com.xx.GiftFragment
類,實際運行時這個類的名字就變成了com.xx.GiftFragment_
。這就致使在com.xx.GiftFragment
的源碼上打斷點是斷不下來的。必須在程序運行起來以後,用IDE的重命名功能把它更名爲com.xx.GiftFragment_
,使得源碼和運行時類名字一致才能斷點。插件
這個設計能不能改進,咱們是反覆考慮了沒有更好的辦法的。可是若是Hack構建過程,確實能夠避免這個問題。設計
這其實是優勢帶來的負面問題,在Shadow的設計中有3個部分:host
,manager
,plugin
,這3個部分是分別發佈版本的。而其餘沒有全動態設計的插件框架只有host
和plugin
兩部分。這些部分之間的版本關係都是多對多的關係,因此版本管理變得更復雜了。這部分版本的管理,在咱們的實現中是一個依賴於騰訊內部後臺框架的後臺服務,所以沒能在此次開源中帶出來。Shadow開源的代碼目前是沒有包括插件下載和版本檢查實現的。manager只實現了下載插件以後的安裝邏輯,也包括升級功能。代理
咱們的業務開發模式實際上是不要求對SDK進行測試的,咱們有強大的測試團隊會對業務功能進行嚴格測試。這能夠保證Shadow就算有Bug也不會出如今咱們現有業務的場景中。可是咱們也知道其實插件框架中的實現不少都是很是相關的,對插件框架中一處小小的改動,確實可能會影響不少看似不相關的功能。因此自動化測試對於插件框架來講實際上是很重要的,這咱們有意識。因此,即使是咱們見過的其餘插件框架都沒有配套的自動化測試,咱們仍是堅持作了自動化測試。惋惜的是因爲人力有限,用例還很是少。咱們儘可能但願將來作出的改動都配套實現自動化測試。版本控制
咱們的業務中對Shadow的應用實際上覆雜程度遠超Sample。咱們的一個業務其實是由多個插件包構成的,這些插件包之間存在依賴關係,不光有類依賴,還有資源依賴。經過一個複雜的manager實現,讓業務邏輯能夠通知manager在須要的時候才下載一些功能插件,作到插件的懶加載。調試
這些多插件相關的功能已經在開源的Shadow代碼中支持了,可是咱們一直沒有精力再寫一個複雜的Sample演示這些功能。
實際上代碼寫了卸載插件的功能。可是咱們的業務對卸載插件需求不強烈,因此咱們更重視更新插件,而對舊插件處理很少。還有一個緣由是舊插件有可能在運行中,也不能貿然刪除。對於卸載的實現,咱們是有討論過和設計的,可是一直沒能實現和驗證。
咱們真的是頗有誠意,但願你們能知根知底的瞭解Shadow的缺點。但人本身真的很難發現本身的全部缺點。因此若是你們認爲Shadow還有什麼缺點,歡迎你們提Issue,咱們共同改進。