如何使用 "adb shell dumpsys activity" 获取片段的全名

How to get the full name of fragments using "adb shell dumpsys activity"

出于测试目的,我使用adb shell dumpsys activity <activity_name>将碎片的信息转储到前台activity。

问题是转储的片段名称只包含 class 名称而不是其全名(全名表示包名称 + class 名称)。例如,如果片段的全名是 aaa.bbb.ccc.MyFragment,则转储的片段名称将是 MyFragment.

如果应用没有被混淆,这不是一个严重的问题。然而,当一个应用程序被混淆时,转储的片段名称将大多像一个单一的字符(例如,abc、...)。因此,很难仅通过转储名称来区分两个不同的片段。

为什么 Android OS 选择只转储 class 名称?倾销全名有哪些难点? adb 用户是否可以执行任何其他选项来在运行时获取片段的全名?

根据 Android 来源,片段的 toString() 使用 DebugUtils.buildShortClassTag() 打印 class 名称。

Fragment.java

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder(128);
        DebugUtils.buildShortClassTag(this, sb);
        if (mIndex >= 0) {
            sb.append(" #");
            sb.append(mIndex);
        }
        if (mFragmentId != 0) {
            sb.append(" id=0x");
            sb.append(Integer.toHexString(mFragmentId));
        }
        if (mTag != null) {
            sb.append(" ");
            sb.append(mTag);
        }
        sb.append('}');
        return sb.toString();
    }

DebugUtils.java

    public static void buildShortClassTag(Object cls, StringBuilder out) {
        if (cls == null) {
            out.append("null");
        } else {
            String simpleName = cls.getClass().getSimpleName();
            if (simpleName == null || simpleName.isEmpty()) {
                simpleName = cls.getClass().getName();
                int end = simpleName.lastIndexOf('.');
                if (end > 0) {
                    simpleName = simpleName.substring(end+1);
                }
            }
            out.append(simpleName);
            out.append('{');
            out.append(Integer.toHexString(System.identityHashCode(cls)));
        }
    }

我们可以看到 buildShortClassTag() 使用 cls.getClass().getSimpleName() 来打印 class 名称。

总之,除非我们更改Android框架的源代码并构建自定义的OS,否则我们无法获得片段的全名。但是这个解决方案并不完美,因为 AndroidX 中的片段有自己的逻辑来打印片段信息。 AndroidX 库被打包在一个 apk 中,它们也被混淆了。