【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码

一、需求描述

最近在研究滴滴公司开源的booster框架的源码,地址:https://github.com/didi/booster

但是会有些以为,里面的代码是怎么写出来的? 有些代码确实有点看不懂,比如下面的

  • https://github.com/didi/booster/blob/master/booster-transform-toast/src/main/kotlin/com/didiglobal/booster/transform/toast/ToastTransformer.kt
    【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第1张图片
    上面这句代码
it.desc == "()V"

到底是怎么写出来的?

L$SHADOW_TOAST;)V

为什么要这么拼成 Landroid/widget/Toast???

这些人写代码的时候,难道是一个一个手动敲的?不会敲错吗?

我想这些这些使用asm操作java字节码的操作,肯定是能够看到java字节码,才把部分逻辑写完的。那么如何查看java字节码呢??

通过网上查询了几篇博客,大概了解了可以使用ASM Bytecode Outline插件来查看java字节码。

  • 【美团技术团队 Java字节码增强探秘】

【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第2张图片

二、如何使用ASM Bytecode Outline插件?

2.1 先下载ASM Bytecode Outline插件

  • 下载地址(https://plugins.jetbrains.com/plugin/5918-asm-bytecode-outline)

【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第3张图片
【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第4张图片
点击【Get】 进入下载版本页面 https://plugins.jetbrains.com/plugin/5918-asm-bytecode-outline/versions

【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第5张图片
选择最新的0.3.5版本,点击【Download】下载下来
在这里插入图片描述

2.2 安装ASM Bytecode Outline插件

【Settings】–>【Plugins】
【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第6张图片
点击右上角图标,选择【Install Plugn from Disk】
【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第7张图片
选择刚下好的 asm-bo-0.3.5.zip 点击 【OK】 即可安装
【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第8张图片
安装好了,点击【Restart IDE】 生效
【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第9张图片

三、如何使用ASM Bytecode Outline插件

重启Android Studio之后,就会有ASM的标志,如下所示
【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第10张图片

点击即可展开
【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第11张图片

选择一个java文件,查看其java字节码 ,如下所示

进入java文件编辑区域,鼠标右键弹出菜单项,选择【Show Bytecode outline】
【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第12张图片
然后后面的ASM框就会显示内容,如下所示

【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第13张图片
SizeConvertUtil.java 源代码如下所示

package com.xtc.common.util;

import android.content.Context;

/**
 * 尺寸转换工具
 * 

* Created by ouyangpeng on 2015/9/21. */ public class SizeConvertUtil { /** * 根据手机的分辨率从 dp 的单位 转成为 px(像素) * * @param context 上下文 * @param dp dp的值 * @return px的值 */ public static int dpToPx(Context context, float dp) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (dp * scale + 0.5f); } /** * 根据手机的分辨率从 px(像素) 的单位 转成为 dp * * @param context 上下文 * @param px px的值 * @return dp的值 */ public static int pxToDp(Context context, float px) { final float scale = context.getResources().getDisplayMetrics().density; return (int) (px / scale + 0.5f); } /** * 将px值转换为sp值,保证文字大小不变 * * @param context 上下文 * @param px px的值 * @return sp的值 */ public static int pxToSp(Context context, float px) { //DisplayMetrics类中属性scaledDensity final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (px / fontScale + 0.5f); } /** * 将sp值转换为px值,保证文字大小不变 * * @param context 上下文 * @param sp sp的值 * @return px的值 */ public static int spToPx(Context context, float sp) { //DisplayMetrics类中属性scaledDensity final float fontScale = context.getResources().getDisplayMetrics().scaledDensity; return (int) (sp * fontScale + 0.5f); } }

  • 对应的字节码如下所示【Bytecode面板内容】
// class version 51.0 (51)
// access flags 0x21
public class com/xtc/common/util/SizeConvertUtil {

  // compiled from: SizeConvertUtil.java

  // access flags 0x1
  public ()V
   L0
    LINENUMBER 10 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object. ()V
    RETURN
   L1
    LOCALVARIABLE this Lcom/xtc/common/util/SizeConvertUtil; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static dpToPx(Landroid/content/Context;F)I
   L0
    LINENUMBER 19 L0
    ALOAD 0
    INVOKEVIRTUAL android/content/Context.getResources ()Landroid/content/res/Resources;
    INVOKEVIRTUAL android/content/res/Resources.getDisplayMetrics ()Landroid/util/DisplayMetrics;
    GETFIELD android/util/DisplayMetrics.density : F
    FSTORE 2
   L1
    LINENUMBER 20 L1
    FLOAD 1
    FLOAD 2
    FMUL
    LDC 0.5
    FADD
    F2I
    IRETURN
   L2
    LOCALVARIABLE context Landroid/content/Context; L0 L2 0
    LOCALVARIABLE dp F L0 L2 1
    LOCALVARIABLE scale F L1 L2 2
    MAXSTACK = 2
    MAXLOCALS = 3

  // access flags 0x9
  public static pxToDp(Landroid/content/Context;F)I
   L0
    LINENUMBER 31 L0
    ALOAD 0
    INVOKEVIRTUAL android/content/Context.getResources ()Landroid/content/res/Resources;
    INVOKEVIRTUAL android/content/res/Resources.getDisplayMetrics ()Landroid/util/DisplayMetrics;
    GETFIELD android/util/DisplayMetrics.density : F
    FSTORE 2
   L1
    LINENUMBER 32 L1
    FLOAD 1
    FLOAD 2
    FDIV
    LDC 0.5
    FADD
    F2I
    IRETURN
   L2
    LOCALVARIABLE context Landroid/content/Context; L0 L2 0
    LOCALVARIABLE px F L0 L2 1
    LOCALVARIABLE scale F L1 L2 2
    MAXSTACK = 2
    MAXLOCALS = 3

  // access flags 0x9
  public static pxToSp(Landroid/content/Context;F)I
   L0
    LINENUMBER 44 L0
    ALOAD 0
    INVOKEVIRTUAL android/content/Context.getResources ()Landroid/content/res/Resources;
    INVOKEVIRTUAL android/content/res/Resources.getDisplayMetrics ()Landroid/util/DisplayMetrics;
    GETFIELD android/util/DisplayMetrics.scaledDensity : F
    FSTORE 2
   L1
    LINENUMBER 45 L1
    FLOAD 1
    FLOAD 2
    FDIV
    LDC 0.5
    FADD
    F2I
    IRETURN
   L2
    LOCALVARIABLE context Landroid/content/Context; L0 L2 0
    LOCALVARIABLE px F L0 L2 1
    LOCALVARIABLE fontScale F L1 L2 2
    MAXSTACK = 2
    MAXLOCALS = 3

  // access flags 0x9
  public static spToPx(Landroid/content/Context;F)I
   L0
    LINENUMBER 57 L0
    ALOAD 0
    INVOKEVIRTUAL android/content/Context.getResources ()Landroid/content/res/Resources;
    INVOKEVIRTUAL android/content/res/Resources.getDisplayMetrics ()Landroid/util/DisplayMetrics;
    GETFIELD android/util/DisplayMetrics.scaledDensity : F
    FSTORE 2
   L1
    LINENUMBER 58 L1
    FLOAD 1
    FLOAD 2
    FMUL
    LDC 0.5
    FADD
    F2I
    IRETURN
   L2
    LOCALVARIABLE context Landroid/content/Context; L0 L2 0
    LOCALVARIABLE sp F L0 L2 1
    LOCALVARIABLE fontScale F L1 L2 2
    MAXSTACK = 2
    MAXLOCALS = 3
}

  • 【ASMified面板内容】
    【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第14张图片
package asm.com.xtc.common.util;

import java.util.*;

import org.objectweb.asm.*;

public class SizeConvertUtilDump implements Opcodes {

    public static byte[] dump() throws Exception {

        ClassWriter cw = new ClassWriter(0);
        FieldVisitor fv;
        MethodVisitor mv;
        AnnotationVisitor av0;

        cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "com/xtc/common/util/SizeConvertUtil", null, "java/lang/Object", null);

        cw.visitSource("SizeConvertUtil.java", null);

        {
            mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(10, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "", "()V", false);
            mv.visitInsn(RETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "Lcom/xtc/common/util/SizeConvertUtil;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "dpToPx", "(Landroid/content/Context;F)I", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(19, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, "android/content/Context", "getResources", "()Landroid/content/res/Resources;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "android/content/res/Resources", "getDisplayMetrics", "()Landroid/util/DisplayMetrics;", false);
            mv.visitFieldInsn(GETFIELD, "android/util/DisplayMetrics", "density", "F");
            mv.visitVarInsn(FSTORE, 2);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(20, l1);
            mv.visitVarInsn(FLOAD, 1);
            mv.visitVarInsn(FLOAD, 2);
            mv.visitInsn(FMUL);
            mv.visitLdcInsn(new Float("0.5"));
            mv.visitInsn(FADD);
            mv.visitInsn(F2I);
            mv.visitInsn(IRETURN);
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLocalVariable("context", "Landroid/content/Context;", null, l0, l2, 0);
            mv.visitLocalVariable("dp", "F", null, l0, l2, 1);
            mv.visitLocalVariable("scale", "F", null, l1, l2, 2);
            mv.visitMaxs(2, 3);
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "pxToDp", "(Landroid/content/Context;F)I", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(31, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, "android/content/Context", "getResources", "()Landroid/content/res/Resources;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "android/content/res/Resources", "getDisplayMetrics", "()Landroid/util/DisplayMetrics;", false);
            mv.visitFieldInsn(GETFIELD, "android/util/DisplayMetrics", "density", "F");
            mv.visitVarInsn(FSTORE, 2);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(32, l1);
            mv.visitVarInsn(FLOAD, 1);
            mv.visitVarInsn(FLOAD, 2);
            mv.visitInsn(FDIV);
            mv.visitLdcInsn(new Float("0.5"));
            mv.visitInsn(FADD);
            mv.visitInsn(F2I);
            mv.visitInsn(IRETURN);
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLocalVariable("context", "Landroid/content/Context;", null, l0, l2, 0);
            mv.visitLocalVariable("px", "F", null, l0, l2, 1);
            mv.visitLocalVariable("scale", "F", null, l1, l2, 2);
            mv.visitMaxs(2, 3);
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "pxToSp", "(Landroid/content/Context;F)I", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(44, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, "android/content/Context", "getResources", "()Landroid/content/res/Resources;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "android/content/res/Resources", "getDisplayMetrics", "()Landroid/util/DisplayMetrics;", false);
            mv.visitFieldInsn(GETFIELD, "android/util/DisplayMetrics", "scaledDensity", "F");
            mv.visitVarInsn(FSTORE, 2);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(45, l1);
            mv.visitVarInsn(FLOAD, 1);
            mv.visitVarInsn(FLOAD, 2);
            mv.visitInsn(FDIV);
            mv.visitLdcInsn(new Float("0.5"));
            mv.visitInsn(FADD);
            mv.visitInsn(F2I);
            mv.visitInsn(IRETURN);
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLocalVariable("context", "Landroid/content/Context;", null, l0, l2, 0);
            mv.visitLocalVariable("px", "F", null, l0, l2, 1);
            mv.visitLocalVariable("fontScale", "F", null, l1, l2, 2);
            mv.visitMaxs(2, 3);
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "spToPx", "(Landroid/content/Context;F)I", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(57, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, "android/content/Context", "getResources", "()Landroid/content/res/Resources;", false);
            mv.visitMethodInsn(INVOKEVIRTUAL, "android/content/res/Resources", "getDisplayMetrics", "()Landroid/util/DisplayMetrics;", false);
            mv.visitFieldInsn(GETFIELD, "android/util/DisplayMetrics", "scaledDensity", "F");
            mv.visitVarInsn(FSTORE, 2);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(58, l1);
            mv.visitVarInsn(FLOAD, 1);
            mv.visitVarInsn(FLOAD, 2);
            mv.visitInsn(FMUL);
            mv.visitLdcInsn(new Float("0.5"));
            mv.visitInsn(FADD);
            mv.visitInsn(F2I);
            mv.visitInsn(IRETURN);
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLocalVariable("context", "Landroid/content/Context;", null, l0, l2, 0);
            mv.visitLocalVariable("sp", "F", null, l0, l2, 1);
            mv.visitLocalVariable("fontScale", "F", null, l1, l2, 2);
            mv.visitMaxs(2, 3);
            mv.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }
}

  • 【Groovified面板内容】

【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第15张图片

// class version 51.0 (51)
// access flags 0x21
public class com/xtc/common/util/SizeConvertUtil {


  @groovyx.ast.bytecode.Bytecode
  public void () {
    aload 0
    INVOKESPECIAL java/lang/Object. ()V
    return
  }

  @groovyx.ast.bytecode.Bytecode
  public static int dpToPx(android.content.Context a,float b) {
    aload 0
    INVOKEVIRTUAL android/content/Context.getResources ()Landroid/content/res/Resources;
    INVOKEVIRTUAL android/content/res/Resources.getDisplayMetrics ()Landroid/util/DisplayMetrics;
    getfield 'android/util/DisplayMetrics.density','F'
    fstore 2
    fload 1
    fload 2
    fmul
    ldc 0.5f
    fadd
    f2i
    ireturn
  }

  @groovyx.ast.bytecode.Bytecode
  public static int pxToDp(android.content.Context a,float b) {
    aload 0
    INVOKEVIRTUAL android/content/Context.getResources ()Landroid/content/res/Resources;
    INVOKEVIRTUAL android/content/res/Resources.getDisplayMetrics ()Landroid/util/DisplayMetrics;
    getfield 'android/util/DisplayMetrics.density','F'
    fstore 2
    fload 1
    fload 2
    fdiv
    ldc 0.5f
    fadd
    f2i
    ireturn
  }

  @groovyx.ast.bytecode.Bytecode
  public static int pxToSp(android.content.Context a,float b) {
    aload 0
    INVOKEVIRTUAL android/content/Context.getResources ()Landroid/content/res/Resources;
    INVOKEVIRTUAL android/content/res/Resources.getDisplayMetrics ()Landroid/util/DisplayMetrics;
    getfield 'android/util/DisplayMetrics.scaledDensity','F'
    fstore 2
    fload 1
    fload 2
    fdiv
    ldc 0.5f
    fadd
    f2i
    ireturn
  }

  @groovyx.ast.bytecode.Bytecode
  public static int spToPx(android.content.Context a,float b) {
    aload 0
    INVOKEVIRTUAL android/content/Context.getResources ()Landroid/content/res/Resources;
    INVOKEVIRTUAL android/content/res/Resources.getDisplayMetrics ()Landroid/util/DisplayMetrics;
    getfield 'android/util/DisplayMetrics.scaledDensity','F'
    fstore 2
    fload 1
    fload 2
    fmul
    ldc 0.5f
    fadd
    f2i
    ireturn
  }
}

从上面的ASM Bytecode Outline 插件我们就可以看到对应的字节码了,对比源文件,大概能够看懂一些些了。

【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第16张图片

四、参考资料

具体关于字节码的相关知识点,请参考下面的链接

  • 【美团技术团队 Java字节码增强探秘】
  • 【Android Transform + ASM 初探】
  • 【Android中Gradle插件和Transform】

作者:欧阳鹏 欢迎转载,与人分享是进步的源泉!
转载请保留原文地址:https://blog.csdn.net/qq446282412/article/details/100566678
☞ 本人QQ: 3024665621
☞ QQ交流群: 123133153
☞ github.com/ouyangpeng
[email protected]


【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第17张图片

【我的Android进阶之旅】Android Studio 使用 ASM Bytecode Outline 插件来研究Java字节码_第18张图片

你可能感兴趣的:(Android应用开发)