refactor: migration to KavaRef

This commit is contained in:
2025-06-26 13:05:42 +08:00
parent 19113c2ba2
commit 8b67e4c000
8 changed files with 116 additions and 84 deletions

View File

@@ -43,7 +43,8 @@ dependencies {
lintPublish(projects.hikageCoreLint)
ksp(projects.hikageCompiler)
implementation(org.lsposed.hiddenapibypass.hiddenapibypass)
implementation(com.highcapable.yukireflection.api)
implementation(com.highcapable.kavaref.kavaref.core)
implementation(com.highcapable.kavaref.kavaref.extension)
api(com.highcapable.betterandroid.ui.extension)
implementation(com.highcapable.betterandroid.system.extension)
implementation(androidx.core.core.ktx)

View File

@@ -25,6 +25,7 @@ package com.highcapable.hikage.bypass
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.res.AssetManager
import android.content.res.XmlResourceParser
import android.content.res.loader.AssetsProvider
import android.content.res.loader.ResourcesProvider
@@ -34,14 +35,13 @@ import com.highcapable.betterandroid.system.extension.tool.SystemVersion
import com.highcapable.betterandroid.ui.extension.view.inflateOrNull
import com.highcapable.betterandroid.ui.extension.view.layoutInflater
import com.highcapable.hikage.core.R
import com.highcapable.yukireflection.factory.classOf
import com.highcapable.yukireflection.factory.lazyClass
import com.highcapable.yukireflection.type.android.AssetManagerClass
import com.highcapable.yukireflection.type.java.BooleanType
import com.highcapable.yukireflection.type.java.IntType
import com.highcapable.yukireflection.type.java.LongType
import com.highcapable.yukireflection.type.java.StringClass
import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.kavaref.condition.type.Modifiers
import com.highcapable.kavaref.extension.lazyClass
import com.highcapable.kavaref.resolver.processor.MemberProcessor
import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import android.R as Android_R
/**
@@ -101,7 +101,7 @@ internal object XmlBlockBypass {
private val ApkAssetsClass by lazyClass("android.content.res.ApkAssets")
/** The xml block class. */
private val XmlBlockClass by lazyClass("android.content.res.XmlBlock")
private val XmlBlockClass by lazyClass<AutoCloseable>("android.content.res.XmlBlock")
/** Global pointer references object. */
private var xmlBlock: Long? = null
@@ -112,6 +112,30 @@ internal object XmlBlockBypass {
/** Whether the initialization is done once. */
private var isInitOnce = false
/** The resolver for member processor. */
private val resolver = object : MemberProcessor.Resolver() {
override fun <T : Any> getDeclaredConstructors(declaringClass: Class<T>): List<Constructor<T>> =
SystemVersion.require(SystemVersion.P, super.getDeclaredConstructors(declaringClass)) {
HiddenApiBypass.getDeclaredMethods(declaringClass).filterIsInstance<Constructor<T>>().toList()
}
override fun <T : Any> getDeclaredMethods(declaringClass: Class<T>): List<Method> =
SystemVersion.require(SystemVersion.P, super.getDeclaredMethods(declaringClass)) {
HiddenApiBypass.getDeclaredMethods(declaringClass).filterIsInstance<Method>().toList()
}
}
private val newParser by lazy {
XmlBlockClass.resolve()
.processor(resolver)
.optional()
.firstMethodOrNull {
name = "newParser"
parameters(Int::class)
}
}
/**
* Initialize.
* @param context the context.
@@ -134,32 +158,40 @@ internal object XmlBlockBypass {
SystemVersion.isHighOrEqualsTo(SystemVersion.R) ->
// private static native long nativeLoad(@FormatType int format, @NonNull String path,
// @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException;
HiddenApiBypass.getDeclaredMethod(
ApkAssetsClass, "nativeLoad",
IntType, StringClass, IntType, classOf<AssetsProvider>()
).apply { isAccessible = true }.invoke(null, FORMAT_APK, sourceDir, PROPERTY_SYSTEM, null)
ApkAssetsClass.resolve()
.processor(resolver)
.optional()
.firstMethodOrNull {
name = "nativeLoad"
parameters(Int::class, String::class, Int::class, AssetsProvider::class)
modifiers(Modifiers.NATIVE)
}?.invokeQuietly(FORMAT_APK, sourceDir, PROPERTY_SYSTEM, null)
SystemVersion.isHighOrEqualsTo(SystemVersion.P) ->
// private static native long nativeLoad(
// @NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
// throws IOException;
HiddenApiBypass.getDeclaredMethod(
ApkAssetsClass, "nativeLoad",
StringClass, BooleanType, BooleanType, BooleanType
).apply { isAccessible = true }.invoke(null, sourceDir, false, false, false)
ApkAssetsClass.resolve()
.processor(resolver)
.optional()
.firstMethodOrNull {
name = "nativeLoad"
parameters(String::class, Boolean::class, Boolean::class, Boolean::class)
modifiers(Modifiers.NATIVE)
}?.invokeQuietly(sourceDir, false, false, false)
else -> error("Unsupported Android version.")
} as? Long? ?: error("Failed to create ApkAssets.")
blockParser = when {
SystemVersion.isHighOrEqualsTo(36) ->
// XmlBlock(@Nullable AssetManager assets, long xmlBlock, boolean usesFeatureFlags)
HiddenApiBypass.getDeclaredConstructor(XmlBlockClass, AssetManagerClass, LongType, BooleanType)
.apply { isAccessible = true }
.newInstance(null, xmlBlock, false)
else ->
// XmlBlock(@Nullable AssetManager assets, long xmlBlock)
HiddenApiBypass.getDeclaredConstructor(XmlBlockClass, AssetManagerClass, LongType)
.apply { isAccessible = true }
.newInstance(null, xmlBlock)
} as? AutoCloseable? ?: error("Failed to create XmlBlock\$Parser.")
blockParser = XmlBlockClass.resolve()
.processor(resolver)
.optional()
.firstConstructorOrNull {
if (SystemVersion.isHighOrEqualsTo(36))
parameters(AssetManager::class, Long::class, Boolean::class)
else parameters(AssetManager::class, Long::class)
}?.let {
if (SystemVersion.isHighOrEqualsTo(36))
it.createQuietly(null, xmlBlock, false)
else it.createQuietly(null, xmlBlock)
} ?: error("Failed to create XmlBlock\$Parser.")
isInitOnce = true
}
@@ -175,13 +207,13 @@ internal object XmlBlockBypass {
* @return [XmlResourceParser]
*/
fun createViewAttrs() = context.layoutInflater.inflateOrNull<HikageAttrsView>(R.layout.layout_hikage_attrs_view)?.attrs
as? XmlResourceParser? ?: error("Failed to create AttributeSet.")
as? XmlResourceParser? ?: error("Failed to create AttributeSet.")
return if (SystemVersion.isHighOrEqualsTo(SystemVersion.P)) {
if (!isInitOnce) return createViewAttrs()
require(blockParser != null) { "Hikage initialization failed." }
HiddenApiBypass.getDeclaredMethod(XmlBlockClass, "newParser", IntType)
.apply { isAccessible = true }
.invoke(blockParser, resId) as? XmlResourceParser? ?: error("Failed to create parser.")
newParser?.copy()?.of(blockParser)
?.invokeQuietly<XmlResourceParser>(resId)
?: error("Failed to create parser.")
} else createViewAttrs()
}
}

View File

@@ -61,17 +61,12 @@ import com.highcapable.hikage.core.base.HikageView
import com.highcapable.hikage.core.base.PerformerException
import com.highcapable.hikage.core.base.ProvideException
import com.highcapable.hikage.core.extension.ResourcesScope
import com.highcapable.yukireflection.factory.buildOf
import com.highcapable.yukireflection.factory.classOf
import com.highcapable.yukireflection.factory.constructor
import com.highcapable.yukireflection.factory.current
import com.highcapable.yukireflection.factory.notExtends
import com.highcapable.yukireflection.type.android.AttributeSetClass
import com.highcapable.yukireflection.type.android.ContextClass
import com.highcapable.yukireflection.type.android.ViewGroup_LayoutParamsClass
import com.highcapable.yukireflection.type.java.IntType
import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.kavaref.extension.classOf
import com.highcapable.kavaref.extension.createInstanceOrNull
import com.highcapable.kavaref.extension.isNotSubclassOf
import com.highcapable.kavaref.resolver.ConstructorResolver
import java.io.Serializable
import java.lang.reflect.Constructor
import java.util.concurrent.atomic.AtomicInteger
/**
@@ -91,7 +86,7 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
private const val LayoutParamsUnspecified = LayoutParamsWrapContent - 1
/** The view constructors map. */
private val viewConstructors = mutableMapOf<String, ViewConstructor>()
private val viewConstructors = mutableMapOf<String, ViewConstructor<*>>()
/** The view atomic id. */
private val viewAtomicId = AtomicInteger(0x7F00000)
@@ -143,7 +138,7 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
attachToParent: Boolean = parent != null,
factory: HikageFactoryBuilder.() -> Unit = {},
performer: HikagePerformer<ViewGroup.LayoutParams>
) = create(ViewGroup_LayoutParamsClass, context, parent, attachToParent, factory, performer)
) = create(classOf<ViewGroup.LayoutParams>(), context, parent, attachToParent, factory, performer)
/**
* Create a new [Hikage].
@@ -195,7 +190,7 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
fun build(
factory: HikageFactoryBuilder.() -> Unit = {},
performer: HikagePerformer<ViewGroup.LayoutParams>
) = build(ViewGroup_LayoutParamsClass, factory, performer)
) = build(classOf<ViewGroup.LayoutParams>(), factory, performer)
/**
* Create a new [Hikage.Delegate].
@@ -229,11 +224,11 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
/**
* The view constructor class.
* @param instance the constructor instance.
* @param resolver the constructor resolver.
* @param parameterCount the parameter count.
*/
private inner class ViewConstructor(
private val instance: Constructor<*>,
private inner class ViewConstructor<V : View>(
private val resolver: ConstructorResolver<V>,
private val parameterCount: Int
) {
@@ -243,11 +238,11 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
* @param attrs the attribute set.
* @return [V] or null.
*/
fun <V : View> build(context: Context, attrs: AttributeSet) = when (parameterCount) {
2 -> instance.newInstance(context, attrs)
1 -> instance.newInstance(context)
fun build(context: Context, attrs: AttributeSet) = when (parameterCount) {
2 -> resolver.createQuietly(context, attrs)
1 -> resolver.createQuietly(context)
else -> null
} as? V?
}
}
/** The performer set. */
@@ -333,17 +328,17 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
/**
* Get the view constructor.
* @param viewClass the view class.
* @return [ViewConstructor] or null.
* @return [ViewConstructor]<[V]> or null.
*/
private fun <V : View> getViewConstructor(viewClass: Class<V>) =
viewConstructors[viewClass.name] ?: run {
viewConstructors[viewClass.name] as? ViewConstructor<V>? ?: run {
var parameterCount = 0
val twoParams = viewClass.constructor {
param(ContextClass, AttributeSetClass)
}.ignored().give()
val onceParam = viewClass.constructor {
param(ContextClass)
}.ignored().give()
val twoParams = viewClass.resolve()
.optional(silent = true)
.firstConstructorOrNull { parameters(Context::class, AttributeSet::class) }
val onceParam = viewClass.resolve()
.optional(silent = true)
.firstConstructorOrNull { parameters(Context::class) }
val constructor = onceParam?.apply { parameterCount = 1 }
?: twoParams?.apply { parameterCount = 2 }
val viewConstructor = constructor?.let { ViewConstructor(it, parameterCount) }
@@ -365,7 +360,7 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
factories.forEach { factory ->
val params = PerformerParams(id, attrs, viewClass as Class<View>)
val view = factory(parent, processed, context, params)
if (view != null && view.javaClass notExtends viewClass) throw PerformerException(
if (view != null && view.javaClass isNotSubclassOf viewClass) throw PerformerException(
"HikageFactory cannot cast the created view type \"${view.javaClass}\" to \"${viewClass.name}\", " +
"please confirm that the view type you created is correct."
)
@@ -897,17 +892,16 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
*/
private fun createDefaultLayoutParams(lparams: ViewGroup.LayoutParams? = null): ViewGroup.LayoutParams {
val wrapped = lparams?.let {
parent?.current(ignored = true)?.method {
parent?.resolve()?.optional(silent = true)?.firstMethodOrNull {
name = "generateLayoutParams"
param(ViewGroup_LayoutParamsClass)
superClass()
}?.invoke<ViewGroup.LayoutParams?>(it)
parameters(ViewGroup.LayoutParams::class)
superclass()
}?.invokeQuietly<ViewGroup.LayoutParams>(it)
} ?: lparams
return wrapped
// Build a default.
?: lpClass.buildOf<ViewGroup.LayoutParams>(LayoutParamsWrapContent, LayoutParamsWrapContent) {
param(IntType, IntType)
} ?: throw PerformerException("Create default layout params failed.")
?: lpClass.createInstanceOrNull(LayoutParamsWrapContent, LayoutParamsWrapContent)
?: throw PerformerException("Create default layout params failed.")
}
/**