|
|
本帖最后由 Ω SS!W I 于 2026-4-1 05:45 编辑
打工人中的牛马,一周10个版本,才刚上线,没想到这么快就要离开了,你永远也不会知道明天会发生什么。因为明天是早八 。
目前通过开发者选项模拟位置的方案已基本实现,虽然在防检测方面相比其他APP还有提升空间,但也在尽力优化,非常欢迎大家分享更好的思路,一起交流进步。
下面简单说说技术实现,其实逻辑并不复杂:
我们通过自定义 Service 服务(LocationService)来模拟位置,利用该服务定时上报位置信息。之所以选择 Service 的定时器而非普通定时器,主要是为了保活。因为系统 GPS 本身会不断获取并更新真实位置,如果模拟的位置提交不够频繁,就容易被真实位置覆盖,导致位置“跳回”。
保活的作用,正是通过持续、快速地向系统提交模拟位置,在频率上抢占优势,从而维持位置模拟的效果。简单来说,就是:你更新没关系,我比你更快就行。
稳定性:前台服务(Notification)+后台保活
所以模拟的稳定性取决于软件在后台的存活率,建议忽略电池优化。
成功率:采用双模式策略:
系统接口模式:使用 addTestProvider / setTestProviderLocation 等官方API,通常需要在开发者选项中开启“允许模拟位置”。
反射模式:通过反射直接设置Location对象的 mIsFromMockProvider 等内部标记,试图让定位结果更“真实”,以绕过某些检测。
可动态切换模式,反射失败时自动回退到系统接口。这可以显著提高模拟成功率。但是开发者选项模拟绝不是长久之计。很容易被检测不说,有效性也并不高,这是显而易见的。
既然有了服务类来提交定时位置,那么实现路线模拟也就简单了,LocationService(上报服务)与MockRouter(路线计算与上报)协同工作,这种分离式设计可以很方便的维护与拓展。在MockRouter类中通过Haversine公式计算两个坐标之间的距离,
- public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
- final int R = 6371; // 地球半径(公里)
- double dLat = Math.toRadians(lat2 - lat1);
- double dLon = Math.toRadians(lon2 - lon1);
- double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
- Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
- Math.sin(dLon/2) * Math.sin(dLon/2);
- double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
- return R * c; // 返回公里数
- }
复制代码
然后根据距离与时间,将两点间的坐标细分成多个坐标,然后只需要依次提交这些坐标点,就能实现路线模拟了,是不是超简单。
然后就是ROOT方案,当然现在并未实现,只是一个灰度版本1.1.0,大多数设备是无法使用的,鉴于各个厂商,各个版本的ADB SHELL都多多少少被魔改过,所以适配起来很麻烦,所以我打算暂时不考虑开发纯ROOT方案,或者有没有有更好的纯ROOT方案或者开源项目供我研究一下。考虑到LSP基于框架的模块兼容性较强,目前仅考虑基于xposed的方案。在线征集各种技术。
|
|