From 142c465914e4aa8e9b63157079e456d8fa91e563 Mon Sep 17 00:00:00 2001 From: SuperMonster003 Date: Sat, 31 Jan 2026 15:09:08 +0800 Subject: [PATCH] =?UTF-8?q?6.7.0=20-=20Alpha19=20-=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=E5=86=85=E7=BD=AE=E6=A8=A1=E5=9D=97=E6=96=B9=E6=B3=95=E8=B0=83?= =?UTF-8?q?=E7=94=A8=E5=8F=AF=E8=83=BD=E5=87=BA=E7=8E=B0=20Rhino=20?= =?UTF-8?q?=E4=B8=8A=E4=B8=8B=E6=96=87=E5=8F=AF=E8=83=BD=E4=B8=8D=E4=B8=80?= =?UTF-8?q?=E8=87=B4=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changelog/lang_zh-Hans.json | 3 +- .../autojs/rhino/extension/ArrayExtensions.kt | 3 +- .../rhino/extension/IterableExtensions.kt | 3 +- .../autojs/autojs/runtime/IScriptBridges.kt | 2 +- .../autojs/autojs/runtime/ScriptBridges.kt | 30 +-- .../runtime/api/augment/AugmentableProxy.kt | 2 +- .../api/augment/automator/Automator.kt | 22 +- .../automator/RootAutomatorNativeObject.kt | 4 +- .../runtime/api/augment/console/Console.kt | 10 +- .../runtime/api/augment/global/Species.kt | 3 +- .../autojs/runtime/api/augment/http/Http.kt | 2 +- .../api/augment/http/RequestBuilderHelper.kt | 10 +- .../augment/http/ResponseBodyNativeObject.kt | 6 +- .../autojs/runtime/api/augment/jsox/Arrayx.kt | 202 +++++++----------- .../runtime/api/augment/selector/Selector.kt | 2 +- .../autojs/runtime/api/augment/ui/UI.kt | 6 +- .../autojs/runtime/api/augment/web/Web.kt | 4 +- .../java/org/autojs/autojs/util/RhinoUtils.kt | 154 ++++++------- version.properties | 8 +- 19 files changed, 231 insertions(+), 245 deletions(-) diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 11922a00..a6cf33c9 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -1,7 +1,7 @@ { "$data": { "v6.7.0": { - "released_date": "2026/01/30", + "released_date": "2026/01/31", "feature": [ "插件中心功能, 支持插件的安装/卸载/更新等操作 (入口: 主页抽屉按钮/主页标签页)", "Paddle OCR (PP-OCRv5) 插件, 用于光学字符识别", @@ -79,6 +79,7 @@ "ocr.detect 方法获得的结果可能与 ocr.mode 不匹配的问题 _[`issue #468`](http://issues.autojs6.com/468)_", "auto.registerEvent 注册的无障碍服务事件会被其他脚本误清理的问题 _[`issue #466`](http://issues.autojs6.com/466)_ _[`issue #343`](http://issues.autojs6.com/343#issuecomment-3263953918)_", "Android 10 UiObject#child 方法可能出现 ArrayIndexOutOfBoundsException 异常的问题 _[`issue #416`](http://issues.autojs6.com/416)_", + "内置模块方法调用可能出现 Rhino 上下文可能不一致的问题", "脚本创建大量浮动窗口后, 脚本退出时可能出现窗口残留的问题", "运行项目时 project.json 配置参数可能无法正常解析的问题", "项目打包时 project.json 的 excludedDirs 配置参数将导致配置文件解析失败的问题 _[`issue #428`](http://issues.autojs6.com/428)_", diff --git a/app/src/main/java/org/autojs/autojs/rhino/extension/ArrayExtensions.kt b/app/src/main/java/org/autojs/autojs/rhino/extension/ArrayExtensions.kt index 9fa98a23..e02bc105 100644 --- a/app/src/main/java/org/autojs/autojs/rhino/extension/ArrayExtensions.kt +++ b/app/src/main/java/org/autojs/autojs/rhino/extension/ArrayExtensions.kt @@ -1,6 +1,7 @@ package org.autojs.autojs.rhino.extension import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief +import org.autojs.autojs.util.RhinoUtils.getOrCreateStandardObjects import org.autojs.autojs.util.RhinoUtils.withRhinoContext import org.mozilla.javascript.Context import org.mozilla.javascript.NativeArray @@ -9,7 +10,7 @@ object ArrayExtensions { fun Array<*>.toNativeArray(): NativeArray { return withRhinoContext { cx -> - val standardObjects = cx.initStandardObjects() + val standardObjects = cx.getOrCreateStandardObjects() cx.newArray(standardObjects, this.toList().map { Context.javaToJS(it, standardObjects) }.toTypedArray()) as NativeArray } } diff --git a/app/src/main/java/org/autojs/autojs/rhino/extension/IterableExtensions.kt b/app/src/main/java/org/autojs/autojs/rhino/extension/IterableExtensions.kt index defc6a62..cf01ded2 100644 --- a/app/src/main/java/org/autojs/autojs/rhino/extension/IterableExtensions.kt +++ b/app/src/main/java/org/autojs/autojs/rhino/extension/IterableExtensions.kt @@ -1,6 +1,7 @@ package org.autojs.autojs.rhino.extension import org.autojs.autojs.util.RhinoUtils +import org.autojs.autojs.util.RhinoUtils.getOrCreateStandardObjects import org.mozilla.javascript.Context import org.mozilla.javascript.NativeArray @@ -8,7 +9,7 @@ object IterableExtensions { fun Iterable<*>.toNativeArray(): NativeArray { return RhinoUtils.withRhinoContext { cx -> - val standardObjects = cx.initStandardObjects() + val standardObjects = cx.getOrCreateStandardObjects() cx.newArray(standardObjects, this.map { Context.javaToJS(it, standardObjects) }.toTypedArray()) as NativeArray } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/IScriptBridges.kt b/app/src/main/java/org/autojs/autojs/runtime/IScriptBridges.kt index b022fa58..b29c0705 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/IScriptBridges.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/IScriptBridges.kt @@ -13,5 +13,5 @@ interface IScriptBridges { fun toString(obj: Any?): String - fun toPrimitive(obj: Any?): Any + fun toPrimitive(obj: Any?): Any? } \ No newline at end of file diff --git a/app/src/main/java/org/autojs/autojs/runtime/ScriptBridges.kt b/app/src/main/java/org/autojs/autojs/runtime/ScriptBridges.kt index 08b4f68e..185b42b4 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/ScriptBridges.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/ScriptBridges.kt @@ -29,12 +29,12 @@ class ScriptBridges : IScriptBridges { this.engine = engine } - fun setJavaPrimitiveWrap(b: Boolean) = useJsContext { - it.wrapFactory.isJavaPrimitiveWrap = b + fun setJavaPrimitiveWrap(b: Boolean) = useJsContext { cx -> + cx.wrapFactory.isJavaPrimitiveWrap = b } - fun isJavaPrimitiveWrap(): Boolean = useJsContext { - it.wrapFactory.isJavaPrimitiveWrap + fun isJavaPrimitiveWrap(): Boolean = useJsContext { cx -> + cx.wrapFactory.isJavaPrimitiveWrap } override fun call(func: BaseFunction, target: Any?, args: Array<*>) = useJsContext { cx -> @@ -46,12 +46,12 @@ class ScriptBridges : IScriptBridges { callFunction(engine.runtime, func, niceScope, thisObj, niceArgs) } - override fun toArray(o: Iterable<*>?): NativeArray = useJsContext { context -> - val scope = context.initStandardObjects() - context.newArray(scope, o?.map { Context.javaToJS(it, scope) }?.toTypedArray()) as NativeArray + override fun toArray(o: Iterable<*>?): NativeArray = useJsContext { cx -> + val scope = engine.runtime.topLevelScope + cx.newArray(scope, o?.map { Context.javaToJS(it, scope) }?.toTypedArray()) as NativeArray } - override fun asArray(listLike: Any): NativeArray = useJsContext { context -> + override fun asArray(listLike: Any): NativeArray = useJsContext { cx -> if (listLike is Iterable<*>) { return@useJsContext toArray(listLike) } @@ -61,7 +61,7 @@ class ScriptBridges : IScriptBridges { listLike::class.java.methods.forEach { val name = it.name val method = NativeJavaMethod(it, name) - val bound = BoundFunction(context, arr, method, boundThis, emptyArray()) + val bound = BoundFunction(cx, arr, method, boundThis, emptyArray()) arr.put(name, arr, bound) } return@useJsContext arr @@ -69,16 +69,18 @@ class ScriptBridges : IScriptBridges { return@useJsContext newNativeArray() } - override fun toString(obj: Any?): String = Context.toString(obj) + override fun toString(obj: Any?): String = + Context.toString(obj) - override fun toPrimitive(obj: Any?): Any = useJsContext { context -> - Context.javaToJS(obj, context.initStandardObjects()) - } + override fun toPrimitive(obj: Any?): Any? = + Context.javaToJS(obj, engine.runtime.topLevelScope) private fun useJsContext(f: (Context) -> T): T { val currentContext = Context.getCurrentContext() return try { - f(currentContext ?: engine.setupContext(Context.enter())) + // Enter Context via engine to ensure WrapFactory and AutoJsContext binding are installed. + // zh-CN: 通过 engine 进入 Context, 确保 WrapFactory 与 AutoJsContext 绑定已安装. + f(currentContext ?: engine.enterContext()) } finally { currentContext ?: Context.exit() } 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 37ef74f5..ec8d88bf 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 @@ -82,7 +82,7 @@ open class AugmentableProxy(private val scriptRuntime: ScriptRuntime) : Augmenta // ! but defined in a certain object in its prototype chain. // ! zh-CN: 表示 `key` 未定义在 `augmented` 上, 但定义在其原型链对象上. !augmented.has(key) && ScriptableObject.hasProperty(augmented, key) -> { - withRhinoContext { cx -> BoundFunction(cx, augmented, value, augmented, arrayOf()) } + withRhinoContext(scriptRuntime) { cx -> BoundFunction(cx, augmented, value, augmented, arrayOf()) } } else -> value } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/automator/Automator.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/automator/Automator.kt index bb64a86a..db378561 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/automator/Automator.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/automator/Automator.kt @@ -309,7 +309,12 @@ class Automator(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { val last = it.last() when { isGestureResultCallbackLike(last) -> { - scriptRuntime.automator.gestureAsync(start, duration, toPointsGroup(it.drop(1).dropLast(1)).toTypedArray(), toGestureResultCallback(last)) + scriptRuntime.automator.gestureAsync( + start = start, + duration = duration, + points = toPointsGroup(it.drop(1).dropLast(1)).toTypedArray(), + callback = toGestureResultCallback(scriptRuntime, last), + ) } else -> scriptRuntime.automator.gestureAsync(start, duration, toPointsGroup(it.drop(1)).toTypedArray()) } @@ -349,7 +354,10 @@ class Automator(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { when { isGestureResultCallbackLike(last) -> { it.dropLast(1).forEach { o -> require((o is List<*>)) { "Arguments for automator.gesturesAsync should be of type Array" } } - scriptRuntime.automator.gesturesAsync(toStrokes(scriptRuntime, it.dropLast(1).toTypedArray()), toGestureResultCallback(last)) + scriptRuntime.automator.gesturesAsync( + strokes = toStrokes(scriptRuntime, it.dropLast(1).toTypedArray()), + callback = toGestureResultCallback(scriptRuntime, last), + ) } else -> { it.dropLast(1).forEach { o -> require((o is List<*>)) { "Arguments for automator.gesturesAsync should be of type Array" } } @@ -662,16 +670,16 @@ class Automator(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { else -> throw WrappedIllegalArgumentException("Invalid arguments length (${args.size}) for \"args\" of Automator#performAction") } - private fun toGestureResultCallback(callback: Any?): AccessibilityService.GestureResultCallback? { + private fun toGestureResultCallback(scriptRuntime: ScriptRuntime, callback: Any?): AccessibilityService.GestureResultCallback? { if (!isGestureResultCallbackLike(callback)) return null return object : AccessibilityService.GestureResultCallback() { override fun onCompleted(gestureDescription: GestureDescription) { when (callback) { - is BaseFunction -> withRhinoContext { cx -> + is BaseFunction -> withRhinoContext(scriptRuntime) { cx -> callback.call(cx, ImporterTopLevel(cx), callback, arrayOf(true)) } is NativeObject -> callback.prop("onCompleted")?.let { - if (it is BaseFunction) withRhinoContext { cx -> + if (it is BaseFunction) withRhinoContext(scriptRuntime) { cx -> it.call(cx, ImporterTopLevel(cx), callback, arrayOf(gestureDescription)) } } @@ -680,11 +688,11 @@ class Automator(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { override fun onCancelled(gestureDescription: GestureDescription) { when (callback) { - is BaseFunction -> withRhinoContext { cx -> + is BaseFunction -> withRhinoContext(scriptRuntime) { cx -> callback.call(cx, ImporterTopLevel(cx), callback, arrayOf(false)) } is NativeObject -> callback.prop("onCancelled")?.let { - if (it is BaseFunction) withRhinoContext { cx -> + if (it is BaseFunction) withRhinoContext(scriptRuntime) { cx -> it.call(cx, ImporterTopLevel(cx), callback, arrayOf(gestureDescription)) } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/automator/RootAutomatorNativeObject.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/automator/RootAutomatorNativeObject.kt index e30c61e1..50999a64 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/automator/RootAutomatorNativeObject.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/automator/RootAutomatorNativeObject.kt @@ -13,7 +13,7 @@ import org.autojs.autojs.core.inputevent.RootAutomator as CoreRootAutomator import org.mozilla.javascript.ScriptRuntime as RhinoScriptRuntime @Suppress("unused") -class RootAutomatorNativeObject(scriptRuntime: ScriptRuntime, waitForReady: Any? = false) : NativeObject() { +class RootAutomatorNativeObject(private val scriptRuntime: ScriptRuntime, waitForReady: Any? = false) : NativeObject() { private val mRootAutomatorObject: Scriptable = run { val rootAutomator = when (waitForReady) { @@ -46,7 +46,7 @@ class RootAutomatorNativeObject(scriptRuntime: ScriptRuntime, waitForReady: Any? // # 'touchDown', 'touchUp', 'touchMove', 'getDefaultId', 'setDefaultId', 'exit', // # ] return when (val o = mRootAutomatorObject.prop(name)) { - is BaseFunction -> withRhinoContext { cx -> + is BaseFunction -> withRhinoContext(scriptRuntime) { cx -> BoundFunction(cx, mRootAutomatorObject, o, mRootAutomatorObject, arrayOf()) } else -> super.get(name, start) diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt index 119d57ca..70b6ff67 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/console/Console.kt @@ -7,15 +7,15 @@ import org.apache.log4j.LogManager import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface import org.autojs.autojs.core.console.ConsoleImpl import org.autojs.autojs.core.console.ConsoleImpl.Companion.DEFAULT_EXIT_ON_CLOSE_TIMEOUT -import org.autojs.autojs.rhino.extension.AnyExtensions.isJsNullish -import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief import org.autojs.autojs.rhino.ArgumentGuards import org.autojs.autojs.rhino.ArgumentGuards.Companion.component1 import org.autojs.autojs.rhino.ArgumentGuards.Companion.component2 +import org.autojs.autojs.rhino.ProxyObject +import org.autojs.autojs.rhino.extension.AnyExtensions.isJsNullish +import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief import org.autojs.autojs.rhino.extension.ScriptableExtensions.hasProp import org.autojs.autojs.rhino.extension.ScriptableExtensions.prop import org.autojs.autojs.rhino.extension.ScriptableObjectExtensions.inquire -import org.autojs.autojs.rhino.ProxyObject import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.api.augment.AugmentableProxy import org.autojs.autojs.runtime.api.augment.s13n.S13n @@ -50,7 +50,7 @@ import org.mozilla.javascript.ScriptableObject import org.mozilla.javascript.Undefined @Suppress("unused", "UNUSED_PARAMETER") -class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) { +class Console(private val scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) { private val mRtConsole = scriptRuntime.console private val mTopLevelScope = scriptRuntime.topLevelScope @@ -137,7 +137,7 @@ class Console(scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRuntime) { ::launch.name to "launchConsole", ) - private fun getStackTrace() = withRhinoContext { cx -> + private fun getStackTrace() = withRhinoContext(scriptRuntime) { cx -> newNativeObject().also { o -> val globalErrorObject = mTopLevelScope.prop(NativeError.ERROR_TAG) as ScriptableObject NativeError.js_captureStackTrace( diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/global/Species.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/global/Species.kt index c9d99c67..22c71156 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/global/Species.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/global/Species.kt @@ -4,6 +4,7 @@ import org.autojs.autojs.annotation.RhinoFunctionBody import org.autojs.autojs.annotation.RhinoSingletonFunctionInterface import org.autojs.autojs.runtime.api.augment.Augmentable import org.autojs.autojs.runtime.api.augment.Invokable +import org.autojs.autojs.util.RhinoUtils.getOrCreateStandardObjects import org.autojs.autojs.util.RhinoUtils.withRhinoContext import org.mozilla.javascript.Context import org.mozilla.javascript.Scriptable @@ -61,7 +62,7 @@ object Species : Augmentable(), Invokable { when { o == null -> "Null" Undefined.isUndefined(o) -> "Undefined" - else -> when (val obj = withRhinoContext { cx -> Context.javaToJS(o, cx.initStandardObjects()) }) { + else -> when (val obj = withRhinoContext { cx -> Context.javaToJS(o, cx.getOrCreateStandardObjects()) }) { is Boolean -> "Boolean" is String -> "String" is BigInteger -> "BigInt" 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 31ae8e08..46fd428c 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 @@ -195,7 +195,7 @@ class Http(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { uiMapper = { response -> // Wrap response into Rhino object on UI thread with Rhino Context. // zh-CN: 在 UI 线程进入 Rhino Context, 将 Response 包装为 Rhino 对象. - withRhinoContext { + withRhinoContext(scriptRuntime) { val wrapped = wrapResponse(scriptRuntime, response, prepared.cacheBody, prepared.cacheThreshold) // Optional: if user provided callback, call it on UI thread. diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/RequestBuilderHelper.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/RequestBuilderHelper.kt index eb79cc99..e6581b3c 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/RequestBuilderHelper.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/RequestBuilderHelper.kt @@ -9,14 +9,14 @@ import okhttp3.RequestBody import okhttp3.RequestBody.Companion.asRequestBody import okhttp3.RequestBody.Companion.toRequestBody import okio.BufferedSink +import org.autojs.autojs.pio.PFile +import org.autojs.autojs.pio.PFileInterface import org.autojs.autojs.rhino.extension.AnyExtensions.isJsNullish import org.autojs.autojs.rhino.extension.AnyExtensions.isJsNumber import org.autojs.autojs.rhino.extension.AnyExtensions.isJsString import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief import org.autojs.autojs.rhino.extension.AnyExtensions.toRuntimePath import org.autojs.autojs.rhino.extension.ScriptableExtensions.prop -import org.autojs.autojs.pio.PFile -import org.autojs.autojs.pio.PFileInterface import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.api.Mime import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException @@ -53,7 +53,7 @@ class RequestBuilderHelper(private val options: NativeObject) { // require(method is String) { "Property method is required for header options" } when { !options.prop(Http.KEY_BODY).isJsNullish() -> { - request.method(method, parseBody()) + request.method(method, parseBody(scriptRuntime)) } !options.prop(Http.KEY_FILES).isJsNullish() -> { request.method(method, parseMultipart(scriptRuntime)) @@ -64,7 +64,7 @@ class RequestBuilderHelper(private val options: NativeObject) { } } - fun parseBody(): RequestBody = when (val body = options.prop(Http.KEY_BODY)) { + fun parseBody(scriptRuntime: ScriptRuntime): RequestBody = when (val body = options.prop(Http.KEY_BODY)) { is RequestBody -> body is String -> { val mediaType = options.prop(Http.KEY_CONTENT_TYPE).takeUnless { it.isJsNullish() } @@ -77,7 +77,7 @@ class RequestBuilderHelper(private val options: NativeObject) { } override fun writeTo(sink: BufferedSink) { - RhinoUtils.withRhinoContext { cx -> + RhinoUtils.withRhinoContext(scriptRuntime) { cx -> body.call(cx, body, body, arrayOf(sink)) } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/ResponseBodyNativeObject.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/ResponseBodyNativeObject.kt index 70367a49..ce883704 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/ResponseBodyNativeObject.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/http/ResponseBodyNativeObject.kt @@ -2,12 +2,12 @@ package org.autojs.autojs.runtime.api.augment.http import okhttp3.ResponseBody import org.autojs.autojs.annotation.RhinoStandardFunctionInterface -import org.autojs.autojs.rhino.extension.AnyExtensions.toRuntimePath +import org.autojs.autojs.pio.PFile import org.autojs.autojs.rhino.ArgumentGuards import org.autojs.autojs.rhino.ArgumentGuards.Companion.component1 import org.autojs.autojs.rhino.ArgumentGuards.Companion.component2 +import org.autojs.autojs.rhino.extension.AnyExtensions.toRuntimePath import org.autojs.autojs.rhino.extension.ScriptableExtensions.prop -import org.autojs.autojs.pio.PFile import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException import org.autojs.autojs.util.RhinoUtils @@ -56,7 +56,7 @@ class ResponseBodyNativeObject( return super.get(name, start) } return when (val o = mResBodyObject.prop(name)) { - is BaseFunction -> withRhinoContext { cx -> + is BaseFunction -> withRhinoContext(scriptRuntime) { cx -> BoundFunction(cx, mResBodyObject, o, mResBodyObject, arrayOf()) } else -> super.get(name, start) diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/Arrayx.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/Arrayx.kt index 47190b9f..7c32f9c2 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/Arrayx.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/jsox/Arrayx.kt @@ -1,6 +1,5 @@ package org.autojs.autojs.runtime.api.augment.jsox -import org.autojs.autojs.annotation.RhinoFunctionBody import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface import org.autojs.autojs.annotation.RhinoRuntimeFunctionWithThisObjInterface import org.autojs.autojs.rhino.ArgumentGuards @@ -12,6 +11,7 @@ import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.api.augment.Augmentable import org.autojs.autojs.runtime.api.augment.util.Util.ensureArrayTypeRhino import org.autojs.autojs.util.ArrayUtils.unshiftWith +import org.autojs.autojs.util.RhinoUtils.callFunction import org.autojs.autojs.util.RhinoUtils.coerceArray import org.autojs.autojs.util.RhinoUtils.coerceFunction import org.autojs.autojs.util.RhinoUtils.undefined @@ -158,18 +158,14 @@ class Arrayx(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRunti @JvmStatic @RhinoRuntimeFunctionInterface - fun distinctBy(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { - distinctByRhino(it) - } - - @JvmStatic - @RhinoFunctionBody - fun distinctByRhino(it: Array): NativeArray = withRhinoContext { cx -> - val (arr, selector) = it - coerceArray(arr).distinctBy { ele -> - require(arr is NativeArray) - coerceFunction(selector).call(cx, arr, arr, arrayOf(ele)) - }.toNativeArray() + fun distinctBy(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { argList -> + withRhinoContext(scriptRuntime) { cx -> + val (arrRaw, selector) = argList + val arr = coerceArray(arrRaw) + arr.distinctBy { ele -> + callFunction(scriptRuntime, coerceFunction(selector), arr, arr, arrayOf(ele)) + }.toNativeArray() + } } @JvmStatic @@ -202,148 +198,116 @@ class Arrayx(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRunti @JvmStatic @RhinoRuntimeFunctionInterface - fun sortBy(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { - val (arr, selector) = it - sortByRhino(arr, selector) - } - - @JvmStatic - @RhinoFunctionBody - fun sortByRhino(arr: Any?, selector: Any?): NativeArray = withRhinoContext { cx -> - require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortBy must be a JavaScript Array" } - require(selector is BaseFunction) { "Argument \"selector\" ${selector.jsBrief()} for Arrayx.sortBy must be a JavaScript Function" } - when { - arr.length < 2 -> arr - else -> { - // In-place sorting (zh-CN: 原地排序) - NativeArray.js_sort(cx, arr, arr, arrayOf(toCompareFunctionAsc(selector))) - arr + fun sortBy(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { argList -> + val (arr, selector) = argList + withRhinoContext(scriptRuntime) { cx -> + require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortBy must be a JavaScript Array" } + require(selector is BaseFunction) { "Argument \"selector\" ${selector.jsBrief()} for Arrayx.sortBy must be a JavaScript Function" } + when { + arr.length < 2 -> arr + else -> { + // In-place sorting (zh-CN: 原地排序) + NativeArray.js_sort(cx, arr, arr, arrayOf(toCompareFunctionAsc(selector))) + arr + } } } } @JvmStatic @RhinoRuntimeFunctionInterface - fun sortByDescending(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { - val (arr, selector) = it - sortByDescendingRhino(arr, selector) - } - - @JvmStatic - @RhinoFunctionBody - fun sortByDescendingRhino(arr: Any?, selector: Any?): NativeArray = withRhinoContext { cx -> - require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortByDescending must be a JavaScript Array" } - require(selector is BaseFunction) { "Argument \"selector\" ${selector.jsBrief()} for Arrayx.sortByDescending must be a JavaScript Function" } - when { - arr.length < 2 -> arr - else -> { - // In-place sorting (zh-CN: 原地排序) - NativeArray.js_sort(cx, arr, arr, arrayOf(toCompareFunctionDesc(selector))) - arr + fun sortByDescending(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { argList -> + val (arr, selector) = argList + withRhinoContext(scriptRuntime) { cx -> + require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortByDescending must be a JavaScript Array" } + require(selector is BaseFunction) { "Argument \"selector\" ${selector.jsBrief()} for Arrayx.sortByDescending must be a JavaScript Function" } + when { + arr.length < 2 -> arr + else -> { + // In-place sorting (zh-CN: 原地排序) + NativeArray.js_sort(cx, arr, arr, arrayOf(toCompareFunctionDesc(selector))) + arr + } } } } @JvmStatic @RhinoRuntimeFunctionInterface - fun sortDescending(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsOnlyOne(args) { - sortDescendingRhino(it) - } - - @JvmStatic - @RhinoFunctionBody - fun sortDescendingRhino(arr: Any?): NativeArray = withRhinoContext { cx -> - require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortDescending must be a JavaScript Array" } - NativeArray.js_sort(cx, arr, arr, arrayOf(toCompareFunctionDesc())) - arr + fun sortDescending(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsOnlyOne(args) { o -> + withRhinoContext(scriptRuntime) { cx -> + require(o is NativeArray) { "Argument \"arr\" ${o.jsBrief()} for Arrayx.sortDescending must be a JavaScript Array" } + NativeArray.js_sort(cx, o, o, arrayOf(toCompareFunctionDesc())) + o + } } @JvmStatic @RhinoRuntimeFunctionInterface - fun sorted(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsOnlyOne(args) { - sortedRhino(it) - } - - @JvmStatic - @RhinoFunctionBody - fun sortedRhino(it: Any?): NativeArray = withRhinoContext { cx -> - require(it is NativeArray) { "Argument \"arr\" ${it.jsBrief()} for Arrayx.sorted must be a JavaScript Array" } - val copied = it.slice(it.indices).toNativeArray() - NativeArray.js_sort(cx, it, copied, arrayOf(toCompareFunctionAsc())) - copied + fun sorted(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsOnlyOne(args) { o -> + withRhinoContext(scriptRuntime) { cx -> + require(o is NativeArray) { "Argument \"arr\" ${o.jsBrief()} for Arrayx.sorted must be a JavaScript Array" } + val copied = o.slice(o.indices).toNativeArray() + NativeArray.js_sort(cx, o, copied, arrayOf(toCompareFunctionAsc())) + copied + } } @JvmStatic @RhinoRuntimeFunctionInterface - fun sortedDescending(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsOnlyOne(args) { - sortedDescendingRhino(it) - } - - @JvmStatic - @RhinoFunctionBody - fun sortedDescendingRhino(it: Any?): NativeArray = withRhinoContext { cx -> - require(it is NativeArray) { "Argument \"arr\" ${it.jsBrief()} for Arrayx.sortedDescending must be a JavaScript Array" } - val copied = it.slice(it.indices).toNativeArray() - NativeArray.js_sort(cx, it, copied, arrayOf(toCompareFunctionDesc())) - copied + fun sortedDescending(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsOnlyOne(args) { o -> + withRhinoContext(scriptRuntime) { cx -> + require(o is NativeArray) { "Argument \"arr\" ${o.jsBrief()} for Arrayx.sortedDescending must be a JavaScript Array" } + val copied = o.slice(o.indices).toNativeArray() + NativeArray.js_sort(cx, o, copied, arrayOf(toCompareFunctionDesc())) + copied + } } @JvmStatic @RhinoRuntimeFunctionInterface - fun sortedBy(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { - val (arr, selector) = it - sortedByRhino(arr, selector) - } - - @JvmStatic - @RhinoFunctionBody - fun sortedByRhino(arr: Any?, selector: Any?): NativeArray = withRhinoContext { cx -> - require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortedBy must be a JavaScript Array" } - require(selector is BaseFunction) { "Argument \"selector\" ${selector.jsBrief()} for Arrayx.sortedBy must be a JavaScript Function" } - val copied = arr.slice(arr.indices).toNativeArray() - when { - arr.length < 2 -> copied - else -> { - NativeArray.js_sort(cx, arr, copied, arrayOf(toCompareFunctionAsc(selector))) - copied + fun sortedBy(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { argList -> + val (arr, selector) = argList + withRhinoContext(scriptRuntime) { cx -> + require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortedBy must be a JavaScript Array" } + require(selector is BaseFunction) { "Argument \"selector\" ${selector.jsBrief()} for Arrayx.sortedBy must be a JavaScript Function" } + val copied = arr.slice(arr.indices).toNativeArray() + when { + arr.length < 2 -> copied + else -> { + NativeArray.js_sort(cx, arr, copied, arrayOf(toCompareFunctionAsc(selector))) + copied + } } } } @JvmStatic @RhinoRuntimeFunctionInterface - fun sortedByDescending(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { - val (arr, selector) = it - sortedByDescendingRhino(arr, selector) - } - - @JvmStatic - @RhinoFunctionBody - fun sortedByDescendingRhino(arr: Any?, selector: Any?): NativeArray = withRhinoContext { cx -> - require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortedByDescending must be a JavaScript Array" } - require(selector is BaseFunction) { "Argument \"selector\" ${selector.jsBrief()} for Arrayx.sortedByDescending must be a JavaScript Function" } - val copied = arr.slice(arr.indices).toNativeArray() - when { - arr.length < 2 -> copied - else -> { - NativeArray.js_sort(cx, arr, copied, arrayOf(toCompareFunctionDesc(selector))) - copied + fun sortedByDescending(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsLength(args, 2) { argList -> + val (arr, selector) = argList + withRhinoContext(scriptRuntime) { cx -> + require(arr is NativeArray) { "Argument \"arr\" ${arr.jsBrief()} for Arrayx.sortedByDescending must be a JavaScript Array" } + require(selector is BaseFunction) { "Argument \"selector\" ${selector.jsBrief()} for Arrayx.sortedByDescending must be a JavaScript Function" } + val copied = arr.slice(arr.indices).toNativeArray() + when { + arr.length < 2 -> copied + else -> { + NativeArray.js_sort(cx, arr, copied, arrayOf(toCompareFunctionDesc(selector))) + copied + } } } } @JvmStatic @RhinoRuntimeFunctionInterface - fun shuffle(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsOnlyOne(args) { - shuffleRhino(it) - } - - @JvmStatic - @RhinoFunctionBody - fun shuffleRhino(it: Any?): NativeArray = withRhinoContext { cx -> - require(it is NativeArray) { "Argument \"arr\" ${it.jsBrief()} for Arrayx.shuffle must be a JavaScript Array" } - NativeArray.js_sort(cx, it, it, arrayOf(toCompareFunctionRandom())) - it + fun shuffle(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsOnlyOne(args) { o -> + withRhinoContext(scriptRuntime) { cx -> + require(o is NativeArray) { "Argument \"arr\" ${o.jsBrief()} for Arrayx.shuffle must be a JavaScript Array" } + NativeArray.js_sort(cx, o, o, arrayOf(toCompareFunctionRandom())) + o + } } private fun toCompareFunctionAsc(selector: BaseFunction) = object : BaseFunction() { diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/selector/Selector.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/selector/Selector.kt index cb6a587e..327c3ebe 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/selector/Selector.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/selector/Selector.kt @@ -56,7 +56,7 @@ class Selector(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRun // @Hint by SuperMonster003 on Jul 25, 2024. // ! For scope binding. // ! zh-CN: 用于绑定作用域. - withRhinoContext { cx -> + withRhinoContext(scriptRuntime) { cx -> global.defineProp(methodName, newBaseFunction(null, { argList -> val methodKey = coerceString(argList[0]) newBaseFunction(methodKey, { arguments -> 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 c6d209b4..3c5a97a2 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 @@ -232,7 +232,7 @@ class UI(private val scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRunt val widgets = scriptRuntime.ui.widgets if (widgets.contains(viewName)) { val ctor = widgets.prop(viewName) as BaseFunction - val widget = withRhinoContext { cx -> + val widget = withRhinoContext(scriptRuntime) { cx -> ctor.construct(cx, scriptRuntime.topLevelScope, arrayOf()) } as ScriptableObject val f = widget.prop("renderInternal") as BaseFunction @@ -881,7 +881,7 @@ class UI(private val scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRunt } } }, NOT_CONSTRUCTABLE) - withRhinoContext { cx -> + withRhinoContext(scriptRuntime) { cx -> arrayObserveFunc.call(cx, global, globalArray, arrayOf(dataSource, handlerFunc)) } } @@ -899,7 +899,7 @@ class UI(private val scriptRuntime: ScriptRuntime) : AugmentableProxy(scriptRunt isAutoJsUiMode -> { callFunction(scriptRuntime, action, scriptRuntime.topLevelScope, arrayOf()) } - else -> withRhinoContext { cx -> + else -> withRhinoContext(scriptRuntime) { cx -> val scope = scriptRuntime.topLevelScope val exitIfErrorFunc = scope.prop("__exitIfError__") as BaseFunction exitIfErrorFunc.call(cx, scope, scope, arrayOf(newBaseFunction("action", { diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/web/Web.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/web/Web.kt index a44eab7d..00b05c14 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/web/Web.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/web/Web.kt @@ -35,7 +35,7 @@ class Web(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { @JvmStatic @RhinoFunctionBody - fun newInjectableWebViewRhinoWithRuntime(scriptRuntime: ScriptRuntime, vararg args: Any?): InjectableWebView = withRhinoContext { cx -> + fun newInjectableWebViewRhinoWithRuntime(scriptRuntime: ScriptRuntime, vararg args: Any?): InjectableWebView = withRhinoContext(scriptRuntime) { cx -> when (args.size) { 2 -> { val (androidContext, url) = args @@ -60,7 +60,7 @@ class Web(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { @JvmStatic @RhinoRuntimeFunctionInterface fun newInjectableWebClient(scriptRuntime: ScriptRuntime, args: Array): InjectableWebClient = ensureArgumentsIsEmpty(args) { - withRhinoContext { cx -> InjectableWebClient(cx, scriptRuntime.topLevelScope) } + withRhinoContext(scriptRuntime) { cx -> InjectableWebClient(cx, scriptRuntime.topLevelScope) } } @JvmStatic 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 b337a762..c2bf5a5b 100644 --- a/app/src/main/java/org/autojs/autojs/util/RhinoUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/RhinoUtils.kt @@ -9,6 +9,7 @@ import android.os.Parcelable import org.autojs.autojs.AutoJs import org.autojs.autojs.annotation.RhinoStandardFunctionInterface import org.autojs.autojs.core.automator.UiObjectCollection +import org.autojs.autojs.engine.RhinoJavaScriptEngine import org.autojs.autojs.rhino.TopLevelScope import org.autojs.autojs.rhino.extension.AnyExtensions.isJsNullish import org.autojs.autojs.rhino.extension.AnyExtensions.jsBrief @@ -95,13 +96,28 @@ object RhinoUtils { private val TAG = RhinoUtils::class.java.simpleName + private val STANDARD_OBJECTS_KEY = Any() + @JvmStatic val UNDEFINED = Undefined.instance as Undefined + @JvmStatic + fun Context.getOrCreateStandardObjects(): ScriptableObject { + // Cache standard objects per Context to avoid repeated initStandardObjects(). + // zh-CN: 按 Context 缓存标准对象, 避免重复调用 initStandardObjects(). + val cached = this.getThreadLocal(STANDARD_OBJECTS_KEY) as? ScriptableObject + if (cached != null) return cached + return this.initStandardObjects().also { created -> + this.putThreadLocal(STANDARD_OBJECTS_KEY, created) + } + } + @JvmStatic val standardObjects: ScriptableObject by lazy { + // Create a global singleton standard objects as a low-fidelity fallback. + // zh-CN: 创建全局单例标准对象, 用作低保真兜底. try { - Context.enter().initStandardObjects() + Context.enter().getOrCreateStandardObjects() } finally { Context.exit() } @@ -125,33 +141,25 @@ object RhinoUtils { } @JvmStatic - fun callGlobalFunction(name: String, paramsToFunction: Array): Any? { - return callGlobalFunction(null, name, paramsToFunction) - } + fun callToStringFunction(o: Scriptable): String = + Context.toString(callFunction(o, "toString", arrayOf())) @JvmStatic - fun callGlobalFunction(scriptRuntime: ScriptRuntime?, name: String, paramsToFunction: Array) = withRhinoContext { cx -> - val topLevel = ImporterTopLevel(cx) - callFunction(scriptRuntime, topLevel, name, paramsToFunction) - } - - @JvmStatic - fun callToStringFunction(o: Scriptable): String { - return callToStringFunction(null, o) - } - - @JvmStatic - fun callToStringFunction(scriptRuntime: ScriptRuntime?, o: Scriptable): String = Context.toString(callFunction(scriptRuntime, o, "toString", arrayOf())) + fun callToStringFunction(scriptRuntime: ScriptRuntime, o: Scriptable): String = + Context.toString(callFunction(scriptRuntime, o, "toString", arrayOf())) @JvmStatic @Throws(NoSuchMethodException::class, InvocationTargetException::class, IllegalAccessException::class) fun callFunction(obj: Scriptable, name: String, paramsToFunction: Array): Any? { - return callFunction(null, obj, name, paramsToFunction) + 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 instead of ${property.jsBrief()}") + return callFunction(property, obj, obj, paramsToFunction) } @JvmStatic @Throws(NoSuchMethodException::class, InvocationTargetException::class, IllegalAccessException::class) - fun callFunction(scriptRuntime: ScriptRuntime?, obj: Scriptable, name: String, paramsToFunction: Array): Any? { + 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 instead of ${property.jsBrief()}") @@ -160,38 +168,40 @@ object RhinoUtils { @JvmStatic @Throws(NoSuchMethodException::class, InvocationTargetException::class, IllegalAccessException::class) - fun callFunction(func: BaseFunction, paramsToFunction: Array): Any? { - return callFunction(null, func, paramsToFunction) - } + fun callFunction(func: BaseFunction, paramsToFunction: Array): Any? = + callFunction(func, null, paramsToFunction) @JvmStatic @Throws(NoSuchMethodException::class, InvocationTargetException::class, IllegalAccessException::class) - fun callFunction(scriptRuntime: ScriptRuntime?, func: BaseFunction, paramsToFunction: Array): Any? { - return callFunction(scriptRuntime, func, null, paramsToFunction) - } + fun callFunction(scriptRuntime: ScriptRuntime, func: BaseFunction, paramsToFunction: Array): Any? = + callFunction(scriptRuntime, func, null, paramsToFunction) @JvmStatic @Throws(NoSuchMethodException::class, InvocationTargetException::class, IllegalAccessException::class) - fun callFunction(func: BaseFunction, scope: Scriptable?, args: Array): Any? { - return callFunction(null, func, scope, args) - } + fun callFunction(func: BaseFunction, scope: Scriptable?, args: Array): Any? = + callFunction(func, scope, scope, args) @JvmStatic @Throws(NoSuchMethodException::class, InvocationTargetException::class, IllegalAccessException::class) - fun callFunction(scriptRuntime: ScriptRuntime?, func: BaseFunction, scope: Scriptable?, args: Array): Any? { - return callFunction(scriptRuntime, func, scope, scope, args) - } + fun callFunction(scriptRuntime: ScriptRuntime, func: BaseFunction, scope: Scriptable?, args: Array): Any? = + callFunction(scriptRuntime, func, scope, scope, args) @JvmStatic @Throws(NoSuchMethodException::class, InvocationTargetException::class, IllegalAccessException::class) - fun callFunction(func: BaseFunction, scope: Scriptable?, thisObj: Scriptable?, args: Array): Any? { - return callFunction(null, func, scope, thisObj, args) - } + fun callFunction(func: BaseFunction, scope: Scriptable?, thisObj: Scriptable?, args: Array): Any? = + callFunction(null, func, scope, thisObj, args) @JvmStatic - fun callFunction(scriptRuntime: ScriptRuntime?, func: BaseFunction, scope: Scriptable?, thisObj: Scriptable?, args: Array): Any? = withRhinoContext { cx -> + fun callFunction(scriptRuntime: ScriptRuntime?, func: BaseFunction, scope: Scriptable?, thisObj: Scriptable?, args: Array): Any? = withRhinoContext(scriptRuntime) { cx -> try { - val niceScope = scope ?: cx.initStandardObjects() + // Prefer an existing scope to avoid repeatedly creating standard objects. + // zh-CN: 优先使用已有的作用域, 避免反复创建标准对象. + val niceScope = when { + scope != null -> scope + func.parentScope != null -> func.parentScope + scriptRuntime != null -> scriptRuntime.topLevelScope + else -> ImporterTopLevel(cx) + } when { RhinoScriptRuntime.hasTopCall(cx) -> func.call(cx, niceScope, thisObj, args) else -> RhinoScriptRuntime.doTopCall(func, cx, niceScope, thisObj, args, false) @@ -369,28 +379,23 @@ object RhinoUtils { } @JvmStatic - fun encodeURI(str: String): String = encodeURI(null, str) + fun encodeURI(scriptRuntime: ScriptRuntime, str: String): String = + Context.toString(callGlobalFunction(scriptRuntime, "encodeURI", arrayOf(str))) @JvmStatic - fun encodeURI(scriptRuntime: ScriptRuntime?, str: String): String = Context.toString(callGlobalFunction(scriptRuntime, "encodeURI", arrayOf(str))) + fun parseInt(scriptRuntime: ScriptRuntime, str: String?): Double = + Context.toNumber(callGlobalFunction(scriptRuntime, "parseInt", arrayOf(str))) @JvmStatic - fun parseInt(str: String?): Double = parseInt(null, str) + fun parseInt(scriptRuntime: ScriptRuntime, str: String?, radix: Number): Double = + Context.toNumber(callGlobalFunction(scriptRuntime, "parseInt", arrayOf(str, radix.toDouble()))) @JvmStatic - fun parseInt(scriptRuntime: ScriptRuntime?, str: String?): Double = Context.toNumber(callGlobalFunction(scriptRuntime, "parseInt", arrayOf(str))) + fun parseFloat(scriptRuntime: ScriptRuntime, str: String?): Double = + Context.toNumber(callGlobalFunction(scriptRuntime, "parseFloat", arrayOf(str))) - @JvmStatic - fun parseInt(str: String?, radix: Number): Double = parseInt(null, str, radix) - - @JvmStatic - fun parseInt(scriptRuntime: ScriptRuntime?, str: String?, radix: Number): Double = Context.toNumber(callGlobalFunction(scriptRuntime, "parseInt", arrayOf(str, radix.toDouble()))) - - @JvmStatic - fun parseFloat(str: String?): Double = parseFloat(null, str) - - @JvmStatic - fun parseFloat(scriptRuntime: ScriptRuntime?, str: String?): Double = Context.toNumber(callGlobalFunction(scriptRuntime, "parseFloat", arrayOf(str))) + private fun callGlobalFunction(scriptRuntime: ScriptRuntime, name: String, paramsToFunction: Array) = + callFunction(scriptRuntime, scriptRuntime.topLevelScope, name, paramsToFunction) @JvmStatic fun ensureNativeArrayLength(o: NativeArray, length: Int, desc: String) { @@ -417,7 +422,8 @@ object RhinoUtils { @JvmStatic fun runJavaScript(code: String): Any? = withRhinoContext { cx -> - cx.evaluateString(standardObjects, code, null, 1, null) + val scope = cx.getOrCreateStandardObjects() + cx.evaluateString(scope, code, null, 1, null) } @JvmStatic @@ -466,13 +472,7 @@ object RhinoUtils { @JvmStatic @JvmOverloads - fun coerceRunnable(o: Any?, def: Runnable? = null): Runnable { - return coerceRunnable(null, o, def) - } - - @JvmStatic - @JvmOverloads - fun coerceRunnable(scriptRuntime: ScriptRuntime?, o: Any?, def: Runnable? = null): Runnable = when { + fun coerceRunnable(scriptRuntime: ScriptRuntime, o: Any?, def: Runnable? = null): Runnable = when { !o.isJsNullish() -> when (o) { is BaseFunction -> Runnable { callFunction(scriptRuntime, o, arrayOf()) } is Runnable -> o @@ -789,16 +789,32 @@ object RhinoUtils { RhinoScriptRuntime.evalSpecial(cx, global, global, arrayOf(s), "eval code", 1) } - fun withRhinoContext(function: (context: Context) -> R): R { + @JvmStatic + @JvmOverloads + fun withRhinoContext(scriptRuntime: ScriptRuntime? = null, function: (context: Context) -> R): R { var cxRhino: Context? = null return try { val cx = Context.getCurrentContext() - ?: Context.enter().also { - it.initStandardObjects() - cxRhino = it - } - cx.languageVersion = Context.VERSION_ES6 - cx.isInterpretedMode = true + ?: when (scriptRuntime) { + null -> { + // This fallback Context.enter() does NOT guarantee WrapFactory from RhinoJavaScriptEngine. + // zh-CN: 这个兜底的 Context.enter() 无法保证使用 RhinoJavaScriptEngine 的 WrapFactory. + Context.enter() + } + else -> { + // Enter Rhino Context via engine's ContextFactory to keep WrapFactory and AutoJsContext bindings effective. + // zh-CN: 通过引擎的 ContextFactory 进入 Rhino Context, 以保持 WrapFactory 和 AutoJsContext 绑定生效. + val engine = scriptRuntime.engines.myEngine() + require(engine is RhinoJavaScriptEngine) { + "Current engine ${engine.javaClass.name} is not a RhinoJavaScriptEngine" + } + engine.enterContext() + } + }.apply { + languageVersion = Context.VERSION_ES6 + isInterpretedMode = true + }.also { cxRhino = it } + function.invoke(cx) } finally { cxRhino?.let { Context.exit() } @@ -870,14 +886,6 @@ object RhinoUtils { @JvmStatic fun initNativeObjectPrototype(o: NativeObject): NativeObject { - // val cx = ContextWrapper.getCurrentContext() - // try { - // val tmpScope: Scriptable = cx.initStandardObjects() - // NativeObject.init(tmpScope, false) - // o.prototype = tmpScope.get("Object", tmpScope) as Scriptable - // } finally { - // Context.exit() - // } return o.apply { prototype = objectPrototype } } diff --git a/version.properties b/version.properties index e6caa69e..9dcac162 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Fri Jan 30 20:56:33 CST 2026 -BUILD_TIME=1769777793096 +#Sat Jan 31 15:04:03 CST 2026 +BUILD_TIME=1769843043403 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=3673 -VERSION_NAME=6.7.0 Alpha18 +VERSION_BUILD=3678 +VERSION_NAME=6.7.0 Alpha19 VSCODE_EXT_REQUIRED_VERSION=1.0.13