diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt index 755da777..ddd3e415 100644 --- a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt +++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/YukiHookXposedProcessor.kt @@ -34,7 +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 com.highcapable.yukihookapi_ksp_xposed.bean.GenerateData +import com.highcapable.yukihookapi_ksp_xposed.factory.sources import org.w3c.dom.Element import org.w3c.dom.Node import java.io.File @@ -68,11 +69,11 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { /** * 创建一个环境方法体方便调用 - * @param ignoredError 是否忽略错误 - 默认否 + * @param ignored 是否忽略错误 - 默认否 * @param env 方法体 */ - private fun environment(ignoredError: Boolean = false, env: SymbolProcessorEnvironment.() -> Unit) { - if (ignoredError) runCatching { environment.apply(env) } + private fun environment(ignored: Boolean = false, env: SymbolProcessorEnvironment.() -> Unit) { + if (ignored) runCatching { environment.apply(env) } else environment.apply(env) } @@ -86,6 +87,18 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { throw RuntimeException("[$TAG] $msg\n$helpMsg") } + /** + * 创建代码文件 - 类型 kt + * @param fileName 文件名 + * @param packageName 包名 + * @param content 代码内容 + */ + private fun SymbolProcessorEnvironment.createCodeFile(fileName: String, packageName: String, content: String?) = + codeGenerator.createNewFile( + dependencies = Dependencies.ALL_FILES, + packageName, fileName + ).apply { content?.toByteArray()?.let { write(it) }; flush() }.close() + /** * 发出警告 * @param msg 错误消息 @@ -98,10 +111,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { */ private fun String.removeSpecialChars() = replace("\\s*|\t|\r|\n".toRegex(), replacement = "").replace(oldValue = "\"", newValue = "'") - override fun process(resolver: Resolver) = emptyList().let { - startProcess(resolver) - it - } + override fun process(resolver: Resolver) = emptyList().let { startProcess(resolver); it } /** * 开始作业入口 @@ -109,40 +119,28 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { */ private fun startProcess(resolver: Resolver) = environment { var isInjectOnce = true + val data = GenerateData() resolver.getSymbolsWithAnnotation(annotationName).apply { /** * 检索需要注入的类 * @param sourcePath 指定的 source 路径 - * @param custMPackageName 自定义模块包名 - * @param xInitClassName xposed_init 入口类名 - * @param isUsingResourcesHook 是否启用 Resources Hook */ - fun fetchKSClassDeclaration( - sourcePath: String, - custMPackageName: String, - xInitClassName: String, - isUsingResourcesHook: Boolean - ) { + fun fetchKSClassDeclaration(sourcePath: String) { asSequence().filterIsInstance().forEach { if (isInjectOnce) when { it.superTypes.any { type -> type.element.toString() == "IYukiHookXposedInit" } -> { - val xInitPatchName = xInitClassName.ifBlank { "${it.simpleName.asString()}$xposedClassShortName" } - if (xInitClassName == it.simpleName.asString()) problem(msg = "Duplicate entryClassName \"$xInitClassName\"") - generateAssetsFile( - codePath = (it.location as? FileLocation?)?.filePath ?: "", - sourcePath = sourcePath, - packageName = it.packageName.asString(), - custMPackageName = custMPackageName, - entryClassName = it.simpleName.asString(), - xInitClassName = xInitPatchName, - isUsingResourcesHook = isUsingResourcesHook - ) + val xInitPatchName = data.xInitClassName.ifBlank { "${it.simpleName.asString()}$xposedClassShortName" } + if (data.xInitClassName == it.simpleName.asString()) + problem(msg = "Duplicate entryClassName \"${data.xInitClassName}\"") + data.entryPackageName = it.packageName.asString() + data.entryClassName = it.simpleName.asString() + data.xInitClassName = xInitPatchName + generateAssetsFile(codePath = (it.location as? FileLocation?)?.filePath ?: "", sourcePath = sourcePath, data) } it.superTypes.any { type -> type.element.toString() == "YukiHookXposedInitProxy" } -> problem(msg = "\"YukiHookXposedInitProxy\" was deprecated, please replace to \"IYukiHookXposedInit\"") else -> problem(msg = "HookEntryClass \"${it.simpleName.asString()}\" must be implements \"IYukiHookXposedInit\"") - } - else problem(msg = "\"@InjectYukiHookWithXposed\" only can be use in once times") + } else problem(msg = "\"@InjectYukiHookWithXposed\" only can be use in once times") /** 仅处理第一个标记的类 - 再次处理将拦截并报错 */ isInjectOnce = false } @@ -150,30 +148,27 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { forEach { it.annotations.forEach { annotation -> var sourcePath = "" // 项目相对路径 - var custMPackageName = "" // 自定义模块包名 - var entryClassName = "" // xposed_init 入口类名 - var isUsingResourcesHook = false // 是否启用 Resources Hook annotation.arguments.forEach { args -> if (args.name?.asString() == "sourcePath") sourcePath = args.value.toString().trim() if (args.name?.asString() == "modulePackageName") - custMPackageName = args.value.toString().trim() + data.customMPackageName = args.value.toString().trim() if (args.name?.asString() == "entryClassName") - entryClassName = args.value.toString().trim() + data.entryClassName = args.value.toString().trim() if (args.name?.asString() == "isUsingResourcesHook") - isUsingResourcesHook = args.value as? Boolean ?: true + data.isUsingResourcesHook = args.value as? Boolean ?: true } - if ((custMPackageName.startsWith(".") || - custMPackageName.endsWith(".") || - custMPackageName.contains(".").not() || - custMPackageName.contains("..")) && - custMPackageName.isNotEmpty() - ) problem(msg = "Invalid modulePackageName \"$custMPackageName\"") - if ((Pattern.compile("[*,.:~`'\"|/\\\\?!^()\\[\\]{}%@#$&\\-+=<>]").matcher(entryClassName).find() || - true.let { for (i in 0..9) if (entryClassName.startsWith(i.toString())) return@let true;false }) - && entryClassName.isNotEmpty() - ) problem(msg = "Invalid entryClassName \"$entryClassName\"") - else fetchKSClassDeclaration(sourcePath, custMPackageName, entryClassName, isUsingResourcesHook) + if ((data.customMPackageName.startsWith(".") || + data.customMPackageName.endsWith(".") || + data.customMPackageName.contains(".").not() || + data.customMPackageName.contains("..")) && + data.customMPackageName.isNotEmpty() + ) problem(msg = "Invalid modulePackageName \"${data.customMPackageName}\"") + if ((Pattern.compile("[*,.:~`'\"|/\\\\?!^()\\[\\]{}%@#$&\\-+=<>]").matcher(data.entryClassName).find() || + true.let { for (i in 0..9) if (data.entryClassName.startsWith(i.toString())) return@let true; false }) + && data.entryClassName.isNotEmpty() + ) problem(msg = "Invalid entryClassName \"${data.entryClassName}\"") + else fetchKSClassDeclaration(sourcePath) } } } @@ -183,21 +178,9 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { * 自动生成 Xposed assets 入口文件 * @param codePath 注解类的完整代码文件路径 * @param sourcePath 指定的 source 路径 - * @param packageName 包名 - * @param custMPackageName 自定义模块包名 - * @param entryClassName 入口类名 - * @param xInitClassName xposed_init 入口类名 - * @param isUsingResourcesHook 是否启用 Resources Hook + * @param data 生成的模板数据 */ - private fun generateAssetsFile( - codePath: String, - sourcePath: String, - packageName: String, - custMPackageName: String, - entryClassName: String, - xInitClassName: String, - isUsingResourcesHook: Boolean - ) = environment { + private fun generateAssetsFile(codePath: String, sourcePath: String, data: GenerateData) = environment { if (codePath.isBlank()) problem(msg = "Project CodePath not available") if (sourcePath.isBlank()) problem(msg = "Project SourcePath not available") /** @@ -214,7 +197,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { val projectPath = when { codePath.contains("\\") -> sourcePath.replace("/", "\\") codePath.contains("/") -> sourcePath.replace("\\", "/") - else -> error("Unix File Separator unknown") + else -> error("Unknown Unix File Separator") }.let { if (codePath.contains(it)) codePath.split(it)[0].apply { rootPath = this } + it @@ -226,78 +209,52 @@ class YukiHookXposedProcessor : SymbolProcessorProvider { val manifestFile = File("$projectPath${separator}AndroidManifest.xml") if (manifestFile.exists()) { if (assetsFile.exists().not() || assetsFile.isDirectory.not()) assetsFile.apply { delete(); mkdirs() } - val modulePackageName = parseModulePackageName(manifestFile, gradleFile, gradleKtsFile) - if (modulePackageName.isBlank() && custMPackageName.isBlank()) + data.modulePackageName = parseModulePackageName(manifestFile, gradleFile, gradleKtsFile) + if (data.modulePackageName.isBlank() && data.customMPackageName.isBlank()) problem(msg = "Cannot identify your Module App's package name, tried AndroidManifest.xml, build.gradle and build.gradle.kts") File("${assetsFile.absolutePath}${separator}xposed_init") - .writeText(text = "$packageName.$xInitClassName") + .writeText(text = "${data.entryPackageName}.${data.xInitClassName}") File("${assetsFile.absolutePath}${separator}yukihookapi_init") - .writeText(text = "$packageName.$entryClassName") - generateClassFile(packageName, modulePackageName, custMPackageName, entryClassName, xInitClassName, isUsingResourcesHook) + .writeText(text = "${data.entryPackageName}.${data.entryClassName}") + generateClassFile(data) } else problem(msg = "Project Source Path \"$sourcePath\" verify failed! Is this an Android Project?") } /** * 自动生成指定类文件 - * @param packageName 包名 - * @param modulePackageName 模块包名 - * @param customMPackageName 自定义模块包名 - * @param entryClassName 入口类名 - * @param xInitClassName xposed_init 入口类名 - * @param isUsingResourcesHook 是否启用 Resources Hook + * @param data 生成的模板数据 */ - private fun generateClassFile( - packageName: String, - modulePackageName: String, - customMPackageName: String, - entryClassName: String, - xInitClassName: String, - isUsingResourcesHook: Boolean - ) = environment(ignoredError = true) { - if (customMPackageName.isNotBlank()) - warn(msg = "You set the customize module package name to \"$customMPackageName\", please check for yourself if it is correct") + private fun generateClassFile(data: GenerateData) = environment(ignored = true) { + if (data.customMPackageName.isNotBlank()) warn( + msg = "You set the customize module package name to \"${data.customMPackageName}\", " + + "please check for yourself if it is correct" + ) val mdAppInjectPackageName = "com.highcapable.yukihookapi.hook.xposed.application.inject" val ykBridgeInjectPackageName = "com.highcapable.yukihookapi.hook.xposed.bridge.inject" /** 插入 ModuleApplication_Injector 代码 */ - codeGenerator.createNewFile( - dependencies = Dependencies.ALL_FILES, + createCodeFile( + fileName = "ModuleApplication_Injector", packageName = mdAppInjectPackageName, - fileName = "ModuleApplication_Injector" - ).apply { - write(CodeSourceFileTemplate.getModuleApplicationInjectorFileByteArray(mdAppInjectPackageName, packageName, entryClassName)) - flush() - close() - } + content = data.apply { injectPackageName = mdAppInjectPackageName }.sources()["ModuleApplication_Injector"] + ) /** 插入 YukiHookBridge_Injector 代码 */ - codeGenerator.createNewFile( - dependencies = Dependencies.ALL_FILES, + createCodeFile( + fileName = "YukiHookBridge_Injector", packageName = ykBridgeInjectPackageName, - fileName = "YukiHookBridge_Injector" - ).apply { - write(CodeSourceFileTemplate.getYukiHookBridgeInjectorFileByteArray(ykBridgeInjectPackageName)) - flush() - close() - } + content = data.apply { injectPackageName = ykBridgeInjectPackageName }.sources()["YukiHookBridge_Injector"] + ) /** 插入 xposed_init 代码 */ - codeGenerator.createNewFile( - dependencies = Dependencies.ALL_FILES, - packageName = packageName, - fileName = xInitClassName - ).apply { - write(CodeSourceFileTemplate.getXposedInitFileByteArray(packageName, entryClassName, xInitClassName, isUsingResourcesHook)) - flush() - close() - } + createCodeFile( + fileName = data.xInitClassName, + packageName = data.entryPackageName, + content = data.sources()["xposed_init"] + ) /** 插入 xposed_init_Impl 代码 */ - codeGenerator.createNewFile( - dependencies = Dependencies.ALL_FILES, - packageName = packageName, - fileName = "${entryClassName}_Impl" - ).apply { - write(CodeSourceFileTemplate.getXposedInitImplFileByteArray(packageName, modulePackageName, customMPackageName, entryClassName)) - flush() - close() - } + createCodeFile( + fileName = "${data.entryClassName}_Impl", + packageName = data.entryPackageName, + content = data.sources()["xposed_init_Impl"] + ) } /** diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/bean/GenerateData.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/bean/GenerateData.kt new file mode 100644 index 00000000..717b781b --- /dev/null +++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/bean/GenerateData.kt @@ -0,0 +1,48 @@ +/* + * 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/9/20. + */ +package com.highcapable.yukihookapi_ksp_xposed.bean + +/** + * 生成的模板数据实例 + * @param entryPackageName 入口类包名 + * @param injectPackageName 注入类包名 + * @param modulePackageName 模块包名 (命名空间) + * @param customMPackageName 自定义模块包名 + * @param entryClassName 入口类名 + * @param xInitClassName xposed_init 入口类名 + * @param isUsingResourcesHook 是否启用 Resources Hook + */ +data class GenerateData( + var entryPackageName: String = "", + var injectPackageName: String = "", + var modulePackageName: String = "", + var customMPackageName: String = "", + var entryClassName: String = "", + var xInitClassName: String = "", + var isUsingResourcesHook: Boolean = true +) \ No newline at end of file diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt new file mode 100644 index 00000000..b07c17cb --- /dev/null +++ b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/factory/CodeSourceFileFactory.kt @@ -0,0 +1,180 @@ +/* + * 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/9/20. + */ +package com.highcapable.yukihookapi_ksp_xposed.factory + +import com.highcapable.yukihookapi_ksp_xposed.bean.GenerateData +import java.text.SimpleDateFormat +import java.util.* + +/** + * 创建文件注释 + * @param entryClassName 入口类名 - 空则不生成 + * @param currrentClassTag 当前注入类标签 + * @return [String] + */ +private fun createCommentContent(entryClassName: String = "", currrentClassTag: String) = + ("/**\n" + + " * $currrentClassTag Inject Class\n" + + " *\n" + + " * Compiled from YukiHookXposedProcessor\n" + + " *\n" + + (if (entryClassName.isNotBlank()) " * HookEntryClass: [$entryClassName]\n *\n" else "") + + " * 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") + +/** + * 获得注入文件代码内容 + * @return [Map]<[String],[String]> + */ +fun GenerateData.sources() = mapOf( + "ModuleApplication_Injector" to ("@file:Suppress(\"ClassName\")\n" + + "\n" + + "package $entryPackageName\n" + + "\n" + + "import $entryPackageName.$entryClassName\n" + + "\n" + + createCommentContent(entryClassName, currrentClassTag = "ModuleApplication") + + "object ModuleApplication_Injector {\n" + + "\n" + + " @JvmStatic\n" + + " fun callApiInit() = try {\n" + + " $entryClassName().onInit()\n" + + " } catch (_: Throwable) {\n" + + " }\n" + + "}"), + "YukiHookBridge_Injector" to ("@file:Suppress(\"ClassName\")\n" + + "\n" + + "package $entryPackageName\n" + + "\n" + + createCommentContent(currrentClassTag = "YukiHookBridge") + + "object YukiHookBridge_Injector {\n" + + "\n" + + " @JvmStatic\n" + + " fun getModuleGeneratedVersion() = \"${System.currentTimeMillis()}\"\n" + + "}"), + "xposed_init" to ("@file:Suppress(\"ClassName\")\n" + + "\n" + + "package $entryPackageName\n" + + "\n" + + "import androidx.annotation.Keep\n" + + "import com.highcapable.yukihookapi.hook.xposed.bridge.event.YukiXposedEvent\n" + + "import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" + + (if (isUsingResourcesHook) "import de.robv.android.xposed.IXposedHookInitPackageResources\n" else "") + + "import de.robv.android.xposed.IXposedHookLoadPackage\n" + + "import de.robv.android.xposed.IXposedHookZygoteInit\n" + + (if (isUsingResourcesHook) "import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" else "") + + "import de.robv.android.xposed.callbacks.XC_LoadPackage\n" + + "\n" + + createCommentContent(entryClassName, currrentClassTag = "Xposed Init") + + "@Keep\n" + + "@YukiGenerateApi\n" + + "class $xInitClassName : IXposedHookZygoteInit, IXposedHookLoadPackage" + + "${if (isUsingResourcesHook) ", IXposedHookInitPackageResources" else ""} {\n" + + "\n" + + " override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" + + " ${entryClassName}_Impl.callInitZygote(sparam)\n" + + " YukiXposedEvent.EventHandler.callInitZygote(sparam)\n" + + " }\n" + + "\n" + + " override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" + + " ${entryClassName}_Impl.callHandleLoadPackage(lpparam)\n" + + " YukiXposedEvent.EventHandler.callHandleLoadPackage(lpparam)\n" + + " }\n" + + (if (isUsingResourcesHook) + ("\n override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" + + " ${entryClassName}_Impl.callHandleInitPackageResources(resparam)\n" + + " YukiXposedEvent.EventHandler.callHandleInitPackageResources(resparam)\n" + + " }\n") else "") + + "}"), + "xposed_init_Impl" to ("@file:Suppress(\"ClassName\")\n" + + "\n" + + "package $entryPackageName\n" + + "\n" + + "import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" + + "import com.highcapable.yukihookapi.hook.log.loggerE\n" + + "import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge\n" + + "import de.robv.android.xposed.IXposedHookZygoteInit\n" + + "import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" + + "import de.robv.android.xposed.callbacks.XC_LoadPackage\n" + + (if (customMPackageName.isBlank()) "import $modulePackageName.BuildConfig\n" else "") + + "\n" + + createCommentContent(entryClassName, currrentClassTag = "Xposed Init Impl") + + "@YukiGenerateApi\n" + + "object ${entryClassName}_Impl {\n" + + "\n" + + " private const val modulePackageName = " + + (if (customMPackageName.isNotBlank()) "\"$customMPackageName\"" else "BuildConfig.APPLICATION_ID") + "\n" + + "\n" + + " private var isZygoteBinded = false\n" + + "\n" + + " private val hookEntry = $entryClassName()\n" + + "\n" + + " private fun callXposedLoaded(\n" + + " isZygoteLoaded: Boolean = false,\n" + + " lpparam: XC_LoadPackage.LoadPackageParam? = null,\n" + + " resparam: XC_InitPackageResources.InitPackageResourcesParam? = null\n" + + " ) {\n" + + " if (isZygoteBinded.not()) runCatching {\n" + + " hookEntry.onXposedEvent()\n" + + " hookEntry.onInit()\n" + + " if (YukiHookBridge.isXposedCallbackSetUp) {\n" + + " loggerE(msg = \"You cannot load a hooker in \\\"onInit\\\" or \\\"onXposedEvent\\\" method! Aborted\")\n" + + " return\n" + + " }\n" + + " hookEntry.onHook()\n" + + " YukiHookBridge.callXposedInitialized()\n" + + " YukiHookBridge.modulePackageName = modulePackageName\n" + + " }.onFailure { loggerE(msg = \"YukiHookAPI try to load HookEntryClass failed\", e = it) }\n" + + " YukiHookBridge.callXposedLoaded(isZygoteLoaded, lpparam, resparam)\n" + + " }\n" + + "\n" + + " @YukiGenerateApi\n" + + " fun callInitZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" + + " if (sparam == null) return\n" + + " runCatching {\n" + + " YukiHookBridge.callXposedZygoteLoaded(sparam)\n" + + " }.onFailure { loggerE(msg = \"YukiHookAPI bind initZygote failed\", e = it) }\n" + + " callXposedLoaded(isZygoteLoaded = true)\n" + + " isZygoteBinded = true\n" + + " }\n" + + "\n" + + " @YukiGenerateApi\n" + + " fun callHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" + + " if (lpparam != null) callXposedLoaded(lpparam = lpparam)\n" + + " }\n" + + "\n" + + " @YukiGenerateApi\n" + + " fun callHandleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" + + " if (resparam != null) callXposedLoaded(resparam = resparam)\n" + + " }\n" + + "}") +) \ No newline at end of file diff --git a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/sources/CodeSourceFileTemplate.kt b/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/sources/CodeSourceFileTemplate.kt deleted file mode 100644 index c3384254..00000000 --- a/yukihookapi-ksp-xposed/src/api/kotlin/com/highcapable/yukihookapi_ksp_xposed/sources/CodeSourceFileTemplate.kt +++ /dev/null @@ -1,214 +0,0 @@ -/* - * 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 { - - /** - * 获得文件注释 - * @param entryClassName 入口类名 - 空则不生成 - * @param currrentClassTag 当前注入类标签 - * @return [String] - */ - private fun getCommentContent(entryClassName: String = "", currrentClassTag: String) = - ("/**\n" + - " * $currrentClassTag Inject Class\n" + - " *\n" + - " * Compiled from YukiHookXposedProcessor\n" + - " *\n" + - (if (entryClassName.isNotBlank()) " * HookEntryClass: [$entryClassName]\n *\n" else "") + - " * 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() - - /** - * 获得 YukiHookBridge_Injector 注入文件 - * @param packageName 包名 - * @return [ByteArray] - */ - fun getYukiHookBridgeInjectorFileByteArray(packageName: String) = - ("@file:Suppress(\"ClassName\")\n" + - "\n" + - "package $packageName\n" + - "\n" + - getCommentContent(currrentClassTag = "YukiHookBridge") + - "object YukiHookBridge_Injector {\n" + - "\n" + - " @JvmStatic\n" + - " fun getModuleGeneratedVersion() = \"${System.currentTimeMillis()}\"\n" + - "}").toByteArray() - - /** - * 获得 xposed_init 注入文件 - * @param packageName 包名 - * @param entryClassName 入口类名 - * @param xInitClassName xposed_init 入口类名 - * @param isUsingResourcesHook 是否启用 Resources Hook - * @return [ByteArray] - */ - fun getXposedInitFileByteArray(packageName: String, entryClassName: String, xInitClassName: String, isUsingResourcesHook: Boolean) = - ("@file:Suppress(\"ClassName\")\n" + - "\n" + - "package $packageName\n" + - "\n" + - "import androidx.annotation.Keep\n" + - "import com.highcapable.yukihookapi.hook.xposed.bridge.event.YukiXposedEvent\n" + - "import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" + - (if (isUsingResourcesHook) "import de.robv.android.xposed.IXposedHookInitPackageResources\n" else "") + - "import de.robv.android.xposed.IXposedHookLoadPackage\n" + - "import de.robv.android.xposed.IXposedHookZygoteInit\n" + - (if (isUsingResourcesHook) "import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" else "") + - "import de.robv.android.xposed.callbacks.XC_LoadPackage\n" + - "\n" + - getCommentContent(entryClassName, currrentClassTag = "Xposed Init") + - "@Keep\n" + - "@YukiGenerateApi\n" + - "class $xInitClassName : IXposedHookZygoteInit, IXposedHookLoadPackage" + - "${if (isUsingResourcesHook) ", IXposedHookInitPackageResources" else ""} {\n" + - "\n" + - " override fun initZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" + - " ${entryClassName}_Impl.callInitZygote(sparam)\n" + - " YukiXposedEvent.EventHandler.callInitZygote(sparam)\n" + - " }\n" + - "\n" + - " override fun handleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" + - " ${entryClassName}_Impl.callHandleLoadPackage(lpparam)\n" + - " YukiXposedEvent.EventHandler.callHandleLoadPackage(lpparam)\n" + - " }\n" + - (if (isUsingResourcesHook) - ("\n override fun handleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" + - " ${entryClassName}_Impl.callHandleInitPackageResources(resparam)\n" + - " YukiXposedEvent.EventHandler.callHandleInitPackageResources(resparam)\n" + - " }\n") else "") + - "}").toByteArray() - - /** - * 获得 xposed_init_Impl 注入文件 - * @param packageName 包名 - * @param modulePackageName 模块包名 - * @param customMPackageName 自定义模块包名 - * @param entryClassName 入口类名 - * @return [ByteArray] - */ - fun getXposedInitImplFileByteArray(packageName: String, modulePackageName: String, customMPackageName: String, entryClassName: String) = - ("@file:Suppress(\"ClassName\")\n" + - "\n" + - "package $packageName\n" + - "\n" + - "import com.highcapable.yukihookapi.annotation.YukiGenerateApi\n" + - "import com.highcapable.yukihookapi.hook.log.loggerE\n" + - "import com.highcapable.yukihookapi.hook.xposed.bridge.YukiHookBridge\n" + - "import de.robv.android.xposed.IXposedHookZygoteInit\n" + - "import de.robv.android.xposed.callbacks.XC_InitPackageResources\n" + - "import de.robv.android.xposed.callbacks.XC_LoadPackage\n" + - (if (customMPackageName.isBlank()) "import $modulePackageName.BuildConfig\n" else "") + - "\n" + - getCommentContent(entryClassName, currrentClassTag = "Xposed Init Impl") + - "@YukiGenerateApi\n" + - "object ${entryClassName}_Impl {\n" + - "\n" + - " private const val modulePackageName = " + - (if (customMPackageName.isNotBlank()) "\"$customMPackageName\"" else "BuildConfig.APPLICATION_ID") + "\n" + - "\n" + - " private var isZygoteBinded = false\n" + - "\n" + - " private val hookEntry = $entryClassName()\n" + - "\n" + - " private fun callXposedLoaded(\n" + - " isZygoteLoaded: Boolean = false,\n" + - " lpparam: XC_LoadPackage.LoadPackageParam? = null,\n" + - " resparam: XC_InitPackageResources.InitPackageResourcesParam? = null\n" + - " ) {\n" + - " if (isZygoteBinded.not()) runCatching {\n" + - " hookEntry.onXposedEvent()\n" + - " hookEntry.onInit()\n" + - " if (YukiHookBridge.isXposedCallbackSetUp) {\n" + - " loggerE(msg = \"You cannot load a hooker in \\\"onInit\\\" or \\\"onXposedEvent\\\" method! Aborted\")\n" + - " return\n" + - " }\n" + - " hookEntry.onHook()\n" + - " YukiHookBridge.callXposedInitialized()\n" + - " YukiHookBridge.modulePackageName = modulePackageName\n" + - " }.onFailure { loggerE(msg = \"YukiHookAPI try to load HookEntryClass failed\", e = it) }\n" + - " YukiHookBridge.callXposedLoaded(isZygoteLoaded, lpparam, resparam)\n" + - " }\n" + - "\n" + - " @YukiGenerateApi\n" + - " fun callInitZygote(sparam: IXposedHookZygoteInit.StartupParam?) {\n" + - " if (sparam == null) return\n" + - " runCatching {\n" + - " YukiHookBridge.callXposedZygoteLoaded(sparam)\n" + - " }.onFailure { loggerE(msg = \"YukiHookAPI bind initZygote failed\", e = it) }\n" + - " callXposedLoaded(isZygoteLoaded = true)\n" + - " isZygoteBinded = true\n" + - " }\n" + - "\n" + - " @YukiGenerateApi\n" + - " fun callHandleLoadPackage(lpparam: XC_LoadPackage.LoadPackageParam?) {\n" + - " if (lpparam != null) callXposedLoaded(lpparam = lpparam)\n" + - " }\n" + - "\n" + - " @YukiGenerateApi\n" + - " fun callHandleInitPackageResources(resparam: XC_InitPackageResources.InitPackageResourcesParam?) {\n" + - " if (resparam != null) callXposedLoaded(resparam = resparam)\n" + - " }\n" + - "}").toByteArray() -} \ No newline at end of file