必须用原生能力检测:安卓端查su文件路径及build.tags是否含test-keys,ios端查cydia目录、越狱dylib和环境变量dyld_insert_libraries。

不能靠 uni.getSystemInfo 或任何 H5 层 API 判断 Root/越狱状态——这些接口根本接触不到系统底层,返回值全是无效的。真要检测,必须用原生能力,在 App 端(仅限 iOS/Android 打包)执行文件扫描、命令调用或系统属性检查。
安卓端检测 Root:查文件 + 查 build.tags
最常用且兼容性较好的方式是组合判断:/system/bin/su、/system/xbin/su 等路径是否存在,再看 Build.TAGS 是否含 test-keys。
-
plus.android.invoke或plus.android.importClass('android.os.Build')可读取Build.TAGS -
new plus.io.File().exists('/system/bin/su')能判断 su 文件是否存在(注意权限,部分 ROM 会拦截) - 额外可查常见 Root 应用包名:
com.topjohnwu.magisk、eu.chainfire.supersu,用plus.runtime.isApplicationExist({pname: 'xxx'}) - 不建议直接执行
su -c id:用户可能已隐藏 su,或 Magisk 启用了 Zygisk 隐藏模式,命令会静默失败或被拦截
iOS 端检测越狱:查目录 + 查 dylib + 查环境变量
iOS 没有统一 Root 概念,但越狱设备有明显痕迹。关键不是“有没有越狱”,而是“能不能绕过沙箱限制”——所以检测点集中在系统完整性破坏迹象上。
- 用
plus.ios.invoke调用stat("/Applications/Cydia.app", &stat_info)判断 Cydia 是否存在 - 检查
/Library/MobileSubstrate/MobileSubstrate.dylib或/usr/lib/libsubstrate.dylib是否可读 - 读取环境变量:
getenv("DYLD_INSERT_LIBRARIES")若非空,大概率已注入动态库 - 慎用
dladdr检查系统库路径:iOS 15+ 对符号解析更严格,部分越狱方案已绕过该检测
为什么 uni-app 里不能只写 JS 就完成检测
所有可靠的 Root/越狱检测都依赖原生接口,而 uni-app 的 JS 层无法直接访问:
-
plus.android和plus.ios必须在plus.ready后才能调用,否则对象为undefined - Webview 层完全隔离,
fetch、XMLHttpRequest、FileReader均无法读取系统路径 - 云打包时若未启用 Native.js 支持,
plus.*调用会静默失败,需在 manifest.json 中确认勾选「Native.js 支持」 - Magisk Hide / KernelSU 的隐藏策略会让多数静态检测失效,纯客户端检测天然存在被绕过的可能
真正上线的应用,检测逻辑得和后端风控联动——客户端只做轻量级特征采集(如 su 文件存在、build.tags 异常),关键判定应由服务端结合设备指纹、行为日志等综合决策。单独依赖前端检测,既不准,也容易被针对性绕过。











