mirror of
https://github.com/BetterAndroid/Hikage.git
synced 2025-09-05 10:15:37 +08:00
refactor: migration to KavaRef
This commit is contained in:
@@ -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)
|
||||
|
@@ -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()
|
||||
}
|
||||
}
|
@@ -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.")
|
||||
}
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user