「RePlugin將在6月底開源,這將是咱們獻給安卓世界最好的禮物。」當咱們宣佈這一消息時,心中的激動,無以言表。是的,三年的「厚積」,現在的「薄發」,看似平凡的話,實際上卻飽含了咱們太多的激動、辛酸與淚。git
那麼今天,咱們就來詳細的和您聊一聊,這個從2014年中旬,正式在手機衛士上啓用,並即將開源的360 RePlugin,究竟能爲咱們,更爲您能帶來什麼。github
GitHub地址:https://github.com/Qihoo360/RePlugin。歡迎您爲RePlugin項目加Star、發送Pull Request,提Issue。咱們會竭盡所能回答您們的疑惑。安全
RePlugin是一套完整的、穩定的、適合全面使用的,佔坑類插件化方案。其主要優點有:框架
RePlugin的核心優點ide
RePlugin與現有插件化框架的對比組件化
在講述咱們團隊爲什麼要在2013年末,設計一套屬於本身的插件化以前,咱們先來簡單談談,有了插件化方案後,能爲咱們帶來多大的便利,它究竟解決了什麼問題。性能
如上所述,不管是對用戶,仍是對開發者而言,使用插件化框架都是大有益處的,理應作到「飛入尋常應用家」。學習
然而,在實際調查過程當中,咱們卻發現了一個和這些好處徹底不匹配的奇怪現象。到底是什麼呢?插件
雖然我事先已作好功課,然而在一次技術大會上的調查結果卻讓人大跌眼鏡——在參會的200多位安卓開發者中,僅有不足5%的比例,使用了插件化方案。超過九成的開發者,目前上沒有將插件化應用在軟件開發之中。設計
實際上,這和咱們在線下觀察到的結果基本吻合。結合以前的調查,咱們發現,有三大挑戰制約了插件化在Android開發界的普及:
然而,經過咱們多年的實踐證實,以上三大挑戰,實際上是能夠被攻克的。這也是咱們今天要爲您介紹的,360手機衛士首款Android開源項目——RePlugin。
既然這麼大膽,那麼,咱們到底是怎麼作到的呢?
前文提到,不夠穩定的主要緣由是Hook了太多。那麼市面上比較靈活的插件化框架,究竟Hook了哪些呢?
注意:這裏所說的「Hook」是指經過Java反射手段,獲取並修改與系統Server等交互的Internal API,來讓框架正常工做的行爲,如上面所列部分。正常狀況下的反射(例如反射類內部本身的字段)不屬於Hook。
看似靈活,然而下列三種狀況,將頗有可能致使插件甚至應用,完全不能工做:
基於上述的狀況,咱們團隊在2014年初,研究全新佔坑插件化框架(注意,此時DroidPlugin類方案尚未出現)時,就定了個「小目標」:讓Hook越少越好。通過一次次的研究討論,最終肯定只Hook一個點:ClassLoader,且要求「堅持到底」,全部改動都是基於此來展開。
對咱們而言,這是里程碑式的決定,即使到如今來看也是如此。
修改ClassLoader的點其實不難,如上圖所示逐步反射便可。然而須要注意的是,這個ClassLoader必定得繼承自PathClassLoader,防止Android 7.x因使用addDexPath而有問題。
除此以外,此ClassLoader所在位置也很是穩定。目前來看,從Android 2.1至今都沒有發生過位置、名稱上的變化,能夠長期使用。
關於這一點,咱們以後會有一篇文章來詳述,敬請期待。
前文提到,就目前市面上的插件化框架而言,若作的足夠穩定,則多少會失去一些靈活性。對於咱們擁有這麼多模塊的產品而言,這一樣也是不可接受的。
爲此,咱們在「堅持一個Hook點」原則的前提下,經過不斷創新,最終解決了上述問題。
咱們的核心思路,是2015年之後纔開始「老生常談」的一個詞,那就是:坑位。
固然,咱們當初設計坑位思想(恕我再強調,是2014年初)時,也毫不僅僅針對Activity,而是整個四大組件,甚至到了後期,連Theme、進程、Task-Affinity等都作到了「坑位化」,只不過實現方式各異而已。
因篇幅所限,這裏僅以經常使用的Activity來簡述。有關更詳細的內容,歡迎繼續關注咱們的《RePlugin深度剖析》系列文章。
目前市面上的完整坑位方案,Hook的地段能夠說是「各有千秋」,從AMS、Instrumentation到ContextImpl都有,並以此讓插件變得更靈活。
而咱們的方案和他們有些不一樣:除了ClassLoader是Hook的,其他一概不須要。那麼咱們到底是如何開啓一個插件的Activity呢?
簡單來講,咱們有五個核心步驟:
其中,PM.startActivity能夠由插件/宿主直接調用。若在插件內部,則能夠直接經過startActivity方法來打開,更爲方便。
固然,這只是核心思路,而每一步咱們都會作各免費催收系統軟件種邏輯處理,尤爲是「尋找坑」一節,這也是咱們的核心之一。
找坑是有很是多的注意點:
篇幅所限,之後會寫詳細介紹,敬請期待。
經過剛纔的敘述,像PM.startActivity等確實可經過一些方法,來讓插件「無成本使用」。可是,像Provider的調用(本質是IContentProvider),Service的stopSelf(是final的),以及因涉及坑位分配,而不得不需複寫相應方法的Activity等。這裏面存在兩個矛盾點:
利弊相間,使人頭疼。
針對這個問題,咱們的核心理念是:「毫不在Hook及穩定性上作任何妥協」,轉而創新性的作一套「動態編譯方案」,力圖從「編譯期」來解決這個難題。
大致而言,就是把一些咱們認爲須要開發者修改的類和方法,藉助神奇的JavaAssist來作自動化修改,這樣可節省開發者的改動成本,達到想要的效果。
一圖以蔽之:
而作到了這一點之後,你會發現,下面的「夢想」就變成了現實:
例如,有個名叫「360桌面」的應用,它想把本身變成「插件」跑起來。那麼,有了「動態編譯方案」,結合「插件類庫」和框架的支持,最終的效果是——只需改幾行Gradle,就能直接生成一個APK。這個APK:
是的,就是這麼的神奇!
固然遠不止這些。我在曾演示過一段視頻,將龐大又複雜的360桌面變成插件,運行在360手機衛士中。
試想,一個桌面插件涉及到的功能是「方方面面」的,小到TaskDesription和SO的使用,大到四大組件、Task-Affinity坑位、靜態Receiver和進程坑位的處理,都需一一兼顧。因此,要作到這一點,毫不僅僅是前面所說的那幾點就能搞定的。
固然,「讓360桌面變成插件」,還不是最有意義的。真正讓RePlugin變得更有意義的,就是拿咱們的360手機衛士來「開刀」,讓數百個——甚至說,近乎一切——的模塊,都成爲RePlugin的插件,並完美的運行起來。
前文提到,之因此「功能豐富項目專用」,主要和目前市面上的插件化方案的定位有關,以致於開發者認爲:「插件 = 免安裝」、「基礎放在主程序裏更放心」、「插件開發成本高」等。
然而,仔細分析深層緣由後發現,其實最爲核心的緣由,是插件化和相關框架(包括熱更新方案等)的「定位」不一樣。我知道的有:
那麼,咱們是這三種目標之一嗎?
顯然,都不是。那麼,咱們的目標到底是什麼?
咱們的目標只有一個:全面插件化。
也就是說,不管是UI、核心業務、合做插件、後臺服務,仍是基礎功能,均可以變成插件,並在RePlugin框架內穩定又靈活的運行起來。甚至,不只大項目能用,小項目——甚至只是個計算器——均可以使用RePlugin來提高本身的靈活性,並最終實現「插件滿天下」的神奇效果。
而這一點,則是咱們,和目前市面上大多數插件化框架的主要差別。
目前手機衛士已有的插件,能夠分爲如下幾類,供各App開發者參考:
而這樣的插件,咱們有102個。能夠想見,一旦這些插件不能用,那麼手機衛士瞬間變空殼。三年已過,回頭想一想,值得回味。
說到這兒,讓我想起了Lody(VirtualApp做者,高中大牛)在一次採訪時說過一段話:
「插件化技術的成熟程度雖然在最近幾年呈上升趨勢,可是整體而言仍然處於初、中級階段。App沙盒技術的出現就是插件化發展的創新和第一階段的產物。在將來,我相信不少插件化技術會被更多的應用,若是插件化穩定到了必定的程度,甚至能夠顛覆App開發的方式。」
這,其實也是RePlugin的終極價值,那就是——讓插件化能「飛入尋常應用家」,作到穩定、靈活、自由,大小項目兼用。
固然,在「全面插件化」甚至「全民插件化」的道路上,咱們還有太多的路要走,而如此龐大又複雜的RePlugin,是十多位研發人員共同努力的成果,且獲得了部門領導,和公司技術委員會的大力支持。我相信,RePlugin的開源,是一場新的開始