如何重启autojs6后执行某个脚本?
我发现,当jvm内存占用过高时,autojs6会奔溃。 于是我打算写一个逻辑在代码里:监控jvm内存,当内存快满的时候,重启autojs6,达到释放内存的目的,然后重新执行脚本。
我发现,通过定时任务,广播设置:autojs6启动时,能够达到启动执行脚本的目的。 but,重启要点击autojs6左上角菜单展开的下方“重启”按钮才行。
我自己写的重启代码,成功重启autojs6,但无法触发定时任务“启动时”。
如果通过无障碍服务布局分析,一步步打开菜单去点击“重启”按钮,貌似也可以,但属于最差方案。
方案一:脚本通过命令执行重启和执行脚本,全程无感。 方案二:无感重启+autojs6定时任务“启动时”配合。
方案三:布局分析点击“重启”按钮+autojs6定时任务“启动时”配合。
现在只能做到方案三。
方案二也难以实现,不知道我的重启代码问题在哪儿。 方案一也搞不定
未来 AutoJs6 会支持 autojs.restart / autojs.exit 方法用于重启或退出应用:
autojs.restart(); // 重启应用
autojs.restart('test-123'); // 重启应用并在启动时自动执行工作目录下的 test-123.js 脚本
autojs.restart(['a', 'b', 'c']); // 重启应用并在启动时自动依次执行工作目录下的 a.js, b.js, c.js 脚本. 但注意 b.js 并不会等待 a.js 执行完毕后才会执行, 除非脚本中使用 engines 模块做了监测
autojs.restart('@'); // 重启应用并在启动时自动执行当前脚本, 即执行了 `autojs.restart('@');` 代码的脚本自身
如果需要的话, 我可以提供上述代码的内部具体实现.
如果可以的话, 请提供你重启代码的关键代码, 我可以帮你分析问题出现的原因.
AutoJs6下一个版本有发布计划吗?
function restartAndRunScript(scriptPath) {
try {
let packageName = "org.autojs.autojs6";
let activityManager = context.getSystemService(context.ACTIVITY_SERVICE);
console.log("准备重启 Auto.js 并执行脚本:", scriptPath);
// 1. 先强制停止应用
activityManager.killBackgroundProcesses(packageName);
console.log("已强制停止 Auto.js");
sleep(2000);
// 2. 通过 PackageManager 获取启动 Intent 并传递脚本路径
let pm = context.getPackageManager();
let intent = pm.getLaunchIntentForPackage(packageName);
if (intent) {
// 设置 Intent 标志
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
// 传递脚本路径参数
intent.putExtra("auto_run_script", scriptPath);
intent.putExtra("timestamp", Date.now());
// 启动应用
context.startActivity(intent);
console.log("已发送重启命令,脚本路径:", scriptPath);
// 3. 退出当前脚本
setTimeout(() => engines.myEngine().forceStop(), 500);
} else {
throw new Error("无法获取启动 Intent");
}
} catch (e) {
console.error("系统服务方式失败:", e);
// 回退到 Shell 命令方式
}
}
// 使用示例
let targetScript = "/storage/emulated/0/Download/AJS6脚本/小社/【小社脚本】启动程序.js";
restartAndRunScript(targetScript);
这段代码只有重启功能,重启后无法执行脚本。 也无法触发AutoJS6自带的定时任务→广播→AutoJS6 启动时
我想要内部实现,JS版的,可以吗?
function restartAndRunScript(scriptPath) {
try {
let packageName = "org.autojs.autojs6";
let activityManager = context.getSystemService(context.ACTIVITY_SERVICE);
console.log("准备重启 Auto.js 并执行脚本:", scriptPath);
// 1. 先强制停止应用
activityManager.killBackgroundProcesses(packageName);
console.log("已强制停止 Auto.js");
sleep(2000);
// 2. 通过 PackageManager 获取启动 Intent 并传递脚本路径
let pm = context.getPackageManager();
let intent = pm.getLaunchIntentForPackage(packageName);
if (intent) {
// 设置 Intent 标志
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
// 传递脚本路径参数
intent.putExtra("auto_run_script", scriptPath);
intent.putExtra("timestamp", Date.now());
// 启动应用
context.startActivity(intent);
console.log("已发送重启命令,脚本路径:", scriptPath);
// 3. 退出当前脚本
setTimeout(() => engines.myEngine().forceStop(), 500);
} else {
throw new Error("无法获取启动 Intent");
}
} catch (e) {
console.error("系统服务方式失败:", e);
// 回退到 Shell 命令方式
}
}
// 使用示例
let targetScript = "/storage/emulated/0/Download/AJS6脚本/小社/【小社脚本】启动程序.js";
restartAndRunScript(targetScript);
提供的上述代码似乎只是停止了后台进程, 没有杀掉 AutoJs6 前台进程, 因此不是真正意义上的 "退出" 应用.
另外 startActivity 如果希望清空包含当前任务的任务栈的话, 应该加上 CLEAR_TASK 标志位.
而 engines.myEngine().forceStop() 只是停止了脚本引擎, 并未让 AutoJs6 进程退出.
我想要内部实现,JS版的,可以吗?
可以的.
以下提供两个脚本, 一个包含 restart/exit 核心功能 (你可以作为模块导出相关函数), 另一个暂时将其命名为 'run-after-restart-if-needed.js', 它作为检测 restart 方法写入 storages 中需要自启的脚本名称列表, 你可以将它设置为一个定时任务 (AutoJs6 启动时).
const AlarmManager = android.app.AlarmManager;
const SystemClock = android.os.SystemClock;
const ActivityManager = android.app.ActivityManager;
const UNIQUE_REQUEST_CODE = 1001;
const STORAGE_NAME = 'autojs6_restart_helper';
const STORAGE_KEY_SCRIPTS_AFTER_RESTART = 'scripts_after_app_restart';
function getLaunchIntent() {
let pkgName = context.getPackageName();
let pm = context.getPackageManager();
let launchIntent = pm.getLaunchIntentForPackage(pkgName);
if (launchIntent == null) return null;
launchIntent.setAction(pkgName + '.action.RESTART_UNIQUE');
launchIntent.addFlags(
Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TOP
| Intent.FLAG_ACTIVITY_CLEAR_TASK,
);
return launchIntent;
}
function finishAllAppTasksSafely() {
try {
let am = context.getSystemService(Context.ACTIVITY_SERVICE);
let appTasks = am.getAppTasks();
if (appTasks != null) {
let it = appTasks.iterator();
while (it.hasNext()) {
try {
let task = it.next();
task.finishAndRemoveTask();
} catch (e) {
/* Ignored. */
}
}
}
} catch (e) {
/* Ignored. */
}
}
function tryCleanupNative() {
tryInvoke(org.autojs.autojs.ui.floating.FloatyWindowManger, 'hideCircularMenuAndSaveState');
tryInvoke(org.autojs.autojs.ui.enhancedfloaty.FloatyService, 'stopService');
tryInvoke(org.autojs.autojs.core.image.capture.ScreenCapturerForegroundService, 'stopService');
tryInvoke(org.autojs.autojs.AutoJs.getInstance().getScriptEngineService(), 'stopAll')
tryInvoke(org.autojs.autojs.AutoJs.getInstance(), 'clear')
tryInvoke(org.autojs.autojs.App.getApp(), 'clear')
tryInvoke(com.huaban.analysis.jieba.WordDictionaryDatabase.getInstance(context), 'close');
tryInvoke(com.huaban.analysis.jieba.CharsDictionaryDatabase.getInstance(context), 'close');
tryInvoke(com.huaban.analysis.jieba.PhrasesDictionaryDatabase.getInstance(context), 'close');
tryInvoke(org.autojs.autojs.runtime.api.WrappedShizuku, 'onDestroy');
}
function tryInvoke(object, methodName, argList) {
try {
if (typeof object[methodName] === 'function') {
object[methodName].apply(object, argList || []);
}
} catch (e) {
/* Ignored. */
}
}
function restart() {
let launchIntent = getLaunchIntent();
if (!launchIntent) {
throw new Error('Failed to create launch intent for AutoJs6');
}
let args = Array.from(arguments);
let storage = storages.create(STORAGE_NAME);
let scriptsToRunAfterRestart = ( /* @IIFE */ () => {
if (![0, 1].includes(args.length)) {
throw new Error(`Arguments length (${args.length}) is invalid for restart`);
}
let scriptsToRun;
if (args.length > 0) {
if (Array.isArray(args[0])) {
scriptsToRun = args[0];
} else {
let s = args[0];
if (typeof s !== 'string') {
throw new Error(`Script ${s} is not a valid name for restart`);
}
scriptsToRun = [s];
}
}
let scriptToRunFromSto = storage.get(STORAGE_KEY_SCRIPTS_AFTER_RESTART, null);
if (Array.isArray(scriptToRunFromSto)) {
scriptsToRun = scriptToRunFromSto.concat(scriptsToRun);
}
return scriptsToRun || [];
})();
let list = scriptsToRunAfterRestart
.map(function (s) {
return (s || '').trim();
})
.filter(function (s) {
return s.length > 0;
});
if (list.length > 0) {
storage.put(STORAGE_KEY_SCRIPTS_AFTER_RESTART, list.join('\n'));
}
let delayMs = 300;
let triggerAtMillis = SystemClock.elapsedRealtime() + delayMs;
try {
let pendingIntent = PendingIntent.getActivity(
context,
UNIQUE_REQUEST_CODE,
launchIntent,
PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_IMMUTABLE,
);
let am = context.getSystemService(Context.ALARM_SERVICE);
am.cancel(pendingIntent);
am.setExactAndAllowWhileIdle(
AlarmManager.ELAPSED_REALTIME,
triggerAtMillis,
pendingIntent,
);
} catch (e) {
/* Ignored. */
}
/* 延时以便 storages 模块完成写入. */
setTimeout(exit, 500);
}
function exit() {
tryCleanupNative();
finishAllAppTasksSafely();
java.lang.System.exit(0);
}
restart('test-123');
上述示例代码以 'test-123' 为例, 将其作为重启后自动执行的脚本, 如需多个, 可传入数组. 需要注意, 自动执行脚本需要监测, 将下面的脚本加入定时任务, 可以实现监测功能:
const STORAGE_NAME = 'autojs6_restart_helper';
const STORAGE_KEY_SCRIPTS_AFTER_RESTART = 'scripts_after_app_restart';
function runAfterRestartIfNeeded() {
let storage = storages.create(STORAGE_NAME);
let value = storage.get(STORAGE_KEY_SCRIPTS_AFTER_RESTART, null);
if (value == null) return;
let scripts = String(value)
.split('\n')
.map((s) => (s || '').trim())
.filter((s) => s.length > 0);
let workingDir = files.cwd();
let failures = {};
scripts.forEach(function (script) {
try {
let file = toScriptFile(script, workingDir);
if (file.exists()) {
engines.execScriptFile(file.getAbsolutePath());
} else {
throw new Error('File not found: ' + file.getAbsolutePath());
}
} catch (e) {
failures[toScriptFile(script, workingDir).getAbsolutePath()] = e;
}
});
let keys = Object.keys(failures);
if (keys.length > 0) {
dialogs.alert('脚本执行失败', `共 ${keys.length} 项自启动脚本执行失败:\n\n${keys.join('\n')}`, () => {
keys.forEach((k) => {
console.error(k);
console.error('-'.repeat(20));
console.error(failures[k]);
});
});
}
storage.remove(STORAGE_KEY_SCRIPTS_AFTER_RESTART);
}
function toScriptFile(inputPath, workingDir) {
let path = inputPath;
if (!/\.js$/i.test(path)) {
path = path + '.js';
}
let f = new File(path);
if (f.exists() || path.startsWith('$remote/')) {
return f;
}
let wk = workingDir;
if (wk.endsWith('/')) {
wk = wk.substring(0, wk.length - 1);
}
if (f.getAbsolutePath().startsWith(wk)) {
return f;
}
return new File(new File(workingDir), path);
}
runAfterRestartIfNeeded();
如有其他问题, 欢迎继续讨论.
第一段代码,报错。 但能重启,重启后没反应,效果跟我前面那段代码一样,重启后不会执行指定脚本,也不会触发定时任务→广播→AutoJS6启动时。
第二段代码还没测试,这个要开什么样的定时任务?每分钟启动一次吗? 是不是必须配合第二段监控,第一段代码才能生效?
将第二段代码保存到任意文件中, 例如 run-after-restart-if-needed.js, 文件管理器找到这个文件, 选择 "定时任务", "广播触发任务", "AutoJs6 启动时".
这样, 它将每次随 AutoJs6 启动而启动, 作为 restart 方法传入参数的监测文件. 基本原理是 restart 方法将参数写入 storages 模块创建的 SharedPreferences, 然后 run-after-restart-if-needed.js 文件读取其存入的数据执行对应的脚本.
我还是等待更新吧。
检查了代码,似乎没有截图等内存泄漏的操作,跑几天感觉程序就自动退出了。期望自身重启api尽快上线。
检查了代码,似乎没有截图等内存泄漏的操作,跑几天感觉程序就自动退出了。期望自身重启api尽快上线。
// JVM内存信息
function getMemoryInfo() {
let runtime = java.lang.Runtime.getRuntime();
let maxMemory = runtime.maxMemory(); // 最大内存
let totalMemory = runtime.totalMemory(); //总内存
let freeMemory = runtime.freeMemory(); // 空闲内存
let usedMemory = totalMemory - freeMemory; //已使用
return {
maxMemory: maxMemory,
totalMemory: totalMemory,
freeMemory: freeMemory,
usedMemory: usedMemory,
maxMemoryMB: (maxMemory / (1024 * 1024)).toFixed(0),
totalMemoryMB: (totalMemory / (1024 * 1024)).toFixed(2),
freeMemoryMB: (freeMemory / (1024 * 1024)).toFixed(2),
usedMemoryMB: ((usedMemory) / (1024 * 1024)).toFixed(2),
usagePercentage: ((usedMemory / maxMemory) * 100).toFixed(2)
};
}
// 打印jvm内存信息
function printJVMMemory() {
let info = getMemoryInfo();
console.error("JVM:" +
info.usedMemoryMB + "/" +
info.maxMemoryMB +
" MB (" + info.usagePercentage + "%)");
}
监控jvm,使用过程中jvm内存总体递增,当100%时,AutoJS6就会oom,或奔溃。 重启才能释放内存