6.7.0 - Alpha13 - runtime.loadJar 支持 Multi-Dex. 增强并发安全, 优化临时文件清理逻辑 (pr #475)
This commit is contained in:
@@ -69,6 +69,7 @@
|
|||||||
"构建工具启用 isCleanup[Paddle/Rapid]Ocr 配置选项时无法正常完成 Rebuild Project 任务的问题"
|
"构建工具启用 isCleanup[Paddle/Rapid]Ocr 配置选项时无法正常完成 Rebuild Project 任务的问题"
|
||||||
],
|
],
|
||||||
"improvement": [
|
"improvement": [
|
||||||
|
"runtime.loadJar 方法增强兼容性 (by [LYS86](https://github.com/LYS86)) _[`pr #475`](http://pr.autojs6.com/475)_",
|
||||||
"ui.statusBarHeight 属性 (getter) 增强一定程度的兼容性",
|
"ui.statusBarHeight 属性 (getter) 增强一定程度的兼容性",
|
||||||
"console.log 等方法打印全局对象 (images, app, ocr 等) 时支持显示详细信息",
|
"console.log 等方法打印全局对象 (images, app, ocr 等) 时支持显示详细信息",
|
||||||
"android.graphics.Paint#setColor 支持正常解析 ColorInt/ColorHex/ColorName 等颜色参数",
|
"android.graphics.Paint#setColor 支持正常解析 ColorInt/ColorHex/ColorName 等颜色参数",
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"android_studio_latest_recommended_file_name_of_tar": "android-studio-2025.2.2.8-linux.tar.gz",
|
"android_studio_latest_recommended_file_name_of_tar": "android-studio-2025.2.2.8-linux.tar.gz",
|
||||||
"android_studio_latest_recommended_download_address_of_tar": "https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.2.2.8/android-studio-2025.2.2.8-linux.tar.gz",
|
"android_studio_latest_recommended_download_address_of_tar": "https://redirector.gvt1.com/edgedl/android/studio/ide-zips/2025.2.2.8/android-studio-2025.2.2.8-linux.tar.gz",
|
||||||
"android_studio_latest_recommended_file_size_of_tar": "1.38 GiB",
|
"android_studio_latest_recommended_file_size_of_tar": "1.38 GiB",
|
||||||
"var_date_contribution_table_data_updated": "2025/09/06",
|
"var_date_contribution_table_data_updated": "2025/12/26",
|
||||||
"latest_rhino_engine_name_with_github_lineno_address": "[v2.0.0-SNAPSHOT](http://rhino.autojs6.com/blob/master/gradle.properties#L3)",
|
"latest_rhino_engine_name_with_github_lineno_address": "[v2.0.0-SNAPSHOT](http://rhino.autojs6.com/blob/master/gradle.properties#L3)",
|
||||||
"var_date_rhino_engine_latest_committed": "2025/12/25",
|
"var_date_rhino_engine_latest_committed": "2025/12/25",
|
||||||
"var_date_jdk_max_supported": "%CURRENT_DATE%",
|
"var_date_jdk_max_supported": "%CURRENT_DATE%",
|
||||||
|
|||||||
@@ -382,6 +382,7 @@ autojs6-v6.6.2-arm64-v8a-0f2a9d74.apk
|
|||||||
|
|
||||||
| <span style="word-break:keep-all;white-space:nowrap">{{ table_header_contribution_contributors }}</span> | <span style="word-break:keep-all;white-space:nowrap">{{ table_header_contribution_number_of_commits }}</span> | <span style="word-break:keep-all;white-space:nowrap">{{ table_header_contribution_recent_submissions }}</span> |
|
| <span style="word-break:keep-all;white-space:nowrap">{{ table_header_contribution_contributors }}</span> | <span style="word-break:keep-all;white-space:nowrap">{{ table_header_contribution_number_of_commits }}</span> | <span style="word-break:keep-all;white-space:nowrap">{{ table_header_contribution_recent_submissions }}</span> |
|
||||||
|:------:|:------:|:------:|
|
|:------:|:------:|:------:|
|
||||||
|
| <span style="word-break:keep-all;white-space:nowrap">[LYS86](https://github.com/LYS86) `(Lin)`</span> | <span style="word-break:keep-all;white-space:nowrap">[4](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3ALYS86)</span> | <span style="word-break:keep-all;white-space:nowrap">`2025/12/26`</span> |
|
||||||
| <span style="word-break:keep-all;white-space:nowrap">[wirsnow](https://github.com/wirsnow)</span> | <span style="word-break:keep-all;white-space:nowrap">[1](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3Awirsnow)</span> | <span style="word-break:keep-all;white-space:nowrap">`2025/05/19`</span> |
|
| <span style="word-break:keep-all;white-space:nowrap">[wirsnow](https://github.com/wirsnow)</span> | <span style="word-break:keep-all;white-space:nowrap">[1](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3Awirsnow)</span> | <span style="word-break:keep-all;white-space:nowrap">`2025/05/19`</span> |
|
||||||
| <span style="word-break:keep-all;white-space:nowrap">[TonyJiangWJ](https://github.com/TonyJiangWJ)</span> | <span style="word-break:keep-all;white-space:nowrap">[4](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3ATonyJiangWJ)</span> | <span style="word-break:keep-all;white-space:nowrap">`2025/04/24`</span> |
|
| <span style="word-break:keep-all;white-space:nowrap">[TonyJiangWJ](https://github.com/TonyJiangWJ)</span> | <span style="word-break:keep-all;white-space:nowrap">[4](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3ATonyJiangWJ)</span> | <span style="word-break:keep-all;white-space:nowrap">`2025/04/24`</span> |
|
||||||
| <span style="word-break:keep-all;white-space:nowrap">[luckyloogn](https://github.com/luckyloogn)</span> | <span style="word-break:keep-all;white-space:nowrap">[3](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3Aluckyloogn)</span> | <span style="word-break:keep-all;white-space:nowrap">`2024/12/31`</span> |
|
| <span style="word-break:keep-all;white-space:nowrap">[luckyloogn](https://github.com/luckyloogn)</span> | <span style="word-break:keep-all;white-space:nowrap">[3](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3Aluckyloogn)</span> | <span style="word-break:keep-all;white-space:nowrap">`2024/12/31`</span> |
|
||||||
@@ -390,8 +391,6 @@ autojs6-v6.6.2-arm64-v8a-0f2a9d74.apk
|
|||||||
| <span style="word-break:keep-all;white-space:nowrap">[LZX284](https://github.com/LZX284) `(AI)`</span> | <span style="word-break:keep-all;white-space:nowrap">[7](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3ALZX284)</span> | <span style="word-break:keep-all;white-space:nowrap">`2023/11/15`</span> |
|
| <span style="word-break:keep-all;white-space:nowrap">[LZX284](https://github.com/LZX284) `(AI)`</span> | <span style="word-break:keep-all;white-space:nowrap">[7](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3ALZX284)</span> | <span style="word-break:keep-all;white-space:nowrap">`2023/11/15`</span> |
|
||||||
| <span style="word-break:keep-all;white-space:nowrap">[little‑alei](https://github.com/little-alei) `(抠脚本人)`</span> | <span style="word-break:keep-all;white-space:nowrap">[12](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3Alittle-alei)</span> | <span style="word-break:keep-all;white-space:nowrap">`2023/07/12`</span> |
|
| <span style="word-break:keep-all;white-space:nowrap">[little‑alei](https://github.com/little-alei) `(抠脚本人)`</span> | <span style="word-break:keep-all;white-space:nowrap">[12](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3Alittle-alei)</span> | <span style="word-break:keep-all;white-space:nowrap">`2023/07/12`</span> |
|
||||||
| <span style="word-break:keep-all;white-space:nowrap">[aiselp](https://github.com/aiselp)</span> | <span style="word-break:keep-all;white-space:nowrap">[6](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3Aaiselp)</span> | <span style="word-break:keep-all;white-space:nowrap">`2023/06/14`</span> |
|
| <span style="word-break:keep-all;white-space:nowrap">[aiselp](https://github.com/aiselp)</span> | <span style="word-break:keep-all;white-space:nowrap">[6](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3Aaiselp)</span> | <span style="word-break:keep-all;white-space:nowrap">`2023/06/14`</span> |
|
||||||
| <span style="word-break:keep-all;white-space:nowrap">[LYS86](https://github.com/LYS86) `(Lin)`</span> | <span style="word-break:keep-all;white-space:nowrap">[2](https://github.com/SuperMonster003/AutoJs6/pulls?q=is%3Apr+is%3Amerged+author%3ALYS86)</span> | <span style="word-break:keep-all;white-space:nowrap">`2023/06/03`</span> |
|
|
||||||
|
|
||||||
{{ p_contribution_table_data_updated_on }}.
|
{{ p_contribution_table_data_updated_on }}.
|
||||||
|
|
||||||
{{ p_contribution_table_data_entries_sorted_by_recent_submissions }}.
|
{{ p_contribution_table_data_entries_sorted_by_recent_submissions }}.
|
||||||
|
|||||||
@@ -251,7 +251,7 @@ dependencies /* Unclassified */ {
|
|||||||
implementation(libs.icu4j)
|
implementation(libs.icu4j)
|
||||||
|
|
||||||
// R8
|
// R8
|
||||||
implementation("com.android.tools:r8:8.13.17")
|
implementation(libs.r8)
|
||||||
|
|
||||||
// Plugin API: Paddle OCR
|
// Plugin API: Paddle OCR
|
||||||
implementation(project(":plugin-api:paddle-ocr"))
|
implementation(project(":plugin-api:paddle-ocr"))
|
||||||
|
|||||||
@@ -20,12 +20,15 @@ import java.io.ByteArrayInputStream
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileNotFoundException
|
import java.io.FileNotFoundException
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
import kotlin.random.Random
|
||||||
import com.legacy.android.dx.command.dexer.Main as LegacyMain
|
import com.legacy.android.dx.command.dexer.Main as LegacyMain
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by Stardust on Apr 5, 2017.
|
* Created by Stardust on Apr 5, 2017.
|
||||||
* Modified by SuperMonster003 as of Jul 5, 2023.
|
* Modified by SuperMonster003 as of Jul 5, 2023.
|
||||||
* Transformed by SuperMonster003 on Jul 5, 2023.
|
* Transformed by SuperMonster003 on Jul 5, 2023.
|
||||||
|
* Modified by LYS86 (https://github.com/LYS86) as of Dec 26, 2025.
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
* Create a new instance with the given parent classloader and cache directory
|
* Create a new instance with the given parent classloader and cache directory
|
||||||
@@ -35,7 +38,11 @@ import com.legacy.android.dx.command.dexer.Main as LegacyMain
|
|||||||
*/
|
*/
|
||||||
class AndroidClassLoader(private val parent: ClassLoader, private val cacheDir: File) : ClassLoader(), GeneratedClassLoader {
|
class AndroidClassLoader(private val parent: ClassLoader, private val cacheDir: File) : ClassLoader(), GeneratedClassLoader {
|
||||||
|
|
||||||
private val mDexClassLoaders = HashMap<String, DexClassLoader>()
|
private val mDexClassLoaders = ConcurrentHashMap<String, DexClassLoader>()
|
||||||
|
|
||||||
|
// Ensure per-jar conversion is thread-safe.
|
||||||
|
// zh-CN: 确保对同一个 jar 的转换过程线程安全.
|
||||||
|
private val conversionLocks = ConcurrentHashMap<String, Any>()
|
||||||
|
|
||||||
init {
|
init {
|
||||||
if (cacheDir.exists()) {
|
if (cacheDir.exists()) {
|
||||||
@@ -88,31 +95,40 @@ class AndroidClassLoader(private val parent: ClassLoader, private val cacheDir:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun loadJar(file: File): DexClassLoader {
|
@Throws(IOException::class, FileNotFoundException::class)
|
||||||
try {
|
fun loadJar(jar: File): DexClassLoader {
|
||||||
val dexFile = jarToDex(file, cacheDir)
|
Log.d(TAG, "loadJar: jar = ${jar.path}")
|
||||||
return loadDex(dexFile)
|
if (!jar.exists() || !jar.canRead()) {
|
||||||
} catch (e: Exception) {
|
throw FileNotFoundException(str(R.string.file_not_exist_or_readable, jar.path))
|
||||||
Log.e(TAG, "loadJar: failed to load jar ${file.path}", e)
|
}
|
||||||
return loadJar1(file)
|
|
||||||
|
val key = generateArtifactsCacheName(jar)
|
||||||
|
val lock = conversionLocks.getOrPut(key) { Any() }
|
||||||
|
|
||||||
|
return synchronized(lock) {
|
||||||
|
runCatching {
|
||||||
|
jarToDexDx(jar)
|
||||||
|
}.recoverCatching { eDx ->
|
||||||
|
Log.e(TAG, "Failed: jarToDexDx", eDx)
|
||||||
|
jarToDexR8(jar)
|
||||||
|
}.getOrElse { eR8 ->
|
||||||
|
Log.e(TAG, "Failed: jarToDexR8", eR8)
|
||||||
|
throw eR8
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Throws(IOException::class)
|
@Throws(IOException::class, FileNotFoundException::class)
|
||||||
fun loadJar1(file: File): DexClassLoader {
|
private fun jarToDexDx(jar: File): DexClassLoader {
|
||||||
val path = file.path
|
val cacheName = generateArtifactsCacheName(jar)
|
||||||
Log.d(TAG, "loadJar: jar = $path")
|
val cacheFile = File(cacheDir, "$cacheName.jar")
|
||||||
if (!file.exists() || !file.canRead()) {
|
if (cacheFile.exists()) {
|
||||||
throw FileNotFoundException(str(R.string.file_not_exist_or_readable, path))
|
return loadDex(cacheFile)
|
||||||
}
|
|
||||||
val dexFile = File(cacheDir, generateDexFileName(file))
|
|
||||||
if (dexFile.exists()) {
|
|
||||||
return loadDex(dexFile)
|
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
val classFile = generateTempFile(path, false)
|
val classFile = generateTempFile(jar.path, false)
|
||||||
val zipFile = ZipFile(classFile)
|
val zipFile = ZipFile(classFile)
|
||||||
val jarFile = ZipFile(file)
|
val jarFile = ZipFile(jar)
|
||||||
for (header in jarFile.fileHeaders) {
|
for (header in jarFile.fileHeaders) {
|
||||||
if (!header.isDirectory) {
|
if (!header.isDirectory) {
|
||||||
zipFile.addStream(jarFile.getInputStream(header), ZipParameters().apply {
|
zipFile.addStream(jarFile.getInputStream(header), ZipParameters().apply {
|
||||||
@@ -120,7 +136,7 @@ class AndroidClassLoader(private val parent: ClassLoader, private val cacheDir:
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val classLoader = dexJar(classFile, dexFile)
|
val classLoader = dexJar(classFile, cacheFile)
|
||||||
if (!classFile.delete()) {
|
if (!classFile.delete()) {
|
||||||
Log.e(TAG, "classFile.delete() failed")
|
Log.e(TAG, "classFile.delete() failed")
|
||||||
}
|
}
|
||||||
@@ -176,9 +192,13 @@ class AndroidClassLoader(private val parent: ClassLoader, private val cacheDir:
|
|||||||
} catch (e: ClassNotFoundException) {
|
} catch (e: ClassNotFoundException) {
|
||||||
throw FatalLoadingException(e)
|
throw FatalLoadingException(e)
|
||||||
} finally {
|
} finally {
|
||||||
if (classFile != null) {
|
when {
|
||||||
if (!classFile.delete()) {
|
// Treat as a temporary file that has been generated.
|
||||||
Log.e(TAG, "classFile.delete() failed")
|
// zh-CN: 视为临时文件已生成.
|
||||||
|
classFile != null -> {
|
||||||
|
if (!classFile.delete()) {
|
||||||
|
Log.e(TAG, "classFile.delete() failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -202,9 +222,13 @@ class AndroidClassLoader(private val parent: ClassLoader, private val cacheDir:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val loader = loadDex(niceDexFile)
|
val loader = loadDex(niceDexFile)
|
||||||
if (dexFile == null) /* is temporary file generated */ {
|
when (dexFile) {
|
||||||
if (!niceDexFile.delete()) {
|
// Treat as a temporary file that has been generated.
|
||||||
Log.e(TAG, "dexFile.delete() failed")
|
// zh-CN: 视为临时文件已生成.
|
||||||
|
null -> {
|
||||||
|
if (!niceDexFile.delete()) {
|
||||||
|
Log.e(TAG, "dexFile.delete() failed")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return loader
|
return loader
|
||||||
@@ -227,39 +251,74 @@ class AndroidClassLoader(private val parent: ClassLoader, private val cacheDir:
|
|||||||
return file
|
return file
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateDexFileName(jar: File) = md5("${jar.path}_${jar.lastModified()}")
|
private fun generateArtifactsCacheName(jar: File) = md5("${jar.path}_${jar.lastModified()}")
|
||||||
|
|
||||||
private fun jarToDex(jar: File, cacheDir: File): File {
|
@Throws(IOException::class, FileNotFoundException::class)
|
||||||
val dexName = generateDexFileName(jar)
|
private fun jarToDexR8(jar: File): DexClassLoader {
|
||||||
val dexFile = File(cacheDir, "$dexName.dex")
|
val cacheName = generateArtifactsCacheName(jar)
|
||||||
|
|
||||||
|
val dexFile = File(cacheDir, "$cacheName.dex")
|
||||||
|
val dexJarFile = File(cacheDir, "$cacheName.jar")
|
||||||
|
|
||||||
|
if (dexJarFile.exists()) {
|
||||||
|
return loadDex(dexJarFile)
|
||||||
|
}
|
||||||
if (dexFile.exists()) {
|
if (dexFile.exists()) {
|
||||||
return dexFile
|
return loadDex(dexFile)
|
||||||
}
|
}
|
||||||
val tmpOut = File(cacheDir, "${dexName}_tmp").apply { mkdirs() }
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
val tmpOut = File(cacheDir, "${cacheName}_tmp_${System.currentTimeMillis()}_${Random.nextInt(1000, 9999)}")
|
||||||
val cmd = D8Command.builder()
|
if (!tmpOut.mkdirs()) {
|
||||||
.addProgramFiles(jar.toPath())
|
throw IOException("Failed to create temp output directory: ${tmpOut.path}")
|
||||||
.setOutput(tmpOut.toPath(), OutputMode.DexIndexed)
|
|
||||||
.setMode(CompilationMode.RELEASE)
|
|
||||||
.build()
|
|
||||||
D8.run(cmd)
|
|
||||||
} else {
|
|
||||||
val args = arrayOf(
|
|
||||||
"--output", tmpOut.absolutePath,
|
|
||||||
"--release",
|
|
||||||
jar.absolutePath
|
|
||||||
)
|
|
||||||
D8.main(args)
|
|
||||||
}
|
}
|
||||||
val classesDex = File(tmpOut, "classes.dex")
|
|
||||||
if (classesDex.exists().not()) {
|
try {
|
||||||
throw IOException("R8 did not produce classes.dex")
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
|
val cmd = D8Command.builder()
|
||||||
|
.addProgramFiles(jar.toPath())
|
||||||
|
.setOutput(tmpOut.toPath(), OutputMode.DexIndexed)
|
||||||
|
.setMode(CompilationMode.RELEASE)
|
||||||
|
.build()
|
||||||
|
D8.run(cmd)
|
||||||
|
} else {
|
||||||
|
val args = arrayOf(
|
||||||
|
"--output", tmpOut.absolutePath,
|
||||||
|
"--release",
|
||||||
|
jar.absolutePath
|
||||||
|
)
|
||||||
|
D8.main(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
val dexFiles = tmpOut.listFiles { _, name ->
|
||||||
|
Regex("classes\\d*\\.dex").matches(name)
|
||||||
|
}?.sortedBy { it.name } ?: emptyList()
|
||||||
|
|
||||||
|
if (dexFiles.isEmpty()) {
|
||||||
|
throw IOException("D8 did not produce any classes*.dex")
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (dexFiles.size == 1) {
|
||||||
|
val classesDex = dexFiles.first()
|
||||||
|
if (!classesDex.renameTo(dexFile)) {
|
||||||
|
dexFile.outputStream().use { out ->
|
||||||
|
classesDex.inputStream().use { it.copyTo(out) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadDex(dexFile)
|
||||||
|
} else {
|
||||||
|
// Multi-dex output: pack all classes*.dex into a single jar for DexClassLoader.
|
||||||
|
// zh-CN: 多 dex 输出: 将所有 classes*.dex 打包到单个 jar 文件中供 DexClassLoader 使用.
|
||||||
|
val zip = ZipFile(dexJarFile)
|
||||||
|
dexFiles.forEach { f ->
|
||||||
|
zip.addStream(f.inputStream(), ZipParameters().apply {
|
||||||
|
fileNameInZip = f.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
loadDex(dexJarFile)
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
tmpOut.deleteRecursively()
|
||||||
}
|
}
|
||||||
if (classesDex.renameTo(dexFile).not()) {
|
|
||||||
dexFile.outputStream().use { out -> classesDex.inputStream().use { it.copyTo(out) } }
|
|
||||||
}
|
|
||||||
tmpOut.deleteRecursively()
|
|
||||||
return dexFile
|
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ log4j = "1.2.17"
|
|||||||
#purpose : Compatibility of java.time.* for Android API Level < 26 (Android 8.0) [O]
|
#purpose : Compatibility of java.time.* for Android API Level < 26 (Android 8.0) [O]
|
||||||
desugar = "2.1.5"
|
desugar = "2.1.5"
|
||||||
|
|
||||||
analytics = "14.4.0"
|
|
||||||
android-device-names = "2.1.1"
|
android-device-names = "2.1.1"
|
||||||
android-logging-log4j = "1.0.3"
|
android-logging-log4j = "1.0.3"
|
||||||
android-support-v7 = "28.0.0"
|
android-support-v7 = "28.0.0"
|
||||||
@@ -82,6 +81,7 @@ paho-client-mqttv3 = "1.2.5"
|
|||||||
pinyin4j = "2.5.1"
|
pinyin4j = "2.5.1"
|
||||||
preference-ktx = "1.2.1"
|
preference-ktx = "1.2.1"
|
||||||
prov = "1.58.0.0"
|
prov = "1.58.0.0"
|
||||||
|
r8 = "8.13.17"
|
||||||
recyclerview = "1.4.0"
|
recyclerview = "1.4.0"
|
||||||
retrofit = "3.0.0"
|
retrofit = "3.0.0"
|
||||||
retrofit2-kotlin-coroutines-adapter = "0.9.2"
|
retrofit2-kotlin-coroutines-adapter = "0.9.2"
|
||||||
@@ -160,6 +160,7 @@ paho-client-mqttv3 = { module = "org.eclipse.paho:org.eclipse.paho.client.mqttv3
|
|||||||
pinyin4j = { module = "com.belerweb:pinyin4j", version.ref = "pinyin4j" }
|
pinyin4j = { module = "com.belerweb:pinyin4j", version.ref = "pinyin4j" }
|
||||||
preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "preference-ktx" }
|
preference-ktx = { module = "androidx.preference:preference-ktx", version.ref = "preference-ktx" }
|
||||||
prov = { module = "com.madgag.spongycastle:prov", version.ref = "prov" }
|
prov = { module = "com.madgag.spongycastle:prov", version.ref = "prov" }
|
||||||
|
r8 = { module = "com.android.tools:r8", version.ref = "r8" }
|
||||||
recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
|
recyclerview = { module = "androidx.recyclerview:recyclerview", version.ref = "recyclerview" }
|
||||||
recyclerview-v7 = { module = "com.android.support:recyclerview-v7", version.ref = "android-support-v7" }
|
recyclerview-v7 = { module = "com.android.support:recyclerview-v7", version.ref = "android-support-v7" }
|
||||||
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
retrofit = { module = "com.squareup.retrofit2:retrofit", version.ref = "retrofit" }
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
#Thu Dec 25 16:35:57 CST 2025
|
#Fri Dec 26 16:11:42 CST 2025
|
||||||
BUILD_TIME=1766651757534
|
BUILD_TIME=1766736702142
|
||||||
COMPILE_SDK_VERSION=36
|
COMPILE_SDK_VERSION=36
|
||||||
IMAGE_QUANT_CMAKE_VERSION=3.22.1
|
IMAGE_QUANT_CMAKE_VERSION=3.22.1
|
||||||
IMAGE_QUANT_NDK_VERSION=26.1.10909125
|
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
|
RAPID_OCR_OPENCV_MOBILE_VERSION=4.5.3
|
||||||
TARGET_SDK_VERSION=36
|
TARGET_SDK_VERSION=36
|
||||||
TARGET_SDK_VERSION_INRT=29
|
TARGET_SDK_VERSION_INRT=29
|
||||||
VERSION_BUILD=3548
|
VERSION_BUILD=3551
|
||||||
VERSION_NAME=6.7.0 Alpha13
|
VERSION_NAME=6.7.0 Alpha13
|
||||||
VSCODE_EXT_REQUIRED_VERSION=1.0.8
|
VSCODE_EXT_REQUIRED_VERSION=1.0.8
|
||||||
|
|||||||
Reference in New Issue
Block a user