6.7.0 - Alpha6 - Gradle 构建脚本支持自动生成 VersionCodesList 类所需数据以降低脚本启动延迟

This commit is contained in:
SuperMonster003
2025-10-09 17:12:26 +08:00
parent aa603aac44
commit 0ff16b8ec0
20 changed files with 412 additions and 182 deletions

View File

@@ -1,7 +1,7 @@
{
"$data": {
"v6.7.0": {
"released_date": "2025/10/05",
"released_date": "2025/10/09",
"feature": [
"zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))",
"mediainfo 模块, 用于查看媒体文件的详细信息 (参阅 项目文档 > [媒体信息](https://docs.autojs6.com/#/mediainfo))",
@@ -43,6 +43,7 @@
"使用 LiveData 及 SharedFlow 替代已弃用的 LocalBroadcastManager",
"Gradle 构建脚本提升 7z 格式文件的解压效率",
"Gradle 构建脚本支持获取详细的 Android Studio IDE 版本 (如 \"2025.1.4.7\")",
"Gradle 构建脚本支持自动生成 VersionCodesList 类所需数据以降低脚本启动延迟",
"使用版本目录 (Version Catalogs) 集中管理 Gradle 依赖和插件版本",
"模块化 Gradle 构建脚本, 将共享构建逻辑迁移至 buildSrc 并抽象为约定插件",
"使用 Toolchain 替代 sourceCompatibility/targetCompatibility 以降低构建环境差异"

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="app (legacy)" type="AndroidRunConfigurationType" factoryName="Android App" singleton="true">
<module name="AutoJs6.app.main" />
<module name="root.app.main" />
<option name="DEPLOY" value="true" />
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />
<option name="DEPLOY_AS_INSTANT" value="false" />

View File

@@ -1,6 +1,6 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="app (modern)" type="AndroidRunConfigurationType" factoryName="Android App" singleton="true">
<module name="AutoJs6.app" />
<module name="root.app" />
<option name="ANDROID_RUN_CONFIGURATION_SCHEMA_VERSION" value="1" />
<option name="DEPLOY" value="true" />
<option name="DEPLOY_APK_FROM_BUNDLE" value="false" />

1
app/.gitignore vendored
View File

@@ -6,4 +6,3 @@
/src/main/assets/modules/obsolete/
**/*.bak.java
gradle-util-*.js

View File

@@ -405,6 +405,11 @@ dependencies /* Auto.js Extensions */ {
implementation(project(":modules:color-picker"))
}
dependencies /* Build Logic */ {
// Version Codes Generator
ksp(libs.ksp.version.codes.processor)
}
dependencies /* Archived */ {
// Kotlin
// @Comment by SuperMonster003 on May 19, 2022.

View File

@@ -2,71 +2,17 @@ package org.autojs.autojs.runtime.api.augment.util
import android.os.Build
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import org.autojs.autojs.util.RhinoUtils.newNativeObject
import org.mozilla.javascript.ScriptableObject.PERMANENT
import org.mozilla.javascript.ScriptableObject.READONLY
object VersionCodesInfo {
// @Updated by SuperMonster003 on Jun 26, 2025.
// @Reference https://en.wikipedia.org/wiki/Android_version_history
private val raw = mutableMapOf(
"BAKLAVA" to listOf("Android 16", "Baklava", "16", "36", "Jun 10, 2025"),
"VANILLA_ICE_CREAM" to listOf("Android 15", "Vanilla Ice Cream", "15", "35", "September 3, 2024"),
"UPSIDE_DOWN_CAKE" to listOf("Android 14", "Upside Down Cake", "14", "34", "October 4, 2023"),
"TIRAMISU" to listOf("Android 13", "Tiramisu", "13", "33", "August 15, 2022"),
"S_V2" to listOf("Android 12L", "Snow Cone v2", "12.1", "32", "March 7, 2022"),
"S" to listOf("Android 12", "Snow Cone", "12", "31", "October 4, 2021"),
"R" to listOf("Android 11", "Red Velvet Cake", "11", "30", "September 8, 2020"),
"Q" to listOf("Android 10", "Quince Tart", "10", "29", "September 3, 2019"),
"P" to listOf("Android Pie", "Pistachio Ice Cream", "9", "28", "August 6, 2018"),
"O_MR1" to listOf("Android Oreo", "Oatmeal Cookie", "8.1", "27", "December 5, 2017"),
"O" to listOf("Android Oreo", "Oatmeal Cookie", "8.0", "26", "August 21, 2017"),
"N_MR1" to listOf("Android Nougat", "New York Cheesecake", "7.1-7.1.2", "25", "October 4, 2016"),
"N" to listOf("Android Nougat", "New York Cheesecake", "7.0", "24", "August 22, 2016"),
"M" to listOf("Android Marshmallow", "Macadamia Nut Cookie", "6.0-6.0.1", "23", "October 2, 2015"),
"LOLLIPOP_MR1" to listOf("Android Lollipop", "Lemon Meringue Pie", "5.1-5.1.1", "22", "March 2, 2015"),
"LOLLIPOP" to listOf("Android Lollipop", "Lemon Meringue Pie", "5.0-5.0.2", "21", "November 4, 2014"),
"KITKAT_WATCH" to listOf("Android KitKat", "Key Lime Pie", "4.4W-4.4W.2", "20", "June 25, 2014"),
"KITKAT" to listOf("Android KitKat", "Key Lime Pie", "4.4-4.4.4", "19", "October 31, 2013"),
"JELLY_BEAN_MR2" to listOf("Android Jelly Bean", "Jelly Bean", "4.3-4.3.1", "18", "July 24, 2013"),
"JELLY_BEAN_MR1" to listOf("Android Jelly Bean", "Jelly Bean", "4.2-4.2.2", "17", "November 13, 2012"),
"JELLY_BEAN" to listOf("Android Jelly Bean", "Jelly Bean", "4.1-4.1.2", "16", "July 9, 2012"),
"ICE_CREAM_SANDWICH_MR1" to listOf("Android Ice Cream Sandwich", "Ice Cream Sandwich", "4.0.3-4.0.4", "15", "December 16, 2011"),
"ICE_CREAM_SANDWICH" to listOf("Android Ice Cream Sandwich", "Ice Cream Sandwich", "4.0-4.0.2", "14", "October 18, 2011"),
"HONEYCOMB_MR2" to listOf("Android Honeycomb", "Honeycomb", "3.2-3.2.6", "13", "July 15, 2011"),
"HONEYCOMB_MR1" to listOf("Android Honeycomb", "Honeycomb", "3.1", "12", "May 10, 2011"),
"HONEYCOMB" to listOf("Android Honeycomb", "Honeycomb", "3.0", "11", "February 22, 2011"),
"GINGERBREAD_MR1" to listOf("Android Gingerbread", "Gingerbread", "2.3.3-2.3.7", "10", "February 9, 2011"),
"GINGERBREAD" to listOf("Android Gingerbread", "Gingerbread", "2.3-2.3.2", "9", "December 6, 2010"),
"FROYO" to listOf("Android Froyo", "Froyo", "2.2-2.2.3", "8", "May 20, 2010"),
"ECLAIR_MR1" to listOf("Android Eclair", "Eclair", "2.1", "7", "January 11, 2010"),
"ECLAIR_0_1" to listOf("Android Eclair", "Eclair", "2.0.1", "6", "December 3, 2009"),
"ECLAIR" to listOf("Android Eclair", "Eclair", "2.0", "5", "October 27, 2009"),
"DONUT" to listOf("Android Donut", "Donut", "1.6", "4", "September 15, 2009"),
"CUPCAKE" to listOf("Android Cupcake", "Cupcake", "1.5", "3", "April 27, 2009"),
"BASE_1_1" to listOf("Android 1.1", "Petit Four", "1.1", "2", "February 9, 2009"),
"BASE" to listOf("Android 1.0", "", "1.0", "1", "September 23, 2008"),
)
val list = mutableListOf<VersionCodes.Info>()
val obj = newNativeObject()
init {
for ((versionCode, infoList) in raw) {
val (releaseName, internalCodename, platformVersion, apiLevel, releaseDate) = infoList
val info = VersionCodes.Info(versionCode, releaseName, internalCodename, platformVersion, apiLevel, releaseDate)
obj.defineProperty(versionCode, { info.toNativeObject() }, null, READONLY or PERMANENT)
list += info
}
}
val list = VersionCodesInfoGenerated.list
val obj = VersionCodesInfoGenerated.obj
@JvmStatic
@JvmOverloads
fun briefOfVersionInt(versionInt: Int, isCompat: Boolean = false): String {
fun briefOfVersionInt(versionInt: Int, isCompact: Boolean = false): String {
return list.find { runCatching { it.apiLevel.toInt() }.getOrNull() == versionInt }?.let { info ->
var result = "${if (isCompat) "API Lv." else "Android API Level "}${info.apiLevel}"
var result = "${if (isCompact) "API Lv." else "Android API Level "}${info.apiLevel}"
info.releaseName.takeIf { it.isNotBlank() }?.let { result += " ($it)" }
info.internalCodename.takeIf { it.isNotBlank() }?.let { result += " [$it]" }
result

2
build-logic/.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
.idea/
/build/

View File

@@ -0,0 +1,49 @@
import java.util.*
plugins {
`kotlin-dsl` /* kotlin("jvm") */
}
repositories {
mavenCentral()
google()
}
gradle.extra["jdk"] = run determineBuildLogicJdk@{
val propsFile: File = rootDir.parentFile.resolve("version.properties")
val minSupported: Int = Properties().let { props ->
require(propsFile.isFile) {
"version.properties not found in root directory"
}
propsFile.inputStream().use { props.load(it) }
val minSupportedVersion = props.getProperty("JAVA_VERSION_MIN_SUPPORTED")
require(minSupportedVersion != null) {
"version.properties does not contain \"JAVA_VERSION_MIN_SUPPORTED\""
}
minSupportedVersion.toInt()
}
val current = JavaVersion.current().majorVersion.toIntOrNull() ?: minSupported
fun tryAdjustByKotlinJvmTarget(sourceVersion: Int): Int {
return runCatching {
val cls = Class.forName("org.jetbrains.kotlin.gradle.dsl.JvmTarget")
val enumConstants = cls.enumConstants ?: return sourceVersion
var tmpVersion = sourceVersion
while (tmpVersion > minSupported) {
val wanted = "JVM_$tmpVersion"
if (enumConstants.any { it?.toString().equals(wanted, ignoreCase = true) }) {
return tmpVersion
}
tmpVersion -= 1
}
return@runCatching sourceVersion
}.getOrDefault(sourceVersion)
}
tryAdjustByKotlinJvmTarget(maxOf(current, minSupported)).also {
println("Toolchain: selected [$it] / current [$current] / min [$minSupported]")
}
}.also { jdk ->
kotlin { jvmToolchain(jdk) }
java { toolchain.languageVersion.set(JavaLanguageVersion.of(jdk)) }
}

View File

@@ -1,3 +1,3 @@
/build
/.gradle
/.kotlin
/.gradle/
/.kotlin/
/build/

View File

@@ -1,5 +1,3 @@
import java.util.Properties
plugins {
`kotlin-dsl` /* kotlin("jvm") */
`java-gradle-plugin`
@@ -7,6 +5,7 @@ plugins {
repositories {
mavenCentral()
google()
}
dependencies {
@@ -19,28 +18,28 @@ dependencies {
gradlePlugin {
plugins {
register("utils") {
id = "org.autojs.build.utils"
implementationClass = "org.autojs.build.UtilsPlugin"
displayName = "AutoJs6 Build Utils Plugin"
description = "Provides utilities for downloading, extracting archives, and version helpers."
id = "org.autojs.build.utils"
implementationClass = "org.autojs.build.UtilsPlugin"
displayName = "AutoJs6 Build Utils Plugin"
description = "Provides utilities for downloading, extracting archives, and version helpers."
}
register("versions") {
id = "org.autojs.build.versions"
implementationClass = "org.autojs.build.VersionsPlugin"
displayName = "AutoJs6 Versions Plugin"
description = "Provides version helpers."
id = "org.autojs.build.versions"
implementationClass = "org.autojs.build.VersionsPlugin"
displayName = "AutoJs6 Versions Plugin"
description = "Provides version helpers."
}
register("signs") {
id = "org.autojs.build.signs"
implementationClass = "org.autojs.build.SignsPlugin"
displayName = "AutoJs6 Signs Plugin"
description = "Provides signing helpers."
id = "org.autojs.build.signs"
implementationClass = "org.autojs.build.SignsPlugin"
displayName = "AutoJs6 Signs Plugin"
description = "Provides signing helpers."
}
register("properties") {
id = "org.autojs.build.properties"
implementationClass = "org.autojs.build.PropertiesPlugin"
displayName = "AutoJs6 Properties Plugin"
description = "Provides properties helpers."
id = "org.autojs.build.properties"
implementationClass = "org.autojs.build.PropertiesPlugin"
displayName = "AutoJs6 Properties Plugin"
description = "Provides properties helpers."
}
register("jvmConvention") {
id = "org.autojs.build.jvm-convention"
@@ -51,48 +50,7 @@ gradlePlugin {
}
}
run determineBuildSrcJdk@{
val propsFile: File = rootDir.parentFile.resolve("version.properties")
val minSupported: Int = Properties().let { props ->
require(propsFile.isFile) {
"version.properties not found in root directory"
}
propsFile.inputStream().use { props.load(it) }
val minSupportedVersion = props.getProperty("JAVA_VERSION_MIN_SUPPORTED")
require(minSupportedVersion != null) {
"version.properties does not contain \"JAVA_VERSION_MIN_SUPPORTED\""
}
minSupportedVersion.toInt()
}
val current = JavaVersion.current().majorVersion.toIntOrNull() ?: minSupported
fun tryAdjustByKotlinJvmTarget(sourceVersion: Int): Int {
return runCatching {
val cls = Class.forName("org.jetbrains.kotlin.gradle.dsl.JvmTarget")
val enumConstants = cls.enumConstants ?: return sourceVersion
var tmpVersion = sourceVersion
while (tmpVersion > minSupported) {
val wanted = "JVM_$tmpVersion"
if (enumConstants.any { it?.toString().equals(wanted, ignoreCase = true) }) {
return tmpVersion
}
tmpVersion -= 1
}
return@runCatching sourceVersion
}.getOrDefault(sourceVersion)
}
tryAdjustByKotlinJvmTarget(maxOf(current, minSupported)).also {
println("Toolchain: selected [$it] / current [$current] / min [$minSupported]")
}
}.let { jdk ->
kotlin {
jvmToolchain(jdk)
}
java {
toolchain.languageVersion.set(JavaLanguageVersion.of(jdk))
}
(gradle.extra["jdk"] as Int).let { jdk ->
kotlin { jvmToolchain(jdk) }
java { toolchain.languageVersion.set(JavaLanguageVersion.of(jdk)) }
}

View File

@@ -66,14 +66,22 @@ object Utils {
}
/**
* 统一 "版本信息打印 + 部署 + 清理" 生命周期钩子.
* Unified lifecycle hooks for "version info printing + deployment + cleanup".
*
* @param project 当前模块 Project
* @param projectDisplayName 用于打印的项目展示名 (默认用模块名)
* @param versionLines 版本信息行 (如 ["OpenCV: 4.2.0", "NDK: 21.1.6352462"])
* @param libsToDeploy 需要部署/清理的 LibDeployer 列表
* @param cleanupFlagKey gradle.ext 的布尔开关键 (如 "isCleanupPaddleOcr"), null 表示不参与清理逻辑
* @param extraFilesToDeleteOnClean clean 时额外需删除的相对路径
* zh-CN: 统一 "版本信息打印 + 部署 + 清理" 生命周期钩子.
*
* @param project Current module Project.<br>
* zh-CN: 当前模块 Project.
* @param projectDisplayName Project display name for printing (defaults to module name).<br>
* zh-CN: 用于打印的项目展示名 (默认用模块名).
* @param versionLines Version information lines (e.g. ["OpenCV: 4.2.0", "NDK: 21.1.6352462"]).<br>
* zh-CN: 版本信息行 (如 ["OpenCV: 4.2.0", "NDK: 21.1.6352462"]).
* @param libsToDeploy List of LibDeployer objects that need to be deployed/cleaned.<br>
* zh-CN: 需要部署/清理的 LibDeployer 列表.
* @param cleanupFlagKey Boolean switch key in gradle.ext (e.g. "isCleanupPaddleOcr"), null means not participating in cleanup logic.<br>
* zh-CN: gradle.ext 的布尔开关键 (如 "isCleanupPaddleOcr"), null 表示不参与清理逻辑.
* @param extraFilesToDeleteOnClean Additional relative paths to delete during clean.<br>
* zh-CN: clean 时额外需删除的相对路径.
*/
@JvmOverloads
fun configureLibraryLifecycleHooks(
@@ -87,10 +95,12 @@ object Utils {
val gradle = project.gradle
val onlyClean = AtomicBoolean(false)
// 单一监听器: 既判断 "是否纯 clean", 也负责非 clean 流程的打印与部署
// Single listener: both determines "is pure clean"
// and handles non-clean flow printing and deployment.
// zh-CN: 单一监听器: 既判断 "是否纯 clean", 也负责非 clean 流程的打印与部署.
gradle.taskGraph.addTaskExecutionGraphListener { graph ->
val all = graph.allTasks
val isOnlyClean = all.isNotEmpty() && all.all { it.name.contains("clean", ignoreCase = true) }
val tasks = graph.allTasks
val isOnlyClean = tasks.isNotEmpty() && tasks.all { it.name.contains("clean", ignoreCase = true) }
onlyClean.set(isOnlyClean)
if (!isOnlyClean) {
@@ -103,7 +113,8 @@ object Utils {
}
}
// clean 钩子 (显式 Java SAM, 避免 Kotlin/Groovy 重载歧义)
// "clean" hooks (explicit Java SAM to avoid Kotlin/Groovy overload ambiguity).
// zh-CN: "clean" 钩子 (显式 Java SAM, 避免 Kotlin/Groovy 重载歧义).
@Suppress("ObjectLiteralToLambda")
project.tasks.named("clean").configure(object : Action<Task> {
override fun execute(cleanTask: Task) {
@@ -113,7 +124,8 @@ object Utils {
project.delete(project.file(rel))
}
// 未提供开关键则直接跳过清理逻辑
// Skip the cleanup logic if no cleanup flag key is provided.
// zh-CN: 未提供开关键则直接跳过清理逻辑.
val key = cleanupFlagKey ?: return@doFirst
val cleanupEnabled = gradle.extra.require<Boolean>(key)
if (cleanupEnabled && onlyClean.get()) {
@@ -128,14 +140,22 @@ object Utils {
}
/**
* 注册模板 APK 拷贝: 在指定 assemble 任务完成后, 将 universal APK 拷贝为 assets 模板.
* Register template APK copying: After the specified assemble task is completed, copy universal APK as assets template.
*
* @param project 当前模块 Project
* @param taskName 构建任务名 (如 "assembleInrtRelease")
* @param srcDir APK 输出目录 (如 "build/outputs/apk/inrt/release")
* @param destDir 目标目录 (如 "src/main/assets-app")
* @param templateApkName 模板文件名 (如 "template.apk")
* @param universalNameFn 从版本名得出源 APK 名的函数 (默认 inrt-v<ver>-universal.apk)
* zh-CN: 注册模板 APK 拷贝: 在指定 assemble 任务完成后, 将 universal APK 拷贝为 assets 模板.
*
* @param project Current module Project.<br>
* zh-CN: 当前模块 Project.
* @param taskName Build task name (like "assembleInrtRelease").<br>
* zh-CN: 构建任务名 (如 "assembleInrtRelease").
* @param srcDir APK output directory (like "build/outputs/apk/inrt/release").<br>
* zh-CN: APK 输出目录 (如 "build/outputs/apk/inrt/release").
* @param destDir Target directory (like "src/main/assets-app").<br>
* zh-CN: 目标目录 (如 "src/main/assets-app").
* @param templateApkName Template file name (like "template.apk").<br>
* zh-CN: 模板文件名 (如 "template.apk").
* @param universalNameFn Function to derive source APK name from version name (default inrt-v<ver>-universal.apk).<br>
* zh-CN: 从版本名得出源 APK 名的函数 (默认 inrt-v<ver>-universal.apk).
*/
@JvmOverloads
fun registerTemplateApkCopy(
@@ -149,7 +169,8 @@ object Utils {
val versions = newVersions(project)
val versionName = versions.appVersionName
// 待所有项目评估完成后再定位并配置任务, 避免早期查找不到任务
// Wait for all projects to be evaluated before locating and configuring tasks to avoid early lookup failure.
// zh-CN: 待所有项目评估完成后再定位并配置任务, 避免早期查找不到任务.
project.gradle.projectsEvaluated {
val assembleTask = project.tasks.findByName(taskName)
if (assembleTask == null) {
@@ -207,15 +228,21 @@ object Utils {
private fun capitalize(s: String) = "${s[0].uppercase(Locale.getDefault())}${s.substring(1)}"
/**
* 统一为 Android 模块配置 Java/Kotlin 的目标版本:
* - Android.compileOptions.sourceCompatibility/targetCompatibility = versions.javaVersion
* - Kotlin 编译任务的 jvmTarget = versions.javaVersion 对应级别
*
* 注意:
* - Android 扩展在 projectsEvaluated 后稳定可得
* - Kotlin 任务用 tasks.configureEach 动态配置, 任务何时创建都能命中
*/
// Configure Java/Kotlin target version uniformly for Android modules:
// - Android.compileOptions.sourceCompatibility/targetCompatibility = versions.javaVersion
// - Kotlin compile tasks jvmTarget = versions.javaVersion level
// Note:
// - Android extension is stably available after projectsEvaluated
// - Kotlin tasks use tasks.configureEach for dynamic configuration to catch whenever tasks are created
//
// zh-CN:
//
// 统一为 Android 模块配置 Java/Kotlin 的目标版本:
// - Android.compileOptions.sourceCompatibility/targetCompatibility = versions.javaVersion
// - Kotlin 编译任务的 jvmTarget = versions.javaVersion 对应级别
// 注意:
// - Android 扩展在 projectsEvaluated 后稳定可得
// - Kotlin 任务用 tasks.configureEach 动态配置, 任务何时创建都能命中
@JvmStatic
fun configureJvmForAndroidModule(project: Project) {
val versions = newVersions(project)
@@ -224,11 +251,15 @@ object Utils {
val installer = {
project.logInfo("[JvmConv] Detected Android plugin in module='${project.path}', installing configuration")
// A) Java: 使用 Toolchain (模块级 + 任务级), 不要设置 --release
// Java: Use Toolchain (module-level + task-level), do not set --release.
// zh-CN: Java: 使用 Toolchain (模块级 + 任务级), 不要设置 --release.
configureJavaToolchainLanguageLevel(project, versions.javaVersionInt)
configureJavaToolchainForAllJavaCompile(project, versions.javaVersionInt)
// B) Kotlin: 继续懒配置设置 jvmTarget (你之前已验证成功)
// Kotlin: Continue lazy configuration to set jvmTarget.
// zh-CN: Kotlin: 继续懒配置设置 jvmTarget.
configureKotlinJvmTargetLazily(project, versions)
project.logInfo("[JvmConv] Installed Java toolchain (module+tasks) and Kotlin jvmTarget for '${project.path}'")
@@ -238,7 +269,8 @@ object Utils {
project.plugins.withId("com.android.library") { installer() }
}
// 模块级 Toolchain: AGP/Gradle 知道本模块应使用的 JDK 语言级别
// Module-level toolchain: Let AGP/Gradle know which JDK language level should be used for this module.
// zh-CN: 模块级 Toolchain: 让 AGP/Gradle 知道本模块应使用的 JDK 语言级别.
private fun configureJavaToolchainLanguageLevel(project: Project, target: Int) {
val javaExt = project.extensions.findByType(JavaPluginExtension::class.java)
if (javaExt == null) {
@@ -254,7 +286,8 @@ object Utils {
}
}
// 任务级 Toolchain: 对所有 JavaCompile 指定 javaCompiler, 且不要设置 --release (AGP 禁止)
// Task-level Toolchain: Specify javaCompiler for all JavaCompile tasks, without setting --release (prohibited by AGP).
// zh-CN: 任务级 Toolchain: 对所有 JavaCompile 指定 javaCompiler, 且不要设置 --release (AGP 禁止).
private fun configureJavaToolchainForAllJavaCompile(project: Project, target: Int) {
val toolchains = runCatching {
project.extensions.getByType(JavaToolchainService::class.java)
@@ -272,17 +305,20 @@ object Utils {
}.onFailure {
project.logError("[JvmConv] '${t.path}' set javaCompiler(toolchain) failed: ${it.message}", it)
}
// 不要设置 t.options.release, AGP 会报错阻止
// 也不强制改写 sourceCompatibility/targetCompatibility, 交给 AGP + toolchain 统一管理
}
})
}
// 为 KotlinCompile 任务设置 jvmTarget: 使用 configureEach, 任务实现时自动应用; 兼容新旧 API
// Configure jvmTarget for KotlinCompile tasks:
// Use configureEach for lazy configuration on task creation;
// Compatible with old and new APIs.
// zh-CN:
// 为 KotlinCompile 任务设置 jvmTarget:
// 使用 configureEach, 任务实现时自动应用;
// 兼容新旧 API.
private fun configureKotlinJvmTargetLazily(project: Project, versions: Versions) {
val desiredStr = versions.javaVersionString // 例如 "22"
val desiredEnumName = "JVM_${desiredStr}" // 例如 "JVM_22"
val desiredStr = versions.javaVersionString // e.g. "22"
val desiredEnumName = "JVM_${desiredStr}" // e.g. "JVM_22"
project.logInfo("[JvmConv] Will configure Kotlin jvmTarget lazily to '$desiredEnumName' in '${project.path}'")
project.tasks.configureEach(object : Action<Task> {
@@ -291,7 +327,8 @@ object Utils {
project.logInfo("[JvmConv] <KotlinTask> '${task.path}' class='${task.javaClass.name}'")
// 优先尝试 Kotlin 2.x: compilerOptions.jvmTarget(Property<JvmTarget>)
// Try Kotlin 2.x first: compilerOptions.jvmTarget(Property<JvmTarget>).
// zh-CN: 优先尝试 Kotlin 2.x: compilerOptions.jvmTarget(Property<JvmTarget>).
val compilerOptions = runCatching {
task.javaClass.methods.firstOrNull { it.name == "getCompilerOptions" && it.parameterTypes.isEmpty() }
?.also { project.logInfo("[JvmConv] '${task.path}' found method: ${it.toGenericString()}") }
@@ -344,7 +381,8 @@ object Utils {
project.logWarn("[JvmConv] '${task.path}' compilerOptions not found, trying legacy kotlinOptions")
}
// 兼容旧 API: kotlinOptions.setJvmTarget(String)
// Fallback to legacy API: kotlinOptions.setJvmTarget(String).
// zh-CN: 兼容旧 API: kotlinOptions.setJvmTarget(String).
val kotlinOptions = runCatching {
task.javaClass.methods.firstOrNull { it.name == "getKotlinOptions" && it.parameterTypes.isEmpty() }
?.also { project.logInfo("[JvmConv] '${task.path}' found method: ${it.toGenericString()}") }

View File

@@ -0,0 +1,2 @@
.idea/
/build/

View File

@@ -0,0 +1,20 @@
plugins {
kotlin("jvm")
}
repositories {
mavenCentral()
google()
}
dependencies {
implementation(gradleApi())
implementation(kotlin("stdlib"))
implementation("com.google.devtools.ksp:symbol-processing-api:${System.getProperty("com.google.devtools.ksp")}")
implementation(libs.kotlin.csv.jvm)
}
(gradle.extra["jdk"] as Int).let { jdk ->
kotlin { jvmToolchain(jdk) }
java { toolchain.languageVersion.set(JavaLanguageVersion.of(jdk)) }
}

View File

@@ -0,0 +1,146 @@
@file:Suppress("SameParameterValue", "AssignedValueIsNeverRead")
package org.autojs.autojs.ksp
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import com.google.devtools.ksp.symbol.KSAnnotated
import java.io.BufferedReader
class VersionCodesProcessorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return VersionCodesProcessor(environment)
}
}
class VersionCodesProcessor(private val env: SymbolProcessorEnvironment) : SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
val rows = readFromResource("version-codes.csv")
if (rows.isEmpty()) return emptyList()
val sorted = rows.sortedByDescending { it.apiLevel.toIntOrNull() ?: Int.MIN_VALUE }
val pkg = "org.autojs.autojs.runtime.api.augment.util"
val fileName = "VersionCodesInfoGenerated"
val fileExtension = "kt"
val content = buildString {
appendLine("// Generated by KSP. DO NOT EDIT.")
appendLine("@file:Suppress(\"unused\",\"MemberVisibilityCanBePrivate\",\"RedundantVisibilityModifier\")")
appendLine("package $pkg")
appendLine()
appendLine("import org.autojs.autojs.runtime.api.augment.util.VersionCodes")
appendLine("import org.autojs.autojs.util.RhinoUtils.newNativeObject")
appendLine("import org.mozilla.javascript.ScriptableObject.PERMANENT")
appendLine("import org.mozilla.javascript.ScriptableObject.READONLY")
appendLine()
appendLine("internal object $fileName {")
appendLine(" @JvmField")
appendLine(" val list: List<VersionCodes.Info> = listOf(")
sorted.forEachIndexed { idx, r ->
val comma = if (idx < sorted.lastIndex) "," else ""
appendLine(
" VersionCodes.Info(${q(r.versionCode)}, ${q(r.releaseName)}, ${q(r.internalCodename)}, ${q(r.platformVersion)}, ${q(r.apiLevel)}, ${q(r.releaseDate)})$comma"
)
}
appendLine(" )")
appendLine()
appendLine(" @JvmField")
appendLine(" val obj = newNativeObject().apply {")
sorted.forEach { r ->
appendLine(" run {")
appendLine(" val info = VersionCodes.Info(${q(r.versionCode)}, ${q(r.releaseName)}, ${q(r.internalCodename)}, ${q(r.platformVersion)}, ${q(r.apiLevel)}, ${q(r.releaseDate)})")
appendLine(" defineProperty(${q(r.versionCode)}, { info.toNativeObject() }, null, READONLY or PERMANENT)")
appendLine(" }")
}
appendLine(" }")
appendLine("}")
}
val bytes = content.toByteArray()
try {
resolver.getNewFiles().find {
it.fileName == "${fileName}.${fileExtension}" && it.packageName.asString() == pkg
} ?: env.codeGenerator.createNewFile(
dependencies = Dependencies(aggregating = false),
packageName = pkg,
fileName = fileName,
extensionName = fileExtension,
).use { it.write(bytes) }
} catch (_: FileAlreadyExistsException) {
// Already written in the same/previous round, skip directly.
// zh-CN: 已被同一/前一轮写入, 直接跳过.
}
return emptyList()
}
data class Row(
val versionCode: String,
val releaseName: String,
val internalCodename: String,
val platformVersion: String,
val apiLevel: String,
val releaseDate: String,
)
private fun readFromResource(name: String): List<Row> {
val url = javaClass.classLoader.getResource(name) ?: throw RuntimeException("Resource not found: $name")
return url.openStream().bufferedReader().use { br -> parseCsv(br) }
}
private fun parseCsv(br: BufferedReader): List<Row> {
val rows = mutableListOf<Row>()
var isHeader = true
br.forEachLine { raw ->
val line = raw.trim()
if (line.isEmpty() || line.startsWith("#")) return@forEachLine
if (isHeader) {
isHeader = false; return@forEachLine
}
val cells = splitCsv(line)
if (cells.size < 6) throw RuntimeException("Invalid line: $raw")
rows += Row(
versionCode = cells[0],
releaseName = cells[1],
internalCodename = cells[2],
platformVersion = cells[3],
apiLevel = cells[4],
releaseDate = cells[5],
)
}
return rows
}
// Simple CSV implementation with minimal quote handling.
// zh-CN: 简单 CSV, 此处实现了最小引号处理.
private fun splitCsv(line: String): List<String> {
val out = mutableListOf<String>()
val sb = StringBuilder()
var inQuotes = false
var i = 0
while (i < line.length) {
val c = line[i]
when {
c == '"' -> {
if (inQuotes && i + 1 < line.length && line[i + 1] == '"') {
sb.append('"'); i++
} else {
inQuotes = !inQuotes
}
}
c == ',' && !inQuotes -> {
out += sb.toString(); sb.setLength(0)
}
else -> sb.append(c)
}
i++
}
out += sb.toString()
return out.map { it.trim().removeSurrounding("\"") }
}
private fun q(s: String) = "\"" + s.replace("\\", "\\\\").replace("\"", "\\\"") + "\""
}

View File

@@ -0,0 +1 @@
org.autojs.autojs.ksp.VersionCodesProcessorProvider

View File

@@ -0,0 +1,37 @@
VERSION_CODE,RELEASE_NAME,INTERNAL_CODENAME,PLATFORM_VERSION,API_LEVEL,RELEASE_DATE
BAKLAVA,Android 16,Baklava,16,36,"June 10, 2025"
VANILLA_ICE_CREAM,Android 15,Vanilla Ice Cream,15,35,"September 3, 2024"
UPSIDE_DOWN_CAKE,Android 14,Upside Down Cake,14,34,"October 4, 2023"
TIRAMISU,Android 13,Tiramisu,13,33,"August 15, 2022"
S_V2,Android 12L,Snow Cone v2,12.1,32,"March 7, 2022"
S,Android 12,Snow Cone,12,31,"October 4, 2021"
R,Android 11,Red Velvet Cake,11,30,"September 8, 2020"
Q,Android 10,Quince Tart,10,29,"September 3, 2019"
P,Android Pie,Pistachio Ice Cream,9,28,"August 6, 2018"
O_MR1,Android Oreo,Oatmeal Cookie,8.1,27,"December 5, 2017"
O,Android Oreo,Oatmeal Cookie,8.0,26,"August 21, 2017"
N_MR1,Android Nougat,New York Cheesecake,7.1-7.1.2,25,"October 4, 2016"
N,Android Nougat,New York Cheesecake,7.0,24,"August 22, 2016"
M,Android Marshmallow,Macadamia Nut Cookie,6.0-6.0.1,23,"September 29, 2015"
LOLLIPOP_MR1,Android Lollipop,Lemon Meringue Pie,5.1-5.1.1,22,"March 2, 2015"
LOLLIPOP,Android Lollipop,Lemon Meringue Pie,5.0-5.0.2,21,"November 4, 2014"
KITKAT_WATCH,Android KitKat,Key Lime Pie,4.4W-4.4W.2,20,"June 25, 2014"
KITKAT,Android KitKat,Key Lime Pie,4.4-4.4.4,19,"October 31, 2013"
JELLY_BEAN_MR2,Android Jelly Bean,Jelly Bean,4.3-4.3.1,18,"July 24, 2013"
JELLY_BEAN_MR1,Android Jelly Bean,Jelly Bean,4.2-4.2.2,17,"November 13, 2012"
JELLY_BEAN,Android Jelly Bean,Jelly Bean,4.1-4.1.2,16,"July 9, 2012"
ICE_CREAM_SANDWICH_MR1,Android Ice Cream Sandwich,Ice Cream Sandwich,4.0.3-4.0.4,15,"December 16, 2011"
ICE_CREAM_SANDWICH,Android Ice Cream Sandwich,Ice Cream Sandwich,4.0-4.0.2,14,"October 18, 2011"
HONEYCOMB_MR2,Android Honeycomb,Honeycomb,3.2-3.2.6,13,"July 15, 2011"
HONEYCOMB_MR1,Android Honeycomb,Honeycomb,3.1,12,"May 10, 2011"
HONEYCOMB,Android Honeycomb,Honeycomb,3.0,11,"February 22, 2011"
GINGERBREAD_MR1,Android Gingerbread,Gingerbread,2.3.3-2.3.7,10,"February 9, 2011"
GINGERBREAD,Android Gingerbread,Gingerbread,2.3-2.3.2,9,"December 6, 2010"
FROYO,Android Froyo,Froyo,2.2-2.2.3,8,"May 20, 2010"
ECLAIR_MR1,Android Eclair,Eclair,2.1,7,"January 11, 2010"
ECLAIR_0_1,Android Eclair,Eclair,2.0.1,6,"December 3, 2009"
ECLAIR,Android Eclair,Eclair,2.0,5,"October 27, 2009"
DONUT,Android Donut,Donut,1.6,4,"September 15, 2009"
CUPCAKE,Android Cupcake,Cupcake,1.5,3,"April 27, 2009"
BASE_1_1,Android 1.1,Petit Four,1.1,2,"February 9, 2009"
BASE,Android 1.0,"",1.0,1,"September 23, 2008"
1 VERSION_CODE RELEASE_NAME INTERNAL_CODENAME PLATFORM_VERSION API_LEVEL RELEASE_DATE
2 BAKLAVA Android 16 Baklava 16 36 June 10, 2025
3 VANILLA_ICE_CREAM Android 15 Vanilla Ice Cream 15 35 September 3, 2024
4 UPSIDE_DOWN_CAKE Android 14 Upside Down Cake 14 34 October 4, 2023
5 TIRAMISU Android 13 Tiramisu 13 33 August 15, 2022
6 S_V2 Android 12L Snow Cone v2 12.1 32 March 7, 2022
7 S Android 12 Snow Cone 12 31 October 4, 2021
8 R Android 11 Red Velvet Cake 11 30 September 8, 2020
9 Q Android 10 Quince Tart 10 29 September 3, 2019
10 P Android Pie Pistachio Ice Cream 9 28 August 6, 2018
11 O_MR1 Android Oreo Oatmeal Cookie 8.1 27 December 5, 2017
12 O Android Oreo Oatmeal Cookie 8.0 26 August 21, 2017
13 N_MR1 Android Nougat New York Cheesecake 7.1-7.1.2 25 October 4, 2016
14 N Android Nougat New York Cheesecake 7.0 24 August 22, 2016
15 M Android Marshmallow Macadamia Nut Cookie 6.0-6.0.1 23 September 29, 2015
16 LOLLIPOP_MR1 Android Lollipop Lemon Meringue Pie 5.1-5.1.1 22 March 2, 2015
17 LOLLIPOP Android Lollipop Lemon Meringue Pie 5.0-5.0.2 21 November 4, 2014
18 KITKAT_WATCH Android KitKat Key Lime Pie 4.4W-4.4W.2 20 June 25, 2014
19 KITKAT Android KitKat Key Lime Pie 4.4-4.4.4 19 October 31, 2013
20 JELLY_BEAN_MR2 Android Jelly Bean Jelly Bean 4.3-4.3.1 18 July 24, 2013
21 JELLY_BEAN_MR1 Android Jelly Bean Jelly Bean 4.2-4.2.2 17 November 13, 2012
22 JELLY_BEAN Android Jelly Bean Jelly Bean 4.1-4.1.2 16 July 9, 2012
23 ICE_CREAM_SANDWICH_MR1 Android Ice Cream Sandwich Ice Cream Sandwich 4.0.3-4.0.4 15 December 16, 2011
24 ICE_CREAM_SANDWICH Android Ice Cream Sandwich Ice Cream Sandwich 4.0-4.0.2 14 October 18, 2011
25 HONEYCOMB_MR2 Android Honeycomb Honeycomb 3.2-3.2.6 13 July 15, 2011
26 HONEYCOMB_MR1 Android Honeycomb Honeycomb 3.1 12 May 10, 2011
27 HONEYCOMB Android Honeycomb Honeycomb 3.0 11 February 22, 2011
28 GINGERBREAD_MR1 Android Gingerbread Gingerbread 2.3.3-2.3.7 10 February 9, 2011
29 GINGERBREAD Android Gingerbread Gingerbread 2.3-2.3.2 9 December 6, 2010
30 FROYO Android Froyo Froyo 2.2-2.2.3 8 May 20, 2010
31 ECLAIR_MR1 Android Eclair Eclair 2.1 7 January 11, 2010
32 ECLAIR_0_1 Android Eclair Eclair 2.0.1 6 December 3, 2009
33 ECLAIR Android Eclair Eclair 2.0 5 October 27, 2009
34 DONUT Android Donut Donut 1.6 4 September 15, 2009
35 CUPCAKE Android Cupcake Cupcake 1.5 3 April 27, 2009
36 BASE_1_1 Android 1.1 Petit Four 1.1 2 February 9, 2009
37 BASE Android 1.0 1.0 1 September 23, 2008

View File

@@ -1,5 +1,10 @@
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
rootProject.name = "logic"
include(":convention")
include(":ksp-version-codes-processor")
dependencyResolutionManagement {
repositories {
mavenCentral()
@@ -12,6 +17,20 @@ dependencyResolutionManagement {
}
}
include(":convention")
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version System.getProperty("org.gradle.toolchains.foojay-resolver-convention")
}
}
rootProject.name = "build-logic"
plugins {
// @Hint by SuperMonster003 on Oct 6, 2025.
// ! Enable JDK auto-resolution/download capability for build modules.
// ! zh-CN: 让构建模块具备 JDK 自动解析/下载能力.
id("org.gradle.toolchains.foojay-resolver-convention")
}

View File

@@ -70,6 +70,7 @@ junit = "4.13.2"
junit-jupiter = "5.13.4"
junit-quickcheck-core = "1.0"
junit-quickcheck-generators = "1.0"
kotlin-csv-jvm = "1.10.0"
leakcanary = "2.14"
licensesdialog = "2.2.0"
material = "1.13.0"
@@ -144,6 +145,8 @@ junit = { module = "junit:junit", version.ref = "junit" }
junit-jupiter = { module = "org.junit.jupiter:junit-jupiter", version.ref = "junit-jupiter" }
junit-quickcheck-core = { module = "com.pholser:junit-quickcheck-core", version.ref = "junit-quickcheck-core" }
junit-quickcheck-generators = { module = "com.pholser:junit-quickcheck-generators", version.ref = "junit-quickcheck-generators" }
kotlin-csv-jvm = { module = "com.github.doyaaaaaken:kotlin-csv-jvm", version.ref = "kotlin-csv-jvm" }
ksp-version-codes-processor = { module = "logic:ksp-version-codes-processor" }
leakcanary = { module = "com.squareup.leakcanary:leakcanary-android", version.ref = "leakcanary" }
licensesdialog = { module = "de.psdev.licensesdialog:licensesdialog", version.ref = "licensesdialog" }
log4j = { module = "log4j:log4j", version.ref = "log4j" }

View File

@@ -1,5 +1,12 @@
@file:Suppress("SpellCheckingInspection")
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
rootProject.name = "root"
includeBuild("build-logic")
private val modules = listOf(
"jieba-analysis",
"apk-signer",
@@ -129,7 +136,7 @@ pluginManagement {
data class Classpath(val id: String, val version: String)
data class Plugin(val id: String, val version: String, val isApply: Boolean = false)
data class Plugin(val id: String, val version: String, val isApply: Boolean = false, val share: Boolean = false)
class Formatted(title: String, private val contents: Collection<String> = emptyList(), subtitle: String? = null, footers: Collection<String> = emptyList()) {
private val formattedOutput = run {
@@ -390,8 +397,8 @@ pluginManagement {
Classpath(id = "org.jetbrains.kotlin:kotlin-gradle-plugin", version = overriddenKotlinVersion ?: "auto:kotlin"),
Classpath(id = "org.apache.commons:commons-compress", version = "toml:commons-compress"),
Classpath(id = "org.tukaani:xz", version = "toml:xz"),
Plugin(id = "com.google.devtools.ksp", version = overriddenKspVersion ?: "auto:ksp"),
Plugin(id = "org.gradle.toolchains.foojay-resolver-convention", version = "toml:foojay-resolver-convention"),
Plugin(id = "com.google.devtools.ksp", version = overriddenKspVersion ?: "auto:ksp", share = true),
Plugin(id = "org.gradle.toolchains.foojay-resolver-convention", version = "toml:foojay-resolver-convention", share = true),
)
abstract inner class Platform(
@@ -676,6 +683,9 @@ pluginManagement {
lib.version
}
}
if (lib.share) {
System.setProperty(lib.id, version)
}
console.versionInfo += "Plugin: \"${lib.id}:$version\"${if (config.isHideConsoleInfoHintSuffix) "" else suffix}"
mapOf("id" to lib.id, "version" to version, "isApply" to lib.isApply)
}
@@ -799,9 +809,3 @@ plugins {
// ! zh-CN: 让构建模块具备 JDK 自动解析/下载能力.
id("org.gradle.toolchains.foojay-resolver-convention")
}
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
includeBuild("build-logic")
rootProject.name = "AutoJs6"

View File

@@ -1,5 +1,5 @@
#Mon Oct 06 12:48:51 CST 2025
BUILD_TIME=1759726131752
#Thu Oct 09 17:07:45 CST 2025
BUILD_TIME=1760000865200
COMPILE_SDK_VERSION=36
IMAGE_QUANT_CMAKE_VERSION=3.22.1
IMAGE_QUANT_NDK_VERSION=26.1.10909125
@@ -27,6 +27,6 @@ RAPID_OCR_OPENCV_MOBILE_LABEL_VERSION=13
RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3
TARGET_SDK_VERSION=36
TARGET_SDK_VERSION_INRT=29
VERSION_BUILD=3405
VERSION_BUILD=3410
VERSION_NAME=6.7.0 Alpha6
VSCODE_EXT_REQUIRED_VERSION=1.0.8