简介:这份文档面向 Android 开发初学者与需要联调测试的工程师,聚焦模拟器与电脑不在同一网段、无法联网或通信失败这一常见痛点,系统梳理 AVD 模拟器 IP 与 DNS 的修改流程。内容从启动模拟器、进入 platform-tools 执行 adb shell 讲起,覆盖 getprop 查看默认 DNS(10.0.2.3)与默认 IP(10.0.2.15)、setprop 修改 DNS 和 net.gprs.local-ip、再次 getprop 验证生效等关键环节,并给出 device '(null)' not found、device offline 等报错的 adb 进程重启排错思路。资源包共 1 个 doc 文件,约 47KB,篇幅精炼、步骤配图,适合边看边操作。目前已有 2149 人学习,可作为 Android 模拟器网络配置的速查手册,帮助读者快速打通模拟器与电脑的通信链路,减少环境调试耗时。
1. 模拟器 IP 和电脑不在一个网段:这份文档把 adb 改 IP 的完整链路拆开了
做 Android 开发的人几乎都遇到过这个场景:模拟器里跑着一个要连本地服务的 App,电脑上服务监听在 192.168.5.x,模拟器里ping过去却死活不通,浏览器打开网页也转圈。很多人第一反应是去模拟器设置里找 Wi-Fi 配置,翻半天发现根本没有可改的地方。这份《Android 及 AVD 模拟器 IP 设置详细操作》文档,讲的就是用adb shell配合getprop、setprop把模拟器的 DNS 和 IP 手动拉到和电脑同一网段的完整步骤,适合正在做本地联调、接口测试、抓包分析的 Android 开发者,尤其是被模拟器网络隔离卡住过的人。它不是什么高深技术,但胜在把每一步命令和报错都写清楚了,照着敲能少走不少弯路。
2. 先搞懂 AVD 的网络模型:10.0.2.x 是怎么来的
2.1 模拟器默认网络的隔离逻辑
Android 模拟器(AVD)跑起来之后,并不是直接桥接到你电脑的物理网卡上,而是挂在一个由模拟器进程自己维护的虚拟网络里。默认情况下,这个虚拟网络用的是10.0.2.0/24这一段,模拟器自己拿10.0.2.15,网关是10.0.2.2,DNS 是10.0.2.3。这三个地址是 QEMU 那套用户态网络栈定死的,你在模拟器里getprop看到的net.dns1和net.gprs.local-ip就是它们。
问题就出在这里:你电脑的局域网是192.168.5.x,模拟器在10.0.2.x,两边天然不在一个广播域。模拟器访问外网时,流量会经过10.0.2.2这个虚拟网关做 NAT 转发,所以「模拟器能不能上网」和「模拟器能不能被电脑局域网里的其他设备访问」是两件不同的事。前者通常没问题,后者基本不通。文档里让你把 IP 改成192.168.5.100、DNS 改成192.168.5.1,本质上是想绕过这层 NAT,让模拟器在属性层面「看起来」和电脑同网段。
这里要泼一盆冷水:setprop net.gprs.local-ip改的只是一个系统属性,并不会真的给模拟器的虚拟网卡配上这个地址。它影响的是某些读取该属性的应用和框架层逻辑,对底层 socket 的路由选择并不起决定作用。所以这份文档的价值在于「让依赖该属性的测试场景跑通」,而不是「把模拟器变成局域网里一台独立主机」。理解这个边界,后面才不会白折腾。
2.2 为什么选 adb shell 而不是图形界面
较新的 AVD 在设置里确实有代理、DNS 之类的入口,但 IP 相关的属性并没有暴露成可点的开关。adb shell是唯一能直接读写net.*属性的通道,而且getprop/setprop这两个命令在所有 Android 版本上都稳定存在,不依赖模拟器厂商的定制界面。对于需要反复切换测试环境的场景,把命令写成脚本比每次点界面可靠得多。
另一个现实原因是排错。图形界面出错时你只能看到一个「保存失败」,而adb shell里每一步的返回、每一条error:都是线索。文档里专门写了error: device '(null)' not found和error: device offline两种报错的处理方式,这个细节说明作者是真踩过坑的——前者是 adb 服务端状态错乱,后者是模拟器没起来或者 adb 没识别到设备,两者的解法完全不同。
3. 动手改 IP:从 adb 连接到 setprop 生效的完整命令链
3.1 环境准备与 adb 连接
先把模拟器启动起来,等它完全进入桌面再操作。然后确认platform-tools目录的位置,把它加进 PATH 或者直接cd进去。下面这段是连接和状态检查的标准流程:
# 进入 SDK 的 platform-tools 目录(路径按自己机器改) cd /path/to/android-sdk/platform-tools # 查看当前 adb 识别到的设备,确认模拟器在线 adb devices # 如果列表为空或显示 offline,先重启 adb 服务 adb kill-server adb start-server # 再次确认设备状态,正常应显示 device 而非 offline adb devices # 进入模拟器的 shell adb shelladb devices的输出是判断一切的前提。正常应该看到一行emulator-5554 device,device这个状态词很关键——如果是offline,说明 adb 连上了端口但模拟器系统还没准备好,等几秒再试;如果是unauthorized,那是真机场景的授权问题,模拟器一般不会出现。adb kill-server加adb start-server这一对操作,解决的是 adb 服务端进程卡死或端口占用导致的device '(null)' not found,这个报错的意思是 adb 知道有个设备槽位但拿不到设备标识,重启服务端能强制它重新扫描。
进入adb shell之后,提示符会变成generic_x86:/ $之类的形式,说明你已经站在模拟器系统内部了。后面的getprop和setprop都在这个 shell 里执行,不需要再加adb前缀。
3.2 用 getprop 读出当前网络属性
进 shell 后先别急着改,把现状读出来存档:
# 读出全部系统属性,输出很长,建议配合 grep 过滤 getprop | grep -E "net\.dns|net\.gprs|net\.eth" # 单独确认 DNS 属性 getprop net.dns1 # 单独确认模拟器本地 IP 属性 getprop net.gprs.local-ipgetprop不带参数会打印几百行属性,直接翻很难找。用grep过滤net.开头的键是常规做法。默认情况下net.dns1返回10.0.2.3,net.gprs.local-ip可能返回10.0.2.15或者干脆为空——不同系统镜像的行为有差异,空值不代表出错,只是该属性没被初始化。
这里有个容易忽略的点:getprop读的是属性服务里的键值,和ip addr看到的网卡地址是两套东西。你可以同时跑一下ip addr对比,会发现eth0或wlan0上的地址仍然是10.0.2.15,不会因为你setprop就变。这个对比能帮你建立正确的心理预期,避免改完发现ping还是不通就以为命令没生效。
3.3 setprop 修改 DNS 与 IP 并验证
确认现状后开始改。顺序上建议先改 DNS 再改 IP,因为某些应用在启动时会缓存 DNS 解析结果:
# 把 DNS 改成电脑所在局域网的 DNS 服务器地址 setprop net.dns1 192.168.5.1 # 把模拟器本地 IP 属性改到和电脑同网段 setprop net.gprs.local-ip 192.168.5.100 # 重新读取,确认两个属性都已更新 getprop net.dns1 getprop net.gprs.local-ipsetprop的语法就是setprop <key> <value>,值一律按字符串处理,不需要引号(除非值里有空格)。192.168.5.1和192.168.5.100这两个地址要换成你自己电脑实际所在的网段和可用的空闲地址,别照抄。选192.168.5.100这种偏后的地址,是为了降低和局域网里 DHCP 分配地址冲突的概率。
改完之后getprop能读回新值,只证明属性写进去了,不证明网络通了。真正的验证要分两层:第一层在模拟器 shell 里ping 192.168.5.1,看能不能通到网关;第二层在电脑上起一个监听服务,从模拟器里用curl或 App 去连。如果第一层就不通,说明属性修改没有影响实际路由,这时候要么接受「这个属性只对特定应用生效」的现实,要么改用端口转发方案(见下一章)。
注意:
setprop写入的属性在模拟器重启后会丢失,每次冷启动都要重新执行。需要持久化的话,得把命令塞进启动脚本或者用adb shell批量下发。
4. 改完还是不通:端口转发与网络模式的替代方案
4.1 adb forward 解决电脑到模拟器的访问
如果你的真实诉求是「电脑上的工具要访问模拟器里的服务」,那根本不需要改 IP,adb forward是更干净的做法:
# 把电脑的 8080 端口转发到模拟器的 8080 端口 adb forward tcp:8080 tcp:8080 # 查看当前所有转发规则 adb forward --list # 用完撤销 adb forward --remove tcp:8080这条命令建立的是 adb 通道上的端口映射,电脑上访问127.0.0.1:8080就等于访问模拟器里的8080。它不依赖网段,不受10.0.2.x隔离影响,模拟器重启后规则会失效需要重新加。对于接口调试、抓包、本地 Web 服务联调,这个方案比改 IP 属性靠谱得多,也是我平时优先用的。
4.2 模拟器网络模式的取舍
AVD 管理器里其实有网络模式的选项,不同版本叫法不一,常见的有 NAT 和桥接两类。桥接模式下模拟器会尝试直接挂到物理网络,能拿到和电脑同网段的真实地址,但配置依赖宿主机的网卡和权限,跨平台表现不稳定,出问题时排查成本高。NAT 模式就是默认的10.0.2.x,稳定但隔离。
我的建议是:日常开发用 NAT 加adb forward,需要模拟器被局域网其他设备主动访问时再考虑桥接。文档里那套setprop改属性的方法,适合「某个测试用例硬性读取net.gprs.local-ip做判断」这种特定场景,不适合当成通用的网络配置手段。把这三条路分清,遇到问题才知道该往哪个方向查。
5. 避坑记录:五条血泪经验
5.1 改完属性 ping 不通就以为命令错了
现象:setprop执行成功,getprop也读回了新值,但ping 192.168.5.1依然 100% 丢包。 原因:net.gprs.local-ip只是属性,不改变虚拟网卡的实际路由,ICMP 走的是底层网络栈。 解决:别用ping验证属性修改,改用读取该属性的应用逻辑去验证;真要通网络,走adb forward或桥接模式。
5.2 adb devices 显示 offline 就反复 kill-server
现象:模拟器明明开着,adb devices一直offline,重启 adb 服务也没用。 原因:模拟器系统还在启动过程中,adbd 守护进程没就绪,或者模拟器进程本身卡死。 解决:先等模拟器完全进入桌面,再执行adb devices;仍不行就冷启动模拟器(emulator -avd <名字> -no-snapshot-load),而不是无脑重启 adb。
5.3 照抄文档里的 192.168.5.x 导致地址冲突
现象:改完 IP 后局域网里某台设备掉线或 IP 冲突告警。 原因:192.168.5.100是文档示例值,直接照抄可能撞上你局域网里已分配的地址。 解决:先ipconfig/ifconfig看自己网段,选一个明显在 DHCP 池之外、且ping不通的空闲地址。
5.4 重启模拟器后配置全丢
现象:昨天改好的 DNS 和 IP,今天开机又变回10.0.2.3。 原因:setprop写入的是运行时属性,不落盘,模拟器冷启动会重置。 解决:把命令写成 shell 脚本,每次启动模拟器后跑一遍;或者接受这个限制,改用不依赖属性的方案。
5.5 在错误的 shell 里执行 setprop
现象:setprop报Permission denied或提示找不到命令。 原因:在电脑的 cmd 里直接敲了setprop,没先adb shell进去;或者用了非 root 的受限 shell。 解决:确认提示符是模拟器内部的$或#再执行;模拟器默认 shell 一般有权限改net.*属性,真机则需要 root。
6. 把改 IP 固化成可复用脚本:一个我常用的验证套路
单次手动敲命令没问题,但如果你一天要重启模拟器七八次,每次都重复adb shell加两条setprop,迟早会漏步骤。我一般会写一个带前置检查的脚本,把「设备是否在线、属性是否已改、改完是否读回」串成一条链:
#!/bin/bash # 用法: ./set-avd-ip.sh 192.168.5.1 192.168.5.100 DNS=$1 IP=$2 # 前置检查:必须有且仅有一个 device 状态的模拟器 STATE=$(adb devices | awk 'NR>1 && $2=="device" {print $1}') if [ -z "$STATE" ]; then echo "没有在线的模拟器,先启动 AVD" exit 1 fi # 下发属性并逐条读回校验 adb shell setprop net.dns1 "$DNS" adb shell setprop net.gprs.local-ip "$IP" CHECK_DNS=$(adb shell getprop net.dns1 | tr -d '\r') CHECK_IP=$(adb shell getprop net.gprs.local-ip | tr -d '\r') echo "DNS: $CHECK_DNS IP: $CHECK_IP" [ "$CHECK_DNS" = "$DNS" ] && [ "$CHECK_IP" = "$IP" ] \ && echo "属性写入成功" || echo "写入失败,检查 adb 连接"脚本里tr -d '\r'是必须的,adb shell在部分平台上返回的行尾带\r,不处理会导致字符串比较永远不相等,这个坑我踩过一次,排查了半小时才发现是回车符在作怪。awk那行只挑状态为device的设备,避免把offline的僵尸条目算进去。
验证套路上,我习惯在脚本跑完后补一条adb shell ip addr show,把属性值和真实网卡地址并排看一眼。两者不一致是正常的,但能提醒自己当前处于「属性已改、路由未变」的状态,后续测试如果依赖真实网络连通性,就得换方案。这个习惯是从一次联调事故里养成的:当时以为改完 IP 就万事大吉,结果 App 里的 socket 连接一直超时,最后发现是路由没跟着变,白白浪费一下午。
从那以后我每次动模拟器网络配置,都强制走一遍「读现状、改属性、读回、看真实网卡」四步,哪怕只是改个 DNS 也不省。这份文档把命令链路讲得够细,照着做能快速上手,但属性修改的边界得自己心里有数。希望帮到你。
本文还有配套的精品资源,点击获取