uni-app需通过uts插件检测分身:android端比对context.getpackagename()与buildconfig.application_id、查询packagemanager包信息;鸿蒙端校验app.getinfo().bundlename与module.json5中module.name是否一致,js层api无法识别分身。

uni-app 如何检测应用是否被分身?
鸿蒙和 Android 系统本身不提供「当前 App 是否被分身」的直接 API,但可通过间接线索判断——核心依据是 package name 和 content provider authorities 的一致性。分身 App 通常通过修改这两个字段实现共存,而原生运行环境(如 Context.getPackageName()、BuildConfig.APPLICATION_ID)仍返回原始值,导致行为割裂。
在 uni-app 中,无法直接读取这些原生值,必须通过 UTS 插件桥接。例如:在 Android 端用 UTS 调用 context.getPackageName(),再与 manifest 中预设的「合法包名」比对;若不一致,大概率已被篡改或分身。
- 仅靠 JS 层的
uni.getSystemInfoSync().platform或uni.getAppBaseInfo()无法识别分身,它们返回的是运行时环境信息,不是安装标识 - 鸿蒙侧需额外检查
bundleName(来自app.getInfo().bundleName)是否与 module.json5 中声明的module.name一致 - 真机测试时,部分分身工具(如 Parallel Space、多开助手)会劫持
Application初始化流程,导致getPackageName()返回分身后的值,此时需结合PackageManager查询已安装包列表做交叉验证
Android 分身检测的 UTS 实现要点
UTS 是目前 uni-app 在 App 端做深度安全检测的唯一可控出口。检测逻辑不能只依赖单点值,要组合多个可信源:
- 调用
android.content.pm.PackageManager.getPackageInfo(packageName, 0)获取当前进程实际安装的packageName,对比context.getPackageName() - 检查
android.app.ActivityThread.currentApplication().getPackageName()—— 这个值更难被分身框架覆盖 - 读取
BuildConfig.APPLICATION_ID(需确保插件编译时未被混淆或替换),它由 gradle 构建时注入,分身工具通常无法动态修改 - 避免使用
getPackageName()+ 字符串拼接的方式校验 provider authorities,应直接解析context.getPackageManager().resolveContentProvider("xxx", 0)的返回结果
为什么 uni-app 自带 API 无法用于分身检测?
uni-app 的 uni.getSystemInfoSync()、uni.getAppBaseInfo()、uni.getProvider() 等接口,底层均基于标准平台能力封装,不暴露安装包元数据。它们的设计目标是跨平台一致性,而非安全审计。
例如:uni.getAppBaseInfo() 在 Android 上返回的是 applicationId(构建时确定),但这个值可能已被分身工具在 dex 插桩阶段静态替换;而 getPackageName() 返回的是运行时加载的真正包名,二者差异才是关键信号。
- 所有 JS 层可访问的设备/应用信息,都经过 uni-app runtime 层过滤和标准化,天然丢失了原始安装上下文
- 插件市场中所谓「防多开」「防分身」的免费插件,90% 仅检测后台进程数或 Activity 栈深度,完全无效
- 真正有效的检测必须下沉到 UTS 或原生模块,且需签名验证(如校验 APK 签名哈希是否匹配发布证书)来防绕过
分身检测与安全加固的边界在哪?
检测出分身只是第一步,后续动作必须谨慎:强制退出、清空本地存储、上报风控系统,这些都需要服务端配合策略。单纯前端拦截极易被逆向绕过。
尤其要注意,检测逻辑本身不能成为攻击入口——比如把「合法包名」硬编码在 JS 里,或通过明文 HTTP 请求校验签名,都会让整个机制失效。
- 包名校验字符串必须放在 UTS 编译后的 .so/.jar 中,且建议用异或或 base64 混淆,避免被字符串搜索直接定位
- 鸿蒙侧的
bundleManager.getBundleInfoForSelf()返回的bundleName可信度高于 Android 的getPackageName(),但需注意 API 9+ 才支持 - 不要依赖「检测到分身就禁止登录」这种简单策略,真实业务中需结合设备指纹、行为时序、网络环境做联合判定











