[譯] Android Studio Project Marble: Apply Changes

深刻探討 Android Studio 團隊如何構建 Instant Run 的後繼者 —— Apply Changes。

Android Studio 團隊有一系列深刻探討 Project Marble 細節和幕後狀況的文章,本文是其中的第一篇。從發佈 Android Studio 3.3 開始,Project Marble 就致力於保證 IDE 基本功能的穩定性和流暢度。這篇文章是由 Apply Changes 團隊的 Jon Tsao(產品經理),Esteban de la Canal(技術負責人),Fabien Sanglard(工程師)和 Alan Leung(工程師)共同完成。html

Android Studio 的一個主要目標是爲你的 app 提供快速的代碼編輯和驗證工具。當咱們建立 Instant Run 的時候,咱們但願它可以明顯加速你的開發流程,可是如今看來它並無達到預期目標。做爲 Project Marble 的一部分,咱們一直在從新思考 Instant Run,並提出了一個更實用的替代方案 Apply Changes。Apply Changes 做爲一個能夠加快開發流程的新方法,最初在 Android Studio 3.5 的 Canary Channel 發佈預覽。在這篇文章中,咱們想深刻聊聊它是如何工做的,以及迄今爲止咱們的工做。前端

Instant Run

經過 Instant Run,咱們想解決兩個問題:1)節省構建和部署應用程序到設備上的時間,2)使應用程序在不丟失運行狀態的狀況下部署更改。爲了在 Instant Run 中作到這一點,咱們在構建的時候重寫你的 APK 來注入鉤子,以便在運行的時候進行類的替換。要更詳細的瞭解 Instant Run 背後的架構,能夠參考幾年前 Medium 上的這篇文章android

對於簡單的 app,這個方案通常都表現很好,可是對於更復雜的 app 來講,它可能會使構建時間變長,或者會因爲 app 與 Instant Run 構建過程之間有衝突而致使使人頭疼的錯誤。隨着這些問題的出現,咱們在後續的版本中持續改進提高 Instant Run。可是,咱們沒法徹底解決這些問題,讓它符合咱們的指望。ios

咱們後退了一步,決定從頭開始構建一個新的架構,它就是 Apply Changes。和 Instant Run 不一樣,Apply Changes 不會在構建的時候修改你的 APK。取而代之,咱們用 Android 8.0(Oreo)上支持的 Runtime Instrumentation 以及更新的設備和模擬器在運行時重定義類。git

Apply Changes

對於運行在 Android 8.0 或者更新版本上的設備和虛擬機,Android Studio 如今有三個按鈕來控制應用程序重啓的程度:github

  • Run 會部署全部的改動並重啓應用程序。算法

  • Apply Changes 會嘗試應用資源和代碼的更改,並只重啓 Activity 而不是重啓應用程序。數據庫

  • Apply Code Changes 會嘗試應用代碼的更改,而不重啓任何東西。後端

一般只有方法體內部的代碼更改纔對 Apply Changes 具備兼容性。android-studio

原則

基於在 Instant Run 上的經驗和反饋,咱們採用了一些原則來指導咱們的架構設計和決策:

  1. 將構建/部署的速度和狀態丟失二者獨立開。咱們想將節省構建和部署的時間,與在不丟失運行狀態的狀況下部署更改這兩個目標分開。不論是通常的運行或者調試,或者代碼的熱替換,快速構建和部署應該是全部部署類型的目標。做爲構建 Apply Changes 的一部分,咱們發現了不少能夠優化構建和部署速度的領域,在後面的文章中,咱們會詳細介紹它們。

  2. 穩定性相當重要。即使在 100 次中這個功能以極快的速度運行了 99 次,若是你的 app 由於這個功能而崩潰了一次,而且你花半個小時來嘗試找出緣由,那麼其餘 99 次得到的收益也就所有被抵消了。因爲咱們堅持這一原則,Apply Changes 不會像 Instant Run 那樣在構建期間修改你的 APK。帶來的反作用是,在咱們進行穩定性優化的早期版本中,Apply Changes 會比 Instant Run 的平均速度稍慢,可是咱們將繼續提升構建和部署的速度。

  3. 透明。Instant Run 按鈕會自動決定是否在必要時重啓你的 app 或者 Activity,對於這樣不可預測性和行爲不一致性的反饋,咱們也考慮了進來。咱們但願在任什麼時候候你都能清楚透明的瞭解 Apply Changes 要作什麼,若是你的代碼有不兼容的修改會發生什麼。所以若是有檢測到與 Apply Changes 不兼容的修改,咱們如今會明確提示你。

架構

咱們來深刻研究下 Apply Changes 是如何工做的。在你修改 app 以後,當前設備上已經安裝或正在運行的應用程序和 Android Studio 剛剛編譯出來的應用程序是有差別的,Apply Changes 須要弄清楚如何應用這些差別。這個過程能夠分紅兩個步驟:1)弄清楚差別是什麼,2)將差別發送到設備上並應用它。

爲了快速肯定差別,Apply Changes 沒有從設備抓取完整的 APK,而是向設備發送一個快速的請求,去拉取已經安裝 APK 的對應目錄簽名。將這兩部分信息和新 APK 進行比較,Apply Changes 能夠高效地找出自上次部署以來修改過的文件列表,而不須要檢查 APK 的全部內容。須要注意的是,這個算法並不依賴於構建系統,由於差別並非與上一次構建相比較獲得的,而是與安裝到設備上的 APK 比較得來。因爲 Apply Changes 只針對 APK 之間的差別進行操做,所以它並不要求 Gradle 插件版本和 Gradle 同步。這樣,Apply Changes 能夠運行於全部的構建系統上。

在生成更改過的文件列表以後,根據所更改的內容,須要執行不一樣的操做來將這些更改應用到正在運行的 app 上,這也決定了要使這些更改生效,app 須要重啓到什麼程度:

更改 resource/asset 文件。 這種狀況下會從新安裝應用程序,但只會重啓 Activity,並獲取修改後的資源。只有修改過的資源纔會被髮送到設備上。

更改 .dex 文件。 Android 8.0 的 Android Runtime 提供了替換已加載類的字節碼的能力,只要新的字節碼不會改變內存中現有對象的佈局。這意味着要想兼容 Apply Changes,更改的代碼會有一些限制:方法名,類名,和簽名都不能更改,它們的成員變量也不能更改。

但這個機制不能在 .dex 級別,只能在類級別工做。不然,若是 .dex 文件包含成千上萬個類,即使只有一個類更改了,也須要對全部類進行替換,這樣效率過低。對於 .dex 文件,咱們比較它的內容來找出更改過的類,只替換掉它們。若是替換成功(例如,類的佈局沒有改變),爲了不正在運行和已安裝的 app 的版本不一致,會在後檯安裝 app。

更改 .dex 文件和資源文件。 這個狀況是上面兩種狀況的組合。先處理代碼的部分,若是成功了,會和新的資源一塊兒安裝。爲了加載新的資源,主 Activity 會被重啓。這是一個全作或全不作的操做,若是代碼的改變不能成功地應用,正在運行的 app 什麼都不會改變。

更改其餘東西。 這是最糟的狀況,好比 AndroidManifest.xml 或者 native .so 這些文件被更改了。在這種狀況下,是不可能不重啓應用程序來應用更改的。「Apply Changes」 和 「Apply Code Changes」這兩個操做都不會試圖去部署它,它們會告訴用戶應用程序須要重啓。

**Flow of the architecture described above**

關於架構的更多詳細信息,請收聽 Android Developers Backstage 播客的最新一集,技術負責人 Esteban de la Canal 對 Apply Changes 進行了深刻探討。

比較 .dex 文件

前一個部分解釋了 Apply Changes 須要比較並確認在設備上更改(修改/添加/刪除)了哪一個具體的類。爲了避免增長從設備獲取大量內容的開銷,它在後臺使用了 D8 的 DEX 文件分析能力來檢查 Android Studio 部署到設備上的每一個 .dex 文件的內容。根據 .dex 文件中的各個類,計算出校驗和,並臨時保存在主機的一個緩存數據庫中。經過對比新編譯的 .dex 文件和以前的 .dex 文件的校驗和,Apply Changes 能夠在很短的時間內找到更改過的類。

Delta push

如上所述,只有更改了的文件纔會被髮送到設備上,咱們稱之爲 「 delta push」。與上面提到的 DEX 文件對比相似,Apply Changes 計算已安裝的 APK 和最近構建的 APK 之間的差別,而不須要從設備獲取全部內容。此次,它只獲取壓縮文件的 Central Directory,並保守估計相應 APK 之間可能存在的差別。經過只傳輸已經改變的部分,Android Studio 傳輸的數據比完整的 APK 上傳要少不少。在大多數狀況下,總傳輸數據從幾 MiB 減小到幾 KiB。

接下來

如今能夠在 Android Studio 3.5 的 Canary release channel 中使用 Apply Changes。咱們歡迎下載最新的 Android Studio,將 Apply Changes 使用到你的項目中,並向咱們提出早期的反饋。做爲提醒,你能夠同時運行 Android Studio 的穩定版本和 canary release 版本 。若是你在使用 Apply Changes 時遇到任何問題,請提交一個 bug 並附上對應的 idea.log 文件。咱們會持續優化部署性能,修復 bug,並聽取你的建議和反饋。

若是發現譯文存在錯誤或其餘須要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可得到相應獎勵積分。文章開頭的 本文永久連接 即爲本文在 GitHub 上的 MarkDown 連接。


掘金翻譯計劃 是一個翻譯優質互聯網技術文章的社區,文章來源爲 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智能等領域,想要查看更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章
相關標籤/搜索