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

@@ -24,7 +24,7 @@ plugins:
auto-update: false auto-update: false
com.android.application: com.android.application:
alias: android-application alias: android-application
version: 8.9.0 version: 8.9.3
com.android.library: com.android.library:
alias: android-library alias: android-library
version-ref: android-application version-ref: android-application
@@ -37,7 +37,7 @@ plugins:
auto-update: false auto-update: false
com.vanniktech.maven.publish: com.vanniktech.maven.publish:
alias: maven-publish alias: maven-publish
version: 0.31.0 version: 0.33.0
libraries: libraries:
org.jetbrains.kotlin: org.jetbrains.kotlin:
@@ -54,7 +54,7 @@ libraries:
version: 1.2.0 version: 1.2.0
com.squareup: com.squareup:
kotlinpoet: kotlinpoet:
version: 2.1.0 version: 2.2.0
kotlinpoet-ksp: kotlinpoet-ksp:
version-ref: <this>::kotlinpoet version-ref: <this>::kotlinpoet
com.highcapable.betterandroid: com.highcapable.betterandroid:
@@ -67,20 +67,22 @@ libraries:
org.lsposed.hiddenapibypass: org.lsposed.hiddenapibypass:
hiddenapibypass: hiddenapibypass:
version: 6.1 version: 6.1
com.highcapable.yukireflection: com.highcapable.kavaref:
api: kavaref-core:
version: 1.0.3 version: 1.0.0
kavaref-extension:
version: 1.0.0
com.highcapable.pangutext: com.highcapable.pangutext:
pangutext-android: pangutext-android:
version: 1.0.2 version: 1.0.2
androidx.core: androidx.core:
core: core:
version: 1.15.0 version: 1.16.0
core-ktx: core-ktx:
version-ref: <this>::core version-ref: <this>::core
androidx.appcompat: androidx.appcompat:
appcompat: appcompat:
version: 1.7.0 version: 1.7.1
com.google.android.material: com.google.android.material:
material: material:
auto-update: false auto-update: false
@@ -115,7 +117,7 @@ libraries:
version: 1.4.0 version: 1.4.0
androidx.compose.ui: androidx.compose.ui:
ui: ui:
version: 1.7.8 version: 1.8.3
junit: junit:
junit: junit:
version: 4.13.2 version: 4.13.2
@@ -127,7 +129,7 @@ libraries:
version: 3.6.1 version: 3.6.1
com.android.tools.lint: com.android.tools.lint:
lint: lint:
version: 31.9.0 version: 31.11.0
lint-api: lint-api:
version-ref: <this>::lint version-ref: <this>::lint
lint-checks: lint-checks:

View File

@@ -43,7 +43,8 @@ dependencies {
lintPublish(projects.hikageCoreLint) lintPublish(projects.hikageCoreLint)
ksp(projects.hikageCompiler) ksp(projects.hikageCompiler)
implementation(org.lsposed.hiddenapibypass.hiddenapibypass) 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) api(com.highcapable.betterandroid.ui.extension)
implementation(com.highcapable.betterandroid.system.extension) implementation(com.highcapable.betterandroid.system.extension)
implementation(androidx.core.core.ktx) implementation(androidx.core.core.ktx)

View File

@@ -25,6 +25,7 @@ package com.highcapable.hikage.bypass
import android.content.Context import android.content.Context
import android.content.pm.ApplicationInfo import android.content.pm.ApplicationInfo
import android.content.res.AssetManager
import android.content.res.XmlResourceParser import android.content.res.XmlResourceParser
import android.content.res.loader.AssetsProvider import android.content.res.loader.AssetsProvider
import android.content.res.loader.ResourcesProvider 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.inflateOrNull
import com.highcapable.betterandroid.ui.extension.view.layoutInflater import com.highcapable.betterandroid.ui.extension.view.layoutInflater
import com.highcapable.hikage.core.R import com.highcapable.hikage.core.R
import com.highcapable.yukireflection.factory.classOf import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.yukireflection.factory.lazyClass import com.highcapable.kavaref.condition.type.Modifiers
import com.highcapable.yukireflection.type.android.AssetManagerClass import com.highcapable.kavaref.extension.lazyClass
import com.highcapable.yukireflection.type.java.BooleanType import com.highcapable.kavaref.resolver.processor.MemberProcessor
import com.highcapable.yukireflection.type.java.IntType
import com.highcapable.yukireflection.type.java.LongType
import com.highcapable.yukireflection.type.java.StringClass
import org.lsposed.hiddenapibypass.HiddenApiBypass import org.lsposed.hiddenapibypass.HiddenApiBypass
import java.lang.reflect.Constructor
import java.lang.reflect.Method
import android.R as Android_R import android.R as Android_R
/** /**
@@ -101,7 +101,7 @@ internal object XmlBlockBypass {
private val ApkAssetsClass by lazyClass("android.content.res.ApkAssets") private val ApkAssetsClass by lazyClass("android.content.res.ApkAssets")
/** The xml block class. */ /** 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. */ /** Global pointer references object. */
private var xmlBlock: Long? = null private var xmlBlock: Long? = null
@@ -112,6 +112,30 @@ internal object XmlBlockBypass {
/** Whether the initialization is done once. */ /** Whether the initialization is done once. */
private var isInitOnce = false 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. * Initialize.
* @param context the context. * @param context the context.
@@ -134,32 +158,40 @@ internal object XmlBlockBypass {
SystemVersion.isHighOrEqualsTo(SystemVersion.R) -> SystemVersion.isHighOrEqualsTo(SystemVersion.R) ->
// private static native long nativeLoad(@FormatType int format, @NonNull String path, // private static native long nativeLoad(@FormatType int format, @NonNull String path,
// @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException; // @PropertyFlags int flags, @Nullable AssetsProvider asset) throws IOException;
HiddenApiBypass.getDeclaredMethod( ApkAssetsClass.resolve()
ApkAssetsClass, "nativeLoad", .processor(resolver)
IntType, StringClass, IntType, classOf<AssetsProvider>() .optional()
).apply { isAccessible = true }.invoke(null, FORMAT_APK, sourceDir, PROPERTY_SYSTEM, null) .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) -> SystemVersion.isHighOrEqualsTo(SystemVersion.P) ->
// private static native long nativeLoad( // private static native long nativeLoad(
// @NonNull String path, boolean system, boolean forceSharedLib, boolean overlay) // @NonNull String path, boolean system, boolean forceSharedLib, boolean overlay)
// throws IOException; // throws IOException;
HiddenApiBypass.getDeclaredMethod( ApkAssetsClass.resolve()
ApkAssetsClass, "nativeLoad", .processor(resolver)
StringClass, BooleanType, BooleanType, BooleanType .optional()
).apply { isAccessible = true }.invoke(null, sourceDir, false, false, false) .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.") else -> error("Unsupported Android version.")
} as? Long? ?: error("Failed to create ApkAssets.") } as? Long? ?: error("Failed to create ApkAssets.")
blockParser = when { blockParser = XmlBlockClass.resolve()
SystemVersion.isHighOrEqualsTo(36) -> .processor(resolver)
// XmlBlock(@Nullable AssetManager assets, long xmlBlock, boolean usesFeatureFlags) .optional()
HiddenApiBypass.getDeclaredConstructor(XmlBlockClass, AssetManagerClass, LongType, BooleanType) .firstConstructorOrNull {
.apply { isAccessible = true } if (SystemVersion.isHighOrEqualsTo(36))
.newInstance(null, xmlBlock, false) parameters(AssetManager::class, Long::class, Boolean::class)
else -> else parameters(AssetManager::class, Long::class)
// XmlBlock(@Nullable AssetManager assets, long xmlBlock) }?.let {
HiddenApiBypass.getDeclaredConstructor(XmlBlockClass, AssetManagerClass, LongType) if (SystemVersion.isHighOrEqualsTo(36))
.apply { isAccessible = true } it.createQuietly(null, xmlBlock, false)
.newInstance(null, xmlBlock) else it.createQuietly(null, xmlBlock)
} as? AutoCloseable? ?: error("Failed to create XmlBlock\$Parser.") } ?: error("Failed to create XmlBlock\$Parser.")
isInitOnce = true isInitOnce = true
} }
@@ -175,13 +207,13 @@ internal object XmlBlockBypass {
* @return [XmlResourceParser] * @return [XmlResourceParser]
*/ */
fun createViewAttrs() = context.layoutInflater.inflateOrNull<HikageAttrsView>(R.layout.layout_hikage_attrs_view)?.attrs 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)) { return if (SystemVersion.isHighOrEqualsTo(SystemVersion.P)) {
if (!isInitOnce) return createViewAttrs() if (!isInitOnce) return createViewAttrs()
require(blockParser != null) { "Hikage initialization failed." } require(blockParser != null) { "Hikage initialization failed." }
HiddenApiBypass.getDeclaredMethod(XmlBlockClass, "newParser", IntType) newParser?.copy()?.of(blockParser)
.apply { isAccessible = true } ?.invokeQuietly<XmlResourceParser>(resId)
.invoke(blockParser, resId) as? XmlResourceParser? ?: error("Failed to create parser.") ?: error("Failed to create parser.")
} else createViewAttrs() } 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.PerformerException
import com.highcapable.hikage.core.base.ProvideException import com.highcapable.hikage.core.base.ProvideException
import com.highcapable.hikage.core.extension.ResourcesScope import com.highcapable.hikage.core.extension.ResourcesScope
import com.highcapable.yukireflection.factory.buildOf import com.highcapable.kavaref.KavaRef.Companion.resolve
import com.highcapable.yukireflection.factory.classOf import com.highcapable.kavaref.extension.classOf
import com.highcapable.yukireflection.factory.constructor import com.highcapable.kavaref.extension.createInstanceOrNull
import com.highcapable.yukireflection.factory.current import com.highcapable.kavaref.extension.isNotSubclassOf
import com.highcapable.yukireflection.factory.notExtends import com.highcapable.kavaref.resolver.ConstructorResolver
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 java.io.Serializable import java.io.Serializable
import java.lang.reflect.Constructor
import java.util.concurrent.atomic.AtomicInteger 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 private const val LayoutParamsUnspecified = LayoutParamsWrapContent - 1
/** The view constructors map. */ /** The view constructors map. */
private val viewConstructors = mutableMapOf<String, ViewConstructor>() private val viewConstructors = mutableMapOf<String, ViewConstructor<*>>()
/** The view atomic id. */ /** The view atomic id. */
private val viewAtomicId = AtomicInteger(0x7F00000) private val viewAtomicId = AtomicInteger(0x7F00000)
@@ -143,7 +138,7 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
attachToParent: Boolean = parent != null, attachToParent: Boolean = parent != null,
factory: HikageFactoryBuilder.() -> Unit = {}, factory: HikageFactoryBuilder.() -> Unit = {},
performer: HikagePerformer<ViewGroup.LayoutParams> 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]. * Create a new [Hikage].
@@ -195,7 +190,7 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
fun build( fun build(
factory: HikageFactoryBuilder.() -> Unit = {}, factory: HikageFactoryBuilder.() -> Unit = {},
performer: HikagePerformer<ViewGroup.LayoutParams> performer: HikagePerformer<ViewGroup.LayoutParams>
) = build(ViewGroup_LayoutParamsClass, factory, performer) ) = build(classOf<ViewGroup.LayoutParams>(), factory, performer)
/** /**
* Create a new [Hikage.Delegate]. * Create a new [Hikage.Delegate].
@@ -229,11 +224,11 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
/** /**
* The view constructor class. * The view constructor class.
* @param instance the constructor instance. * @param resolver the constructor resolver.
* @param parameterCount the parameter count. * @param parameterCount the parameter count.
*/ */
private inner class ViewConstructor( private inner class ViewConstructor<V : View>(
private val instance: Constructor<*>, private val resolver: ConstructorResolver<V>,
private val parameterCount: Int private val parameterCount: Int
) { ) {
@@ -243,11 +238,11 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
* @param attrs the attribute set. * @param attrs the attribute set.
* @return [V] or null. * @return [V] or null.
*/ */
fun <V : View> build(context: Context, attrs: AttributeSet) = when (parameterCount) { fun build(context: Context, attrs: AttributeSet) = when (parameterCount) {
2 -> instance.newInstance(context, attrs) 2 -> resolver.createQuietly(context, attrs)
1 -> instance.newInstance(context) 1 -> resolver.createQuietly(context)
else -> null else -> null
} as? V? }
} }
/** The performer set. */ /** The performer set. */
@@ -333,17 +328,17 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
/** /**
* Get the view constructor. * Get the view constructor.
* @param viewClass the view class. * @param viewClass the view class.
* @return [ViewConstructor] or null. * @return [ViewConstructor]<[V]> or null.
*/ */
private fun <V : View> getViewConstructor(viewClass: Class<V>) = private fun <V : View> getViewConstructor(viewClass: Class<V>) =
viewConstructors[viewClass.name] ?: run { viewConstructors[viewClass.name] as? ViewConstructor<V>? ?: run {
var parameterCount = 0 var parameterCount = 0
val twoParams = viewClass.constructor { val twoParams = viewClass.resolve()
param(ContextClass, AttributeSetClass) .optional(silent = true)
}.ignored().give() .firstConstructorOrNull { parameters(Context::class, AttributeSet::class) }
val onceParam = viewClass.constructor { val onceParam = viewClass.resolve()
param(ContextClass) .optional(silent = true)
}.ignored().give() .firstConstructorOrNull { parameters(Context::class) }
val constructor = onceParam?.apply { parameterCount = 1 } val constructor = onceParam?.apply { parameterCount = 1 }
?: twoParams?.apply { parameterCount = 2 } ?: twoParams?.apply { parameterCount = 2 }
val viewConstructor = constructor?.let { ViewConstructor(it, parameterCount) } val viewConstructor = constructor?.let { ViewConstructor(it, parameterCount) }
@@ -365,7 +360,7 @@ class Hikage private constructor(private val factories: List<HikageFactory>) {
factories.forEach { factory -> factories.forEach { factory ->
val params = PerformerParams(id, attrs, viewClass as Class<View>) val params = PerformerParams(id, attrs, viewClass as Class<View>)
val view = factory(parent, processed, context, params) 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}\", " + "HikageFactory cannot cast the created view type \"${view.javaClass}\" to \"${viewClass.name}\", " +
"please confirm that the view type you created is correct." "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 { private fun createDefaultLayoutParams(lparams: ViewGroup.LayoutParams? = null): ViewGroup.LayoutParams {
val wrapped = lparams?.let { val wrapped = lparams?.let {
parent?.current(ignored = true)?.method { parent?.resolve()?.optional(silent = true)?.firstMethodOrNull {
name = "generateLayoutParams" name = "generateLayoutParams"
param(ViewGroup_LayoutParamsClass) parameters(ViewGroup.LayoutParams::class)
superClass() superclass()
}?.invoke<ViewGroup.LayoutParams?>(it) }?.invokeQuietly<ViewGroup.LayoutParams>(it)
} ?: lparams } ?: lparams
return wrapped return wrapped
// Build a default. // Build a default.
?: lpClass.buildOf<ViewGroup.LayoutParams>(LayoutParamsWrapContent, LayoutParamsWrapContent) { ?: lpClass.createInstanceOrNull(LayoutParamsWrapContent, LayoutParamsWrapContent)
param(IntType, IntType) ?: throw PerformerException("Create default layout params failed.")
} ?: throw PerformerException("Create default layout params failed.")
} }
/** /**

View File

@@ -39,7 +39,8 @@ android {
dependencies { dependencies {
implementation(projects.hikageCore) implementation(projects.hikageCore)
implementation(com.highcapable.yukireflection.api) implementation(com.highcapable.kavaref.kavaref.core)
implementation(com.highcapable.kavaref.kavaref.extension)
implementation(com.highcapable.betterandroid.ui.component) implementation(com.highcapable.betterandroid.ui.component)
implementation(com.highcapable.betterandroid.ui.extension) implementation(com.highcapable.betterandroid.ui.extension)
implementation(com.highcapable.betterandroid.system.extension) implementation(com.highcapable.betterandroid.system.extension)

View File

@@ -40,7 +40,8 @@ android {
dependencies { dependencies {
implementation(projects.hikageCore) implementation(projects.hikageCore)
implementation(com.highcapable.yukireflection.api) implementation(com.highcapable.kavaref.kavaref.core)
implementation(com.highcapable.kavaref.kavaref.extension)
implementation(com.highcapable.betterandroid.ui.extension) implementation(com.highcapable.betterandroid.ui.extension)
implementation(com.highcapable.betterandroid.system.extension) implementation(com.highcapable.betterandroid.system.extension)
implementation(androidx.core.core.ktx) implementation(androidx.core.core.ktx)

View File

@@ -39,7 +39,8 @@ android {
dependencies { dependencies {
implementation(projects.hikageCore) implementation(projects.hikageCore)
implementation(com.highcapable.yukireflection.api) implementation(com.highcapable.kavaref.kavaref.core)
implementation(com.highcapable.kavaref.kavaref.extension)
implementation(com.highcapable.betterandroid.ui.extension) implementation(com.highcapable.betterandroid.ui.extension)
implementation(com.highcapable.betterandroid.system.extension) implementation(com.highcapable.betterandroid.system.extension)
implementation(androidx.core.core.ktx) implementation(androidx.core.core.ktx)

View File

@@ -31,7 +31,7 @@ import com.highcapable.hikage.core.Hikage
import com.highcapable.hikage.core.base.HikageFactoryBuilder import com.highcapable.hikage.core.base.HikageFactoryBuilder
import com.highcapable.hikage.core.base.HikagePerformer import com.highcapable.hikage.core.base.HikagePerformer
import com.highcapable.hikage.core.base.Hikageable import com.highcapable.hikage.core.base.Hikageable
import com.highcapable.yukireflection.factory.current import com.highcapable.kavaref.KavaRef.Companion.resolve
/** /**
* @see PopupWindow.setContentView * @see PopupWindow.setContentView
@@ -67,5 +67,5 @@ fun PopupWindow.setContentView(
* @return [Context] * @return [Context]
*/ */
private fun PopupWindow.requireContext() = private fun PopupWindow.requireContext() =
current(ignored = true).field { name = "mContext" }.cast<Context?>() resolve().optional(silent = true).firstFieldOrNull { name = "mContext" }?.getQuietly<Context>()
?: error("Hikage need a Context to create PopupWindow content view.") ?: error("Hikage need a Context to create PopupWindow content view.")