diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json
index e7cd190d..b3d95108 100644
--- a/.changelog/lang_zh-Hans.json
+++ b/.changelog/lang_zh-Hans.json
@@ -1,7 +1,7 @@
{
"$data": {
"v6.7.0": {
- "released_date": "2025/10/02",
+ "released_date": "2025/10/05",
"feature": [
"zip 模块, 用于文件压缩与解压缩操作 (Ref to [Auto.js Pro](https://g.pro.autojs.org/)) (参阅 项目文档 > [Zip](https://docs.autojs6.com/#/zip))",
"mediainfo 模块, 用于查看媒体文件的详细信息 (参阅 项目文档 > [媒体信息](https://docs.autojs6.com/#/mediainfo))",
@@ -15,6 +15,7 @@
"timers.keepAlive 方法 timeout 参数功能无效的问题",
"floaty.window/rawWindow 方法无法接受字符串参数的问题",
"util.class[Name]/getClass[Name] 可能返回错误结果的问题",
+ "部分全局对象可能丢失 JavaScript 原型属性及方法的问题",
"使用 XML 语法将 JavaScript 表达式作为属性值时, this 对象可能出现指向错误的问题",
"canvas 元素控件 setMaxFps 方法内部帧率计算错误",
"images.concat 方法纵向拼接时宽度值计算错误",
@@ -32,6 +33,7 @@
"构建工具启用 isCleanup[Paddle/Rapid]Ocr 配置选项时无法正常完成 Rebuild Project 任务的问题"
],
"improvement": [
+ "console.log 等方法打印全局对象 (images, app, ocr 等) 时支持显示详细信息",
"http 模块相关方法支持不安全选项参数 (isInsecure/insecure), 用于忽略证书相关异常 _[`issue #417`](http://issues.autojs6.com/417)_",
"android.graphics.Paint#setColor 支持正常解析 ColorInt/ColorHex/ColorName 等颜色参数",
"内置模块相关方法实参类型的异常消息增加类型摘要信息",
diff --git a/.readme/common.json b/.readme/common.json
index e9aad9ef..3076d392 100644
--- a/.readme/common.json
+++ b/.readme/common.json
@@ -12,7 +12,7 @@
"android_studio_latest_recommended_file_size_of_tar": "1.37 GiB",
"var_date_contribution_table_data_updated": "2025/09/06",
"latest_rhino_engine_name_with_github_lineno_address": "[v1.8.1-SNAPSHOT](http://rhino.autojs6.com/blob/master/gradle.properties#L3)",
- "var_date_rhino_engine_latest_committed": "2025/09/10",
+ "var_date_rhino_engine_latest_committed": "2025/10/05",
"var_date_jdk_max_supported": "%CURRENT_DATE%",
"var_date_active_maintenance_phase_statistics_since_when": "%CURRENT_DATE%"
}
\ No newline at end of file
diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index eb7823d4..ef9f2e80 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -19,7 +19,11 @@ plugins {
idea {
module {
- excludeDirs.add(file("$rootDir/app/src/main/java/com/stardust/"))
+ excludeDirs.addAll(listOf(
+ file("$rootDir/app/src/main/java/com/stardust/"),
+ file("$rootDir/app/src/main/assets/modules/obsolete/"),
+ file("$rootDir/app/src/main/assets-app/js-beautify/"),
+ ))
}
}
diff --git a/app/src/main/java/org/autojs/autojs/engine/RhinoJavaScriptEngine.kt b/app/src/main/java/org/autojs/autojs/engine/RhinoJavaScriptEngine.kt
index 72b4e73d..5162be35 100644
--- a/app/src/main/java/org/autojs/autojs/engine/RhinoJavaScriptEngine.kt
+++ b/app/src/main/java/org/autojs/autojs/engine/RhinoJavaScriptEngine.kt
@@ -30,7 +30,9 @@ import org.mozilla.javascript.NativeArray
import org.mozilla.javascript.NativeObject
import org.mozilla.javascript.Script
import org.mozilla.javascript.Scriptable
+import org.mozilla.javascript.ScriptableObject.DONTENUM
import org.mozilla.javascript.ScriptableObject.PERMANENT
+import org.mozilla.javascript.ScriptableObject.READONLY
import org.mozilla.javascript.commonjs.module.RequireBuilder
import org.mozilla.javascript.commonjs.module.provider.SoftCachingModuleScriptProvider
import java.io.File
@@ -103,7 +105,7 @@ open class RhinoJavaScriptEngine(private val androidContext: android.content.Con
override fun init() {
thread = Thread.currentThread()
- scriptable.defineProp("__engine__", this)
+ scriptable.defineProp("__engine__", this, READONLY or DONTENUM or PERMANENT)
initRequireBuilder(context, scriptable)
runtime.withTimeConsuming("runtime-init-prologue") {
diff --git a/app/src/main/java/org/autojs/autojs/permission/ShizukuPermission.kt b/app/src/main/java/org/autojs/autojs/permission/ShizukuPermission.kt
index 479d5a23..cd373406 100644
--- a/app/src/main/java/org/autojs/autojs/permission/ShizukuPermission.kt
+++ b/app/src/main/java/org/autojs/autojs/permission/ShizukuPermission.kt
@@ -24,7 +24,7 @@ class ShizukuPermission(override val context: Context) : PermissionItemHelper {
} catch (e: Throwable) {
e.printStackTrace()
}
- WrappedShizuku.config(context, true)?.let { true }
+ WrappedShizuku.configWithContext(context, true)?.let { true }
?: ViewUtils.showToast(context, R.string.error_failed_to_grant_shizuku_access).let { false }
}
}
@@ -34,7 +34,7 @@ class ShizukuPermission(override val context: Context) : PermissionItemHelper {
return when {
!WrappedShizuku.isInstalled(context) -> false.also { ViewUtils.showToast(context, R.string.error_shizuku_is_not_installed) }
Shizuku.isPreV11() -> false.also { ViewUtils.showToast(context, R.string.error_shizuku_version_is_not_supported) }
- else -> WrappedShizuku.config(context, false)?.let { true }
+ else -> WrappedShizuku.configWithContext(context, false)?.let { true }
?: ViewUtils.showToast(context, R.string.error_failed_to_revoke_shizuku_access).let { false }
}
}
diff --git a/app/src/main/java/org/autojs/autojs/rhino/ProxyObject.kt b/app/src/main/java/org/autojs/autojs/rhino/ProxyObject.kt
index 0996603d..361bfb41 100644
--- a/app/src/main/java/org/autojs/autojs/rhino/ProxyObject.kt
+++ b/app/src/main/java/org/autojs/autojs/rhino/ProxyObject.kt
@@ -73,6 +73,12 @@ open class ProxyObject() : NativeObject() {
@JvmField
val PROXY_OBJECT_KEY = "__proxy__"
+ @JvmField
+ val AUGMENTED_OBJECT_KEY = "__augmented__"
+
+ @JvmField
+ val AUGMENTED_CUSTOM_TO_STRING_KEY = "__augmented_custom_to_string__"
+
@JvmField
val PROXY_SETTER_KEY = "set"
diff --git a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt
index 68374b58..69d9e490 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/ScriptRuntime.kt
@@ -458,7 +458,7 @@ class ScriptRuntime private constructor(builder: Builder) {
floaty = ApiFloaty(uiHandler, this)
ui = ApiUI(mUiHandlerAppContext, this)
- util = ApiUtil(mUiHandlerAppContext, this)
+ util = ApiUtil
images = ApiImages(mUiHandlerAppContext, this)
device = ApiDevice(mUiHandlerAppContext)
media = ApiMedia(mUiHandlerAppContext, this)
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/Util.kt b/app/src/main/java/org/autojs/autojs/runtime/api/Util.kt
index bc7f3cd0..34b8267d 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/Util.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/Util.kt
@@ -1,9 +1,8 @@
package org.autojs.autojs.runtime.api
import org.autojs.autojs.extension.AnyExtensions.jsBrief
-import org.autojs.autojs.runtime.ScriptRuntime
-class Util(private val context: android.content.Context, private val scriptRuntime: ScriptRuntime) {
+object Util {
fun `class`(o: Any?) = getClassInternal(o, "class")
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt
index 2ebf42b5..78b1beab 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/WrappedShizuku.kt
@@ -120,7 +120,6 @@ object WrappedShizuku {
false.also { if (e.message?.contains(Regex("binder .+n[o']t been received", RegexOption.IGNORE_CASE)) == false) e.printStackTrace() }
}
- @JvmStatic
@ScriptInterface
fun isOperational(): Boolean = isRunning() && hasPermission()
@@ -130,12 +129,11 @@ object WrappedShizuku {
@ScriptInterface
fun requestPermission() = Shizuku.requestPermission(mRequestCode)
- @ScriptInterface
- fun config(isRequest: Boolean?) = config(GlobalAppContext.get(), isRequest)
-
@ScriptInterface
@JvmOverloads
- fun config(context: Context, isRequest: Boolean? = null): Intent? = getLaunchIntent(context)?.also {
+ fun config(isRequest: Boolean? = null) = configWithContext(GlobalAppContext.get(), isRequest)
+
+ fun configWithContext(context: Context, isRequest: Boolean? = null): Intent? = getLaunchIntent(context)?.also {
context.startActivity(it)
val message = when (isRequest) {
true -> "${context.getString(R.string.text_grant_autojs6_access_in_shizuku_app)} (${context.getString(R.string.text_shizuku_service_may_need_to_be_run_first)})"
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt
index d77e350c..21d0c7c0 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/Augmentable.kt
@@ -5,9 +5,11 @@ import org.autojs.autojs.app.GlobalAppContext
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
import org.autojs.autojs.extension.AnyExtensions.jsBrief
import org.autojs.autojs.extension.FlexibleArray
+import org.autojs.autojs.extension.FlexibleArray.Companion.component1
import org.autojs.autojs.extension.ScriptableExtensions.defineProp
import org.autojs.autojs.extension.ScriptableExtensions.prop
import org.autojs.autojs.rhino.ProxyObject
+import org.autojs.autojs.rhino.ProxyObject.Companion.AUGMENTED_CUSTOM_TO_STRING_KEY
import org.autojs.autojs.rhino.ProxyObject.Companion.PROXY_GETTER_KEY
import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.augment.events.Events
@@ -118,8 +120,9 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
/**
* List element cases:
* - <1> - name to getter
+ * - <2> - name to getter to attributes
*/
- open val selfAssignmentGetters = listOf>>()
+ open val selfAssignmentGetters = listOf()
/**
* List element cases:
@@ -264,17 +267,19 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
objProtoList += Events.__asEmitter__(scriptRuntime, emptyArray())
}
- objProtoList.forEachIndexed { index, prototypeObject -> augmentPrototypesAt(index, newObj, prototypeObject) }
- scopeProtoList.forEachIndexed { index, prototypeObject -> augmentPrototypesAt(index, global, prototypeObject) }
+ val newObjOriginalPrototype = newObj.prototype
+ objProtoList.forEachIndexed { index, prototypeObject -> augmentPrototypesAt(index, newObj, prototypeObject, newObjOriginalPrototype) }
+ val globalOriginalPrototype = global.prototype
+ scopeProtoList.forEachIndexed { index, prototypeObject -> augmentPrototypesAt(index, global, prototypeObject, globalOriginalPrototype) }
}
- private fun augmentPrototypesAt(index: Int, o: ScriptableObject, proto: Scriptable) {
+ private fun augmentPrototypesAt(index: Int, o: ScriptableObject, proto: Scriptable, originalProto: Scriptable?) {
when (index) {
- 0 -> o.prototype = proto
- 1 -> o.prototype.prototype = proto
- 2 -> o.prototype.prototype.prototype = proto
- 3 -> o.prototype.prototype.prototype.prototype = proto
- 4 -> o.prototype.prototype.prototype.prototype.prototype = proto
+ 0 -> o.prototype = proto.apply { prototype = originalProto }
+ 1 -> o.prototype.prototype = proto.apply { prototype = originalProto }
+ 2 -> o.prototype.prototype.prototype = proto.apply { prototype = originalProto }
+ 3 -> o.prototype.prototype.prototype.prototype = proto.apply { prototype = originalProto }
+ 4 -> o.prototype.prototype.prototype.prototype.prototype = proto.apply { prototype = originalProto }
else -> throw RuntimeException("Augmentation can only be applied to no more than $index targets")
}
}
@@ -372,6 +377,9 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
if (flag and AS_GLOBAL != 0) {
globalFunctions += name to alias to (PERMANENT or refineAttributes(flag))
}
+ if (flag and AS_FUNCTIONAL_TO_STRING != 0) {
+ targetFunctions += AUGMENTED_CUSTOM_TO_STRING_KEY to AUGMENTED_CUSTOM_TO_STRING_KEY to (DONTENUM or PERMANENT or refineAttributes(flag))
+ }
}
}
else -> throw WrappedIllegalArgumentException("Unknown function element ${item.jsBrief()} for selfAssignmentFunctions")
@@ -381,8 +389,7 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
when (item) {
is String -> globalFunctions += item to item to PERMANENT
is Pair<*, *> -> {
- val first = item.first
- val second = item.second
+ val (first, second) = item
val name: String
val aliasList = mutableListOf()
var flag = 0
@@ -474,33 +481,62 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
throw WrappedRuntimeException(niceMessage)
}
}, NOT_CONSTRUCTABLE)
- destination.defineProperty(funcNameAlias, f, attributes)
+ destination.defineWith(funcNameAlias, f, attributes)
}
}
+ @Suppress("UnnecessaryVariable", "UNCHECKED_CAST")
private fun augmentGettersAndSetters(target: ScriptableObject, global: ScriptableObject) {
- selfAssignmentGetters.forEach { pair ->
- val (name, getter) = pair
- target.defineProperty(name, getter, null, PERMANENT)
+ selfAssignmentGetters.forEach { item ->
+ when (item) {
+ is Pair<*, *> -> {
+ val (first, second) = item
+ when (first) {
+ is String -> {
+ val name = first
+ when (val getter = second) {
+ is Supplier<*> -> {
+ target.defineWith(name, getter as Supplier, null, PERMANENT)
+ }
+ else -> throw WrappedIllegalArgumentException("Unknown second element ${second.jsBrief()} for selfAssignmentGetters")
+ }
+ }
+ is Pair<*, *> -> {
+ val (name, getter) = first
+ require(name is String) {
+ throw WrappedIllegalArgumentException("First element of pair must be a String for selfAssignmentGetters")
+ }
+ when (val attributes = second) {
+ is Int -> {
+ target.defineWith(name, getter as Supplier, null, refineAttributes(attributes))
+ }
+ else -> throw WrappedIllegalArgumentException("Unknown second element ${second.jsBrief()} for selfAssignmentGetters")
+ }
+ }
+ else -> throw WrappedIllegalArgumentException("Unknown item ${item.jsBrief()} for selfAssignmentGetters")
+ }
+ }
+ else -> throw WrappedIllegalArgumentException("Unknown item ${item.jsBrief()} for selfAssignmentGetters")
+ }
}
selfAssignmentGettersAndSetters.forEach { triple ->
val (name, getter, setter) = triple
- target.defineProperty(name, getter, setter, PERMANENT)
+ target.defineWith(name, getter, setter, PERMANENT)
}
globalAssignmentGetters.forEach { pair ->
val (name, getter) = pair
- global.defineProperty(name, getter, null, PERMANENT)
+ global.defineWith(name, getter, null, PERMANENT)
}
}
private fun augmentJavaClasses(target: ScriptableObject, global: ScriptableObject) {
selfAssignmentJavaClasses.forEach { pair ->
val (name, clazz) = pair
- target.defineProperty(name, NativeJavaClass(global, clazz.java), PERMANENT)
+ target.defineWith(name, NativeJavaClass(global, clazz.java), PERMANENT)
}
globalAssignmentJavaClasses.forEach { pair ->
val (name, clazz) = pair
- global.defineProperty(name, NativeJavaClass(global, clazz.java), PERMANENT)
+ global.defineWith(name, NativeJavaClass(global, clazz.java), PERMANENT)
}
}
@@ -512,14 +548,44 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F
companion object : FlexibleArray() {
- const val AS_GLOBAL = 0x1000
- const val AS_IGNORED = 0x2000
+ // @Caution by SuperMonster003 on Oct 5, 2025.
+ // ! These constants are "bit flags", each value is a power of 2, with only one bit being 1 in binary.
+ // ! They can be combined using `bitwise OR (|)` and checked using `bitwise AND (&)` without interference.
+ // ! Do not modify them to the form 0x0101/0x0102/0x0103/0x0104/...,
+ // ! to avoid flag overlap causing combination and detection logic to fail,
+ // ! e.g. `flags & AS_GLOBAL` may give false results.
+ // ! zh-CN:
+ // ! 这些常量是 "位标志" (bit flags), 每个值都是二的幂, 二进制中仅有一位为 1.
+ // ! 可用 `按位或 (|)` 进行组合, `按位与 (&)` 进行检测, 互不干扰.
+ // ! 不可将其修改为 0x0101/0x0102/0x0103/0x0104/... 的形式,
+ // ! 以避免标志重叠造成组合与检测逻辑失效, 如 `flags & AS_GLOBAL` 可能出现误判.
+ // !
+ const val AS_GLOBAL = 0x0100
+ const val AS_IGNORED = 0x0200
+ const val AS_LITERAL_TO_STRING = 0x0400
+ const val AS_FUNCTIONAL_TO_STRING = 0x0800
val globalContext: Context
get() = GlobalAppContext.get()
fun refineAttributes(attributes: Int) = attributes and (READONLY or DONTENUM or PERMANENT or UNINITIALIZED_CONST)
+ private fun isInternalName(value: String) = value.startsWith("__") && value.endsWith("__")
+
+ private fun ScriptableObject.defineWith(name: String, getter: Supplier, setter: Consumer?, attributes: Int) {
+ when (isInternalName(name)) {
+ true -> this.defineProperty(name, getter, setter, DONTENUM or attributes)
+ else -> this.defineProperty(name, getter, setter, attributes)
+ }
+ }
+
+ private fun ScriptableObject.defineWith(name: String, value: Any?, attributes: Int) {
+ when (isInternalName(name)) {
+ true -> this.defineProperty(name, value, DONTENUM or attributes)
+ else -> this.defineProperty(name, value, attributes)
+ }
+ }
+
}
}
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/AugmentableProxy.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/AugmentableProxy.kt
index f87f03b3..d1167d89 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/AugmentableProxy.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/AugmentableProxy.kt
@@ -1,8 +1,11 @@
package org.autojs.autojs.runtime.api.augment
+import org.autojs.autojs.extension.FlexibleArray.Companion.component1
+import org.autojs.autojs.extension.FlexibleArray.Companion.component2
import org.autojs.autojs.extension.ScriptableExtensions.defineProp
import org.autojs.autojs.extension.ScriptableExtensions.prop
import org.autojs.autojs.rhino.ProxyObject
+import org.autojs.autojs.rhino.ProxyObject.Companion.AUGMENTED_OBJECT_KEY
import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import org.autojs.autojs.util.RhinoUtils.UNDEFINED
@@ -70,8 +73,9 @@ open class AugmentableProxy(private val scriptRuntime: ScriptRuntime) : Augmenta
return NOT_FOUND
}
- open fun getCore(augmented: ScriptableObject, key: String): Any? {
- return when (val value = augmented.prop(key)) {
+ open fun getCore(augmented: ScriptableObject, key: String): Any? = when (key) {
+ AUGMENTED_OBJECT_KEY -> augmented
+ else -> when (val value = augmented.prop(key)) {
is BaseFunction -> when {
// @Hint by SuperMonster003 on Nov 6, 2024.
// ! Indicated that `key` is not defined in `augmented`
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/colors/Colors.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/colors/Colors.kt
index 222ec763..c3830a8d 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/colors/Colors.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/colors/Colors.kt
@@ -41,6 +41,7 @@ import org.mozilla.javascript.NativeArray
import org.mozilla.javascript.NativeObject
import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.Scriptable.NOT_FOUND
+import org.mozilla.javascript.ScriptableObject.DONTENUM
import java.util.function.Supplier
import kotlin.math.abs
import kotlin.math.roundToInt
@@ -83,8 +84,10 @@ object Colors : Augmentable(), SimpleGetterProxy {
colorMap
}
+ private val allForNativeObject by lazy { all.toNativeObject() }
+
override val selfAssignmentFunctions = listOf(
- "toString",
+ "toString" to AS_FUNCTIONAL_TO_STRING,
::toInt.name,
::toHex.name,
::toFullHex.name,
@@ -150,8 +153,8 @@ object Colors : Augmentable(), SimpleGetterProxy {
table::class.java.simpleName.lowercase() to table
}
- override val selfAssignmentGetters = listOf>>(
- "all" to Supplier { all.toNativeObject() },
+ override val selfAssignmentGetters = listOf(
+ "all" to Supplier { allForNativeObject } to DONTENUM,
)
@JvmStatic
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/events/Events.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/events/Events.kt
index 9865351b..1a11de72 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/events/Events.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/events/Events.kt
@@ -20,12 +20,15 @@ import org.mozilla.javascript.Context
import org.mozilla.javascript.NativeJavaMethod
import org.mozilla.javascript.Scriptable
import org.mozilla.javascript.ScriptableObject
+import org.mozilla.javascript.ScriptableObject.DONTENUM
+import org.mozilla.javascript.ScriptableObject.PERMANENT
+import org.mozilla.javascript.ScriptableObject.READONLY
import java.lang.reflect.Modifier
class Events(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
override val selfAssignmentFunctions = listOf(
- ::__asEmitter__.name,
+ ::__asEmitter__.name to (READONLY or DONTENUM or PERMANENT),
)
companion object : FlexibleArray() {
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/global/Global.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/global/Global.kt
index 4ee61682..e7594b53 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/global/Global.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/global/Global.kt
@@ -58,7 +58,7 @@ class Global(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRunti
)
override val selfAssignmentFunctions = listOf(
- "toString",
+ "toString" to AS_LITERAL_TO_STRING,
::TODO.name,
::isUiThread.name,
::isJavaObject.name,
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/Http.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/Http.kt
index 84dd0b3b..d0c5ca9b 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/Http.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/Http.kt
@@ -65,7 +65,7 @@ import java.net.URI
class Http(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
override val selfAssignmentProperties = listOf(
- "__okhttp__" to scriptRuntime.http.okhttp to DONTENUM
+ "__okhttp__" to scriptRuntime.http.okhttp to (READONLY or DONTENUM or PERMANENT)
)
override val selfAssignmentFunctions = listOf(
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/ocr/Ocr.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/ocr/Ocr.kt
index c8d8bd9d..7232c48f 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/ocr/Ocr.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/ocr/Ocr.kt
@@ -31,7 +31,7 @@ import org.opencv.core.Rect as OpencvRect
class Ocr(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), Invokable {
override val selfAssignmentFunctions = listOf(
- "toString",
+ "toString" to AS_LITERAL_TO_STRING,
::tap.name,
::recognizeText.name,
::detect.name,
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/ui/UI.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/ui/UI.kt
index 03210b15..ce2856f5 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/ui/UI.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/ui/UI.kt
@@ -123,10 +123,10 @@ class UI(private val scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRunt
::keepScreenOn.name,
)
- override val selfAssignmentGetters = listOf>>(
+ override val selfAssignmentGetters = listOf(
"R" to Supplier { scriptRuntime.topLevelScope.prop("R").jsUnwrapped() },
"__widgets__" to Supplier { scriptRuntime.ui.widgets },
- "root" to Supplier {
+ "root" to Supplier {
val activity = getActivity(scriptRuntime)
(activity as? ScriptExecuteActivity)?.findViewById(android.R.id.content)
},
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/Inspect.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/Inspect.kt
index 422f999d..c9f94732 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/Inspect.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/Inspect.kt
@@ -10,6 +10,9 @@ import org.autojs.autojs.extension.FlexibleArray.Companion.component1
import org.autojs.autojs.extension.FlexibleArray.Companion.component2
import org.autojs.autojs.extension.NumberExtensions.jsString
import org.autojs.autojs.extension.ScriptableExtensions.prop
+import org.autojs.autojs.rhino.ProxyObject
+import org.autojs.autojs.rhino.ProxyObject.Companion.AUGMENTED_CUSTOM_TO_STRING_KEY
+import org.autojs.autojs.rhino.ProxyObject.Companion.AUGMENTED_OBJECT_KEY
import org.autojs.autojs.rhino.ProxyObject.Companion.PROXY_GETTER_KEY
import org.autojs.autojs.rhino.ProxyObject.Companion.PROXY_SETTER_KEY
import org.autojs.autojs.runtime.api.StringReadable
@@ -17,8 +20,8 @@ import org.autojs.autojs.runtime.api.augment.Augmentable
import org.autojs.autojs.runtime.api.augment.Invokable
import org.autojs.autojs.runtime.api.augment.global.Species.isErrorRhino
import org.autojs.autojs.runtime.api.augment.global.Species.isJavaObjectRhino
-import org.autojs.autojs.runtime.api.augment.global.Species.isObjectRhino
import org.autojs.autojs.runtime.api.augment.global.Species.isStringRhino
+import org.autojs.autojs.runtime.api.augment.util.Util.isReferenceRhino
import org.autojs.autojs.runtime.exception.ShouldNeverHappenException
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
import org.autojs.autojs.util.RhinoUtils
@@ -35,10 +38,12 @@ import org.autojs.autojs.util.RhinoUtils.js_object_keys
import org.autojs.autojs.util.RhinoUtils.newNativeObject
import org.mozilla.javascript.BaseFunction
import org.mozilla.javascript.Context
+import org.mozilla.javascript.MemberBox
import org.mozilla.javascript.NativeArray
import org.mozilla.javascript.NativeDate
import org.mozilla.javascript.NativeError
import org.mozilla.javascript.NativeJavaClass
+import org.mozilla.javascript.NativeJavaMethod
import org.mozilla.javascript.NativeJavaPackage
import org.mozilla.javascript.NativeObject
import org.mozilla.javascript.Scriptable
@@ -75,7 +80,6 @@ object Inspect : Augmentable(), Invokable {
* SGR (Select Graphic Rendition) parameters
* @see "ANSI escape code" on Wikipedia (en)
*/
- @Suppress("SpellCheckingInspection")
private val srg = object {
val fg = object {
val BLACK = 30
@@ -306,21 +310,58 @@ object Inspect : Augmentable(), Invokable {
if (value is NativeJavaClass) return value.toString()
if (value.javaClass.isArray) return javaArrayToString(value)
if (value !is ScriptableObject) return Context.toString(value)
+ if (value is ProxyObject) return formatValue(ctx, value[AUGMENTED_OBJECT_KEY], recurseTimes)
// @Hint by SuperMonster003 on Apr 16, 2024.
// ! Check if the object has a custom overwritten toString() method.
// ! zh-CN: 检查对象是否有自定义的 toString() 覆写方法.
- if (isObjectRhino(value)) {
- var tmp: Scriptable = value
- val objectPrototype by lazy { ScriptableObject.getObjectPrototype(value) }
- do {
- if (js_object_hasOwnProperty(tmp, "toString")) {
- if ((tmp.prop("toString") as? BaseFunction)?.arity == 0) {
- return callToStringFunction(value)
- }
+ if (isReferenceRhino(value)) {
+ var cur: Scriptable = value
+ val objProtoForJs: Scriptable? = ScriptableObject.getObjectPrototype(cur)
+ val objProtoForAugmentable: Scriptable = RhinoUtils.objectPrototype
+ val arrProtoForAugmentable: Scriptable = RhinoUtils.arrayPrototype
+ val funcProtoForAugmentable: Scriptable = RhinoUtils.functionPrototype
+ var owner: Scriptable? = null
+ while (true) {
+ if (js_object_hasOwnProperty(cur, "toString")) {
+ owner = cur
+ break
}
- tmp = tmp.prototype ?: break
- } while (tmp != objectPrototype)
+ cur = cur.prototype ?: break
+ }
+ if (js_object_hasOwnProperty(cur, AUGMENTED_CUSTOM_TO_STRING_KEY)) {
+ // Augmentable's custom toString method with special functionality (like Colors.toString)
+ // is not involved in custom determination.
+ // zh-CN: Augmentable 自定义的具有特殊功能的 toString 方法 (如 Colors.toString), 不参与自定义判定.
+ } else if (owner != null) {
+ val fn = owner["toString"]
+ val isCustom = run {
+ if (isJavaObjectToString(fn)) {
+ // Standard Java Object#toString or equivalent implementation, skip custom check.
+ // zh-CN: 标准 Java Object#toString 或等价实现, 视为未自定义, 跳过自定义判定.
+ return@run false
+ }
+ if (fn === objProtoForJs?.get("toString")) {
+ // Standard JavaScript Object.prototype.toString or equivalent implementation, skip custom check.
+ // zh-CN: 标准 JavaScript Object.prototype.toString 或等价实现, 视为未自定义, 跳过自定义判定.
+ return@run false
+ }
+ val augmentableToStringList = listOf(
+ objProtoForAugmentable["toString"],
+ arrProtoForAugmentable["toString"],
+ funcProtoForAugmentable["toString"],
+ )
+ if (fn in augmentableToStringList) {
+ // Terminal toString in Augmentable prototype chain, skip custom check.
+ // zh-CN: Augmentable 原型链终端的 toString, 不参与自定义判定.
+ return@run false
+ }
+ return@run fn is BaseFunction && fn.arity == 0
+ }
+ if (isCustom) {
+ return callToStringFunction(value)
+ }
+ }
}
// Look up the keys of the object.
@@ -328,7 +369,6 @@ object Inspect : Augmentable(), Invokable {
val visibleKeys = newNativeObject().also { o ->
keys.forEach { o.put(Context.toString(it), o, true) }
}
-
if (ctx.showHidden) {
keys = js_object_getOwnPropertyNames(value)
}
@@ -419,6 +459,18 @@ object Inspect : Augmentable(), Invokable {
return reduceToSingleString(output, base, braces)
}
+ private fun isJavaObjectToString(fn: Any?): Boolean {
+ if (fn !is NativeJavaMethod) return false
+ val methods: Array = fn.methods
+ return methods.any { mb ->
+ val m = mb.method()
+ m.name == "toString" &&
+ m.parameterCount == 0 &&
+ m.returnType == String::class.java &&
+ m.declaringClass == Any::class.java
+ }
+ }
+
private fun toJavaObjectString(value: Any) = "[JavaObject: ${value.javaClass.name}@${Integer.toHexString(value.hashCode())}]"
private fun toJavaObjectString(className: Any?, value: Any?) = "[JavaObject: $className@${Integer.toHexString(value.hashCode())}]"
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/MorseCodeNativeObject.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/MorseCodeNativeObject.kt
index 36db8e4f..d0a62768 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/MorseCodeNativeObject.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/MorseCodeNativeObject.kt
@@ -20,10 +20,10 @@ import org.mozilla.javascript.Scriptable
class MorseCodeNativeObject(val parser: MorseCodeParser) : NativeObject(), StringReadable {
private val mFunctionNames = arrayOf(
+ "toString",
::getPattern.name,
::getCode.name,
::vibrate.name,
- "toString",
)
init {
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/Util.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/Util.kt
index c5ce7906..d516f932 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/Util.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/Util.kt
@@ -62,6 +62,7 @@ import org.mozilla.javascript.ScriptRuntime as RhinoScriptRuntime
object Util : Augmentable() {
override val selfAssignmentFunctions = listOf(
+ ::__assignFunctions__.name to (READONLY or DONTENUM or PERMANENT),
::isArray.name,
::isBoolean.name,
::isNull.name,
@@ -84,7 +85,6 @@ object Util : Augmentable() {
::isEmptyObject.name,
::unwrapJavaObject.name,
::extend.name,
- ::__assignFunctions__.name,
::format.name,
::deprecate.name,
::debuglog.name,
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/VersionCodes.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/VersionCodes.kt
index e293d050..46fe9a07 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/VersionCodes.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/VersionCodes.kt
@@ -5,6 +5,7 @@ import org.autojs.autojs.annotation.RhinoStandardFunctionInterface
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
import org.autojs.autojs.extension.ArrayExtensions.toNativeArray
import org.autojs.autojs.extension.FlexibleArray
+import org.autojs.autojs.extension.FlexibleArray.Companion.component1
import org.autojs.autojs.extension.NumberExtensions.jsString
import org.autojs.autojs.extension.ScriptableExtensions.prop
import org.autojs.autojs.runtime.api.augment.Augmentable
@@ -18,6 +19,7 @@ import org.mozilla.javascript.NativeDate
import org.mozilla.javascript.NativeObject
import org.mozilla.javascript.ScriptRuntime.wrapNumber
import org.mozilla.javascript.Scriptable
+import org.mozilla.javascript.ScriptableObject.DONTENUM
import org.mozilla.javascript.ScriptableObject.PERMANENT
import org.mozilla.javascript.ScriptableObject.READONLY
import java.util.*
@@ -26,7 +28,7 @@ import java.util.*
object VersionCodes : Augmentable() {
override val selfAssignmentFunctions = listOf(
- "toString",
+ "toString" to AS_LITERAL_TO_STRING,
::search.name,
::searchAll.name,
::summary.name,
@@ -84,14 +86,14 @@ object VersionCodes : Augmentable() {
val releaseTimestamp = releaseTimestampLong.jsString
fun toNativeObject() = newNativeObject().also {
- it.put("versionCode", it, versionCode)
- it.put("apiLevel", it, apiLevel.toInt())
- it.put("releaseName", it, releaseName)
- it.put("platformVersion", it, platformVersion)
- it.put("internalCodename", it, internalCodename)
- it.put("releaseDate", it, releaseDate)
- it.put("releaseTimestamp", it, releaseTimestampLong)
- it.defineFunctionProperties(arrayOf("valueOf"), javaClass, READONLY and PERMANENT)
+ it.defineProperty("versionCode", versionCode, READONLY or PERMANENT)
+ it.defineProperty("apiLevel", apiLevel.toInt(), READONLY or PERMANENT)
+ it.defineProperty("releaseName", releaseName, READONLY or PERMANENT)
+ it.defineProperty("platformVersion", platformVersion, READONLY or PERMANENT)
+ it.defineProperty("internalCodename", internalCodename, READONLY or PERMANENT)
+ it.defineProperty("releaseDate", releaseDate, READONLY or PERMANENT)
+ it.defineProperty("releaseTimestamp", releaseTimestampLong, READONLY or PERMANENT)
+ it.defineFunctionProperties(arrayOf("valueOf"), javaClass, READONLY or DONTENUM or PERMANENT)
}
private fun parseTimestamp(s: String): Long {
@@ -130,7 +132,9 @@ object VersionCodes : Augmentable() {
fun valueOf(cx: Context, thisObj: Scriptable, args: Array, funObj: Function): Any? {
return thisObj.prop("apiLevel")
}
+
}
+
}
internal object Searcher {
diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/VersionCodesList.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/VersionCodesList.kt
index 6e7038bd..22b6578f 100644
--- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/VersionCodesList.kt
+++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/util/VersionCodesList.kt
@@ -3,6 +3,8 @@ 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 {
@@ -55,7 +57,7 @@ object VersionCodesInfo {
for ((versionCode, infoList) in raw) {
val (releaseName, internalCodename, platformVersion, apiLevel, releaseDate) = infoList
val info = VersionCodes.Info(versionCode, releaseName, internalCodename, platformVersion, apiLevel, releaseDate)
- obj.put(versionCode, obj, info.toNativeObject())
+ obj.defineProperty(versionCode, { info.toNativeObject() }, null, READONLY or PERMANENT)
list += info
}
}
diff --git a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java
index 4934241b..8e235a67 100644
--- a/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java
+++ b/app/src/main/java/org/autojs/autojs/ui/floating/CircularMenu.java
@@ -217,7 +217,7 @@ public class CircularMenu implements Recorder.OnStateChangedListener, LayoutInsp
}
private void applyComponentInformation() {
- if (WrappedShizuku.isOperational() && WrappedShizuku.service != null) {
+ if (WrappedShizuku.INSTANCE.isOperational() && WrappedShizuku.service != null) {
try {
mRunningPackage = WrappedShizuku.service.currentPackage();
mRunningActivity = WrappedShizuku.service.currentActivity();
diff --git a/app/src/main/java/org/autojs/autojs/util/RhinoUtils.kt b/app/src/main/java/org/autojs/autojs/util/RhinoUtils.kt
index d963f822..cdb3e548 100644
--- a/app/src/main/java/org/autojs/autojs/util/RhinoUtils.kt
+++ b/app/src/main/java/org/autojs/autojs/util/RhinoUtils.kt
@@ -127,7 +127,7 @@ object RhinoUtils {
fun callFunction(scriptRuntime: ScriptRuntime?, obj: Scriptable, name: String, paramsToFunction: Array): Any? {
val property = obj.prop(name)
if (property == NOT_FOUND) throw IllegalArgumentException("Property $name not found on $obj")
- if (property !is BaseFunction) throw IllegalArgumentException("Property $name on $obj must be a BaseFunction")
+ if (property !is BaseFunction) throw IllegalArgumentException("Property $name on $obj must be a BaseFunction instead of ${property.jsBrief()}")
return callFunction(scriptRuntime, property, obj, obj, paramsToFunction)
}
diff --git a/libs/org.mozilla.rhino-1.8.1-SNAPSHOT.jar b/libs/org.mozilla.rhino-1.8.1-SNAPSHOT.jar
index 66da0538..4b3c272c 100644
Binary files a/libs/org.mozilla.rhino-1.8.1-SNAPSHOT.jar and b/libs/org.mozilla.rhino-1.8.1-SNAPSHOT.jar differ
diff --git a/version.properties b/version.properties
index 229bd927..2a249afa 100644
--- a/version.properties
+++ b/version.properties
@@ -1,5 +1,5 @@
-#Thu Oct 02 17:27:13 CST 2025
-BUILD_TIME=1759397233140
+#Sun Oct 05 13:27:08 CST 2025
+BUILD_TIME=1759642028837
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=3395
+VERSION_BUILD=3404
VERSION_NAME=6.7.0 Alpha6
VSCODE_EXT_REQUIRED_VERSION=1.0.8