Skip to content

guodongAndroid/Sword

Repository files navigation

Sword

License: Apache 2.0 Maven Central

使用 kotlin compiler plugin 实现,目前仅作用于 Kotlin 函数,为 Kotlin 函数提供代理实现。

Implemented using kotlin compiler plugin, currently only applicable to Kotlin functions, providing proxy implementation for Kotlin functions.

集成

Kotlin KSP Sword PluginId
1.9.21 1.9.21-1.0.15 0.0.4 com.sunxiaodou.kotlin.sword.kcp
1.8.22 1.8.22-1.0.11 0.0.3 com.sunxiaodou.kotlin.sword.kcp
1.7.10 1.7.10-1.0.6 0.0.2 com.sunxiaodou.kotlin.sword.kcp

Top-level build.gradle.kts

plugins {
    id("com.sunxiaodou.kotlin.sword.kcp") version "<latest-version>" apply false
    
    // Option KSP
    id("com.google.devtools.ksp") version "<ksp-version>" apply false
}

Module-level build.gradle.kts

plugins {
    id("com.sunxiaodou.kotlin.sword.kcp")
    
    // Option KSP
    id("com.google.devtools.ksp")
}

dependencies {
    implementation("com.sunxiaodou.kotlin:sword-api-kt:<latest-version>")
    
    // Option 为标记[InvocationHandler]的子类生成FqName索引类`HandlerFqNames`
    ksp("com.sunxiaodou.kotlin:sword-compiler-ksp:<latest-version>")
}

Api

@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.BINARY)
annotation class Proxy(
    /**
     * 是否启用, 默认True
     */
    val enable: Boolean = true,

    /**
     * [InvocationHandler]实现类的全限定名, 实现类必须有无参构造方法
     *
     * e.g. com.example.ProxyTestInvocationHandler
     */
    val handler: String = "",
)

interface InvocationHandler {

    fun invoke(className: String, methodName: String, args: Array<Any?>): Any?
}

/**
 * 标记[InvocationHandler]的子类, 为其生成FqName索引类`HandlerFqNames`
 *
 * 使用 ksp 实现
 *
 * Created by guodongAndroid on 2022/8/17.
 */
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.BINARY)
annotation class ProxyHandler(
    /**
     * 生成字段的名称, 默认为类名
     *
     * `paramName`参数名称不要随意变动
     */
    val paramName: String = ""
)

Proxy 注解中的 handler 参数注入 InvocationHandler 实现类的全限定名(Fully Qualified Name),其实现类必须有无参构造方法

Usage

class Test {

    @Proxy(
        enable = BuildConfig.isDebug,
        handler = HandlerFqNames.GET_TEXT_NO_ARG
    )
    fun getTextNoArg() = "guodongAndroid"

    @Proxy(
        enable = BuildConfig.isDebug,
        handler = HandlerFqNames.GetTextArgInvocationHandler
    )
    fun getTextArg(
        b: Byte,
        z: Boolean,
        c: Char,
        s: Short,
        i: Int,
        l: Long,
        f: Float,
        d: Double,
        str: String,
        ia: IntArray,
        sa: Array<String>,
        ls: List<String>,
        lls: List<List<String>>,
        map: Map<String, String>,
        user: User,
        callback: Callback,
    ): User {
        return User("guodongAndroid-Release", 28)
    }
}
@ProxyHandler
class GetTextArgInvocationHandler : InvocationHandler {

    private val TAG = GetTextArgInvocationHandler::class.java.simpleName

    override fun invoke(className: String, methodName: String, args: Array<Any?>): Any? {
        Log.e(TAG, "invoke: className = $className, methodName = $methodName, args(${args.size}) = ${args.joinToString()}")
        return User("guodongAndroid-Debug", 18)
    }
}

@ProxyHandler("GET_TEXT_NO_ARG")
class GetTextNoArgInvocationHandler : InvocationHandler {

    private val TAG = GetTextNoArgInvocationHandler::class.java.simpleName

    override fun invoke(className: String, methodName: String, args: Array<Any?>): Any? {
        Log.e(TAG, "invoke: className = $className, methodName = $methodName, args(${args.size}) = ${args.joinToString()}")
        return "guodongAndroid-Debug"
    }
}

HandlerFqNames

// The file is automatic generated by Sword, don't modify it.
package com.guodong.android.sword.app

import kotlin.String

/**
 * The class is automatic generated by Sword, don't modify it.
 *
 * [com.guodong.android.sword.api.kt.InvocationHandler]实现类的全限定名
 */
public object HandlerFqNames {
  /**
   * [com.guodong.android.sword.app.GetTextArgInvocationHandler]
   */
  public const val GetTextArgInvocationHandler: String =
      "com.guodong.android.sword.app.GetTextArgInvocationHandler"

  /**
   * [com.guodong.android.sword.app.GetTextNoArgInvocationHandler]
   */
  public const val GET_TEXT_NO_ARG: String =
      "com.guodong.android.sword.app.GetTextNoArgInvocationHandler"
}