diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 0331588d..9df80299 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -3,7 +3,8 @@ "v6.6.3": { "released_date": "2025/04/19", "feature": [ - "timers.keepAlive 方法 (已全局化), 用于保持脚本活跃状态" + "timers.keepAlive 方法 (已全局化), 用于保持脚本活跃状态", + "engines.on('start/stop/error', callback) 等事件监听方法, 用于监听脚本引擎全局事件" ], "fix": [ "主页文档标签显示在线文档时部分内容被系统导航栏遮挡的问题", diff --git a/app/src/main/java/org/autojs/autojs/engine/ScriptEngineService.java b/app/src/main/java/org/autojs/autojs/engine/ScriptEngineService.java index f5e40103..844dd001 100644 --- a/app/src/main/java/org/autojs/autojs/engine/ScriptEngineService.java +++ b/app/src/main/java/org/autojs/autojs/engine/ScriptEngineService.java @@ -217,7 +217,9 @@ public class ScriptEngineService { } public Set> getEngines() { - return mScriptEngineManager.getEngines(); + synchronized (mScriptEngineManager) { + return new LinkedHashSet<>(mScriptEngineManager.getEngines()); + } } public Collection getScriptExecutions() { diff --git a/app/src/main/java/org/autojs/autojs/execution/ScriptExecutionGlobalListener.java b/app/src/main/java/org/autojs/autojs/execution/ScriptExecutionGlobalListener.java index 907d33db..81f8604d 100644 --- a/app/src/main/java/org/autojs/autojs/execution/ScriptExecutionGlobalListener.java +++ b/app/src/main/java/org/autojs/autojs/execution/ScriptExecutionGlobalListener.java @@ -1,23 +1,35 @@ package org.autojs.autojs.execution; -import static org.autojs.autojs.util.StringUtils.str; - -import android.annotation.SuppressLint; - import org.autojs.autojs.AutoJs; import org.autojs.autojs.core.pref.Language; +import org.autojs.autojs.engine.JavaScriptEngine; +import org.autojs.autojs.engine.ScriptEngine; +import org.autojs.autojs.runtime.ScriptRuntime; import org.autojs.autojs.runtime.api.Console; +import org.autojs.autojs.runtime.api.augment.engines.Engines; +import org.autojs.autojs.script.ScriptSource; import org.autojs.autojs6.R; +import java.util.List; +import java.util.stream.Collectors; + +import static org.autojs.autojs.util.StringUtils.str; + /** * Created by Stardust on May 3, 2017. + * Modified by SuperMonster003 as of Jan 1, 2022. */ public class ScriptExecutionGlobalListener implements ScriptExecutionListener { + private static final String ENGINE_TAG_START_TIME = "org.autojs.autojs.autojs.Goodbye, World"; @Override public void onStart(ScriptExecution execution) { - execution.getEngine().setTag(ENGINE_TAG_START_TIME, System.currentTimeMillis()); + ScriptEngine engine = execution.getEngine(); + + emitEngineEvent("start", engine); + + engine.setTag(ENGINE_TAG_START_TIME, System.currentTimeMillis()); } @Override @@ -25,29 +37,50 @@ public class ScriptExecutionGlobalListener implements ScriptExecutionListener { onFinish(execution); } - @SuppressLint("DefaultLocale") private void onFinish(ScriptExecution execution) { - Long millis = (Long) execution.getEngine().getTag(ENGINE_TAG_START_TIME); - if (millis != null) { - printSeconds(execution, millis); + ScriptEngine engine = execution.getEngine(); + + emitEngineEvent("finish", engine); + emitEngineEvent("exit", engine); + emitEngineEvent("stop", engine); + + Long startTime = (Long) engine.getTag(ENGINE_TAG_START_TIME); + if (startTime != null) { + printSeconds(execution, startTime); } } - private void printSeconds(ScriptExecution execution, Long millis) { - double seconds = (System.currentTimeMillis() - millis) / 1000.0; + private void printSeconds(ScriptExecution execution, Long startTime) { + double seconds = (System.currentTimeMillis() - startTime) / 1000.0; String secondsString = String.format(Language.getPrefLanguage().getLocale(), "%.3f", seconds).stripTrailing(); - printSeconds(execution, secondsString); - } - - private void printSeconds(ScriptExecution execution, String seconds) { Console console = AutoJs.getInstance().getScriptEngineService().getGlobalConsole(); String path = execution.getSource().getElegantPath(); - console.verbose(str(R.string.text_execution_finished, path, seconds)); + console.verbose(str(R.string.text_execution_finished, path, secondsString)); } @Override public void onException(ScriptExecution execution, Throwable e) { + ScriptEngine engine = execution.getEngine(); + + emitEngineEvent("exception", engine, e); + emitEngineEvent("error", engine, e); + onFinish(execution); } -} + private void emitEngineEvent(String eventName, ScriptEngine engine, Object... args) { + List jsEngines = AutoJs.getInstance() + .getScriptEngineService() + .getEngines() + .stream() + .filter(JavaScriptEngine.class::isInstance) + .map(JavaScriptEngine.class::cast) + .collect(Collectors.toList()); + + for (JavaScriptEngine jsEngine : jsEngines) { + ScriptRuntime runtime = jsEngine.getRuntime(); + Engines.emit(runtime, eventName, engine, args); + } + } + +} \ No newline at end of file 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 6de725f5..ea681315 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 @@ -29,7 +29,6 @@ import org.mozilla.javascript.ScriptableObject.DONTENUM import org.mozilla.javascript.ScriptableObject.PERMANENT import org.mozilla.javascript.ScriptableObject.READONLY import org.mozilla.javascript.ScriptableObject.UNINITIALIZED_CONST -import org.mozilla.javascript.WrappedException import java.lang.reflect.InvocationTargetException import java.util.function.Consumer import java.util.function.Supplier @@ -158,7 +157,7 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F val message = e.message?.let { globalContext.getString(R.string.error_failed_to_instantiate_with_cause, key, it) } ?: globalContext.getString(R.string.error_failed_to_instantiate, key) - throw RuntimeException(message, e) + throw WrappedRuntimeException(message, e) } } @@ -429,7 +428,7 @@ abstract class Augmentable(private val scriptRuntime: ScriptRuntime? = null) : F else -> t } if (ScriptInterruptedException.causedByInterrupt(e)) { - throw WrappedException(e) + throw e } val funcNameSuffix = if (funcName != funcNameAlias) " (${globalContext.getString(R.string.text_alias)}: $funcNameAlias)" else "" val methodDescription = "$key.$funcName$funcNameSuffix" diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/engines/Engines.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/engines/Engines.kt index 7821a59b..4cddc9f9 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/engines/Engines.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/engines/Engines.kt @@ -9,21 +9,25 @@ import org.autojs.autojs.extension.AnyExtensions.isJsNullish import org.autojs.autojs.extension.AnyExtensions.jsBrief import org.autojs.autojs.extension.AnyExtensions.toRuntimePath import org.autojs.autojs.extension.FlexibleArray +import org.autojs.autojs.extension.ScriptableExtensions.prop import org.autojs.autojs.extension.ScriptableObjectExtensions.inquire import org.autojs.autojs.runtime.ScriptRuntime +import org.autojs.autojs.runtime.api.augment.AsEmitter import org.autojs.autojs.runtime.api.augment.Augmentable import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException import org.autojs.autojs.script.ScriptSource +import org.autojs.autojs.util.RhinoUtils.callFunction import org.autojs.autojs.util.RhinoUtils.coerceIntNumber import org.autojs.autojs.util.RhinoUtils.coerceLongNumber import org.autojs.autojs.util.RhinoUtils.coerceString import org.autojs.autojs.util.RhinoUtils.newNativeObject +import org.mozilla.javascript.BaseFunction import org.mozilla.javascript.NativeArray import org.mozilla.javascript.NativeObject import org.mozilla.javascript.ScriptableObject @Suppress("unused") -class Engines(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { +class Engines(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime), AsEmitter { override val selfAssignmentFunctions = listOf( ::all.name, @@ -56,6 +60,13 @@ class Engines(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRunt companion object : FlexibleArray() { + @JvmStatic + fun emit(scriptRuntime: ScriptRuntime, eventName: String, vararg args: Any?) { + val engines = scriptRuntime.topLevelScope.prop("engines") as? ScriptableObject ?: return + val emitFunc = engines.prop("emit") as BaseFunction + callFunction(scriptRuntime, emitFunc, arrayOf(eventName, *args)) + } + @JvmStatic @RhinoRuntimeFunctionInterface fun all(scriptRuntime: ScriptRuntime, args: Array): NativeArray = ensureArgumentsIsEmpty(args) { 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 b0fd2593..550f0fd5 100644 --- a/app/src/main/java/org/autojs/autojs/util/RhinoUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/RhinoUtils.kt @@ -17,6 +17,7 @@ import org.autojs.autojs.extension.ScriptableExtensions.prop import org.autojs.autojs.rhino.TopLevelScope import org.autojs.autojs.runtime.ScriptRuntime import org.autojs.autojs.runtime.exception.ScriptInterruptedException +import org.autojs.autojs.runtime.exception.WrappedRuntimeException import org.autojs.autojs6.BuildConfig import org.mozilla.javascript.AbstractEcmaObjectOperations import org.mozilla.javascript.BaseFunction @@ -176,9 +177,9 @@ object RhinoUtils { e.printStackTrace() when { isMainThread() -> { - scriptRuntime?.exit(e) ?: throw RuntimeException(e) + scriptRuntime?.exit(e) ?: throw WrappedRuntimeException(e) } - else -> throw RuntimeException(e) + else -> throw WrappedRuntimeException(e) } } }