Merge XposedProcessor code source files to template

This commit is contained in:
2022-04-28 01:12:02 +08:00
parent d038c369b4
commit 69b5cf3704
2 changed files with 199 additions and 138 deletions

View File

@@ -34,8 +34,8 @@ import com.google.devtools.ksp.processing.*
import com.google.devtools.ksp.symbol.FileLocation
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.highcapable.yukihookapi_ksp_xposed.sources.CodeSourceFileTemplate
import java.io.File
import java.text.SimpleDateFormat
import java.util.*
import java.util.regex.Pattern
@@ -49,18 +49,6 @@ import java.util.regex.Pattern
@AutoService(SymbolProcessorProvider::class)
class YukiHookXposedProcessor : SymbolProcessorProvider {
companion object {
/** 定义 Jvm 方法名 */
private const val IS_ACTIVE_METHOD_NAME = "__--"
/** 定义 Jvm 方法名 */
private const val GET_XPOSED_VERSION_METHOD_NAME = "--__"
/** 定义 Jvm 方法名 */
private const val GET_XPOSED_TAG_METHOD_NAME = "_-_-"
}
override fun create(environment: SymbolProcessorEnvironment) = object : SymbolProcessor {
/** 自动处理程序的 TAG */
@@ -114,22 +102,22 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
* 检索需要注入的类
* @param sourcePath 指定的 source 路径
* @param modulePackageName 模块包名
* @param entryClassName 入口类名
* @param xInitClassName xposed_init 入口类名
*/
fun fetchKSClassDeclaration(sourcePath: String, modulePackageName: String, entryClassName: String) {
fun fetchKSClassDeclaration(sourcePath: String, modulePackageName: String, xInitClassName: String) {
asSequence().filterIsInstance<KSClassDeclaration>().forEach {
if (isInjectOnce) when {
it.superTypes.any { type -> type.element.toString() == "IYukiHookXposedInit" } -> {
val ecName = entryClassName.ifBlank { "${it.simpleName.asString()}$xposedClassShortName" }
if (entryClassName == it.simpleName.asString()) error(msg = "Duplicate entryClassName \"$entryClassName\"")
val xcName = xInitClassName.ifBlank { "${it.simpleName.asString()}$xposedClassShortName" }
if (xInitClassName == it.simpleName.asString()) error(msg = "Duplicate entryClassName \"$xInitClassName\"")
injectAssets(
codePath = (it.location as? FileLocation?)?.filePath ?: "",
sourcePath = sourcePath,
packageName = it.packageName.asString(),
className = it.simpleName.asString(),
entryClassName = ecName
entryClassName = it.simpleName.asString(),
xInitClassName = xcName
)
injectClass(it.packageName.asString(), it.simpleName.asString(), modulePackageName, ecName)
injectClass(it.packageName.asString(), modulePackageName, it.simpleName.asString(), xcName)
}
it.superTypes.any { type -> type.element.toString() == "YukiHookXposedInitProxy" } ->
error(msg = "\"YukiHookXposedInitProxy\" was deprecated, please replace to \"IYukiHookXposedInit\"")
@@ -142,9 +130,9 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
}
forEach {
it.annotations.forEach { e ->
var sourcePath = ""
var modulePackageName = ""
var entryClassName = ""
var sourcePath = "" // 项目相对路径
var modulePackageName = "" // 模块包名
var entryClassName = "" // xposed_init 入口类名
e.arguments.forEach { pease ->
if (pease.name?.asString() == "sourcePath")
sourcePath = pease.value.toString().trim()
@@ -174,10 +162,10 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
* @param codePath 注解类的完整代码文件路径
* @param sourcePath 指定的 source 路径
* @param packageName 包名
* @param className 类名
* @param entryClassName 入口类名
* @param xInitClassName xposed_init 入口类名
*/
private fun injectAssets(codePath: String, sourcePath: String, packageName: String, className: String, entryClassName: String) =
private fun injectAssets(codePath: String, sourcePath: String, packageName: String, entryClassName: String, xInitClassName: String) =
environment {
if (codePath.isBlank()) error(msg = "Project CodePath not available")
if (sourcePath.isBlank()) error(msg = "Project SourcePath not available")
@@ -206,9 +194,9 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
assFile.mkdirs()
}
File("${assFile.absolutePath}${separator}xposed_init")
.writeText(text = "$packageName.$entryClassName")
.writeText(text = "$packageName.$xInitClassName")
File("${assFile.absolutePath}${separator}yukihookapi_init")
.writeText(text = "$packageName.$className")
.writeText(text = "$packageName.$entryClassName")
} else error(msg = "Project Source Path \"$sourcePath\" verify failed! Is this an Android Project?")
}
}
@@ -216,137 +204,39 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
/**
* 注入并生成指定类
* @param packageName 包名
* @param className 类名
* @param modulePackageName 模块包名
* @param entryClassName 入口类名
* @param xInitClassName xposed_init 入口类名
*/
private fun injectClass(packageName: String, className: String, modulePackageName: String, entryClassName: String) =
private fun injectClass(packageName: String, modulePackageName: String, entryClassName: String, xInitClassName: String) =
environment(ignoredError = true) {
if (modulePackageName.isNotBlank()) warn(msg = "You set the customize module package name to \"$modulePackageName\", please check for yourself if it is correct")
val realPackageName =
if (modulePackageName.isNotBlank())
warn(msg = "You set the customize module package name to \"$modulePackageName\", please check for yourself if it is correct")
val fModulePackageName =
modulePackageName.ifBlank {
if (packageName.contains(".hook.") || packageName.endsWith(".hook"))
if (packageName.contains(other = ".hook.") || packageName.endsWith(suffix = ".hook"))
packageName.split(".hook")[0]
else error(msg = "Cannot identify your App's package name, please manually configure the package name")
else error(msg = "Cannot identify your Module App's package name, please manually configure the package name")
modulePackageName
}
val injectPackageName = "com.highcapable.yukihookapi.hook.xposed.application.inject"
fun commentContent(name: String) = ("/**\n" +
" * $name Inject Class\n" +
" *\n" +
" * Compiled from YukiHookXposedProcessor\n" +
" *\n" +
" * HookEntryClass: [$className]\n" +
" *\n" +
" * Generate Date: ${SimpleDateFormat.getDateTimeInstance().format(Date())}\n" +
" *\n" +
" * Powered by YukiHookAPI (C) HighCapable 2022\n" +
" *\n" +
" * Project Address: [YukiHookAPI](https://github.com/fankes/YukiHookAPI)\n" +
" */\n")
/** 插入 ModuleApplication_Injector 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = injectPackageName,
fileName = "ModuleApplication_Injector"
).apply {
/** 插入 ModuleApplication_Injector 代码 */
write(
("@file:Suppress(\"ClassName\")\n" +
"\n" +
"package $injectPackageName\n" +
"\n" +
"import $packageName.$className\n" +
"\n" +
commentContent(name = "ModuleApplication") +
"object ModuleApplication_Injector {\n" +
"\n" +
" @JvmStatic\n" +
" fun callApiInit() = try {\n" +
" $className().onInit()\n" +
" } catch (_: Throwable) {\n" +
" }\n" +
"}").toByteArray()
)
write(CodeSourceFileTemplate.getModuleApplicationInjectorFileByteArray(injectPackageName, packageName, entryClassName))
flush()
close()
}
/** 插入 xposed_init 代码 */
codeGenerator.createNewFile(
dependencies = Dependencies.ALL_FILES,
packageName = packageName,
fileName = entryClassName
fileName = xInitClassName
).apply {
/** 插入 xposed_init 代码 */
write(
("package $packageName\n" +
"\n" +
"import androidx.annotation.Keep\n" +
"import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookXposedBridge\n" +
"import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus\n" +
"import com.highcapable.yukihookapi.hook.log.loggerE\n" +
"import de.robv.android.xposed.IXposedHookLoadPackage\n" +
"import de.robv.android.xposed.XC_MethodReplacement\n" +
"import de.robv.android.xposed.XposedHelpers\n" +
"import de.robv.android.xposed.XposedBridge\n" +
"import de.robv.android.xposed.callbacks.XC_LoadPackage\n" +
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
"import $packageName.$className\n" +
"\n" +
commentContent(name = "XposedInit") +
"@Keep\n" +
"@YukiGenerateApi\n" +
"class $entryClassName : IXposedHookLoadPackage {\n" +
"\n" +
" override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" +
" if (lpparam == null) return\n" +
" try {\n" +
" $className().apply {\n" +
" onInit()\n" +
" if (YukiHookXposedBridge.isXposedCallbackSetUp) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"You cannot loading a hooker in \\\"onInit\\\" method! Aborted\")\n" +
" return\n" +
" }\n" +
" onHook()\n" +
" }\n" +
" YukiHookXposedBridge.callXposedInitialized()\n" +
" } catch (e: Throwable) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"YukiHookAPI try to load HookEntryClass failed\", e = e)\n" +
" }\n" +
" if (lpparam.packageName == \"$realPackageName\") {\n" +
" XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" +
" \"$IS_ACTIVE_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = true\n" +
" })\n" +
" XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" +
" \"$GET_XPOSED_TAG_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = try {\n" +
" XposedBridge::class.java.getDeclaredField(\"TAG\").apply { isAccessible = true }.get(null) as String\n" +
" } catch (_: Throwable) {\n" +
" \"invalid\"\n" +
" }\n" +
" })\n" +
" XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" +
" \"$GET_XPOSED_VERSION_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = try {\n" +
" XposedBridge.getXposedVersion()\n" +
" } catch (_: Throwable) {\n" +
" -1\n" +
" }\n" +
" })\n" +
" YukiHookXposedBridge.isModulePackageXposedEnv = true\n" +
" }\n" +
" YukiHookXposedBridge.modulePackageName = \"$realPackageName\"\n" +
" YukiHookXposedBridge.callXposedLoaded(lpparam)\n" +
" }\n" +
"}").toByteArray()
)
write(CodeSourceFileTemplate.getXposedInitFileByteArray(packageName, fModulePackageName, entryClassName, xInitClassName))
flush()
close()
}

View File

@@ -0,0 +1,171 @@
/*
* YukiHookAPI - An efficient Kotlin version of the Xposed Hook API.
* Copyright (C) 2019-2022 HighCapable
* https://github.com/fankes/YukiHookAPI
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* This file is Created by fankes on 2022/4/27.
*/
package com.highcapable.yukihookapi_ksp_xposed.sources
import java.text.SimpleDateFormat
import java.util.*
/**
* 代码文件注入器
*/
object CodeSourceFileTemplate {
/** 定义 Jvm 方法名 */
private const val IS_ACTIVE_METHOD_NAME = "__--"
/** 定义 Jvm 方法名 */
private const val GET_XPOSED_VERSION_METHOD_NAME = "--__"
/** 定义 Jvm 方法名 */
private const val GET_XPOSED_TAG_METHOD_NAME = "_-_-"
/**
* 获得文件注释
* @param entryClassName 入口类名
* @param currrentClassTag 当前注入类标签
* @return [String]
*/
private fun getCommentContent(entryClassName: String, currrentClassTag: String) =
("/**\n" +
" * $currrentClassTag Inject Class\n" +
" *\n" +
" * Compiled from YukiHookXposedProcessor\n" +
" *\n" +
" * HookEntryClass: [$entryClassName]\n" +
" *\n" +
" * Generate Date: ${SimpleDateFormat.getDateTimeInstance().format(Date())}\n" +
" *\n" +
" * Powered by YukiHookAPI (C) HighCapable 2022\n" +
" *\n" +
" * Project Address: [YukiHookAPI](https://github.com/fankes/YukiHookAPI)\n" +
" */\n")
/**
* 获得 ModuleApplication_Injector 注入文件
* @param packageName 包名
* @param entryPackageName 入口类包名
* @param entryClassName 入口类名
* @return [ByteArray]
*/
fun getModuleApplicationInjectorFileByteArray(packageName: String, entryPackageName: String, entryClassName: String) =
("@file:Suppress(\"ClassName\")\n" +
"\n" +
"package $packageName\n" +
"\n" +
"import $entryPackageName.$entryClassName\n" +
"\n" +
getCommentContent(entryClassName, currrentClassTag = "ModuleApplication") +
"object ModuleApplication_Injector {\n" +
"\n" +
" @JvmStatic\n" +
" fun callApiInit() = try {\n" +
" $entryClassName().onInit()\n" +
" } catch (_: Throwable) {\n" +
" }\n" +
"}").toByteArray()
/**
* 获得 xposed_init 注入文件
* @param packageName 包名
* @param modulePackageName 模块包名
* @param entryClassName 入口类名
* @param xInitClassName xposed_init 入口类名
* @return [ByteArray]
*/
fun getXposedInitFileByteArray(packageName: String, modulePackageName: String, entryClassName: String, xInitClassName: String) =
("package $packageName\n" +
"\n" +
"import androidx.annotation.Keep\n" +
"import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookXposedBridge\n" +
"import com.highcapable.yukihookapi.hook.xposed.YukiHookModuleStatus\n" +
"import com.highcapable.yukihookapi.hook.log.loggerE\n" +
"import de.robv.android.xposed.IXposedHookLoadPackage\n" +
"import de.robv.android.xposed.XC_MethodReplacement\n" +
"import de.robv.android.xposed.XposedHelpers\n" +
"import de.robv.android.xposed.XposedBridge\n" +
"import de.robv.android.xposed.callbacks.XC_LoadPackage\n" +
"import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" +
"import $packageName.$entryClassName\n" +
"\n" +
getCommentContent(entryClassName, currrentClassTag = "XposedInit") +
"@Keep\n" +
"@YukiGenerateApi\n" +
"class $xInitClassName : IXposedHookLoadPackage {\n" +
"\n" +
" override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" +
" if (lpparam == null) return\n" +
" try {\n" +
" $entryClassName().apply {\n" +
" onInit()\n" +
" if (YukiHookXposedBridge.isXposedCallbackSetUp) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"You cannot loading a hooker in \\\"onInit\\\" method! Aborted\")\n" +
" return\n" +
" }\n" +
" onHook()\n" +
" }\n" +
" YukiHookXposedBridge.callXposedInitialized()\n" +
" } catch (e: Throwable) {\n" +
" loggerE(tag = \"YukiHookAPI\", msg = \"YukiHookAPI try to load HookEntryClass failed\", e = e)\n" +
" }\n" +
" if (lpparam.packageName == \"$modulePackageName\") {\n" +
" XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" +
" \"$IS_ACTIVE_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = true\n" +
" })\n" +
" XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" +
" \"$GET_XPOSED_TAG_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = try {\n" +
" XposedBridge::class.java.getDeclaredField(\"TAG\").apply { isAccessible = true }.get(null) as String\n" +
" } catch (_: Throwable) {\n" +
" \"invalid\"\n" +
" }\n" +
" })\n" +
" XposedHelpers.findAndHookMethod(\n" +
" YukiHookModuleStatus::class.java.name,\n" +
" lpparam.classLoader,\n" +
" \"$GET_XPOSED_VERSION_METHOD_NAME\",\n" +
" object : XC_MethodReplacement() {\n" +
" override fun replaceHookedMethod(param: MethodHookParam?) = try {\n" +
" XposedBridge.getXposedVersion()\n" +
" } catch (_: Throwable) {\n" +
" -1\n" +
" }\n" +
" })\n" +
" YukiHookXposedBridge.isModulePackageXposedEnv = true\n" +
" }\n" +
" YukiHookXposedBridge.modulePackageName = \"$modulePackageName\"\n" +
" YukiHookXposedBridge.callXposedLoaded(lpparam)\n" +
" }\n" +
"}").toByteArray()
}