Android模拟器无法通过https连接到本地托管的Web服务

4

我正在尝试使用https安全连接调用本地网络上托管的Web服务,起初出现了HostNameUnresolved异常,因此我使用IP地址代替名称,现在我遇到了以下错误:

Error in geting tags.=javax.net.ssl.SSLException: 主机名在证书中不匹配: <10.100.248.99> !=

我已经将中间和根证书添加到了Android受信任列表中。

有没有人能给我一个解决方案,使我可以使用主机名而不是IP地址访问本地网络上托管的安全Web服务?


1
请查看此链接:https://dev59.com/-Gw05IYBdhLWcg3waRGz。 - Suave Nti
@Dark Rider 我正在尝试调用本地网络上托管的 Web 服务,而不是我的系统。另外,我无法从模拟器浏览器中查看它。 - Vikram
@EL Guapo,我无法使用HTTP连接到局域网上的Web服务... - Vikram
如何做到这一点是问题所在... - Vikram
如果你在运行基于Unix的操作系统(如Linux或macOS),你可能可以编辑/etc/hosts文件来添加绑定。在Windows下,我认为也有一个hosts文件,但我不知道它在哪里。 - njzk2
显示剩余5条评论
3个回答

2
如其他人所提到的,你需要几个东西才能连接你的Web服务:
- 模拟器必须知道你需要连接的服务器的IP地址
- 通过HTTPS连接的服务器名称URL必须解析为SSL证书的域。

要做到这一点,你需要做以下操作:

  • 将模拟器分区挂载为可写

从你的桌面Shell(以Linux为例,但在Windows上类似,并假设Android SDK已安装在/android-sdk)执行以下命令:

cd /android-sdk/tools/
./emulator -avd NexusS -partition-size 128

其中NexusS是您设备的AVD名称。您必须从命令行启动模拟器,否则在后续步骤中会出现错误。

现在打开另一个shell终端并获取您的模拟器/system/etc/hosts文件:

cd /android-sdk/platform-tools
./adb remount
./adb pull /system/etc/hosts /tmp/

remount是为了将分区设置为可写。上面的pull命令将主机文件复制到您桌面上的/tmp/hosts
从桌面编辑/tmp/hosts文件以符合您的需求,即如果Web服务是https://www.example.com/foo,IP地址是192.168.1.10:

127.0.0.1      locahost
192.168.1.10   www.example.com

然后将其推回模拟器:
cd /android-sdk/platform-tools
./adb push /tmp/hosts /system/etc/

现在您应该能够连接到Web服务。

请注意,如果使用自签名证书仍可能出现错误。

下面的图片是在编辑hosts文件之前:
IP doesn't match the certificate

编辑后:
Server name match


1

你应该使用 HostnameVerifier 来信任 Android 给定的主机。

HttpParams params = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(params, 5000);
HttpConnectionParams.setSoTimeout(params, 30000);
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;

DefaultHttpClient httpClient = new DefaultHttpClient();

SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(httpClient.getParams(), registry);
DefaultHttpClient client = new DefaultHttpClient(mgr, httpClient.getParams());

// Set verifier      
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);

现在,在客户端对象上执行你想要的请求。

1

我曾经在我的同事做的项目中看到过类似的错误,我们发现原因是如果你试图从主UI线程进行网络调用,Android系统会阻止它,尽管这个功能后来被引入API中,但之前它可以正常工作。这样做是为了减轻主UI线程的压力,所以我们创建了一个单独的服务,然后在其中提供了一个异步任务来进行网络调用。我不记得确切的API级别是什么时候引入的,但你可以在谷歌上查找,另外,你使用的API级别是多少?


@Vikram 好的,我的朋友在使用API 2.3时遇到了这个问题。我不确定它是在哪个API级别中包含的,所以你可以尝试一下,看看是否能解决你的问题。如果解决了,请告诉我。 - Nav

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接