如何使用 "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
.
如果应用没有被混淆,这不是一个严重的问题。然而,当一个应用程序被混淆时,转储的片段名称将大多像一个单一的字符(例如,a
、b
、c
、...)。因此,很难仅通过转储名称来区分两个不同的片段。
为什么 Android OS 选择只转储 class 名称?倾销全名有哪些难点? adb 用户是否可以执行任何其他选项来在运行时获取片段的全名?
根据 Android 来源,片段的 toString()
使用 DebugUtils.buildShortClassTag()
打印 class 名称。
@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();
}
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 中,它们也被混淆了。
出于测试目的,我使用adb shell dumpsys activity <activity_name>
将碎片的信息转储到前台activity。
问题是转储的片段名称只包含 class 名称而不是其全名(全名表示包名称 + class 名称)。例如,如果片段的全名是 aaa.bbb.ccc.MyFragment
,则转储的片段名称将是 MyFragment
.
如果应用没有被混淆,这不是一个严重的问题。然而,当一个应用程序被混淆时,转储的片段名称将大多像一个单一的字符(例如,a
、b
、c
、...)。因此,很难仅通过转储名称来区分两个不同的片段。
为什么 Android OS 选择只转储 class 名称?倾销全名有哪些难点? adb 用户是否可以执行任何其他选项来在运行时获取片段的全名?
根据 Android 来源,片段的 toString()
使用 DebugUtils.buildShortClassTag()
打印 class 名称。
@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();
}
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 中,它们也被混淆了。