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