远程连接局域网内的Android模拟器

摘要:

本文主要介绍如何远程连接位于局域网内的 Android 模拟器进行调试。我们知道 Android 模拟器十分耗费资源,尤其对于 Macbook 用户,开启模拟器后风扇狂转,如果这时候有一台空余的机器,可以单独运行一个 Android 模拟器,然后再远程连接到该模拟器,从而能够减轻工作机的负担。

2018年3月8日 Update:修改了 avd 命令

参考

本文主要参考了一篇博文和一个 Sf 上的问答:

Is it possible to connect to Android emulators running on a Mac from a Windows VM? 这篇文章介绍了两种方法,我们使用其中的第二种。

Remote debugging with Android emulator,这个问答思路和上面的第二种方法一直,但是提出了关于 adb 的建议从而解决了 offline 的问题。

下面我们详细介绍使用 SSH 来远程访问同一局域网内的 Android 模拟器。如果你对基础内容十分熟悉,直接进入 命令行快速参考手册

约定

为了方面描述我们做如下约定:

  1. 客户端 Client:我们的开发机,也就是实际运行 Android Studio 程序的机器。
  2. 服务器 Server:模拟器运行的宿主机,也就是我们需要远程访问的机器。

服务器 Server 开启 SSH 访问

这一步是本解决方法的前提,也就是说开启服务器端的 SSH 访问权限,允许客户端远程登录到该服务器。这里我们只用 Mac 来说明其方法,其他平台请自行搜索开启方法。

对于 Mac 来说,开启 SSH 比较简单,只需要在 设置 -> 共享(Preference-> Sharing) 中勾选中远程登录(Remote Login)即可,大家应该可以看到 Remote Login 的状态处于打开,然后下面有解释说 远程登录允许用户的其他电脑通过 SSH 和 SFTP 访问该电脑。一旦打开这个选项,提示会告诉你如何使用 SSH 访问该电脑。

1
ssh [email protected]

其中 Username 就是你当前登录的用户名, Computer 就是你的主机名,其中主机名也可以用 IP 地址来代替。IP 地址可以通过 ifconfig -a 来获取。

这时候我们在客户端打开一个 Terminal,然后输入上面的命令,在输入用户名对应的密码就应该成功的登陆到服务器了。

使用 SSH 进行端口映射

我们首先思考如果在服务器本身访问模拟器的情形,实际上模拟器就是一个虚拟机,但是它的网络和宿主机通过端口映射的,一般为 5554和5555一对端口,宿主机上如果访问模拟器,只需要访问本地网络的两个端口就可以了。

所以如果我们在客户端使用 SSH 登陆到服务器,实际上和在服务器上并没有太大的区别,我们通过 SSH 登陆后也同样可以访问模拟器,但问题的关键是我们需要让我们的开发环境能够识别出这个模拟器,而不是通过 SSH 登陆后访问模拟器。而 SSH 支持端口映射,大家可以查看 SSH 命令手册,其中 -L 选项就是进行本机地址端口和远程服务器的进行映射的。

 -L    [bind_address:]port:host:hostport
 -L    [bind_address:]port:remote_socket
 -L    local_socket:host:hostport
 -L    local_socket:remote_socket
     Specifies that connections    to the given TCP port or Unix socket
     on    the local (client) host    are to be forwarded to the given host
     and port, or Unix socket, on the remote side.  This works by
     allocating    a socket to listen to either a TCP port    on the local
     side, optionally bound to the specified bind_address, or to a
     Unix socket.  Whenever a connection is made to the    local port or
     socket, the connection is forwarded over the secure channel, and
     a connection is made to either host port hostport,    or the Unix
     socket remote_socket, from    the remote machine.

     Port forwardings can also be specified in the configuration file.
     Only the superuser    can forward privileged ports.  IPv6 addresses
     can be specified by enclosing the address in square brackets.

     By    default, the local port    is bound in accordance with the
     GatewayPorts setting.  However, an    explicit bind_address may be
     used to bind the connection to a specific address.     The
     bind_address of ``localhost'' indicates that the listening    port
     be    bound for local    use only, while    an empty address or `*'    indi-
     cates that    the port should    be available from all interfaces.

所以我们只需要把本地的 localhost 的某一个端口映射到远程服务器就可以,当然我们可以选择使用常用的 5554和5555,这样 ADB 就直接可以把远程的模拟器作为本地模拟器了,也可以使用其他端口,只是需要主动使用 adb 命令去连接对应的端口。

其他端口映射

如果服务器的模拟器的端口是 5554,那么我们就需要映射 5555.

  1. 在客户端执行如下命令
1
2
# in client side
ssh -L localhost:15555:localhost:5555 [email protected]

输入密码后进入到服务器的 bash 环境,这时候不需要管这个窗口。

  1. 新打开一个 Terminal 窗口,使用 adb 来连接本地映射的端口:
1
2
3
# in client sied
killall adb
adb connect localhost:15555
  1. 服务器在 Terminal 中将其 adb 的所有服务全部终结,这一步十分重要,否则设备将会是 offline。
1
2
# in server side
killall adb

默认端口映射

如果服务器的模拟器的端口是 5554

  1. 在客户端执行如下命令
1
2
# in client side
sssh -NL 5554:localhost:5554 -L 5555:localhost:5555 [email protected]

输入密码后进入到服务器的 bash 环境,这时候不需要管这个窗口。

  1. 服务器在 Terminal 中将其 adb 的所有服务全部终结,这一步十分重要,否则设备将会是 offline。
1
2
# in server side
killall adb

这时候我们应该能够在 Android Studio 的运行中看到连接的 Android 模拟器。

使用命令行打开模拟器

当前的模拟器需要在 Android Studio 中打开 AVD 管理器才能打开模拟器,对于我们的需求,我们并不需要在服务器端打开 Android Studio。只需要打开模拟器就行了,所以是不是有更简单的方法呢? 实际上 Android Studio 是通过 SDK 中的相应的工具来打开模拟器的,所以我们可以直接用命令行调取对应的执行就行了。

这里需要知道两个工具,avdmanageremulator,其中 emulatorAndroid/sdk/tools 目录下, 而 avdmanagerAndroid/sdk/tools/bin 目录下。默认情况,Mac系统的Android 的 SDK 安装到 ~/Library/Android/sdk,所以大家可以进入到该路径,然后执行对应的命令。

假设我们已经进入了 SDK 下的 tools 目录

1
cd ~/Library/Android/sdk/tools

列出所有 AVD

1
./bin/avdmanager list avd

显示如下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Available Android Virtual Devices:
---------
Name: Nexus_5_API_26
Device: Nexus 5 (Google)
Path: /Users/mengxin/.android/avd/Nexus_5_API_26.avd
Target: Google APIs (Google Inc.)
Based on: Android 7.1.1 (Nougat) Tag/ABI: google_apis/x86_64
Skin: nexus_5
Sdcard: 100M
---------
Name: Nexus_5X_API_25_x86
Device: Nexus 5X (Google)
Path: /Users/mengxin/.android/avd/Nexus_5X_API_25_x86.avd
Target: Google APIs (Google Inc.)
Based on: Android 7.1.1 (Nougat) Tag/ABI: google_apis/x86
Skin: nexus_5x
Sdcard: 800M
Snapshot: no

使用 emulator 打开 avd

1
./emulator -avd Nexus_5X_API_25_x86 &

其中的 Nexus_5X_API_25_x86 为上一个命令的中列出的 AVD 的名字字段:Name

命令行快速参考手册

server side

1
2
3
4
5
6
cd ~/Library/Android/sdk/tools
./bin/avdmanager list avd
# 这里加 & 表示让该命令在后台执行
./emulator -adb Nexus_5X_API_25_x86 &
# 关键步骤,释放本机 adb 服务,
killall adb

client side

1
2
3
4
ssh -NL 5554:localhost:5554 -L 5555:localhost:5555 [email protected]
# 有时候也需要重启一下 adb 服务
killall adb
adb devices

其他命令

将 sdk 工具加入到环境变量

1
2
3
4
5
6
# adb
echo 'export PATH=$PATH:~/Library/Android/sdk/platform-tools' >> ~/.bash_profile
source ~/.bash_profile
# avdmanager
echo 'export PATH=$PATH:~/Library/Android/sdk/tools' >> ~/.bash_profile
source ~/.bash_profile

adb shell 到指定的设备

1
adb -s device-name shell