當 App 達到必定體量的時候,確定是要考慮質量優化。有些小問題,看似只有 0.01% 觸發率,可是若是發生在 DAU 過千萬的產品中,就很嚴重了。java
滴滴這個獨角獸的 DAU 早已過千萬,天然有一些獨到的優化方案。最近滴滴在 Github 上開源了一個 Android App 的質量優化工具 Booster,經過動態發現和加載機制,提供了可擴展的能力。等因而一款移動應用的質量優化框架。android
說到優化好像也不知道具體能幹什麼。從特性上籠統來講,Booster 能夠作到性能檢測和優化、包體積瘦身、代碼注入等。git
稍微看了一下,暫時所支持的優化還比較有限,可是好 Booster 提供了很是便捷的擴展能力,咱們能夠根據業務場景,進行鍼對性的優化。github
雖然 Booster 如今的優化點還不多,可是在開源的同時,也給出了後續發展的 Roadmap,以後的功能應該是會愈來愈完善的。下面就來了解一下滴滴新開源的 Booster。shell
Booster 是專門爲移動應用而設計的簡單易用、輕量級、功能強大且可擴展的質量優化工具包,其經過動態發現和加載機制,提供了可擴展的能力。是一款移動應用的質量優化框架。性能優化
Booster 主要由 Transformer 和 Task 組成。多線程
Transformer 用於對字節碼進行掃描或修改(取決於 Transformer 的功能),而 Task 則用於處理構建中的資源。框架
爲了知足不一樣業務場景下的優化需求,Booster 提供了 Transformer SPI 和 VariantProcessor SPI 接口,來容許開發者進行定製。ide
Booster 的總體框架以下:工具
Booster 對 Gradle 還有一些小的版本要求:
讀了一遍官方的概念,好像仍是不知道 Booster 的用處,這裏就以 Booster 已經支持的一個 Transformer 爲例子,來說解它到底能幹什麼。
Toast 是咱們在平常開發中常常會用到的一個提示信息的組件,而在 Android 7.0 的系統中,它有可能會觸發 BadTokenException 的異常。這個問題,用 Booster 就能夠解決。
Toast 拋 BadTokenException 看起來是在顯示的時候,窗口的 Token 已經失效了,也有可能在顯示 Toast 的時候,窗口已經被銷燬了。
android.view.WindowManager$BadTokenException: at android.view.ViewRootImpl.setView(ViewRootImpl.java) at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java) at android.view.WindowManagerImpl.addView(WindowManagerImpl.java4) at android.widget.Toast$TN.handleShow(Toast.java)
這個問題只出如今 Android 7.0 中,在以後的版本中,爲了解決這個問題,是直接將其 Catch 住這個異常來解決問題的。下面是 Android 8.0 的相關代碼。
try { mWM.addView(mView, mParams); trySendAccessibilityEvent(); } catch (WindowManager.BadTokenException e) { /* ignore */ }
雖然這個問題已經有了一些解決方案,可是 Booster 給了咱們另一個選擇。
在 Booster 中,已經內置了一些 Transformers,其中就有一個 booster-transform-bugfix-toast,是用於修復 Android 7.0 中,Toast 致使的系統錯誤。
ToastBugfixTransformer 的主要源碼在此:
@AutoService(ClassTransformer::class) class ToastBugfixTransformer : ClassTransformer { override fun transform(context: TransformContext, klass: ClassNode): ClassNode { klass.methods.forEach { method -> method.instructions?.iterator()?.asIterable()?.filterIsInstance(MethodInsnNode::class.java)?.filter { it.owner == TOAST && it.name == "show" && it.desc == "()V" }?.forEach { it.owner = `TOAST'` it.desc = "(L$TOAST;)V" it.opcode = Opcodes.INVOKESTATIC } } return klass } } private const val TOAST = "android/widget/Toast" private const val `TOAST'` = "com/didiglobal/booster/$TOAST"
它是將系統的 Toast 傳遞到另外定製的一個 com.didiglobal.booster.android.widget 包下的 Toast 來解決。
public static void show(final android.widget.Toast toast) { if (Build.VERSION.SDK_INT == 25) { workaround(toast).show(); } else { toast.show(); } } private static android.widget.Toast workaround(final android.widget.Toast toast) { final Object tn = getFieldValue(toast, "mTN"); if (null == tn) { Log.w(TAG, "Field mTN of " + toast + " is null"); return toast; } final Object handler = getFieldValue(tn, "mHandler"); if (handler instanceof Handler) { if (setFieldValue(handler, "mCallback", new CaughtCallback((Handler) handler))) { return toast; } } final Object show = getFieldValue(tn, "mShow"); if (show instanceof Runnable) { if (setFieldValue(tn, "mShow", new CaughtRunnable((Runnable) show))) { return toast; } } Log.w(TAG, "Neither field mHandler nor mShow of " + tn + " is accessible"); return toast; }
當 API Level 不爲 25 時,直接調用 Toast.show()
方法,爲 25 時,經過反射來判斷當前 Toast 的狀況,進而返回一個有效的 Toast 對象,再調用 show()
。
到這裏就將 Toast 在 7.0 上的問題修復了,咱們正常開發過程當中,徹底不須要擔憂 Toast 的使用,作質量保證的和作業務的也能夠區分開了。
在 Booster 開源的時候,內部已經內置了一些 Transformer 和 Task,前面介紹的 booster-transform-bugfix-toast 就是其中之一。
內置 Transformers
內置 Tasks
這些 Booster 提供的 Transformer 和 Task,功能還有限,它們更多的是提供一些指導意義,可讓咱們經過源碼瞭解到 Booster 的使用。
有更多想法,能夠本身去實現 Transformer 和 Task。
在發佈的 Roadmap 中,已經提出接下來幾個版本的迭代計劃,例如會專一:性能優化、Lint、資源壓縮、用戶體驗等等。在性能優化上,會對多線程的使用、SP 的使用、WebView 的預加載進行鍼對性的優化。
總體來看,Booster 是一個很是好的性能優化框架,它使用的都是成熟的技術,將其包裝而成,下降了咱們使用的難度。並無什麼太大的深坑,有須要能夠進行嘗試。
更多內容能夠去 Github 上閱讀 Wiki 和源碼,有興趣別忘點個 star。
Github:https://github.com/didi/booster
本文對你有幫助嗎?留言、點贊、轉發是最大的支持,謝謝!
公衆號後臺回覆成長『 成長』,將會獲得我準備的學習資料,也能回覆『 加羣』,一塊兒學習進步;你還能回覆『 提問』,向我發起提問。