Skip to content

Commit

Permalink
Add ClassFinder(1/?)
Browse files Browse the repository at this point in the history
KyuubiRan committed Apr 12, 2024
1 parent f21e8d1 commit 5cf3989
Showing 3 changed files with 408 additions and 2 deletions.
74 changes: 74 additions & 0 deletions EzXHelper/api/EzXHelper.api
Original file line number Diff line number Diff line change
@@ -545,6 +545,79 @@ public final class com/github/kyuubiran/ezxhelper/TypesKt {
public abstract interface annotation class com/github/kyuubiran/ezxhelper/annotations/KotlinOnly : java/lang/annotation/Annotation {
}

public final class com/github/kyuubiran/ezxhelper/finders/ClassFinder : com/github/kyuubiran/ezxhelper/finders/base/BaseFinder {
public static final field Static Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder$Static;
public synthetic fun <init> (Lkotlin/sequences/Sequence;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public final fun filterHasConstructorCount (I)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasConstructorCountIn ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasConstructorCountIn (I)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasConstructorCountIn (II)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasConstructorCountIn (Lkotlin/ranges/IntRange;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static synthetic fun filterHasConstructorCountIn$default (Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;IIILjava/lang/Object;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasConstructorSignature ([Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasFieldName (Ljava/lang/String;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasFieldType (Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasFieldTypeAndCount (Ljava/lang/Class;I)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasFieldTypeAndCountIn (Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasFieldTypeAndCountIn (Ljava/lang/Class;I)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasFieldTypeAndCountIn (Ljava/lang/Class;II)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasFieldTypeAndCountIn (Ljava/lang/Class;Lkotlin/ranges/IntRange;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static synthetic fun filterHasFieldTypeAndCountIn$default (Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;Ljava/lang/Class;IIILjava/lang/Object;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasFieldTypeName (Ljava/lang/String;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasMethodName (Ljava/lang/String;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasMethodReturnType (Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterHasMethodSignature (Ljava/lang/Class;[Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterImplementInterfaces ([Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsAbstract ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsAnnotation ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsAnnotationPresent (Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsAnonymous ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsArray ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsEnum ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsFinal ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsInterface ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsLocal ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsMember ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotAbstract ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotAnnotation ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotAnnotationPresent (Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotAnonymous ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotArray ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotEnum ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotFinal ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotInterface ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotLocal ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotMember ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotPrimitive ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotPublic ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsNotSynthetic ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsPrimitive ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsPublic ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsSubclassOf (Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterIsSynthetic ()Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun filterPackage (Ljava/lang/String;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static final fun fromArray ([Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static final fun fromClassloader (Ljava/lang/ClassLoader;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static final fun fromClassloader (Ljava/lang/ClassLoader;Lkotlin/jvm/functions/Function1;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static final fun fromIterable (Ljava/lang/Iterable;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static final fun fromSequence (Lkotlin/sequences/Sequence;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public fun getName ()Ljava/lang/String;
public static final fun of (Ljava/lang/ClassLoader;[Ljava/lang/String;)V
public static final fun of ([Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
}

public final class com/github/kyuubiran/ezxhelper/finders/ClassFinder$Static {
public final fun fromArray ([Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun fromClassloader (Ljava/lang/ClassLoader;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun fromClassloader (Ljava/lang/ClassLoader;Lkotlin/jvm/functions/Function1;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static synthetic fun fromClassloader$default (Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder$Static;Ljava/lang/ClassLoader;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun fromIterable (Ljava/lang/Iterable;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun fromSequence (Lkotlin/sequences/Sequence;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public final fun of (Ljava/lang/ClassLoader;[Ljava/lang/String;)V
public final fun of ([Ljava/lang/Class;)Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder;
public static synthetic fun of$default (Lcom/github/kyuubiran/ezxhelper/finders/ClassFinder$Static;Ljava/lang/ClassLoader;[Ljava/lang/String;ILjava/lang/Object;)V
}

public final class com/github/kyuubiran/ezxhelper/finders/ConstructorFinder : com/github/kyuubiran/ezxhelper/finders/base/ExecutableFinder {
public static final field -Static Lcom/github/kyuubiran/ezxhelper/finders/ConstructorFinder$-Static;
public synthetic fun <init> (Lkotlin/sequences/Sequence;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
@@ -833,6 +906,7 @@ public final class com/github/kyuubiran/ezxhelper/misc/Utils {
public static final field INSTANCE Lcom/github/kyuubiran/ezxhelper/misc/Utils;
public static final fun findDexClassLoader (Ljava/lang/ClassLoader;Lkotlin/jvm/functions/Function1;)Ldalvik/system/BaseDexClassLoader;
public static synthetic fun findDexClassLoader$default (Ljava/lang/ClassLoader;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ldalvik/system/BaseDexClassLoader;
public static final fun getAllClassesList (Ldalvik/system/BaseDexClassLoader;)Ljava/util/List;
public static final fun getAllClassesList (Ljava/lang/ClassLoader;Lkotlin/jvm/functions/Function1;)Ljava/util/List;
public static synthetic fun getAllClassesList$default (Ljava/lang/ClassLoader;Lkotlin/jvm/functions/Function1;ILjava/lang/Object;)Ljava/util/List;
public final fun getMEMBER_MODIFIER_STRING_MAP ()Ljava/util/Map;
Original file line number Diff line number Diff line change
@@ -0,0 +1,311 @@
@file:Suppress("unused", "MemberVisibilityCanBePrivate")

package com.github.kyuubiran.ezxhelper.finders

import com.github.kyuubiran.ezxhelper.EzXHelper
import com.github.kyuubiran.ezxhelper.MemberExtensions.isAbstract
import com.github.kyuubiran.ezxhelper.MemberExtensions.isFinal
import com.github.kyuubiran.ezxhelper.MemberExtensions.isPublic
import com.github.kyuubiran.ezxhelper.finders.base.BaseFinder
import com.github.kyuubiran.ezxhelper.misc.Utils.findDexClassLoader
import com.github.kyuubiran.ezxhelper.misc.Utils.getAllClassesList
import dalvik.system.BaseDexClassLoader

class ClassFinder private constructor(seq: Sequence<Class<*>>) :
BaseFinder<Class<*>, ClassFinder>(seq) {
override val name: String
get() = "ClassFinder"

@Suppress("RemoveRedundantBackticks")
companion object `Static` {
@JvmStatic
fun fromClassloader(classLoader: ClassLoader) = ClassFinder(
classLoader.getAllClassesList().asSequence()
.map { Class.forName(it, false, classLoader) }).apply {
exceptMessageScope { ctor(this@apply, "No such class found in classloader") }
}

@JvmStatic
fun fromClassloader(
classLoader: ClassLoader,
delegator: (BaseDexClassLoader) -> BaseDexClassLoader = { cl -> cl }
): ClassFinder {
val cl = classLoader.findDexClassLoader(delegator)

return ClassFinder(
(cl?.getAllClassesList()?.asSequence() ?: emptySequence())
.map { Class.forName(it, false, cl) }).apply {
exceptMessageScope { ctor(this@apply, "No such class found in classloader") }
}
}

@JvmStatic
fun fromArray(array: Array<Class<*>>) = ClassFinder(array.asSequence()).apply {
exceptMessageScope { ctor(this@apply, "No such class found in array(size=${array.count()})") }
}

@JvmStatic
fun of(vararg array: Class<*>) = ClassFinder(array.asSequence()).apply {
exceptMessageScope { ctor(this@apply, "No such class found in array(size=${array.count()})") }
}

@JvmStatic
fun of(classLoader: ClassLoader = EzXHelper.safeClassLoader, vararg className: String) {
val classes = className.map { Class.forName(it, false, classLoader) }
ClassFinder(classes.asSequence()).apply {
exceptMessageScope { ctor(this@apply, "No such class found in array(size=${classes.count()})") }
}
}

@JvmStatic
fun fromIterable(iterable: Iterable<Class<*>>) = ClassFinder(iterable.asSequence()).apply {
exceptMessageScope { ctor(this@apply, "No such class found in iterable)") }
}

@JvmStatic
fun fromSequence(seq: Sequence<Class<*>>) = ClassFinder(seq).apply {
exceptMessageScope { ctor(this@apply, "No such class found in sequence(size=${seq.count()})") }
}
}

fun filterPackage(packageName: String) = applyThis {
sequence = sequence.filter { it.name.startsWith(packageName) }
exceptMessageScope { condition("filterPackage($packageName)") }
}

fun filterHasFieldType(type: Class<*>) = applyThis {
sequence = sequence.filter { it.fields.any { field -> field.type == type } }
exceptMessageScope { condition("filterHasFieldType(${type.name})") }
}

fun filterHasFieldTypeAndCount(type: Class<*>, count: Int) = applyThis {
sequence = sequence.filter { it.fields.count { field -> field.type == type } == count }
exceptMessageScope { condition("filterHasFieldTypeAndCount(Type=${type.name}, Cnt=$count)") }
}

@JvmOverloads
fun filterHasFieldTypeAndCountIn(type: Class<*>, min: Int = 1, max: Int = Int.MAX_VALUE) =
applyThis {
sequence = sequence.filter {
val count = it.fields.count { field -> field.type == type }
count in min..max
}
exceptMessageScope { condition("filterHasFieldTypeAndCountIn(Type=${type.name}, Min=$min, Max=$max)") }
}


fun filterHasFieldTypeAndCountIn(type: Class<*>, range: IntRange) =
applyThis {
sequence = sequence.filter {
val count = it.fields.count { field -> field.type == type }
count in range
}
exceptMessageScope { condition("filterHasFieldTypeAndCountIn(Type=${type.name}, Min=${range.first}, Max=${range.last})") }
}

fun filterHasFieldTypeName(typeName: String) = applyThis {
sequence = sequence.filter { it.fields.any { field -> field.type.name == typeName } }
exceptMessageScope { condition("filterHasFieldTypeName($typeName)") }
}

fun filterHasFieldName(fieldName: String) = applyThis {
sequence = sequence.filter { it.fields.any { field -> field.name == fieldName } }
exceptMessageScope { condition("filterHasFieldName($fieldName)") }
}

fun filterHasMethodName(methodName: String) = applyThis {
sequence = sequence.filter { it.methods.any { method -> method.name == methodName } }
exceptMessageScope { condition("filterHasMethodName($methodName)") }
}

fun filterHasMethodReturnType(returnType: Class<*>) = applyThis {
sequence = sequence.filter { it.methods.any { method -> method.returnType == returnType } }
exceptMessageScope { condition("filterHasMethodReturnType($returnType)") }
}

fun filterHasMethodSignature(returnType: Class<*>, vararg paramTypes: Class<*>) = applyThis {
sequence = sequence.filter { clazz ->
clazz.methods.any { method ->
method.returnType == returnType && method.parameterTypes.contentEquals(paramTypes)
}
}
exceptMessageScope {
condition("filterHasMethodSignature(Ret=${returnType.name}, Params=(${paramTypes.joinToString { it.name }}))")
}
}

fun filterHasConstructorSignature(vararg paramTypes: Class<*>) = applyThis {
sequence = sequence.filter { clazz ->
clazz.constructors.any { constructor -> constructor.parameterTypes.contentEquals(paramTypes) }
}
exceptMessageScope {
condition("filterHasConstructorSignature(Params=(${paramTypes.joinToString { it.name }}))")
}
}

fun filterImplementInterfaces(vararg interfaces: Class<*>) = applyThis {
sequence = sequence.filter { clazz ->
interfaces.all { interfaceClass -> interfaceClass.isAssignableFrom(clazz) }
}
exceptMessageScope {
condition("filterImplementInterfaces(${interfaces.joinToString { it.name }})")
}
}

fun filterHasConstructorCount(cnt: Int) = applyThis {
sequence = sequence.filter { clazz -> clazz.constructors.count() == cnt }
exceptMessageScope {
condition("filterHasConstructorCount($cnt)")
}
}

fun filterHasConstructorCountIn(range: IntRange) = applyThis {
sequence = sequence.filter { clazz -> clazz.constructors.count() in range }
exceptMessageScope {
condition("filterHasConstructorCountIn(Min=${range.first}, Max=${range.last})")
}
}

@JvmOverloads
fun filterHasConstructorCountIn(min: Int = 1, max: Int = Int.MAX_VALUE) = applyThis {
sequence = sequence.filter { clazz -> clazz.constructors.count() in min..max }
exceptMessageScope {
condition("filterHasConstructorCountIn(Min=$min, Max=$max)")
}
}

fun filterIsSubclassOf(superclass: Class<*>) = applyThis {
sequence = sequence.filter { superclass.isAssignableFrom(it) }
exceptMessageScope { condition("filterIsSubclassOf(${superclass.name})") }
}

fun filterIsAbstract() = applyThis {
sequence = sequence.filter { it.isAbstract }
exceptMessageScope { condition("filterIsAbstract") }
}

fun filterIsNotAbstract() = applyThis {
sequence = sequence.filter { !it.isAbstract }
exceptMessageScope { condition("filterIsNotAbstract") }
}

fun filterIsInterface() = applyThis {
sequence = sequence.filter { it.isInterface }
exceptMessageScope { condition("filterIsInterface") }
}

fun filterIsNotInterface() = applyThis {
sequence = sequence.filter { !it.isInterface }
exceptMessageScope { condition("filterIsNotInterface") }
}

fun filterIsEnum() = applyThis {
sequence = sequence.filter { it.isEnum }
exceptMessageScope { condition("filterIsEnum") }
}

fun filterIsNotEnum() = applyThis {
sequence = sequence.filter { !it.isEnum }
exceptMessageScope { condition("filterIsNotEnum") }
}

fun filterIsAnnotation() = applyThis {
sequence = sequence.filter { it.isAnnotation }
exceptMessageScope { condition("filterIsAnnotation") }
}

fun filterIsNotAnnotation() = applyThis {
sequence = sequence.filter { !it.isAnnotation }
exceptMessageScope { condition("filterIsNotAnnotation") }
}

fun filterIsPublic() = applyThis {
sequence = sequence.filter { it.isPublic }
exceptMessageScope { condition("filterIsPublic") }
}

fun filterIsNotPublic() = applyThis {
sequence = sequence.filter { !it.isPublic }
exceptMessageScope { condition("filterIsNotPublic") }
}

fun filterIsFinal() = applyThis {
sequence = sequence.filter { it.isFinal }
exceptMessageScope { condition("filterIsFinal") }
}

fun filterIsNotFinal() = applyThis {
sequence = sequence.filter { !it.isFinal }
exceptMessageScope { condition("filterIsNotFinal") }
}

fun filterIsSynthetic() = applyThis {
sequence = sequence.filter { it.isSynthetic }
exceptMessageScope { condition("filterIsSynthetic") }
}

fun filterIsNotSynthetic() = applyThis {
sequence = sequence.filter { !it.isSynthetic }
exceptMessageScope { condition("filterIsNotSynthetic") }
}

fun filterIsAnonymous() = applyThis {
sequence = sequence.filter { it.isAnonymousClass }
exceptMessageScope { condition("filterIsAnonymous") }
}

fun filterIsNotAnonymous() = applyThis {
sequence = sequence.filter { !it.isAnonymousClass }
exceptMessageScope { condition("filterIsNotAnonymous") }
}

fun filterIsLocal() = applyThis {
sequence = sequence.filter { it.isLocalClass }
exceptMessageScope { condition("filterIsLocal") }
}

fun filterIsNotLocal() = applyThis {
sequence = sequence.filter { !it.isLocalClass }
exceptMessageScope { condition("filterIsNotLocal") }
}

fun filterIsMember() = applyThis {
sequence = sequence.filter { it.isMemberClass }
exceptMessageScope { condition("filterIsMember") }
}

fun filterIsNotMember() = applyThis {
sequence = sequence.filter { !it.isMemberClass }
exceptMessageScope { condition("filterIsNotMember") }
}

fun filterIsPrimitive() = applyThis {
sequence = sequence.filter { it.isPrimitive }
exceptMessageScope { condition("filterIsPrimitive") }
}

fun filterIsNotPrimitive() = applyThis {
sequence = sequence.filter { !it.isPrimitive }
exceptMessageScope { condition("filterIsNotPrimitive") }
}

fun filterIsArray() = applyThis {
sequence = sequence.filter { it.isArray }
exceptMessageScope { condition("filterIsArray") }
}

fun filterIsNotArray() = applyThis {
sequence = sequence.filter { !it.isArray }
exceptMessageScope { condition("filterIsNotArray") }
}

fun filterIsAnnotationPresent(annotation: Class<out Annotation>) = applyThis {
sequence = sequence.filter { it.isAnnotationPresent(annotation) }
exceptMessageScope { condition("filterIsAnnotationPresent(${annotation.name})") }
}

fun filterIsNotAnnotationPresent(annotation: Class<out Annotation>) = applyThis {
sequence = sequence.filter { !it.isAnnotationPresent(annotation) }
exceptMessageScope { condition("filterIsNotAnnotationPresent(${annotation.name})") }
}
}
Original file line number Diff line number Diff line change
@@ -35,10 +35,31 @@ object Utils {
@JvmStatic
fun ClassLoader.getAllClassesList(delegator: (BaseDexClassLoader) -> BaseDexClassLoader = { loader -> loader }): List<String> =
findDexClassLoader(delegator)?.let {
val f = BaseDexClassLoader::class.java.getDeclaredField("pathList").also { f -> f.isAccessible = true }
val f = BaseDexClassLoader::class.java.getDeclaredField("pathList")
.also { f -> f.isAccessible = true }
f.get(it)
}?.let {
val f = it::class.java.getDeclaredField("dexElements").also { f -> f.isAccessible = true }
val f =
it::class.java.getDeclaredField("dexElements").also { f -> f.isAccessible = true }
f.get(it) as Array<Any>?
}?.flatMap {
val f = it::class.java.getDeclaredField("dexFile").also { f -> f.isAccessible = true }
val df = f.get(it) ?: return@flatMap emptyList<String>()
val m = df::class.java.getDeclaredMethod("entries").also { m -> m.isAccessible = true }
(m.invoke(df) as Enumeration<String>?)?.toList().orEmpty()
}.orEmpty()

@Suppress("UNCHECKED_CAST")
@SuppressLint("DiscouragedPrivateApi")
@JvmStatic
fun BaseDexClassLoader.getAllClassesList(): List<String> =
this.let {
val f = BaseDexClassLoader::class.java.getDeclaredField("pathList")
.also { f -> f.isAccessible = true }
f.get(it)
}?.let {
val f =
it::class.java.getDeclaredField("dexElements").also { f -> f.isAccessible = true }
f.get(it) as Array<Any>?
}?.flatMap {
val f = it::class.java.getDeclaredField("dexFile").also { f -> f.isAccessible = true }

0 comments on commit 5cf3989

Please sign in to comment.