fix: module package name obtain function

This commit is contained in:
2023-10-05 02:15:15 +08:00
parent c921348572
commit b38d2b63ea
2 changed files with 50 additions and 76 deletions

View File

@@ -44,12 +44,9 @@ import com.highcapable.yukihookapi.factory.ClassName
import com.highcapable.yukihookapi.factory.PackageName import com.highcapable.yukihookapi.factory.PackageName
import com.highcapable.yukihookapi.factory.sources import com.highcapable.yukihookapi.factory.sources
import com.highcapable.yukihookapi.generated.YukiHookAPIProperties import com.highcapable.yukihookapi.generated.YukiHookAPIProperties
import org.w3c.dom.Element
import org.w3c.dom.Node
import java.io.File import java.io.File
import java.util.* import java.util.*
import java.util.regex.Pattern import java.util.regex.Pattern
import javax.xml.parsers.DocumentBuilderFactory
/** /**
* 这是 [YukiHookAPI] 的自动生成处理类 - 核心基于 KSP * 这是 [YukiHookAPI] 的自动生成处理类 - 核心基于 KSP
@@ -99,7 +96,7 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
private fun SymbolProcessorEnvironment.problem(msg: String): Nothing { private fun SymbolProcessorEnvironment.problem(msg: String): Nothing {
val helpMsg = "Looking for help? Please see the documentation link below\n" + val helpMsg = "Looking for help? Please see the documentation link below\n" +
"- English: https://fankes.github.io/YukiHookAPI/en/config/xposed-using\n" + "- English: https://fankes.github.io/YukiHookAPI/en/config/xposed-using\n" +
"- Chinese(Simplified): https://fankes.github.io/YukiHookAPI/zh-cn/config/xposed-using" "- Chinese (Simplified): https://fankes.github.io/YukiHookAPI/zh-cn/config/xposed-using"
logger.error(message = "[$TAG] $msg\n$helpMsg") logger.error(message = "[$TAG] $msg\n$helpMsg")
throw RuntimeException("[$TAG] $msg\n$helpMsg") throw RuntimeException("[$TAG] $msg\n$helpMsg")
} }
@@ -163,8 +160,11 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
ClassKind.CLASS -> false ClassKind.CLASS -> false
ClassKind.OBJECT -> true ClassKind.OBJECT -> true
else -> problem(msg = "Invalid hook entry class \"${it.simpleName.asString()}\" kind \"${it.classKind}\"") else -> problem(msg = "Invalid hook entry class \"${it.simpleName.asString()}\" kind \"${it.classKind}\"")
} }; generateAssetsFile(
generateAssetsFile(codePath = (it.location as? FileLocation?)?.filePath ?: "", sourcePath = sourcePath, data) codePath = (it.location as? FileLocation?)?.filePath?.parseFileSeparator() ?: "",
sourcePath = sourcePath.parseFileSeparator(),
data = data
)
} }
it.superTypes.any { type -> type.element.toString() == "YukiHookXposedInitProxy" } -> it.superTypes.any { type -> type.element.toString() == "YukiHookXposedInitProxy" } ->
problem(msg = "\"YukiHookXposedInitProxy\" was deprecated, please replace to \"IYukiHookXposedInit\"") problem(msg = "\"YukiHookXposedInitProxy\" was deprecated, please replace to \"IYukiHookXposedInit\"")
@@ -212,47 +212,26 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
* @param data 生成的模板数据 * @param data 生成的模板数据
*/ */
private fun generateAssetsFile(codePath: String, sourcePath: String, data: GenerateData) = environment { private fun generateAssetsFile(codePath: String, sourcePath: String, data: GenerateData) = environment {
if (codePath.isBlank()) problem(msg = "Project CodePath not available") if (codePath.isBlank()) problem(msg = "Project code path not available")
if (sourcePath.isBlank()) problem(msg = "Project SourcePath not available") if (sourcePath.isBlank()) problem(msg = "Project source path not available")
/** val projectDir = if (codePath.contains(sourcePath))
* Gradle 在这里自动处理了 Windows 和 Unix 下的反斜杠路径问题 codePath.split(sourcePath)[0].toFile()
* else problem(msg = "Project source path \"$sourcePath\" not matched")
* 为了防止万一还是做了一下反斜杠处理防止旧版本不支持此用法 val manifestFile = projectDir.resolve(sourcePath).resolve("AndroidManifest.xml")
*/ val assetsDir = projectDir.resolve(sourcePath).resolve("assets")
val separator = when { val metaInfDir = projectDir.resolve(sourcePath).resolve("resources").resolve("META-INF")
codePath.contains("\\") -> "\\"
codePath.contains("/") -> "/"
else -> error("Unix File Separator unknown")
}
var rootPath = ""
val projectPath = when {
codePath.contains("\\") -> sourcePath.replace("/", "\\")
codePath.contains("/") -> sourcePath.replace("\\", "/")
else -> error("Unknown Unix File Separator")
}.let {
if (codePath.contains(it))
codePath.split(it)[0].apply { rootPath = this } + it
else problem(msg = "Project Source Path \"$it\" not matched")
}
val gradleFile = File("$rootPath${separator}build.gradle")
val gradleKtsFile = File("$rootPath${separator}build.gradle.kts")
val manifestFile = File("$projectPath${separator}AndroidManifest.xml")
val assetsFolder = File("$projectPath${separator}assets")
val metaInfFolder = File("$projectPath${separator}resources${separator}META-INF")
if (manifestFile.exists()) { if (manifestFile.exists()) {
if (assetsFolder.exists().not() || assetsFolder.isDirectory.not()) assetsFolder.apply { delete(); mkdirs() } if (assetsDir.exists().not() || assetsDir.isDirectory.not()) assetsDir.apply { delete(); mkdirs() }
if (metaInfFolder.exists().not() || metaInfFolder.isDirectory.not()) metaInfFolder.apply { delete(); mkdirs() } if (metaInfDir.exists().not() || metaInfDir.isDirectory.not()) metaInfDir.apply { delete(); mkdirs() }
data.modulePackageName = parseModulePackageName(manifestFile, gradleFile, gradleKtsFile) data.modulePackageName = parseModulePackageName(projectDir)
if (data.modulePackageName.isBlank() && data.customMPackageName.isBlank()) 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") problem(msg = "Cannot identify your Module App's package name, please make sure \"BuildConfig.java\" is generated correctly")
File("${assetsFolder.absolutePath}${separator}xposed_init") assetsDir.resolve("xposed_init").writeText(text = "${data.entryPackageName}.${data.xInitClassName}")
.writeText(text = "${data.entryPackageName}.${data.xInitClassName}") metaInfDir.resolve("yukihookapi_init").writeText(text = "${data.entryPackageName}.${data.entryClassName}")
File("${metaInfFolder.absolutePath}${separator}yukihookapi_init")
.writeText(text = "${data.entryPackageName}.${data.entryClassName}")
/** 移除旧版本 API 创建的入口类名称文件 */ /** 移除旧版本 API 创建的入口类名称文件 */
File("${assetsFolder.absolutePath}${separator}yukihookapi_init").apply { if (exists()) delete() } assetsDir.resolve("yukihookapi_init").apply { if (exists()) delete() }
generateClassFile(data) generateClassFile(data)
} else problem(msg = "Project Source Path \"$sourcePath\" verify failed! Is this an Android Project?") } else problem(msg = "Project source path \"$sourcePath\" verify failed, is this an Android project?")
} }
/** /**
@@ -330,37 +309,33 @@ class YukiHookXposedProcessor : SymbolProcessorProvider {
/** /**
* 解析模块包名 * 解析模块包名
* @param manifestFile AndroidManifest.xml 文件 * @param projectDir 项目目录
* @param gradleFile build.gradle 文件
* @param gradleKtsFile build.gradle.kts 文件
* @return [String] 模块包名 * @return [String] 模块包名
*/ */
private fun parseModulePackageName(manifestFile: File, gradleFile: File, gradleKtsFile: File) = when { private fun parseModulePackageName(projectDir: File): String {
gradleFile.exists() -> runCatching { val buildConfigFile = projectDir
gradleFile.readText() .resolve("build")
.removeSpecialChars() .resolve("generated")
.split("namespace'")[1] .resolve("source")
.split("'")[0] .resolve("buildConfig")
}.getOrNull() .walkTopDown()
gradleKtsFile.exists() -> runCatching { .filter { it.name == "BuildConfig.java" }
gradleKtsFile.readText() .sortedByDescending { it.lastModified() }
.removeSpecialChars() .firstOrNull() ?: return ""
.replace("varnamespace", "") val matcher = "APPLICATION_ID\\s*=\\s*\"([^\"]+)\"".toRegex()
.replace("valnamespace", "") return runCatching { matcher.find(buildConfigFile.readText())?.groups?.get(1)?.value }.getOrNull() ?: ""
.split("namespace='")[1]
.split("'")[0]
}.getOrNull()
else -> null
} ?: runCatching {
DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(manifestFile).let { document ->
document.getElementsByTagName("manifest").let { nodeList ->
nodeList.item(0).let { node ->
if (node.nodeType == Node.ELEMENT_NODE)
(node as? Element?)?.getAttribute("package") ?: ""
else ""
} }
}
} /**
}.getOrNull() ?: "" * 格式化文件分隔符
* @return [String]
*/
private fun String.parseFileSeparator() = replace("\\", "/")
/**
* 字符串转换为 [File]
* @return [File]
*/
private fun String.toFile() = File(parseFileSeparator())
} }
} }

View File

@@ -346,11 +346,10 @@ fun GenerateData.sources() = mapOf(
import de.robv.android.xposed.XposedBridge import de.robv.android.xposed.XposedBridge
import de.robv.android.xposed.callbacks.XC_InitPackageResources import de.robv.android.xposed.callbacks.XC_InitPackageResources
import de.robv.android.xposed.callbacks.XC_LoadPackage import de.robv.android.xposed.callbacks.XC_LoadPackage
${if (customMPackageName.isBlank()) "import $modulePackageName.BuildConfig" else ""}
""".trimIndent() + "\n\n" + createCommentContent("Xposed Init Impl") + "\n" + """ """.trimIndent() + "\n\n" + createCommentContent("Xposed Init Impl") + "\n" + """
object ${entryClassName}_Impl { object ${entryClassName}_Impl {
private const val modulePackageName = ${if (customMPackageName.isNotBlank()) "\"$customMPackageName\"" else "BuildConfig.APPLICATION_ID"} private const val MODULE_PACKAGE_NAME = "${customMPackageName.ifBlank { modulePackageName }}"
private var isZygoteCalled = false private var isZygoteCalled = false
private val hookEntry = ${if (isEntryClassKindOfObject) entryClassName else "$entryClassName()"} private val hookEntry = ${if (isEntryClassKindOfObject) entryClassName else "$entryClassName()"}
@@ -387,7 +386,7 @@ fun GenerateData.sources() = mapOf(
fun callInitZygote(sparam: IXposedHookZygoteInit.StartupParam?) { fun callInitZygote(sparam: IXposedHookZygoteInit.StartupParam?) {
if (sparam == null) return if (sparam == null) return
runCatching { runCatching {
${ExternalCallerName.YukiXposedModuleCaller.second}.callOnStartLoadModule(modulePackageName, sparam.modulePath) ${ExternalCallerName.YukiXposedModuleCaller.second}.callOnStartLoadModule(MODULE_PACKAGE_NAME, sparam.modulePath)
callOnXposedModuleLoaded(isZygoteLoaded = true) callOnXposedModuleLoaded(isZygoteLoaded = true)
isZygoteCalled = true isZygoteCalled = true
}.onFailure { ${ExternalCallerName.YukiXposedModuleCaller.second}.callLogError("An exception occurred when YukiHookAPI loading Xposed Module", it) } }.onFailure { ${ExternalCallerName.YukiXposedModuleCaller.second}.callLogError("An exception occurred when YukiHookAPI loading Xposed Module", it) }