6.7.0 - Alpha11 - 新增 app.isDualInstalled 方法, 用于检测双开应用是否已安装 (需要 Shizuku 或 Root 权限) (issue #450)

This commit is contained in:
SuperMonster003
2025-11-20 16:22:05 +08:00
parent e8f3fbdb5b
commit e393ffc353
14 changed files with 236 additions and 95 deletions

View File

@@ -1,7 +1,7 @@
{
"$data": {
"v6.7.0": {
"released_date": "2025/11/19",
"released_date": "2025/11/20",
"feature": [
"cvt 模块, 用于数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))",
"fmt 模块, 用于数据格式化 (参阅 项目文档 > [格式化](https://docs.autojs6.com/#/fmt))",
@@ -10,6 +10,7 @@
"cvt.bytes 方法, 用于字节数据单位转换 (参阅 项目文档 > [单位转换](https://docs.autojs6.com/#/cvt))",
"fmt.bytes 方法, 用于字节数据格式化 (参阅 项目文档 > [数据格式化](https://docs.autojs6.com/#/fmt))",
"s13n.bytes 方法, 用于标准化字节数据 (参阅 项目文档 > [标准化](https://docs.autojs6.com/#/s13n))",
"app.isDualInstalled 方法, 用于检测双开应用是否已安装 (需要 Shizuku 或 Root 权限) _[`issue #450`](http://issues.autojs6.com/450)_",
"device.getSharedDeviceId 方法, 用于跨应用获取统一共享设备 ID _[`issue #455`](http://issues.autojs6.com/455)_",
"ui.navigationBarHeight 属性 (getter), 用于获取导航栏高度 _[`issue #456`](http://issues.autojs6.com/456)_",
"http 模块请求相关方法获取的 body 对象增加 stream/saveToFile/close 方法 _[`issue #452`](http://issues.autojs6.com/452)_",
@@ -31,7 +32,7 @@
"notice 方法参数数量及类型限制错误 _[`issue #462`](http://issues.autojs6.com/462)_",
"isJavaClass/isJavaPackage 等全局方法无效的问题",
"timers.keepAlive 方法 timeout 参数功能无效的问题",
"floaty.window/rawWindow 方法无法接受字符串参数的问题",
"floaty.window/rawWindow 方法无法接受字符串参数的问题 _[`issue #467`](http://issues.autojs6.com/467)_",
"util.class[Name]/getClass[Name] 可能返回错误结果的问题",
"threads.disposable() 返回的对象在存取数据时可能被意外装箱的问题 _[`issue #435`](http://issues.autojs6.com/435)_",
"console.build 方法多次调用时, 日志浮动窗口样式选项未能正常重置的问题",
@@ -47,7 +48,7 @@
"images 部分相关方法出现异常时 oneShot 标记功能失效的问题 _[`issue #372`](http://issues.autojs6.com/372)_",
"images 部分相关方法可能引发内存泄露的问题 _[`issue #372`](http://issues.autojs6.com/372)_",
"ocr 部分重载方法可能无法正常使用的问题",
"ocr.detect 方法获得的结果可能与 ocr.mode 不匹配的问题",
"ocr.detect 方法获得的结果可能与 ocr.mode 不匹配的问题 _[`issue #468`](http://issues.autojs6.com/468)_",
"Android 10 UiObject#child 方法可能出现 ArrayIndexOutOfBoundsException 异常的问题 _[`issue #416`](http://issues.autojs6.com/416)_",
"运行项目时 project.json 配置参数无法正常解析的问题",
"项目配置文件中构建版本号或构建时间出现较大数字时可能导致应用崩溃的问题",
@@ -66,6 +67,7 @@
"ui.statusBarHeight 属性 (getter) 增强一定程度的兼容性",
"console.log 等方法打印全局对象 (images, app, ocr 等) 时支持显示详细信息",
"android.graphics.Paint#setColor 支持正常解析 ColorInt/ColorHex/ColorName 等颜色参数",
"app.launchDual/startDualActivity 等方法提升执行效率并增强兼容性",
"内置模块相关方法实参类型的异常消息增加类型摘要信息",
"控制台浮动窗口倒计时起始值由 6 秒增加到 9 秒",
"控制台浮动窗口内部实现进行无锁化及队列化处理以提升其参数设置效率与成功率",

View File

@@ -15,6 +15,8 @@ import org.autojs.autojs.annotation.RhinoRuntimeFunctionInterface
import org.autojs.autojs.extension.AnyExtensions.isJsNullish
import org.autojs.autojs.extension.AnyExtensions.jsBrief
import org.autojs.autojs.extension.FlexibleArray
import org.autojs.autojs.extension.FlexibleArray.Companion.component1
import org.autojs.autojs.extension.FlexibleArray.Companion.component2
import org.autojs.autojs.extension.ScriptableExtensions.defineProp
import org.autojs.autojs.extension.ScriptableExtensions.deleteProp
import org.autojs.autojs.extension.ScriptableExtensions.prop
@@ -22,10 +24,14 @@ import org.autojs.autojs.extension.ScriptableObjectExtensions.inquire
import org.autojs.autojs.external.receiver.BaseBroadcastReceiver
import org.autojs.autojs.ipc.LayoutInspectEventBus
import org.autojs.autojs.runtime.ScriptRuntime
import org.autojs.autojs.runtime.api.AbstractShell
import org.autojs.autojs.runtime.api.AppUtils.Companion.ActivityShortForm
import org.autojs.autojs.runtime.api.AppUtils.Companion.BroadcastShortForm
import org.autojs.autojs.runtime.api.WrappedShizuku
import org.autojs.autojs.runtime.api.augment.Augmentable
import org.autojs.autojs.runtime.api.augment.app.App.Companion.ShellAction.Companion.toFallbackShellAction
import org.autojs.autojs.runtime.api.augment.app.App.Companion.ShellAction.Companion.toRootShellAction
import org.autojs.autojs.runtime.api.augment.app.App.Companion.ShellAction.Companion.toShizukuShellAction
import org.autojs.autojs.runtime.api.augment.shell.Shell
import org.autojs.autojs.runtime.exception.ShouldNeverHappenException
import org.autojs.autojs.runtime.exception.WrappedIllegalArgumentException
@@ -82,6 +88,8 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
::launchDualSettings.name to AS_GLOBAL,
::openAppSetting.name to AS_GLOBAL,
::openDualAppSetting.name to AS_GLOBAL,
::isInstalled.name to AS_GLOBAL,
::isDualInstalled.name to AS_GLOBAL,
::uninstall.name to AS_GLOBAL,
::uninstallDual.name to AS_GLOBAL,
::viewFile.name,
@@ -140,14 +148,14 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
options is NativeObject -> obj.configure(scriptRuntime, options).let { configuredIntent ->
when {
checkDualProperty(options) -> startDualActivity(scriptRuntime, args)
checkRootProperty(options) && RootUtils.isRootAvailable() -> {
val tmpIntent = configuredIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Shell.execCommand(scriptRuntime, arrayOf<Any>("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
}
checkShizukuProperty(options) && WrappedShizuku.isOperational() -> {
checkShizukuProperty(options) -> {
val tmpIntent = configuredIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
WrappedShizuku.execCommand("am start ${intentToShellRhino(tmpIntent)}").throwIfError()
}
checkRootProperty(options) -> {
val tmpIntent = configuredIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
Shell.execCommand(scriptRuntime, arrayOf<Any>("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
}
else -> startActivityWithGlobalContext(configuredIntent)
}
}
@@ -165,15 +173,15 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
}
when {
checkDualProperty(opt) -> startDualActivity(scriptRuntime, args)
checkRootProperty(opt) && RootUtils.isRootAvailable() -> {
val tmpIntent = intentRhinoWithRuntime(scriptRuntime, opt).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
Shell.execCommand(scriptRuntime, arrayOf<Any>("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
}
checkShizukuProperty(opt) && WrappedShizuku.isOperational() -> {
checkShizukuProperty(opt) -> {
val tmpIntent = intentRhinoWithRuntime(scriptRuntime, opt).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
val intentCommand = intentToShellRhino(tmpIntent)
WrappedShizuku.execCommand("am start $intentCommand").throwIfError()
}
checkRootProperty(opt) -> {
val tmpIntent = intentRhinoWithRuntime(scriptRuntime, opt).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
Shell.execCommand(scriptRuntime, arrayOf<Any>("am start ${intentToShellRhino(tmpIntent)}", /* withRoot = */ true)).throwIfError()
}
else -> startActivityWithGlobalContext(scriptRuntime, opt)
}
}
@@ -775,12 +783,13 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
@RhinoRuntimeFunctionInterface
fun kill(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLength(args, 1) { argList ->
val packageName = getPackageName(scriptRuntime, argList) ?: return@ensureArgumentsLength false
val command = "am force-stop $packageName"
when {
RootUtils.isRootAvailable() -> Shell.execCommand(scriptRuntime, arrayOf<Any>(command, /* withRoot = */ true))
WrappedShizuku.isOperational() -> WrappedShizuku.execCommand(command)
else -> Shell.execCommand(scriptRuntime, arrayOf<Any>(command, /* withRoot = */ false))
}.code == 0
with("am force-stop $packageName") {
listOf(
toShizukuShellAction(),
toRootShellAction(scriptRuntime),
toFallbackShellAction(scriptRuntime),
).first { it.condition() }.execute().code == 0
}
}
// @Hint by SuperMonster003 on Oct 30, 2024.
@@ -792,7 +801,30 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
fun killDual(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsLength(args, 1) { argList ->
val packageName = getPackageName(scriptRuntime, argList) ?: return@ensureArgumentsLength false
val command = "am force-stop $packageName"
runCatching { execCommandForDualUser(scriptRuntime, command, RootUtils.isRootAvailable(), WrappedShizuku.isOperational()) }.isSuccess
runCatching { execCommandForDualUser(scriptRuntime, command) }.isSuccess
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun isInstalled(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsOnlyOne(args) { o ->
val packageName = getPackageName(scriptRuntime, arrayOf(o)) ?: return@ensureArgumentsOnlyOne false
scriptRuntime.app.isInstalled(packageName)
}
@JvmStatic
@RhinoRuntimeFunctionInterface
fun isDualInstalled(scriptRuntime: ScriptRuntime, args: Array<out Any?>): Boolean = ensureArgumentsOnlyOne(args) { o ->
val packageName = getPackageName(scriptRuntime, arrayOf(o)) ?: return@ensureArgumentsOnlyOne false
isDualInstalledInternal(scriptRuntime, packageName)
}
private fun isDualInstalledInternal(scriptRuntime: ScriptRuntime, packageName: String): Boolean {
val command = "cmd package list packages %USER_ID% $packageName"
return runCatching {
execCommandForDualUser(scriptRuntime, command)?.let { result ->
result.code == 0 && result.result.contains("package:$packageName")
} ?: false
}.getOrElse { false }
}
private fun parseClassName(o: NativeObject): String {
@@ -890,16 +922,16 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
val intent = intentRhinoWithRuntime(scriptRuntime, o).apply { addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
val command = "am start ${intentToShellRhino(intent)}"
when (o) {
is NativeObject -> {
val withRoot = o.inquire("root", ::coerceBoolean, true)
val withShizuku = o.inquire("shizuku", ::coerceBoolean, true)
execCommandForDualUser(scriptRuntime, command, withRoot, withShizuku)
}
is NativeObject -> execCommandForDualUser(scriptRuntime, command, o)
else -> execCommandForDualUser(scriptRuntime, command)
}
}
private fun execCommandForDualUser(scriptRuntime: ScriptRuntime, command: String, withRoot: Boolean = true, withShizuku: Boolean = true) {
private fun execCommandForDualUser(
scriptRuntime: ScriptRuntime,
command: String,
options: NativeObject? = null,
): AbstractShell.Result? {
val userManager = globalContext.getSystemService(Class.forName("android.os.UserManager"))
val getUserProfilesMethod = userManager.javaClass.getDeclaredMethod("getUserProfiles")
@@ -911,19 +943,46 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
val userHandleClass = Class.forName("android.os.UserHandle")
val getIdentifierMethod = userHandleClass.getDeclaredMethod("getIdentifier")
val processUserIdentifier = getIdentifierMethod.invoke(processUserHandle) as Int
val currentUserId = getIdentifierMethod.invoke(processUserHandle) as Int
var lastResult: AbstractShell.Result? = null
@Suppress("LocalVariableName")
for (userHandle in userProfiles) {
val currentUserIdentifier = getIdentifierMethod.invoke(userHandle) as Int
if (currentUserIdentifier != processUserIdentifier) {
val niceCommand = "$command --user $currentUserIdentifier"
when {
withRoot && RootUtils.isRootAvailable() -> Shell.execCommand(scriptRuntime, arrayOf<Any>(niceCommand, /* withRoot = */ true))
withShizuku && WrappedShizuku.isOperational() -> WrappedShizuku.execCommand(niceCommand)
else -> Shell.execCommand(scriptRuntime, arrayOf<Any>(niceCommand, /* withRoot = */ false))
}.throwIfError()
val uid = getIdentifierMethod.invoke(userHandle) as Int
if (uid == currentUserId) continue
val cmd = when {
command.contains("%USER_ID%") -> command.replace("%USER_ID%", "--user $uid")
Regex("""\s--user\s+\d+""").containsMatchIn(command) -> command
else -> "$command --user $uid"
}
val shizuku = cmd.toShizukuShellAction()
val root = cmd.toRootShellAction(scriptRuntime)
val fallback = cmd.toFallbackShellAction(scriptRuntime)
val SRF = listOf(shizuku, root, fallback)
val RSF = listOf(root, shizuku, fallback)
val actions = when (options) {
is NativeObject -> {
val preferShizuku = options.prop("shizuku").takeUnless { it.isJsNullish() }?.let { coerceBoolean(it) }
val preferRoot = options.prop("root").takeUnless { it.isJsNullish() }?.let { coerceBoolean(it) }
when (preferShizuku) {
null -> if (preferRoot == true) RSF else SRF
true -> SRF
else -> if (preferRoot == false) SRF else RSF
}
}
else -> SRF
}
if (actions.first { it.condition() }.execute().also { lastResult = it }.code == 0) {
break
}
}
return lastResult?.apply { throwIfError() }
}
private fun getAppByAliasRhino(o: Any?): PresetApp? {
@@ -953,11 +1012,11 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
})
}
private fun checkRootProperty(o: NativeObject) = o.inquire("root", ::coerceBoolean, false)
private fun checkDualProperty(o: NativeObject) = o.inquire("dual", ::coerceBoolean, false)
private fun checkShizukuProperty(o: NativeObject) = o.inquire("shizuku", ::coerceBoolean, false) && WrappedShizuku.isOperational()
private fun checkDualProperty(o: NativeObject) = o.inquire("dual", ::coerceBoolean, false)
private fun checkRootProperty(o: NativeObject) = o.inquire("root", ::coerceBoolean, false) && RootUtils.isRootAvailable()
private fun Intent.configure(scriptRuntime: ScriptRuntime, o: NativeObject): Intent {
val intent = this
@@ -1055,6 +1114,18 @@ class App(scriptRuntime: ScriptRuntime) : Augmentable(scriptRuntime) {
return intent
}
private data class ShellAction(val cmd: String, val condition: () -> Boolean, private val action: (cmd: String) -> AbstractShell.Result) {
fun execute() = action(cmd)
companion object {
fun String.toShizukuShellAction() = ShellAction(this, { WrappedShizuku.isOperational() }, { WrappedShizuku.execCommand(it) })
fun String.toRootShellAction(scriptRuntime: ScriptRuntime) = ShellAction(this, { RootUtils.isRootAvailable() }, { Shell.execCommand(scriptRuntime, arrayOf<Any>(it, /* withRoot = */ true)) })
fun String.toFallbackShellAction(scriptRuntime: ScriptRuntime) = ShellAction(this, { true }, { Shell.execCommand(scriptRuntime, arrayOf<Any>(it, /* withRoot = */ false)) })
}
}
}
}

View File

@@ -1,26 +1,132 @@
package org.autojs.autojs.util;
import androidx.annotation.NonNull;
import com.stericson.RootShell.RootShell;
import org.autojs.autojs.core.pref.Pref;
import org.autojs.autojs6.R;
import java.io.File;
import java.text.MessageFormat;
import java.util.HashSet;
import java.util.Set;
import static org.autojs.autojs.util.StringUtils.getStringByLanguageTag;
import static org.autojs.autojs.util.StringUtils.key;
import static org.autojs.autojs.util.StringUtils.str;
import androidx.annotation.NonNull;
import com.stericson.RootShell.RootShell;
import org.autojs.autojs.core.pref.Pref;
import org.autojs.autojs6.R;
import java.text.MessageFormat;
/**
* Created by Stardust on Jan 26, 2018.
* Modified by SuperMonster003 as of March 10, 2022.
*/
public class RootUtils {
private static final String[] COMMON_SU_PATHS = new String[]{
"/system/xbin/su",
"/system/bin/su",
"/vendor/bin/su",
"/system_ext/bin/su",
"/odm/bin/su",
"/sbin/su",
"/su/bin/su",
"/system/su"
};
private static String runtimeOverriddenRootMode = RootMode.AUTO_DETECT.key;
public static void setRootMode(RootMode mode, boolean isWriteInfoPreference) {
if (isWriteInfoPreference) {
Pref.setRootMode(mode);
} else {
runtimeOverriddenRootMode = mode.key;
}
}
public static void resetRuntimeOverriddenRootModeState() {
runtimeOverriddenRootMode = RootMode.AUTO_DETECT.key;
}
public static RootMode getRootMode() {
if (runtimeOverriddenRootMode.equals(RootMode.AUTO_DETECT.key)) {
return Pref.getRootMode();
}
return RootMode.getRootMode(runtimeOverriddenRootMode);
}
public static void setRootMode(RootMode mode) {
setRootMode(mode, false);
}
public static boolean isRootAvailable() {
RootMode rootMode = getRootMode();
return rootMode == RootMode.AUTO_DETECT
? isSuPresentFast() || getRootStateWithRootShell()
: rootMode == RootMode.FORCE_ROOT;
}
private static boolean isSuPresentFast() {
try {
// 1. Check common su paths.
// zh-CN: 1. 检查常见 su 路径.
for (String path : COMMON_SU_PATHS) {
if (isExecutableFile(path)) {
return true;
}
}
// 2. Check su in PATH environment.
// zh-CN: 2. 检查 PATH 环境中的 su.
String envPath = System.getenv("PATH");
if (envPath != null && !envPath.isEmpty()) {
String[] paths = envPath.split(":");
Set<String> uniq = new HashSet<>();
for (String p : paths) {
if (p == null || p.isEmpty()) continue;
if (!uniq.add(p)) continue;
String su = (p.endsWith("/") ? p : (p + "/")) + "su";
if (isExecutableFile(su)) {
return true;
}
}
}
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
private static boolean isExecutableFile(String absolutePath) {
File f = new File(absolutePath);
if (!(f.exists() && f.isFile())) return false;
// Quick check using File.canExecute().
// zh-CN: 先用 File.canExecute() 快速判定.
if (f.canExecute()) {
return true;
}
// Try an equivalent check using Os.access (using reflection to avoid class resolution issues).
// zh-CN: 再尝试一次 Os.access 的等效判定 (使用反射避免类解析问题).
try {
Class<?> osClass = Class.forName("android.system.Os");
Class<?> osConstantsClass = Class.forName("android.system.OsConstants");
int xOk = osConstantsClass.getField("X_OK").getInt(null);
osClass.getMethod("access", String.class, Integer.TYPE).invoke(null, absolutePath, xOk);
return true;
} catch (Throwable ignored) {
// Reflection failed or class/method/field not found, consider as non-executable.
// zh-CN: 反射失败或无此类/方法/字段, 视为不可执行.
}
return false;
}
private static boolean getRootStateWithRootShell() {
try {
return RootShell.isRootAvailable();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
public enum RootMode {
FORCE_ROOT(key(R.string.key_root_mode_force_root), getStringByLanguageTag(R.string.entry_root_mode_force_root, "en")),
FORCE_NON_ROOT(key(R.string.key_root_mode_force_non_root), getStringByLanguageTag(R.string.entry_root_mode_force_non_root, "en")),
@@ -50,43 +156,5 @@ public class RootUtils {
}
public static void setRootMode(RootMode mode) {
setRootMode(mode, false);
}
public static void setRootMode(RootMode mode, boolean isWriteInfoPreference) {
if (isWriteInfoPreference) {
Pref.setRootMode(mode);
} else {
runtimeOverriddenRootMode = mode.key;
}
}
public static void resetRuntimeOverriddenRootModeState() {
runtimeOverriddenRootMode = RootMode.AUTO_DETECT.key;
}
public static RootMode getRootMode() {
if (runtimeOverriddenRootMode.equals(RootMode.AUTO_DETECT.key)) {
return Pref.getRootMode();
}
return RootMode.getRootMode(runtimeOverriddenRootMode);
}
public static boolean isRootAvailable() {
RootMode rootMode = getRootMode();
return rootMode == RootMode.AUTO_DETECT
? getRootStateWithRootShell()
: rootMode == RootMode.FORCE_ROOT;
}
private static boolean getRootStateWithRootShell() {
try {
return RootShell.isRootAvailable();
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}

View File

@@ -932,7 +932,7 @@
<string name="text_result">نتيجة</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">قم بإلغاء الوصول إلى AutoJs6 في تطبيق Shizuku</string>
<string name="text_rhino_java_primitive_wrap">تغليف الأنواع البدائية في Java</string>
<string name="text_root_mode_title">فحص الجذر مجموعة القوة</string>
<string name="text_root_mode_title">التحقق من صلاحيات الروت</string>
<string name="text_run">يجري</string>
<string name="text_run_on_battery_change">على البطارية تغيرت</string>
<string name="text_run_on_boot">على التمهيد</string>

View File

@@ -927,7 +927,7 @@
<string name="text_result">Result</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">Revoke AutoJs6 access in Shizuku app</string>
<string name="text_rhino_java_primitive_wrap">Java primitive wrapping</string>
<string name="text_root_mode_title">Force set root check</string>
<string name="text_root_mode_title">Root access check</string>
<string name="text_run">Run</string>
<string name="text_run_on_battery_change">On battery changed</string>
<string name="text_run_on_boot">On booted</string>

View File

@@ -930,7 +930,7 @@
<string name="text_result">Resultado</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">Revocar privilegios de AutoJs6 en una aplicación Shizuku</string>
<string name="text_rhino_java_primitive_wrap">Envoltorio de primitivos de Java</string>
<string name="text_root_mode_title">Forzar la comprobación de root</string>
<string name="text_root_mode_title">Comprobación de acceso root</string>
<string name="text_run">Ejecutar</string>
<string name="text_run_on_battery_change">Al cambiar la batería</string>
<string name="text_run_on_boot">Al arrancar</string>

View File

@@ -930,7 +930,7 @@
<string name="text_result">Résultat</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">Révoquer les privilèges AutoJs6 dans une application Shizuku</string>
<string name="text_rhino_java_primitive_wrap">Encapsulation des types primitifs Java</string>
<string name="text_root_mode_title">Force set root check</string>
<string name="text_root_mode_title">Vérification de l\'accès root</string>
<string name="text_run">Exécuter</string>
<string name="text_run_on_battery_change">Sur changement de batterie</string>
<string name="text_run_on_boot">Sur démarrage</string>

View File

@@ -931,7 +931,7 @@
<string name="text_result">結果</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">Shizuku アプリケーションで AutoJs6 権限を取り消す</string>
<string name="text_rhino_java_primitive_wrap">Java プリミティブ型のラップ</string>
<string name="text_root_mode_title">強制的に root にするチェック</string>
<string name="text_root_mode_title">Root 権限の確認</string>
<string name="text_run">実行</string>
<string name="text_run_on_battery_change">バッテリー交換時</string>
<string name="text_run_on_boot">起動したとき</string>

View File

@@ -932,7 +932,7 @@
<string name="text_result">결과</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">Shizuku 애플리케이션에서 AutoJs6 권한 취소하기</string>
<string name="text_rhino_java_primitive_wrap">Java 원시 타입 래핑</string>
<string name="text_root_mode_title">강제 설정 루트 검사</string>
<string name="text_root_mode_title">루트 권한 확인</string>
<string name="text_run">운영</string>
<string name="text_run_on_battery_change">배터리가 변경되었습니다</string>
<string name="text_run_on_boot">부팅</string>

View File

@@ -930,7 +930,7 @@
<string name="text_result">Результат</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">Отмена привилегий AutoJs6 в приложении Shizuku</string>
<string name="text_rhino_java_primitive_wrap">Обёртка примитивов Java</string>
<string name="text_root_mode_title">Проверка принудительной установки root</string>
<string name="text_root_mode_title">Проверка прав root</string>
<string name="text_run">Запустить</string>
<string name="text_run_on_battery_change">При смене батареи</string>
<string name="text_run_on_boot">При загрузке</string>

View File

@@ -928,7 +928,7 @@
<string name="text_result">結果</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">在 Shizuku 應用中撤銷 AutoJs6 權限</string>
<string name="text_rhino_java_primitive_wrap">Java 原始類型包裝</string>
<string name="text_root_mode_title">強制 Root 權限檢查</string>
<string name="text_root_mode_title">Root 權限檢查</string>
<string name="text_run">運行</string>
<string name="text_run_on_battery_change">電量變化時</string>
<string name="text_run_on_boot">開機時</string>

View File

@@ -928,7 +928,7 @@
<string name="text_result">結果</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">在 Shizuku 應用中撤銷 AutoJs6 許可權</string>
<string name="text_rhino_java_primitive_wrap">Java 原始型別包裝</string>
<string name="text_root_mode_title">強制 Root 許可權檢查</string>
<string name="text_root_mode_title">Root 許可權檢查</string>
<string name="text_run">執行</string>
<string name="text_run_on_battery_change">電量變化時</string>
<string name="text_run_on_boot">開機時</string>

View File

@@ -928,7 +928,7 @@
<string name="text_result">结果</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">在 Shizuku 应用中撤销 AutoJs6 权限</string>
<string name="text_rhino_java_primitive_wrap">Java 原始类型包装</string>
<string name="text_root_mode_title">强制 Root 权限检查</string>
<string name="text_root_mode_title">Root 权限检查</string>
<string name="text_run">运行</string>
<string name="text_run_on_battery_change">电量变化时</string>
<string name="text_run_on_boot">开机时</string>

View File

@@ -1181,7 +1181,7 @@
<string name="text_result">Result</string>
<string name="text_revoke_autojs6_access_in_shizuku_app">Revoke AutoJs6 access in Shizuku app</string>
<string name="text_rhino_java_primitive_wrap">Java primitive wrapping</string>
<string name="text_root_mode_title">Force set root check</string>
<string name="text_root_mode_title">Root access check</string>
<string name="text_run">Run</string>
<string name="text_run_on_battery_change">On battery changed</string>
<string name="text_run_on_boot">On booted</string>