滴滴 App 质量优化黑科技,都做了什么

栏目: Android · 发布时间: 5年前

内容简介:每天 14.00 在看 | 真爱作者: 承香墨影 | 来源:公众号 承香墨影

点击上方“ 开发者技术前线 ”,选择“星标”

每天 14.00 在看 | 真爱

作者: 承香墨影 | 来源:公众号 承香墨影

一. 序

当 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 的整体框架如下:

滴滴 App 质量优化黑科技,都做了什么

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 中,在之后的版本中,Google 的工程师为了解决这个问题,是直接将其 Catch 住这个异常来解决问题的。下面是 Android 8.0 的相关代码。

try {
    mWM.addView(mView, mParams);
    trySendAccessibilityEvent();
} catch (WindowManager.BadTokenException e) {
    /* ignore */
}

这种问题,在我们自己的代码中,可以通过定义一个统一的 Toast 帮助类,将其 方法 catch 住。老项目我们就要全文遍历一遍 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。

三. 小结时刻

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

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

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

Github:https://github.com/didi/booster

不错就点个在看吧!


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Lighttpd

Lighttpd

Andre Bogus / Packt Publishing / 2008-10 / 39.99

This is your fast guide to getting started and getting inside the Lighttpd web server. Written from a developer's perspective, this book helps you understand Lighttpd, and get it set up as securely an......一起来看看 《Lighttpd》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具