16、位置模拟:Android模拟器位置发送、DDMS与命令行模拟、测试工具推荐
位置模拟,说白了就是「骗」你的App,让它以为手机在某个地方。
我刚开始做LBS(基于位置的服务)开发时,觉得这功能可有可无。直到有一次,我需要在室内调试一个骑行导航App,GPS死活搜不到星……嗯,从那以后,我再也不敢轻视位置模拟了。
为什么需要位置模拟?
你想想看,真实场景下测试位置功能有多麻烦:
- 你要跑到某个坐标点去测
- 信号不好时,GPS定位飘忽不定
- 跨国场景下,你总不能飞过去测吧?
位置模拟就是解决这些痛点的。它让你坐在工位上,就能模拟全球任意地点的定位数据。
一、Android模拟器位置发送
这是最基础的方式。Android自带的模拟器(AVD)就支持位置模拟。
1. 通过模拟器扩展控件发送
启动模拟器后,右侧工具栏有个「…」按钮,点开找到Location选项卡。这里你可以:
- 输入经纬度,点Send
- 导入GPX文件模拟路线
- 导入KML文件模拟地理围栏
我个人习惯用GPX文件做路线模拟。比如测试外卖App的配送轨迹,我会先录一段真实骑行路线,导出GPX,然后导入模拟器。这样测出来的效果跟真机几乎一样。
2. 通过命令行发送
如果你跟我一样喜欢命令行操作,可以用telnet连接模拟器:
telnet localhost 5554
geo fix 116.397128 39.916527
geo fix 116.397128 39.916527 100 10 5
最后一行参数分别是:经度、纬度、海拔(米)、速度(节)、方向(度)。
为什么要用命令行?我在自动化测试脚本里经常这么干——跑一个循环,每5秒换一个坐标,模拟车辆行驶轨迹。比手动点Send高效多了。
二、DDMS与命令行模拟
DDMS(Dalvik Debug Monitor Server)是Android老牌调试工具。虽然Android Studio已经把它整合了,但单独用DDMS在某些场景下更顺手。
1. DDMS位置模拟
启动DDMS:
# 在Android SDK的tools目录下
./ddms
连接设备后,在Emulator Control面板找到Location Controls:
- Manual:手动输入经纬度
- GPX:加载GPX文件模拟路线
- KML:加载KML文件模拟地理围栏
我曾经踩过一个坑:用DDMS给真机发送位置时,发现App收不到回调。后来排查了半天,发现是DDMS默认只给模拟器发位置,真机需要先开启「允许模拟位置」权限。嗯,这个坑我记了好几年。
2. adb命令模拟位置
这是我最推荐的方式,兼容性最好:
# 先开启模拟位置权限(真机需要)
adb shell appops set <package_name> android:mock_location allow
# 发送位置
adb shell am broadcast -a android.intent.action.MOCK_LOCATION \
--ef location.latitude 39.916527 \
--ef location.longitude 116.397128
注意:这种方式需要你的App在AndroidManifest.xml中声明android:mockLocation权限,并且系统设置里开启了「允许模拟位置」。
三、测试工具推荐
工欲善其事,必先利其器。下面这几个工具是我实际项目中用过的,各有千秋。
| 工具名称 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| Fake GPS | 快速单点模拟 | 操作简单,免费 | 不支持路线模拟 |
| GPS Joystick | 路线模拟、摇杆控制 | 支持摇杆实时移动,可录制路线 | 部分机型需要root |
| Mock Locations | 批量测试、自动化 | 支持脚本控制,可导入GPX/KML | 界面较简陋 |
| Location Spoofer | 专业测试 | 支持多设备、多路线同时模拟 | 收费,价格不低 |
我个人最常用的是GPS Joystick。为什么?因为它支持摇杆控制,我可以一边走一边模拟移动,特别适合测导航App的实时路径纠偏。有一次测一个骑行App,我拿着手机在办公室转圈,同事以为我疯了……其实我在模拟骑行路线。
四、代码方式模拟位置
如果你需要更精细的控制,可以在代码里实现位置模拟:
// 创建一个模拟位置提供者
LocationManager locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
locationManager.addTestProvider(
LocationManager.GPS_PROVIDER,
false, // requiresNetwork
false, // requiresSatellite
false, // requiresCell
false, // hasMonetaryCost
true, // supportsAltitude
true, // supportsSpeed
true, // supportsBearing
android.location.Criteria.POWER_LOW,
android.location.Criteria.ACCURACY_FINE
);
// 设置模拟位置
Location mockLocation = new Location(LocationManager.GPS_PROVIDER);
mockLocation.setLatitude(39.916527);
mockLocation.setLongitude(116.397128);
mockLocation.setAltitude(50);
mockLocation.setAccuracy(5);
mockLocation.setTime(System.currentTimeMillis());
mockLocation.setElapsedRealtimeNanos(SystemClock.elapsedRealtimeNanos());
locationManager.setTestProviderLocation(
LocationManager.GPS_PROVIDER,
mockLocation
);
注意:这段代码需要在AndroidManifest.xml中添加android.permission.ACCESS_MOCK_LOCATION权限,并且只能在开启了「允许模拟位置」的设备上运行。
- 模拟器位置发送:最简单,适合快速验证
- DDMS/命令行:适合自动化测试和批量操作
- 第三方工具:功能丰富,适合复杂场景
- 代码模拟:最灵活,适合深度定制
五、避坑指南
做位置模拟这么多年,我总结了几条血泪教训:
- 真机模拟位置必须开「开发者选项」里的「允许模拟位置」——我刚开始不知道,折腾了一下午。
- Android 10+ 对模拟位置限制更严——很多老工具失效了,建议用adb或代码方式。
- 模拟位置的时间戳要更新——如果时间戳是旧的,系统会丢弃这个位置。我遇到过App收不到位置更新,就是因为忘了更新时间戳。
- 不要在生产环境用模拟位置——这会导致定位不准、耗电增加,甚至被系统判定为恶意行为。
六、知识体系总览
下面这张图帮你理清位置模拟的整个知识脉络:
位置模拟是LBS开发中绕不开的一环。从最简单的模拟器发送,到复杂的代码模拟,每种方式都有它的用武之地。我个人建议:日常调试用模拟器,自动化测试用adb,复杂场景用专业工具。这样搭配起来,效率最高。
公众号:蓝海资料掘金营,微信deep3321