16、位置模拟:Android模拟器位置发送、DDMS与命令行模拟、测试工具推荐

位置模拟,说白了就是「骗」你的App,让它以为手机在某个地方。

我刚开始做LBS(基于位置的服务)开发时,觉得这功能可有可无。直到有一次,我需要在室内调试一个骑行导航App,GPS死活搜不到星……嗯,从那以后,我再也不敢轻视位置模拟了。

为什么需要位置模拟?

你想想看,真实场景下测试位置功能有多麻烦:

  • 你要跑到某个坐标点去测
  • 信号不好时,GPS定位飘忽不定
  • 跨国场景下,你总不能飞过去测吧?

位置模拟就是解决这些痛点的。它让你坐在工位上,就能模拟全球任意地点的定位数据。

一、Android模拟器位置发送

这是最基础的方式。Android自带的模拟器(AVD)就支持位置模拟。

1. 通过模拟器扩展控件发送

启动模拟器后,右侧工具栏有个「…」按钮,点开找到Location选项卡。这里你可以:

  • 输入经纬度,点Send
  • 导入GPX文件模拟路线
  • 导入KML文件模拟地理围栏

我个人习惯用GPX文件做路线模拟。比如测试外卖App的配送轨迹,我会先录一段真实骑行路线,导出GPX,然后导入模拟器。这样测出来的效果跟真机几乎一样。

小技巧:GPX文件可以用手机上的运动App(如Keep、Strava)录制导出,也可以用在线工具生成。

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默认只给模拟器发位置,真机需要先开启「允许模拟位置」权限。嗯,这个坑我记了好几年。

注意:Android 10及以上版本,DDMS的位置模拟功能受限。建议用adb命令或代码方式替代。

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收不到位置更新,就是因为忘了更新时间戳。
  • 不要在生产环境用模拟位置——这会导致定位不准、耗电增加,甚至被系统判定为恶意行为。

六、知识体系总览

下面这张图帮你理清位置模拟的整个知识脉络:

位置模拟知识体系 位置模拟 模拟器位置发送 扩展控件 telnet命令 DDMS/命令行 DDMS面板 adb命令 测试工具推荐 Fake GPS GPS Joystick 代码方式模拟位置 TestProvider MockLocation 选择合适的方式,避免踩坑

位置模拟是LBS开发中绕不开的一环。从最简单的模拟器发送,到复杂的代码模拟,每种方式都有它的用武之地。我个人建议:日常调试用模拟器,自动化测试用adb,复杂场景用专业工具。这样搭配起来,效率最高。


公众号:蓝海资料掘金营,微信deep3321