You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在KMM项目中能否通过反射获取类的声明函数?

在KMM中实现获取带指定注解的类方法

KMM的CommonMain无法直接使用Kotlin标准库的反射API(比如declaredFunctions、hasAnnotation),因为iOS平台对Kotlin反射的支持有限,必须通过expect/actual机制分平台实现。以下是完整方案,重点说明iOS端的实现:

1. 定义Common层的预期接口

在CommonMain中声明通用的反射功能接口,由各平台实现:

// CommonMain/AnnotationReflector.kt
expect class AnnotationReflector {
    fun <T : Annotation> getMethodsWithAnnotation(clazz: KClass<*>, annotationClass: KClass<T>): List<KFunction<*>>
}

2. Android端实现(参考)

Android端直接复用Kotlin/JVM反射API,和你已有的实现逻辑一致:

// AndroidMain/AnnotationReflector.kt
actual class AnnotationReflector {
    actual fun <T : Annotation> getMethodsWithAnnotation(clazz: KClass<*>, annotationClass: KClass<T>): List<KFunction<*>> {
        return clazz.declaredFunctions.filter { it.hasAnnotation<T>() }
    }
}

3. iOS端实现

iOS端需要借助Objective-C Runtime来实现,因为Kotlin/Native的反射不支持直接获取注解和方法。

3.1 确保注解在iOS端可见

你的MyAnnotation注解必须添加@ObjCAnnotation,才能被ObjC Runtime识别,同时保留运行时注解:

// CommonMain/MyAnnotation.kt
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.FUNCTION)
@ObjCAnnotation // 关键:让注解能被ObjC Runtime识别
annotation class MyAnnotation

3.2 iOS端的具体实现代码

在iOSMain中编写如下代码,通过ObjC Runtime遍历方法并检查注解,再映射回Kotlin的KFunction:

// iOSMain/AnnotationReflector.kt
import kotlinx.cinterop.*
import objc.runtime.*

actual class AnnotationReflector {
    actual fun <T : Annotation> getMethodsWithAnnotation(clazz: KClass<*>, annotationClass: KClass<T>): List<KFunction<*>> {
        val matchedMethods = mutableListOf<KFunction<*>>()
        // 获取Kotlin类对应的Objective-C类
        val objcClass = clazz.objCClass ?: return matchedMethods
        
        // 遍历类的所有方法
        var methodCount = UIntVar()
        val methods = class_copyMethodList(objcClass, methodCount) ?: return matchedMethods
        try {
            for (index in 0 until methodCount.value.toInt()) {
                val method = methods[index] ?: continue
                val selector = method_getName(method)
                val objcMethodName = NSStringFromSelector(selector)
                
                // 检查当前方法是否带有目标注解
                if (methodHasTargetAnnotation(method, annotationClass.javaClass.name)) {
                    // 通过方法名匹配Kotlin侧的KFunction
                    clazz.declaredFunctions.firstOrNull { it.name == objcMethodName }?.let {
                        matchedMethods.add(it)
                    }
                }
            }
        } finally {
            methods?.let { free(it) }
        }
        return matchedMethods
    }
    
    // 辅助方法:检查方法是否包含指定注解
    private fun methodHasTargetAnnotation(method: COpaquePointer, annotationClassName: String): Boolean {
        val annotationAttr = method_copyAttributeValue(method, "annotations") ?: return false
        try {
            val annotationStr = annotationAttr.toKString()
            // 注解字符串格式类似 "@com.example.MyAnnotation()",直接判断类名是否存在
            return annotationClassName in annotationStr
        } finally {
            free(annotationAttr)
        }
    }
}

iOS端注意事项

  • 方法名匹配需要注意Kotlin到ObjC的转换规则:比如Kotlin的fun test(param: String)在ObjC中会变成testWithParam:,如果你的方法带参数,需要调整objcMethodName和Kotlin方法名的匹配逻辑,或者在注解中额外标记方法名。
  • 如果注解带有参数,methodHasTargetAnnotation中的判断逻辑需要更严谨,比如解析完整的注解字符串结构。

通用调用方式

在CommonMain中直接使用即可:

fun testMethod() {
    val reflector = AnnotationReflector()
    val targetMethods = reflector.getMethodsWithAnnotation(MyClass::class, MyAnnotation::class)
    targetMethods.forEach {
        // 执行你的逻辑
    }
}

内容的提问来源于stack exchange,提问作者Zhou Haibo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 06:10:32