滴滴 App 质量优化黑科技,大家都能用!

一. 序

当 App 达到一定体量的时候,肯定是要考虑质量优化。有些小问题,看似只有 0.01% 触发率,但是如果发生在 DAU 过千万的产品中,就很严重了。

滴滴这个独角兽的 DAU 早已过千万,自然有一些独到的优化方案。最近滴滴在 Github 上开源了一个 Android App 的质量优化工具 Booster,通过动态发现和加载机制,提供了可扩展的能力。等于是一款移动应用的质量优化框架。

说到优化好像也不知道具体能干什么。从特性上笼统来说,Booster 可以做到性能检测和优化、包体积瘦身、代码注入等。

稍微看了一下,暂时所支持的优化还比较有限,但是好 Booster 提供了非常便捷的扩展能力,我们可以根据业务场景,进行针对性的优化。

虽然 Booster 现在的优化点还很少,但是在开源的同时,也给出了后续发展的 Roadmap,之后的功能应该是会越来越完善的。下面就来了解一下滴滴新开源的 Booster。

二. Booster

2.1 什么是 Booster

Booster 是专门为移动应用而设计的简单易用、轻量级、功能强大且可扩展的质量优化工具包,其通过动态发现和加载机制,提供了可扩展的能力。是一款移动应用的质量优化框架。

Booster 主要由 Transformer 和 Task 组成。

Transformer 用于对字节码进行扫描或修改(取决于 Transformer 的功能),而 Task 则用于处理构建中的资源。

为了满足不同业务场景下的优化需求,Booster 提供了 Transformer SPI 和 VariantProcessor SPI 接口,来允许开发者进行定制。

Booster 的整体框架如下:

Booster 对 Gradle 还有一些小的版本要求:

  • Gradle 4.1 以上版本
  • Android Gradle 插件 3.0 以上版本
  • 2.2 Booster 到底能干什么?

    读了一遍官方的概念,好像还是不知道 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 */}

    这种问题,在我们自己的代码中,可以通过定义一个统一的 Toast 帮助类。老项目我们就要全文遍历一遍 Toast 的调用并替换,并且这样的方案也有缺陷,无法避免来自第三方库中使用的 Toast 出现此问题。

    虽然这个问题已经有解决方案,但是 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 的使用,做质量保证的和做业务的也可以区分开了。

    2.3 Booster 已经内置的功能

    在 Booster 开源的时候,内部已经内置了一些 Transformer 和 Task,前面介绍的
    booster-transform-bugfix-toast 就是其中之一。

    内置 Transformers

  • booster-transform-bugfix-toast:修复 7.0 中 Toast 导致的系统错误。
  • booster-transform-lint:检查潜在的性能问题。
  • booster-transform-shrink:用于清除 class 文件中的常量。
  • booster-transform-usage:用于扫描特定 API 的使用情况。
  • 内置 Tasks

  • Booster-task-artifact:提供显示 artifact 的 Task。
  • Booster-task-dependency:提供显示所有依赖项的标识符以及文件路径的 Task。
  • Booster-task-permission:提供显示所有依赖项使用的 Android 权限。
  • 这些 Booster 提供的 Transformer 和 Task,功能还有限,它们更多的是提供一些指导意义,可以让我们通过源码了解到 Booster 的使用。

    有更多想法,可以自己去实现 Transformer 和 Task。

    在发布的 Roadmap 中,已经提出接下来几个版本的迭代计划,例如会专注:性能优化、Lint、资源压缩、用户体验等等。在性能优化上,会对多线程的使用、SP 的使用、WebView 的预加载进行针对性的优化。

    三. 小结时刻

    整体来看,Booster 是一个非常好的性能优化框架,它使用的都是成熟的技术,将其包装而成,降低了我们使用的难度。并没有什么太大的深坑,有需要可以进行尝试。

    更多内容可以去 Github 上阅读 Wiki 和源码,有兴趣别忘点个 star。


    在头条 私信我。我会送你一些我整理的学习资料,包含:Android反编译、算法、设计模式、虚拟机、Linux、Kotlin、Python、爬虫、Web项目源码。

    声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!

    上一篇 2019年3月20日
    下一篇 2019年3月20日

    相关推荐