From bc2f580e1c212caa88c6ea3bdb75660d41b221e7 Mon Sep 17 00:00:00 2001 From: SuperMonster003 Date: Mon, 3 Nov 2025 13:19:47 +0800 Subject: [PATCH] =?UTF-8?q?6.7.0=20-=20Alpha10=20-=20autojs.(restart/exit)?= =?UTF-8?q?=20=E6=96=B9=E6=B3=95=E6=94=AF=E6=8C=81=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E9=87=8D=E5=90=AF=E6=97=B6=E8=87=AA=E5=8A=A8=E8=BF=90=E8=A1=8C?= =?UTF-8?q?=E5=85=B6=E5=8F=82=E6=95=B0=E6=8C=87=E5=AE=9A=E7=9A=84=E8=84=9A?= =?UTF-8?q?=E6=9C=AC=20(issue=20#460)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changelog/lang_zh-Hans.json | 4 +- .../java/org/autojs/autojs/core/pref/Pref.kt | 36 ++-- .../receiver/DynamicBroadcastReceivers.kt | 4 +- .../runtime/api/augment/autojs/Autojs.kt | 91 ++++++--- .../org/autojs/autojs/ui/main/MainActivity.kt | 2 + .../org/autojs/autojs/util/IntentUtils.kt | 185 +++++++++++++++--- app/src/main/res/values-ar/strings.xml | 3 +- app/src/main/res/values-en/strings.xml | 3 +- app/src/main/res/values-es/strings.xml | 3 +- app/src/main/res/values-fr/strings.xml | 3 +- app/src/main/res/values-ja/strings.xml | 3 +- app/src/main/res/values-ko/strings.xml | 3 +- app/src/main/res/values-ru/strings.xml | 3 +- app/src/main/res/values-zh-rHK/strings.xml | 3 +- app/src/main/res/values-zh-rTW/strings.xml | 3 +- app/src/main/res/values-zh/strings.xml | 3 +- app/src/main/res/values/strings.xml | 4 +- .../analysis/jieba/DictionaryDatabase.kt | 4 +- version.properties | 6 +- 19 files changed, 279 insertions(+), 87 deletions(-) diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 1b33ea9b..994f48fb 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -1,7 +1,7 @@ { "$data": { "v6.7.0": { - "released_date": "2025/11/01", + "released_date": "2025/11/02", "feature": [ "cvt 模块, 用于数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))", "fmt 模块, 用于数据格式化 (参阅 项目文档 > [格式化](https://docs.autojs6.com/#/fmt))", @@ -17,7 +17,7 @@ "http 模块请求相关方法支持不安全选项参数 (isInsecure/insecure), 用于忽略证书相关异常 _[`issue #417`](http://issues.autojs6.com/417)_", "http 模块请求相关方法支持 options.client 选项, 用于配置 OkHttpClient.Builder (如 followRedirects 等) _[`issue #454`](http://issues.autojs6.com/454)_", "runtime.(set/is)JavaPrimitiveWrap 方法, 用于设置或获取 Java 原始类型包装策略 _[`issue #435`](http://issues.autojs6.com/435)_", - "autojs.(restart/exit) 方法, 用于重启或退出 AutoJs6 应用", + "autojs.(restart/exit) 方法, 用于重启或退出 AutoJs6 应用, 并支持应用重启时自动运行其参数指定的脚本 _[`issue #460`](http://issues.autojs6.com/460)_", "UiObject#isShifted 方法, 用于检测控件位置变化", "structuredClone 全局方法, 用于深拷贝 JavaScript 对象 (参阅 [MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/structuredClone))", "设置页面增加 \"Java 原始类型包装\" 设置选项 _[`issue #435`](http://issues.autojs6.com/435)_", diff --git a/app/src/main/java/org/autojs/autojs/core/pref/Pref.kt b/app/src/main/java/org/autojs/autojs/core/pref/Pref.kt index 5406db48..77d85ba3 100644 --- a/app/src/main/java/org/autojs/autojs/core/pref/Pref.kt +++ b/app/src/main/java/org/autojs/autojs/core/pref/Pref.kt @@ -5,6 +5,7 @@ import android.content.SharedPreferences import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.content.res.Resources import androidx.appcompat.app.AppCompatDelegate +import androidx.core.content.edit import androidx.preference.PreferenceManager import com.google.gson.Gson import org.autojs.autojs.App.Companion.app @@ -200,12 +201,12 @@ object Pref { fun refreshLastUpdatesAutoCheckedTimestamp() = updateTimestamp(R.string.key_last_updates_auto_checked) @JvmStatic - fun clearUpdatesCheckedStates() = sPref.edit() - .remove(key(R.string.key_last_no_newer_updates)) - .remove(key(R.string.key_last_updates_postponed)) - .remove(key(R.string.key_last_updates_checked)) - .remove(key(R.string.key_last_updates_auto_checked)) - .apply() + fun clearUpdatesCheckedStates() = sPref.edit { + remove(key(R.string.key_last_no_newer_updates)) + .remove(key(R.string.key_last_updates_postponed)) + .remove(key(R.string.key_last_updates_checked)) + .remove(key(R.string.key_last_updates_auto_checked)) + } @JvmStatic fun shouldStartA11yServiceWithRoot() = getBoolean( @@ -240,7 +241,10 @@ object Pref { fun putString(@KeyRes keyRes: Int, value: String?) = putString(key(keyRes), value) @JvmStatic - fun putString(key: String, value: String?) = sPref.edit().putString(key, value).apply() + fun putString(key: String, value: String?) = sPref.edit { putString(key, value) } + + @JvmStatic + fun putStringSync(key: String, value: String?) = sPref.edit(commit = true) { putString(key, value) } @JvmStatic fun getString(@KeyRes keyRes: Int, @KeyRes defKeyRes: Int): String = sPref.getString(key(keyRes), key(defKeyRes))!! @@ -264,10 +268,10 @@ object Pref { fun putBooleanSync(@KeyRes keyRes: Int, value: Boolean) = putBooleanSync(key(keyRes), value) @JvmStatic - fun putBoolean(key: String, value: Boolean) = sPref.edit().putBoolean(key, value).apply() + fun putBoolean(key: String, value: Boolean) = sPref.edit { putBoolean(key, value) } @JvmStatic - fun putBooleanSync(key: String, value: Boolean) = sPref.edit().putBoolean(key, value).commit() + fun putBooleanSync(key: String, value: Boolean) = sPref.edit(commit = true) { putBoolean(key, value) } @JvmStatic fun getBoolean(@KeyRes keyRes: Int, defValue: Boolean) = getBoolean(key(keyRes), defValue) @@ -282,16 +286,16 @@ object Pref { fun putInt(@KeyRes keyRes: Int, value: Int) = putInt(key(keyRes), value) @JvmStatic - fun putInt(key: String, value: Int) = sPref.edit().putInt(key, value).apply() + fun putInt(key: String, value: Int) = sPref.edit { putInt(key, value) } @JvmStatic - fun putIntSync(key: String, value: Int) = sPref.edit().putInt(key, value).commit() + fun putIntSync(key: String, value: Int) = sPref.edit(commit = true) { putInt(key, value) } @JvmStatic - fun putFloat(key: String, value: Float) = sPref.edit().putFloat(key, value).apply() + fun putFloat(key: String, value: Float) = sPref.edit { putFloat(key, value) } @JvmStatic - fun putFloatSync(key: String, value: Float) = sPref.edit().putFloat(key, value).commit() + fun putFloatSync(key: String, value: Float) = sPref.edit(commit = true) { putFloat(key, value) } @JvmStatic fun getInt(@KeyRes keyRes: Int, defValue: Int): Int = getInt(key(keyRes), defValue) @@ -303,13 +307,13 @@ object Pref { fun getFloat(key: String, defValue: Float): Float = sPref.getFloat(key, defValue) @JvmStatic - fun putLong(@KeyRes keyRes: Int, value: Long) = sPref.edit().putLong(key(keyRes), value).apply() + fun putLong(@KeyRes keyRes: Int, value: Long) = sPref.edit { putLong(key(keyRes), value) } @JvmStatic fun getLong(@KeyRes keyRes: Int, defValue: Long) = sPref.getLong(key(keyRes), defValue) @JvmStatic - fun putStringSet(@KeyRes keyRes: Int, values: MutableSet) = sPref.edit().putStringSet(key(keyRes), values).apply() + fun putStringSet(@KeyRes keyRes: Int, values: MutableSet) = sPref.edit { putStringSet(key(keyRes), values) } @JvmStatic fun getStringSet(@KeyRes keyRes: Int, defValues: MutableSet?): MutableSet? = sPref.getStringSet(key(keyRes), defValues) @@ -324,7 +328,7 @@ object Pref { fun containsKey(key: String): Boolean = sPref.all.containsKey(key) @JvmStatic - fun remove(key: String) = sPref.edit().remove(key).apply() + fun remove(key: String) = sPref.edit { remove(key) } @JvmStatic fun getLinkedHashSet(@KeyRes keyRes: Int): LinkedHashSet = when { diff --git a/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.kt b/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.kt index 2d1949b4..b6cbc0a4 100644 --- a/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.kt +++ b/app/src/main/java/org/autojs/autojs/external/receiver/DynamicBroadcastReceivers.kt @@ -94,8 +94,8 @@ class DynamicBroadcastReceivers(private val context: Context) { } mReceiverRegistries.clear() if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { - context.unregisterReceiver(mDefaultActionReceiver) - context.unregisterReceiver(mPackageActionReceiver) + runCatching { context.unregisterReceiver(mDefaultActionReceiver) } + runCatching { context.unregisterReceiver(mPackageActionReceiver) } } } diff --git a/app/src/main/java/org/autojs/autojs/runtime/api/augment/autojs/Autojs.kt b/app/src/main/java/org/autojs/autojs/runtime/api/augment/autojs/Autojs.kt index 6d45eb13..e47814d4 100644 --- a/app/src/main/java/org/autojs/autojs/runtime/api/augment/autojs/Autojs.kt +++ b/app/src/main/java/org/autojs/autojs/runtime/api/augment/autojs/Autojs.kt @@ -4,9 +4,13 @@ import android.Manifest import android.content.pm.PackageManager import android.provider.Settings import android.provider.Settings.System -import org.autojs.autojs.annotation.RhinoSingletonFunctionInterface +import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface import org.autojs.autojs.extension.AnyExtensions.isJsNullish +import org.autojs.autojs.extension.AnyExtensions.isJsString +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.FlexibleArray.Companion.component2 import org.autojs.autojs.extension.ScriptableExtensions.defineProp import org.autojs.autojs.extension.ScriptableExtensions.prop import org.autojs.autojs.rhino.ProxyObject @@ -17,6 +21,7 @@ import org.autojs.autojs.runtime.api.augment.Augmentable import org.autojs.autojs.runtime.api.augment.util.Util.checkStringArgument import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException import org.autojs.autojs.theme.ThemeColorManager +import org.autojs.autojs.util.FileUtils import org.autojs.autojs.util.IntentUtils import org.autojs.autojs.util.RhinoUtils.NOT_CONSTRUCTABLE import org.autojs.autojs.util.RhinoUtils.UNDEFINED @@ -24,7 +29,6 @@ import org.autojs.autojs.util.RhinoUtils.coerceIntNumber import org.autojs.autojs.util.RhinoUtils.coerceString import org.autojs.autojs.util.RhinoUtils.newBaseFunction import org.autojs.autojs.util.RhinoUtils.newNativeObject -import org.autojs.autojs.util.RhinoUtils.undefined import org.autojs.autojs.util.RootUtils import org.autojs.autojs.util.RootUtils.RootMode import org.autojs.autojs6.BuildConfig @@ -38,7 +42,8 @@ import java.util.* import java.util.function.Supplier import android.content.Context as AndroidContext -class Autojs(private val scriptRuntime: ScriptRuntime) : Augmentable() { +@Suppress("unused") +class Autojs(private val scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) { private val mCachedR = mutableMapOf() @@ -103,32 +108,32 @@ class Autojs(private val scriptRuntime: ScriptRuntime) : Augmentable() { companion object : FlexibleArray() { @JvmStatic - @RhinoSingletonFunctionInterface - fun isScreenPortrait(args: Array): Boolean = ensureArgumentsIsEmpty(args) { + @RhinoRuntimeFunctionInterface + fun isScreenPortrait(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsIsEmpty(args) { ScreenMetrics.isScreenPortrait } @JvmStatic - @RhinoSingletonFunctionInterface - fun isScreenLandscape(args: Array): Boolean = ensureArgumentsIsEmpty(args) { + @RhinoRuntimeFunctionInterface + fun isScreenLandscape(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsIsEmpty(args) { ScreenMetrics.isScreenLandscape } @JvmStatic - @RhinoSingletonFunctionInterface - fun isRootAvailable(args: Array): Boolean = ensureArgumentsIsEmpty(args) { + @RhinoRuntimeFunctionInterface + fun isRootAvailable(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsIsEmpty(args) { RootUtils.isRootAvailable() } @JvmStatic - @RhinoSingletonFunctionInterface - fun getRootMode(args: Array): RootMode = ensureArgumentsIsEmpty(args) { + @RhinoRuntimeFunctionInterface + fun getRootMode(scriptRuntime: ScriptRuntime, args: Array): RootMode = ensureArgumentsIsEmpty(args) { RootUtils.getRootMode() } @JvmStatic - @RhinoSingletonFunctionInterface - fun setRootMode(args: Array): Undefined = ensureArgumentsLengthInRange(args, 1..2) { + @RhinoRuntimeFunctionInterface + fun setRootMode(scriptRuntime: ScriptRuntime, args: Array): Undefined = ensureArgumentsLengthInRange(args, 1..2) { val (modeArg, isWriteIntoPrefArg) = it val isWriteIntoPref = when { @@ -173,45 +178,71 @@ class Autojs(private val scriptRuntime: ScriptRuntime) : Augmentable() { } @JvmStatic - @RhinoSingletonFunctionInterface - fun canModifySystemSettings(args: Array): Boolean = ensureArgumentsIsEmpty(args) { + @RhinoRuntimeFunctionInterface + fun canModifySystemSettings(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsIsEmpty(args) { System.canWrite(globalContext) } @JvmStatic - @RhinoSingletonFunctionInterface - fun canWriteSecureSettings(args: Array): Boolean = ensureArgumentsIsEmpty(args) { + @RhinoRuntimeFunctionInterface + fun canWriteSecureSettings(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsIsEmpty(args) { globalContext.checkCallingOrSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS) == PackageManager.PERMISSION_GRANTED } @JvmStatic - @RhinoSingletonFunctionInterface - fun canDisplayOverOtherApps(args: Array): Boolean = ensureArgumentsIsEmpty(args) { + @RhinoRuntimeFunctionInterface + fun canDisplayOverOtherApps(scriptRuntime: ScriptRuntime, args: Array): Boolean = ensureArgumentsIsEmpty(args) { Settings.canDrawOverlays(globalContext) } @JvmStatic - @RhinoSingletonFunctionInterface - fun getLanguage(args: Array): Locale = ensureArgumentsIsEmpty(args) { + @RhinoRuntimeFunctionInterface + fun getLanguage(scriptRuntime: ScriptRuntime, args: Array): Locale = ensureArgumentsIsEmpty(args) { org.autojs.autojs.core.pref.Language.getPrefLanguage().locale } @JvmStatic - @RhinoSingletonFunctionInterface - fun getLanguageTag(args: Array): String = ensureArgumentsIsEmpty(args) { - getLanguage(arrayOf()).toLanguageTag() + @RhinoRuntimeFunctionInterface + fun getLanguageTag(scriptRuntime: ScriptRuntime, args: Array): String = ensureArgumentsIsEmpty(args) { + getLanguage(scriptRuntime, arrayOf()).toLanguageTag() } @JvmStatic - @RhinoSingletonFunctionInterface - fun restart(args: Array): Undefined = ensureArgumentsIsEmpty(args) { - undefined { IntentUtils.App.restart(globalContext) } + @RhinoRuntimeFunctionInterface + fun restart(scriptRuntime: ScriptRuntime, args: Array): Undefined = ensureArgumentsAtMost(args, 1) { argList -> + val (scripts) = argList + when { + scripts.isJsNullish() -> IntentUtils.App.restart(globalContext) + scripts.isJsString() -> IntentUtils.App.restart(globalContext, scriptsAfterRestart = listOf(coerceString(scripts).normalizeScriptName(scriptRuntime))) + scripts is List<*> -> IntentUtils.App.restart(globalContext, scriptsAfterRestart = scripts.normalizeScriptNames(scriptRuntime)) + else -> throw WrappedIllegalArgumentException("Argument \"scriptsAfterRestart\" ${scripts.jsBrief()} is invalid for autojs.restart") + } + UNDEFINED } @JvmStatic - @RhinoSingletonFunctionInterface - fun exit(args: Array): Undefined = ensureArgumentsIsEmpty(args) { - undefined { IntentUtils.App.exit(globalContext) } + @RhinoRuntimeFunctionInterface + fun exit(scriptRuntime: ScriptRuntime, args: Array): Undefined = ensureArgumentsAtMost(args, 1) { argList -> + val (scripts) = argList + when { + scripts.isJsNullish() -> IntentUtils.App.exit(globalContext) + scripts.isJsString() -> IntentUtils.App.exit(globalContext, scriptsAfterRestart = listOf(coerceString(scripts).normalizeScriptName(scriptRuntime))) + scripts is List<*> -> IntentUtils.App.exit(globalContext, scriptsAfterRestart = scripts.normalizeScriptNames(scriptRuntime)) + else -> throw WrappedIllegalArgumentException("Argument \"scriptsAfterRestart\" ${scripts.jsBrief()} is invalid for autojs.exit") + } + UNDEFINED + } + + private fun String.normalizeScriptName(scriptRuntime: ScriptRuntime): String { + val jsExt = FileUtils.TYPE.JAVASCRIPT.extensionWithDot + return when (val s = this.trim()) { + "@" -> scriptRuntime.engines.myEngine().source.fullPath + else -> s.let { if (it.endsWith(jsExt)) it else "$it$jsExt" } + } + } + + private fun List.normalizeScriptNames(scriptRuntime: ScriptRuntime): List { + return this.mapNotNull { it?.toString()?.normalizeScriptName(scriptRuntime) } } } diff --git a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt index f62b140c..d9bbf177 100644 --- a/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt +++ b/app/src/main/java/org/autojs/autojs/ui/main/MainActivity.kt @@ -53,6 +53,7 @@ import org.autojs.autojs.ui.main.task.TaskManagerFragment import org.autojs.autojs.ui.settings.PreferencesActivity import org.autojs.autojs.ui.widget.DrawerAutoClose import org.autojs.autojs.ui.widget.SearchViewItem +import org.autojs.autojs.util.IntentUtils import org.autojs.autojs.util.StringUtils.key import org.autojs.autojs.util.UpdateUtils import org.autojs.autojs.util.ViewUtils @@ -147,6 +148,7 @@ class MainActivity : BaseActivity(), DelegateHost, HostActivity { override fun onPostResume() { recreateIfNeeded() UpdateUtils.autoCheckForUpdatesIfNeededWithSnackbar(this) + IntentUtils.App.runAfterRestartIfNeeded(this) super.onPostResume() } diff --git a/app/src/main/java/org/autojs/autojs/util/IntentUtils.kt b/app/src/main/java/org/autojs/autojs/util/IntentUtils.kt index 111460a9..1e5cba7c 100644 --- a/app/src/main/java/org/autojs/autojs/util/IntentUtils.kt +++ b/app/src/main/java/org/autojs/autojs/util/IntentUtils.kt @@ -1,5 +1,6 @@ package org.autojs.autojs.util +import android.app.ActivityManager import android.app.AlarmManager import android.app.PendingIntent import android.content.ActivityNotFoundException @@ -7,7 +8,6 @@ import android.content.Context import android.content.Context.ALARM_SERVICE import android.content.Intent import android.net.Uri -import android.os.Process import android.os.SystemClock import android.provider.OpenableColumns import android.provider.Settings @@ -15,19 +15,33 @@ import android.view.View import androidx.appcompat.app.AppCompatActivity import androidx.core.content.FileProvider import androidx.core.net.toUri +import androidx.work.Constraints +import androidx.work.ExistingWorkPolicy +import androidx.work.OneTimeWorkRequestBuilder +import androidx.work.WorkManager +import androidx.work.Worker +import androidx.work.WorkerParameters +import com.afollestad.materialdialogs.MaterialDialog import com.google.android.material.snackbar.Snackbar import com.huaban.analysis.jieba.CharsDictionaryDatabase import com.huaban.analysis.jieba.PhrasesDictionaryDatabase import com.huaban.analysis.jieba.WordDictionaryDatabase import org.autojs.autojs.AutoJs import org.autojs.autojs.core.image.capture.ScreenCapturerForegroundService +import org.autojs.autojs.core.pref.Pref +import org.autojs.autojs.execution.ExecutionConfig import org.autojs.autojs.external.fileprovider.AppFileProvider +import org.autojs.autojs.model.script.ScriptFile import org.autojs.autojs.runtime.api.Mime import org.autojs.autojs.runtime.api.WrappedShizuku import org.autojs.autojs.ui.enhancedfloaty.FloatyService import org.autojs.autojs.ui.floating.FloatyWindowManger +import org.autojs.autojs.util.StringUtils.key import org.autojs.autojs6.R import java.io.File +import java.io.FileNotFoundException +import java.util.concurrent.TimeUnit +import kotlin.system.exitProcess object IntentUtils { @@ -330,39 +344,56 @@ object IntentUtils { object App { + private const val UNIQUE_REQUEST_CODE = 1001 + @JvmStatic @JvmOverloads - fun restart(context: Context, extraActions: (() -> Unit)? = null) { - val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)?.apply { - addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK) - } + fun restart(context: Context, beforeExit: (() -> Unit)? = null, scriptsAfterRestart: List? = null) { + val launchIntent = getLaunchIntent(context) + ?: throw RuntimeException("Failed to create launch intent for AutoJs6") when (context) { is AppCompatActivity -> { context.startActivity(launchIntent) } else -> { - val pendingIntent = PendingIntent.getActivity( - /* context = */ context, - /* requestCode = */ 1001, - /* intent = */ launchIntent, - /* flags = */ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE, - ) - val am = context.getSystemService(ALARM_SERVICE) as AlarmManager - am.setExactAndAllowWhileIdle( - /* type = */ AlarmManager.ELAPSED_REALTIME, - /* triggerAtMillis = */ SystemClock.elapsedRealtime() + 300L, - /* operation = */ pendingIntent, - ) + val delay = TimeUnit.MILLISECONDS.toMillis(300) + val triggerAtMillis = SystemClock.elapsedRealtime() + delay + runCatching tryWithAlarmManager@{ + val pendingIntent = PendingIntent.getActivity( + /* context = */ context, + /* requestCode = */ UNIQUE_REQUEST_CODE, + /* intent = */ launchIntent, + /* flags = */ PendingIntent.FLAG_CANCEL_CURRENT or PendingIntent.FLAG_IMMUTABLE, + ) + val am = context.getSystemService(ALARM_SERVICE) as AlarmManager + am.cancel(pendingIntent) + am.setExactAndAllowWhileIdle( + /* type = */ AlarmManager.ELAPSED_REALTIME, + /* triggerAtMillis = */ triggerAtMillis, + /* operation = */ pendingIntent, + ) + }.onFailure tryWithWorkManager@{ + it.printStackTrace() + val request = OneTimeWorkRequestBuilder() + .setInitialDelay(delay, TimeUnit.MILLISECONDS) + .setConstraints(Constraints.NONE) + .build() + WorkManager.getInstance(context).enqueueUniqueWork( + uniqueWorkName = "work-task-restart-autojs6", + existingWorkPolicy = ExistingWorkPolicy.REPLACE, + request = request, + ) + } } } - exit(context, extraActions) + exit(context, beforeExit, scriptsAfterRestart) } @JvmStatic @JvmOverloads - fun exit(context: Context, extraActions: (() -> Unit)? = null) { + fun exit(context: Context, beforeExit: (() -> Unit)? = null, scriptsAfterRestart: List? = null) { FloatyWindowManger.hideCircularMenuAndSaveState() FloatyService.stopService() @@ -379,11 +410,121 @@ object IntentUtils { WrappedShizuku.onDestroy() - extraActions?.invoke() + beforeExit?.invoke() - Process.killProcess(Process.myPid()) + if (!scriptsAfterRestart.isNullOrEmpty()) { + Pref.putStringSync(key(R.string.key_scripts_after_app_restart), scriptsAfterRestart.joinToString("\n") { it.trim() }) + } + + finishAllAppTasksSafely(context) + + exitProcess(0) + } + + private fun getLaunchIntent(context: Context): Intent? { + val appCtx = context.applicationContext + val pkgName = appCtx.packageName + return appCtx.packageManager.getLaunchIntentForPackage(pkgName)?.apply { + setAction("$pkgName.action.RESTART_UNIQUE") + addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_CLEAR_TASK) + } + } + + private fun finishAllAppTasksSafely(context: Context) { + // Use AppTask API to remove all task stacks of the current application (AutoJs6). + // zh-CN: 使用 AppTask API 移除当前应用 (AutoJs6) 的所有任务栈. + runCatching { + val am = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager + am.appTasks?.forEach { it.runCatching { finishAndRemoveTask() } } + } + } + + @JvmStatic + fun runAfterRestartIfNeeded(activity: AppCompatActivity) { + val prefKey = key(R.string.key_scripts_after_app_restart) + val prefValue = Pref.getStringOrNull(prefKey) ?: return + val scripts = prefValue.split("\n").filter { it.isNotBlank() } + + val workingDir = WorkingDirectoryUtils.path + val scriptsFailedToRun = mutableMapOf() + + try { + activity.runOnUiThread { + scripts.forEach { script -> + try { + val file = script.toScriptFile(workingDir) + when { + file.exists() -> AutoJs.instance.scriptEngineService.execute( + /* source = */ ScriptFile(file.absolutePath).toSource(), + /* config = */ ExecutionConfig(workingDir), + ) + else -> throw FileNotFoundException(file.absolutePath) + } + } catch (e: Exception) { + e.printStackTrace() + scriptsFailedToRun[script.toScriptFile(workingDir).absolutePath] = e.stackTraceToString() + } + } + } + } finally { + Pref.remove(prefKey) + } + + if (scriptsFailedToRun.isEmpty()) return + + val size = scriptsFailedToRun.size + val summary = activity.resources.getQuantityString(R.plurals.text_items_total_sum_with_colon, size, size) + val hint = activity.getString(R.string.text_click_item_to_show_details) + MaterialDialog.Builder(activity) + .title(R.string.error_failed_to_run_script) + .content("$summary\n\n$hint") + .items(scriptsFailedToRun.map { it.key }) + .itemsCallback { _, _, _, text -> + val stackTrace = scriptsFailedToRun[text] + val content = "$text\n\n$stackTrace" + MaterialDialog.Builder(activity) + .title(R.string.text_details) + .content(content) + .neutralText(R.string.dialog_button_copy) + .neutralColorRes(R.color.dialog_button_hint) + .onNeutral { d, _ -> + ClipboardUtils.setClip(activity, content) + ViewUtils.showSnack(d.view, R.string.text_already_copied_to_clip, false) + } + .positiveText(R.string.dialog_button_dismiss) + .onPositive { d, _ -> d.dismiss() } + .autoDismiss(false) + .show() + } + .positiveText(R.string.dialog_button_dismiss) + .onPositive { dialog, _ -> dialog.dismiss() } + .cancelable(false) + .autoDismiss(false) + .show() + } + + private fun String.toScriptFile(workingDir: String): File { + val file = when (this.endsWith(FileUtils.TYPE.JAVASCRIPT.extensionWithDot)) { + true -> this + else -> this + FileUtils.TYPE.JAVASCRIPT.extensionWithDot + }.let { File(it) } + return when { + file.exists() -> file + file.absolutePath.startsWith(workingDir.removeSuffix("/")) -> file + file.path.startsWith("\$remote/") -> file + else -> File(workingDir, file.path) + } + } + + class RestartWorker(context: Context, params: WorkerParameters) : Worker(context, params) { + override fun doWork(): Result = when { + runCatching { applicationContext.startActivity(getLaunchIntent(applicationContext)) }.isSuccess -> { + Result.success() + } + else -> Result.failure() + } } } -} \ No newline at end of file +} diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 98ca7f48..cc802958 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -1072,6 +1072,7 @@ يتحكم في الآلية الأساسية لتشغيل السكربتات بشكل مجدول.\n\nAlarmManager: عبر منح إذن \"السماح بتعيين المنبّهات والتذكيرات\" يمكن أن تصبح المهام أقرب إلى التنفيذ في الوقت المحدد.\nWorkManager: صديق للنظام؛ مناسب للمهام غير الحرجة التي تتحمل بعض التأخير.\nJobScheduler: تنفيذ قديم محفوظ للتوافق؛ احتمال التأخير أعلى. فشل فتح صفحة الإعدادات يُوصى بمنح إذن \"السماح بتعيين المنبّهات والتذكيرات\" لضمان تنفيذ المهام المجدولة بأكبر قدر ممكن من الدقة حتى عند إيقاف الشاشة أو في وضع السكون - حالات الاستخدام والفروقات:\n\n1) AlarmManager\nمناسب للمهام الحسّاسة للتوقيت، مثل [التذكيرات/السكربتات الدقيقة التوقيت/...].\nعلى Android 12+ ومع منح إذن \"السماح بتعيين المنبّهات والتذكيرات\" يمكن التنفيذ بدقة أكبر حتى مع إيقاف الشاشة أو في وضع السكون.\nبدون الإذن قد يقلل النظام الدقة أو يؤخر التنفيذ.\n\n2) WorkManager\nمناسب للمهام التي لا تتطلب دقة زمنية صارمة مثل [مزامنة غير حرجة/تنظيف/إحصاءات/...].\nيتم الجدولة وفق [حالة البطارية/الشبكة/الشحن/سياسات السكون/...], وقد تتأخر المهام عند إيقاف الشاشة أو في وضع السكون.\nلا يضمن الدقة الزمنية لكنه يوفر مزايا في [إتمام موثوق/إعادة المحاولة عند الفشل/سلاسل المهام/إزالة التكرار].\n\n3) JobScheduler\nتنفيذ تاريخي لأغراض التوافق.\nفي إصدارات أندرويد الحديثة قد تحدث تأخيرات أكبر.\nلا يُنصح به إلا لاعتبارات التوافق. + حالات الاستخدام والفروقات:\n\n1. AlarmManager\nمناسب للمهام الحسّاسة للتوقيت، مثل [التذكيرات/السكربتات الدقيقة التوقيت/...].\nعلى Android 12+ ومع منح إذن \"السماح بتعيين المنبّهات والتذكيرات\" يمكن التنفيذ بدقة أكبر حتى مع إيقاف الشاشة أو في وضع السكون.\nبدون الإذن قد يقلل النظام الدقة أو يؤخر التنفيذ.\n\n2. WorkManager\nمناسب للمهام التي لا تتطلب دقة زمنية صارمة مثل [مزامنة غير حرجة/تنظيف/إحصاءات/...].\nيتم الجدولة وفق [حالة البطارية/الشبكة/الشحن/سياسات السكون/...], وقد تتأخر المهام عند إيقاف الشاشة أو في وضع السكون.\nلا يضمن الدقة الزمنية لكنه يوفر مزايا في [إتمام موثوق/إعادة المحاولة عند الفشل/سلاسل المهام/إزالة التكرار].\n\n3. JobScheduler\nتنفيذ تاريخي لأغراض التوافق.\nفي إصدارات أندرويد الحديثة قد تحدث تأخيرات أكبر.\nلا يُنصح به إلا لاعتبارات التوافق. + اضغط على العنصر لعرض التفاصيل diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index a574e238..cae4725d 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -1067,6 +1067,7 @@ Controls the underlying mechanism for triggering scripts on a schedule.\n\nAlarmManager: With the “Allow setting alarms and reminders” permission granted, scheduled tasks can fire closer to the exact time.\nWorkManager: System-friendly; suitable for non-critical tasks that can tolerate some delay.\nJobScheduler: Legacy implementation kept for compatibility; higher chance of delays. Failed to open the settings page Granting the “Allow setting alarms and reminders” permission is recommended to help tasks run as punctually as possible even when the screen is off or the device is idle - Use cases and differences:\n\n1) AlarmManager\nBest for time-sensitive tasks, e.g., [reminders/strictly scheduled scripts/...].\nOn Android 12+ with the “Allow setting alarms and reminders” permission, tasks can run more on time even when the screen is off or the device is idle.\nWithout it, the system may degrade exactness or delay execution.\n\n2) WorkManager\nBest for tasks that don’t require strict timing, e.g., [non-critical sync/cleanup/statistics/...].\nScheduling depends on [battery/network/charging/idle policies/...], so execution may be postponed when the screen is off or idle.\nWhile it can’t guarantee exact timing, it excels at [reliable completion/retries/chaining/unique work de-duplication].\n\n3) JobScheduler\nHistorical implementation for compatibility.\nOn newer Android versions, tasks may be delayed more noticeably.\nGenerally not recommended unless required for compatibility. + Use cases and differences:\n\n1. AlarmManager\nBest for time-sensitive tasks, e.g., [reminders/strictly scheduled scripts/...].\nOn Android 12+ with the “Allow setting alarms and reminders” permission, tasks can run more on time even when the screen is off or the device is idle.\nWithout it, the system may degrade exactness or delay execution.\n\n2. WorkManager\nBest for tasks that don’t require strict timing, e.g., [non-critical sync/cleanup/statistics/...].\nScheduling depends on [battery/network/charging/idle policies/...], so execution may be postponed when the screen is off or idle.\nWhile it can’t guarantee exact timing, it excels at [reliable completion/retries/chaining/unique work de-duplication].\n\n3. JobScheduler\nHistorical implementation for compatibility.\nOn newer Android versions, tasks may be delayed more noticeably.\nGenerally not recommended unless required for compatibility. + Click an item to view details diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index 0c876177..f2eab621 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1070,6 +1070,7 @@ Controla el mecanismo subyacente para activar scripts de forma programada.\n\nAlarmManager: Mediante la concesión del permiso \"Permitir configurar alarmas y recordatorios\", las tareas programadas pueden dispararse con mayor puntualidad.\nWorkManager: Amigable con el sistema; adecuado para tareas no críticas que toleran cierta demora.\nJobScheduler: Implementación antigua, mantenida por compatibilidad; la ejecución puede retrasarse con mayor probabilidad. No se pudo abrir la página de ajustes Se recomienda conceder el permiso \"Permitir configurar alarmas y recordatorios\" para asegurar que las tareas programadas se ejecuten lo más puntualmente posible incluso con la pantalla apagada o en espera - Escenarios de uso y diferencias:\n\n1. AlarmManager\nAdecuado para tareas sensibles a la puntualidad, p. ej., [recordatorios/scripts estrictamente programados/...].\nEn Android 12+ y con el permiso \"Permitir configurar alarmas y recordatorios\", puede ejecutar tareas de forma más puntual con la pantalla apagada o en estado de espera.\nSin dicho permiso, el sistema puede degradar la exactitud o retrasar la ejecución.\n\n2. WorkManager\nAdecuado para tareas que no requieren estricta puntualidad, p. ej., [sincronización no crítica/limpieza/estadísticas/...].\nSe programa según [batería/red/carga/estrategias de reposo/...], por lo que puede posponer la ejecución con la pantalla apagada o en espera.\nAunque no garantiza precisión temporal, tiene ventajas en [finalización fiable/reintentos en caso de fallo/encadenamiento/deduplicación de trabajos].\n\n3. JobScheduler\nImplementación histórica para compatibilidad.\nEn versiones recientes de Android, las tareas pueden experimentar mayores retrasos.\nPor lo general, no se recomienda salvo por motivos de compatibilidad. + Escenarios de uso y diferencias:\n\n1. AlarmManager\nAdecuado para tareas sensibles a la puntualidad, p. ej., [recordatorios/scripts estrictamente programados/...].\nEn Android 12+ y con el permiso \"Permitir configurar alarmas y recordatorios\", puede ejecutar tareas de forma más puntual con la pantalla apagada o en estado de espera.\nSin dicho permiso, el sistema puede degradar la exactitud o retrasar la ejecución.\n\n2. WorkManager\nAdecuado para tareas que no requieren estricta puntualidad, p. ej., [sincronización no crítica/limpieza/estadísticas/...].\nSe programa según [batería/red/carga/estrategias de reposo/...], por lo que puede posponer la ejecución con la pantalla apagada o en espera.\nAunque no garantiza precisión temporal, tiene ventajas en [finalización fiable/reintentos en caso de fallo/encadenamiento/deduplicación de trabajos].\n\n3. JobScheduler\nImplementación histórica para compatibilidad.\nEn versiones recientes de Android, las tareas pueden experimentar mayores retrasos.\nPor lo general, no se recomienda salvo por motivos de compatibilidad. + Toca un elemento para ver los detalles diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 3cde301b..f4c992fb 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1070,6 +1070,7 @@ Contrôle le mécanisme sous-jacent de déclenchement programmé des scripts.\n\nAlarmManager : En accordant l\'autorisation \"Autoriser la définition d\'alarmes et de rappels\", les tâches peuvent se déclencher avec une meilleure ponctualité.\nWorkManager : Plus conciliant avec le système ; adapté aux tâches non critiques tolérant un certain délai.\nJobScheduler : Ancienne implémentation conservée pour la compatibilité, avec un risque accru de retard. Échec d\'ouverture de la page des paramètres Il est recommandé d\'accorder l\'autorisation \"Autoriser la définition d\'alarmes et de rappels\" afin d\'assurer un déclenchement aussi ponctuel que possible, même écran éteint ou en veille - Scénarios d\'usage et différences :\n\n1. AlarmManager\nConvient aux tâches sensibles à la ponctualité, p. ex. [rappels/scripts strictement planifiés/...].\nSous Android 12+ avec l\'autorisation \"Autoriser la définition d\'alarmes et de rappels\", l\'exécution reste plus ponctuelle écran éteint ou en veille.\nSans cette autorisation, le système peut réduire la précision ou retarder l\'exécution.\n\n2. WorkManager\nConvient aux tâches ne nécessitant pas une ponctualité stricte, p. ex. [synchronisation non critique/nettoyage/statistiques/...].\nL\'ordonnancement dépend de [la batterie/le réseau/la charge/les stratégies de veille/...], ce qui peut retarder l\'exécution écran éteint ou en veille.\nBien qu\'il ne garantisse pas la précision temporelle, il offre des atouts en [achèvement fiable/reprise en cas d\'échec/chaînage/déduplication des travaux].\n\n3. JobScheduler\nImplémentation historique conservée pour compatibilité.\nSur les versions récentes d\'Android, les tâches peuvent subir des retards plus importants.\nSauf besoin de compatibilité, il n\'est généralement pas recommandé. + Scénarios d\'usage et différences :\n\n1. AlarmManager\nConvient aux tâches sensibles à la ponctualité, p. ex. [rappels/scripts strictement planifiés/...].\nSous Android 12+ avec l\'autorisation \"Autoriser la définition d\'alarmes et de rappels\", l\'exécution reste plus ponctuelle écran éteint ou en veille.\nSans cette autorisation, le système peut réduire la précision ou retarder l\'exécution.\n\n2. WorkManager\nConvient aux tâches ne nécessitant pas une ponctualité stricte, p. ex. [synchronisation non critique/nettoyage/statistiques/...].\nL\'ordonnancement dépend de [la batterie/le réseau/la charge/les stratégies de veille/...], ce qui peut retarder l\'exécution écran éteint ou en veille.\nBien qu\'il ne garantisse pas la précision temporelle, il offre des atouts en [achèvement fiable/reprise en cas d\'échec/chaînage/déduplication des travaux].\n\n3. JobScheduler\nImplémentation historique conservée pour compatibilité.\nSur les versions récentes d\'Android, les tâches peuvent subir des retards plus importants.\nSauf besoin de compatibilité, il n\'est généralement pas recommandé. + Touchez un élément pour afficher les détails diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index a966e6ce..ff294642 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1071,6 +1071,7 @@ スクリプトを定時で起動するための基盤メカニズムを制御します.\n\nAlarmManager: システムの \"アラームとリマインダーの設定を許可\" 権限を付与すると/より正確な時刻での実行に近づきます.\nWorkManager: システムに優しく/一定の遅延を許容できる非重要タスクに適しています.\nJobScheduler: 旧来の実装で互換性のために残されていますが/遅延が発生しやすいです. 設定画面を開けませんでした 画面消灯中や待機時でもできるだけ正確に実行できるよう/[アラームとリマインダーの設定を許可] 権限の付与を推奨します - 利用シーンと違い: \n\n1. AlarmManager\n[リマインダー/厳密な時刻のスクリプト/...] など/時刻精度が重要なタスクに適しています.\nAndroid 12 以降で \"アラームとリマインダーの設定を許可\" 権限がある場合/画面消灯/待機中でも比較的正確に実行されます.\n権限がない場合/システムにより不正確または遅延実行になる可能性があります.\n\n2. WorkManager\n[非重要な同期/クリーンアップ/統計/...] など/厳密な時刻精度を必要としないタスクに適しています.\n[バッテリー/ネットワーク/充電状況/待機ポリシー/...] に応じてスケジューリングされ/消灯/待機中は実行が遅れることがあります.\n時間精度は保証されませんが/[確実な完了/失敗時の再試行/チェーン実行/一意タスクの重複排除] に強みがあります.\n\n3. JobScheduler\n互換性維持のための歴史的実装です.\n新しい Android では遅延が大きくなりやすい傾向があります.\n互換性の必要がない限り/通常は非推奨です. + 利用シーンと違い: \n\n1. AlarmManager\n[リマインダー/厳密な時刻のスクリプト/...] など/時刻精度が重要なタスクに適しています.\nAndroid 12 以降で \"アラームとリマインダーの設定を許可\" 権限がある場合/画面消灯/待機中でも比較的正確に実行されます.\n権限がない場合/システムにより不正確または遅延実行になる可能性があります.\n\n2. WorkManager\n[非重要な同期/クリーンアップ/統計/...] など/厳密な時刻精度を必要としないタスクに適しています.\n[バッテリー/ネットワーク/充電状況/待機ポリシー/...] に応じてスケジューリングされ/消灯/待機中は実行が遅れることがあります.\n時間精度は保証されませんが/[確実な完了/失敗時の再試行/チェーン実行/一意タスクの重複排除] に強みがあります.\n\n3. JobScheduler\n互換性維持のための歴史的実装です.\n新しい Android では遅延が大きくなりやすい傾向があります.\n互換性の必要がない限り/通常は非推奨です. + 項目をタップして詳細を表示します diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 41ab5a03..3d991bc3 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1072,6 +1072,7 @@ 스크립트를 정해진 시간에 실행하는 기본 메커니즘을 제어합니다.\n\nAlarmManager: 시스템의 \"알람 및 알림 설정 허용\" 권한을 부여하면 보다 정확한 시각에 가깝게 실행됩니다.\nWorkManager: 시스템 친화적이며, 일정 지연을 허용할 수 있는 비중요 작업에 적합합니다.\nJobScheduler: 호환성 유지를 위해 남겨둔 구방식으로, 지연 발생 가능성이 큽니다. 설정 페이지를 열지 못했습니다 화면이 꺼져 있거나 대기 상태에서도 최대한 정시에 실행되도록, \"알람 및 알림 설정 허용\" 권한 부여를 권장합니다 - 사용 시나리오 및 차이점:\n\n1. AlarmManager\n[리마인더/엄격한 정시 스크립트/...] 등 시간 정확도가 중요한 작업에 적합합니다.\nAndroid 12+ 에서 \"알람 및 알림 설정 허용\" 권한이 있으면, 화면 꺼짐/대기 중에도 비교적 정확하게 실행됩니다.\n 권한이 없으면 시스템이 정확도를 낮추거나 실행을 지연할 수 있습니다.\n\n2. WorkManager\n[비중요 동기화/정리/통계/...] 등 엄격한 정시성이 필요 없는 작업에 적합합니다.\n[배터리/네트워크/충전 상태/대기 정책/...] 에 따라 스케줄링되며, 화면 꺼짐/대기 중에는 지연될 수 있습니다.\n 시간 정확도는 보장되지 않지만, [신뢰성 있는 완료/실패 재시도/체이닝/단일 작업 중복 방지] 에 장점이 있습니다.\n\n3. JobScheduler\n 호환성 유지를 위한 기존 구현입니다.\n 신형 Android 에서는 지연이 더 커질 수 있습니다.\n 특별한 호환성 목적이 아니라면 일반적으로 권장하지 않습니다. + 사용 시나리오 및 차이점:\n\n1. AlarmManager\n[리마인더/엄격한 정시 스크립트/...] 등 시간 정확도가 중요한 작업에 적합합니다.\nAndroid 12+ 에서 \"알람 및 알림 설정 허용\" 권한이 있으면, 화면 꺼짐/대기 중에도 비교적 정확하게 실행됩니다.\n 권한이 없으면 시스템이 정확도를 낮추거나 실행을 지연할 수 있습니다.\n\n2. WorkManager\n[비중요 동기화/정리/통계/...] 등 엄격한 정시성이 필요 없는 작업에 적합합니다.\n[배터리/네트워크/충전 상태/대기 정책/...] 에 따라 스케줄링되며, 화면 꺼짐/대기 중에는 지연될 수 있습니다.\n 시간 정확도는 보장되지 않지만, [신뢰성 있는 완료/실패 재시도/체이닝/단일 작업 중복 방지] 에 장점이 있습니다.\n\n3. JobScheduler\n 호환성 유지를 위한 기존 구현입니다.\n 신형 Android 에서는 지연이 더 커질 수 있습니다.\n 특별한 호환성 목적이 아니라면 일반적으로 권장하지 않습니다. + 항목을 탭하면 자세한 정보를 볼 수 있습니다 diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 7db4b6b1..d23cd6cd 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -1070,6 +1070,7 @@ Управляет базовым механизмом по расписанию запуска скриптов.\n\nAlarmManager: При выдаче разрешения "Разрешить настройку будильников и напоминаний" задачи выполняются более точно по времени.\nWorkManager: Дружелюбен к системе; подходит для некритичных задач, допускающих задержку.\nJobScheduler: Устаревшая реализация, сохранена для совместимости; вероятность задержек выше. Не удалось открыть страницу настроек Рекомендуется выдать разрешение "Разрешить настройку будильников и напоминаний", чтобы обеспечить максимально точный запуск задач даже при выключенном экране или в режиме ожидания - Сценарии и отличия:\n\n1. AlarmManager\nПодходит для задач, чувствительных к точности времени, например [напоминания/строго по расписанию/...].\nВ Android 12+ при наличии разрешения "Разрешить настройку будильников и напоминаний" задачи запускаются более точно даже при выключенном экране/в ожидании.\nБез него система может понизить точность или отложить выполнение.\n\n2. WorkManager\nПодходит для задач без строгих требований к времени, например [некритичная синхронизация/очистка/статистика/...].\nПланирование учитывает [батарею/сеть/зарядку/политику сна/...], возможны задержки при выключенном экране или в ожидании.\nХотя точность не гарантируется, он силён в [надёжном завершении/повторных попытках/цепочках/дедупликации работ].\n\n3. JobScheduler\nИсторическая реализация для совместимости.\nНа новых версиях Android возможны более существенные задержки.\nНе рекомендуется, если это не необходимо ради совместимости. + Сценарии и отличия:\n\n1. AlarmManager\nПодходит для задач, чувствительных к точности времени, например [напоминания/строго по расписанию/...].\nВ Android 12+ при наличии разрешения "Разрешить настройку будильников и напоминаний" задачи запускаются более точно даже при выключенном экране/в ожидании.\nБез него система может понизить точность или отложить выполнение.\n\n2. WorkManager\nПодходит для задач без строгих требований к времени, например [некритичная синхронизация/очистка/статистика/...].\nПланирование учитывает [батарею/сеть/зарядку/политику сна/...], возможны задержки при выключенном экране или в ожидании.\nХотя точность не гарантируется, он силён в [надёжном завершении/повторных попытках/цепочках/дедупликации работ].\n\n3. JobScheduler\nИсторическая реализация для совместимости.\nНа новых версиях Android возможны более существенные задержки.\nНе рекомендуется, если это не необходимо ради совместимости. + Нажмите на пункт, чтобы просмотреть подробности diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 8f37c5a8..b368d3b4 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -1068,6 +1068,7 @@ 控制腳本定時觸發的底層機制.\n\nAlarmManager: 通過申請 \"允許設置鬧鐘和提醒\" 權限, 可使定時任務的觸發更接近準時.\nWorkManager: 系統友好, 適合可接受一定延遲的非關鍵定時任務.\nJobScheduler: 舊實現, 僅用作兼容保留, 定時任務出現延遲的概率較大. 跳轉設置頁面失敗 建議授予 \"允許設置鬧鐘和提醒\" 權限以確保定時任務在息屏或待機狀態時儘可能準時執行 - 使用場景與差異説明: \n\n1. AlarmManager\n適用於準時性敏感的定時任務, 如 [提醒/嚴格定時腳本/...].\n在 Android 12+ 獲取 \"允許設置鬧鐘和提醒\" 權限後, 在息屏或待機狀態時能夠較準時地執行定時任務.\n在未授予 \"允許設置鬧鐘和提醒\" 權限時, 系統可能降級為不準時或延後執行任務.\n\n2. WorkManager\n適用於不要求嚴格準時執行的定時任務, 如 [非關鍵性同步/清理/統計/...].\n根據系統 [ 電量/網絡/充電情況/待機策略/... ] 進行調度, 息屏或待機狀態時可能推遲任務執行.\n雖無法保證時間精確性, 但在 [ 可靠完成/失敗重試/鏈式執行/唯一任務去重 ] 等方面擁有獨特優勢.\n\n3. Job\n歷史實現, 為兼容保留.\n在高版本安卓系統中定時任務可能存在較大的延遲執行問題.\n除非出於兼容需要, 一般不推薦使用. + 使用場景與差異説明: \n\n1. AlarmManager\n適用於準時性敏感的定時任務, 如 [提醒/嚴格定時腳本/...].\n在 Android 12+ 獲取 \"允許設置鬧鐘和提醒\" 權限後, 在息屏或待機狀態時能夠較準時地執行定時任務.\n在未授予 \"允許設置鬧鐘和提醒\" 權限時, 系統可能降級為不準時或延後執行任務.\n\n2. WorkManager\n適用於不要求嚴格準時執行的定時任務, 如 [非關鍵性同步/清理/統計/...].\n根據系統 [ 電量/網絡/充電情況/待機策略/... ] 進行調度, 息屏或待機狀態時可能推遲任務執行.\n雖無法保證時間精確性, 但在 [ 可靠完成/失敗重試/鏈式執行/唯一任務去重 ] 等方面擁有獨特優勢.\n\n3. Job\n歷史實現, 為兼容保留.\n在高版本安卓系統中定時任務可能存在較大的延遲執行問題.\n除非出於兼容需要, 一般不推薦使用. + 點擊條目可查看詳情 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 0ef56442..7bc50ce6 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1068,6 +1068,7 @@ 控制指令碼定時觸發的底層機制.\n\nAlarmManager: 透過申請 \"允許設定鬧鐘和提醒\" 許可權, 可使定時任務的觸發更接近準時.\nWorkManager: 系統友好, 適合可接受一定延遲的非關鍵定時任務.\nJobScheduler: 舊實現, 僅用作相容保留, 定時任務出現延遲的機率較大. 跳轉設定頁面失敗 建議授予 \"允許設定鬧鐘和提醒\" 許可權以確保定時任務在息屏或待機狀態時儘可能準時執行 - 使用場景與差異說明: \n\n1. AlarmManager\n適用於準時性敏感的定時任務, 如 [提醒/嚴格定時指令碼/...].\n在 Android 12+ 獲取 \"允許設定鬧鐘和提醒\" 許可權後, 在息屏或待機狀態時能夠較準時地執行定時任務.\n在未授予 \"允許設定鬧鐘和提醒\" 許可權時, 系統可能降級為不準時或延後執行任務.\n\n2. WorkManager\n適用於不要求嚴格準時執行的定時任務, 如 [非關鍵性同步/清理/統計/...].\n根據系統 [ 電量/網路/充電情況/待機策略/... ] 進行排程, 息屏或待機狀態時可能推遲任務執行.\n雖無法保證時間精確性, 但在 [ 可靠完成/失敗重試/鏈式執行/唯一任務去重 ] 等方面擁有獨特優勢.\n\n3. Job\n歷史實現, 為相容保留.\n在高版本安卓系統中定時任務可能存在較大的延遲執行問題.\n除非出於相容需要, 一般不推薦使用. + 使用場景與差異說明: \n\n1. AlarmManager\n適用於準時性敏感的定時任務, 如 [提醒/嚴格定時指令碼/...].\n在 Android 12+ 獲取 \"允許設定鬧鐘和提醒\" 許可權後, 在息屏或待機狀態時能夠較準時地執行定時任務.\n在未授予 \"允許設定鬧鐘和提醒\" 許可權時, 系統可能降級為不準時或延後執行任務.\n\n2. WorkManager\n適用於不要求嚴格準時執行的定時任務, 如 [非關鍵性同步/清理/統計/...].\n根據系統 [ 電量/網路/充電情況/待機策略/... ] 進行排程, 息屏或待機狀態時可能推遲任務執行.\n雖無法保證時間精確性, 但在 [ 可靠完成/失敗重試/鏈式執行/唯一任務去重 ] 等方面擁有獨特優勢.\n\n3. Job\n歷史實現, 為相容保留.\n在高版本安卓系統中定時任務可能存在較大的延遲執行問題.\n除非出於相容需要, 一般不推薦使用. + 點選條目可檢視詳情 diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index c83b3a2e..9259677a 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -1068,6 +1068,7 @@ 控制脚本定时触发的底层机制.\n\nAlarmManager: 通过申请 \"允许设置闹钟和提醒\" 权限, 可使定时任务的触发更接近准时.\nWorkManager: 系统友好, 适合可接受一定延迟的非关键定时任务.\nJobScheduler: 旧实现, 仅用作兼容保留, 定时任务出现延迟的概率较大. 跳转设置页面失败 建议授予 \"允许设置闹钟和提醒\" 权限以确保定时任务在息屏或待机状态时尽可能准时执行 - 使用场景与差异说明: \n\n1. AlarmManager\n适用于准时性敏感的定时任务, 如 [提醒/严格定时脚本/...].\n在 Android 12+ 获取 \"允许设置闹钟和提醒\" 权限后, 在息屏或待机状态时能够较准时地执行定时任务.\n在未授予 \"允许设置闹钟和提醒\" 权限时, 系统可能降级为不准时或延后执行任务.\n\n2. WorkManager\n适用于不要求严格准时执行的定时任务, 如 [非关键性同步/清理/统计/...].\n根据系统 [ 电量/网络/充电情况/待机策略/... ] 进行调度, 息屏或待机状态时可能推迟任务执行.\n虽无法保证时间精确性, 但在 [ 可靠完成/失败重试/链式执行/唯一任务去重 ] 等方面拥有独特优势.\n\n3. Job\n历史实现, 为兼容保留.\n在高版本安卓系统中定时任务可能存在较大的延迟执行问题.\n除非出于兼容需要, 一般不推荐使用. + 使用场景与差异说明: \n\n1. AlarmManager\n适用于准时性敏感的定时任务, 如 [提醒/严格定时脚本/...].\n在 Android 12+ 获取 \"允许设置闹钟和提醒\" 权限后, 在息屏或待机状态时能够较准时地执行定时任务.\n在未授予 \"允许设置闹钟和提醒\" 权限时, 系统可能降级为不准时或延后执行任务.\n\n2. WorkManager\n适用于不要求严格准时执行的定时任务, 如 [非关键性同步/清理/统计/...].\n根据系统 [ 电量/网络/充电情况/待机策略/... ] 进行调度, 息屏或待机状态时可能推迟任务执行.\n虽无法保证时间精确性, 但在 [ 可靠完成/失败重试/链式执行/唯一任务去重 ] 等方面拥有独特优势.\n\n3. Job\n历史实现, 为兼容保留.\n在高版本安卓系统中定时任务可能存在较大的延迟执行问题.\n除非出于兼容需要, 一般不推荐使用. + 点击条目可查看详情 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 78f3e2d9..76a3de7c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -142,6 +142,7 @@ key_$_root_record_out_file_type key_$_root_record_out_file_type_binary key_$_root_record_out_file_type_js + key_$_scripts_after_app_restart key_$_server_address key_$_server_socket_normally_closed key_$_stable_mode @@ -1311,6 +1312,7 @@ Controls the underlying mechanism for triggering scripts on a schedule.\n\nAlarmManager: With the “Allow setting alarms and reminders” permission granted, scheduled tasks can fire closer to the exact time.\nWorkManager: System-friendly; suitable for non-critical tasks that can tolerate some delay.\nJobScheduler: Legacy implementation kept for compatibility; higher chance of delays. Failed to open the settings page Granting the “Allow setting alarms and reminders” permission is recommended to help tasks run as punctually as possible even when the screen is off or the device is idle - Use cases and differences:\n\n1) AlarmManager\nBest for time-sensitive tasks, e.g., [reminders/strictly scheduled scripts/...].\nOn Android 12+ with the “Allow setting alarms and reminders” permission, tasks can run more on time even when the screen is off or the device is idle.\nWithout it, the system may degrade exactness or delay execution.\n\n2) WorkManager\nBest for tasks that don’t require strict timing, e.g., [non-critical sync/cleanup/statistics/...].\nScheduling depends on [battery/network/charging/idle policies/...], so execution may be postponed when the screen is off or idle.\nWhile it can’t guarantee exact timing, it excels at [reliable completion/retries/chaining/unique work de-duplication].\n\n3) JobScheduler\nHistorical implementation for compatibility.\nOn newer Android versions, tasks may be delayed more noticeably.\nGenerally not recommended unless required for compatibility. + Use cases and differences:\n\n1. AlarmManager\nBest for time-sensitive tasks, e.g., [reminders/strictly scheduled scripts/...].\nOn Android 12+ with the “Allow setting alarms and reminders” permission, tasks can run more on time even when the screen is off or the device is idle.\nWithout it, the system may degrade exactness or delay execution.\n\n2. WorkManager\nBest for tasks that don’t require strict timing, e.g., [non-critical sync/cleanup/statistics/...].\nScheduling depends on [battery/network/charging/idle policies/...], so execution may be postponed when the screen is off or idle.\nWhile it can’t guarantee exact timing, it excels at [reliable completion/retries/chaining/unique work de-duplication].\n\n3. JobScheduler\nHistorical implementation for compatibility.\nOn newer Android versions, tasks may be delayed more noticeably.\nGenerally not recommended unless required for compatibility. + Click an item to view details diff --git a/modules/jieba-analysis/src/main/java/com/huaban/analysis/jieba/DictionaryDatabase.kt b/modules/jieba-analysis/src/main/java/com/huaban/analysis/jieba/DictionaryDatabase.kt index 7226ba16..e4c19a96 100644 --- a/modules/jieba-analysis/src/main/java/com/huaban/analysis/jieba/DictionaryDatabase.kt +++ b/modules/jieba-analysis/src/main/java/com/huaban/analysis/jieba/DictionaryDatabase.kt @@ -26,7 +26,9 @@ abstract class DictionaryDatabase internal constructor(context: Context): Closea SQLiteDatabase.openDatabase(context.getDatabasePath(databaseName).absolutePath, null, SQLiteDatabase.OPEN_READONLY) } - override fun close() = database.close() + override fun close() { + runCatching { database.close() } + } private fun copyDatabaseWithCompressionAndMd5(context: Context) { val dbFile = File(context.getDatabasePath(databaseName).path) diff --git a/version.properties b/version.properties index c3d96cfe..6f0c351f 100644 --- a/version.properties +++ b/version.properties @@ -1,5 +1,5 @@ -#Sun Nov 02 19:59:28 CST 2025 -BUILD_TIME=1762084768045 +#Mon Nov 03 13:14:49 CST 2025 +BUILD_TIME=1762146889031 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=3465 +VERSION_BUILD=3468 VERSION_NAME=6.7.0 Alpha10 VSCODE_EXT_REQUIRED_VERSION=1.0.8