从 Android 仿真器和 iOS 模拟器连接到本地 Web 服务

浏览示例。 浏览示例

许多移动和桌面应用使用 Web 服务。 在软件开发阶段,通常会在本地部署 Web 服务,并通过 Android 模拟器或 iOS 模拟器中运行的应用使用它。 这可以避免将 Web 服务部署到托管终结点,并实现简单的调试体验,因为应用和 Web 服务都在本地运行。

在 Windows 或 MacCatalyst 上运行的 .NET 多平台应用 UI (.NET MAUI) 应用可以使用通过 HTTP 或 HTTPS 在本地运行的 ASP.NET Core Web 服务,而无需执行任何其他工作,前提是你信任你的开发证书。 但是,当应用在 Android 模拟器或 iOS 模拟器中运行时,还需要执行其他工作,该过程因 Web 服务是通过 HTTP 还是 HTTPS 运行而异。

本地计算机地址

Android 模拟器和 iOS 模拟器都提供对在本地计算机上通过 HTTP 或 HTTPS 运行的 Web 服务的访问权限。 但它们的本地计算机地址各不相同。

Android

Android模拟器的各个实例独立于开发计算机网络接口,在虚拟路由器的后方运行。 因此,模拟设备无法看到开发计算机或网络中的其他模拟器实例。

但是,各个模拟器的虚拟路由器托管着一个包含预分配地址的特殊网络空间,其中 10.0.2.2 地址是主机环回接口的别名(在开发计算机上为 127.0.0.1)。 因此,对于通过 /api/todoitems/ 相对 URI 公开 GET 操作的本地 Web 服务,在 Android 模拟器中运行的应用可以通过向 http://10.0.2.2:<port>/api/todoitems/https://10.0.2.2:<port>/api/todoitems/ 发送 GET 请求来使用操作。

iOS

iOS 模拟器使用主机网络。 因此,模拟器中运行的应用可以通过计算机 IP 地址或通过 localhost 主机名连接到本地计算机上运行的 Web 服务。 例如,对于通过 /api/todoitems/ 相对 URI 公开 GET 操作的本地 Web 服务,在 iOS 模拟器中运行的应用可以通过向 http://localhost:<port>/api/todoitems/https://localhost:<port>/api/todoitems/ 发送 GET 请求来使用操作。

注意

从 Windows 在 iOS 模拟器中运行 .NET MAUI 应用时,该应用会显示在适用于 Windows 的远程 iOS 模拟器中。 但是,应用在配对的 Mac 上运行。 因此,对于在 Mac 上运行的 iOS 应用,在 Windows 中运行的 Web 服务没有 localhost 访问权限。

通过 HTTP 运行的本地 Web 服务

在 Android 模拟器或 iOS 模拟器中运行的 .NET MAUI 应用可以使用通过 HTTP 在本地运行的 ASP.NET Core Web 服务。 这可以通过配置 .NET MAUI 应用项目和 ASP.NET Core Web 服务项目从而允许明文 HTTP 流量来实现。

在 .NET MAUI 应用中定义本地 Web 服务的 URL 的代码中,确保 Web 服务 URL 指定 HTTP 方案和正确的主机名。 DeviceInfo 类可用于检测正在运行应用的平台。 然后,可以按如下所示设置正确的主机名:

public static string BaseAddress =
    DeviceInfo.Platform == DevicePlatform.Android ? "http://10.0.2.2:5000" : "http://localhost:5000";
public static string TodoItemsUrl = $"{BaseAddress}/api/todoitems/";

有关 DeviceInfo 类的详细信息,请参阅设备信息

此外,要在 Android 上运行应用,必须添加所需的网络配置;要在 iOS 上运行应用,必须选择退出 Apple 传输安全性 (ATS)。 有关详细信息,请参阅 Android 网络配置iOS ATS 配置

还必须确保 ASP.NET Core Web 服务配置为允许 HTTP 流量。 这可以通过将 HTTP 配置文件添加到 ASP.NET Core Web 服务项目中 launchSettings.json 的 profiles 部分来实现:

{
  ...
  "profiles": {
    "http": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "api/todoitems",
      "applicationUrl": "http://localhost:5000",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    ...
  }
}

然后,在 Android 模拟器或 iOS 模拟器中运行的 .NET MAUI 应用可以使用通过 HTTP 在本地运行的 ASP.NET Core Web 服务,前提是 Web 服务通过 http 配置文件启动。

Android 网络配置

在 Android 上启用明文本地流量主要有两种方法:

为所有域启用明文网络流量

可以通过将 Application 特性的 UsesCleartextTraffic 属性设置为 true 来启用所有域的明文网络流量。 这应在 .NET MAUI 应用项目中的 平台 > Android > MainApplication.cs 文件中执行,并且应包装在 #if DEBUG 中,以确保不会在生产应用中意外启用它:

#if DEBUG
[Application(UsesCleartextTraffic = true)]
#else
[Application]
#endif
public class MainApplication : MauiApplication
{
    public MainApplication(IntPtr handle, JniHandleOwnership ownership)
        : base(handle, ownership)
    {
    }

    protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}

注意

如果存在网络安全配置文件,则会在 Android 7.0 (API 24) 和更高版本上忽略 UsesCleartextTraffic 属性。

为 localhost 域启用明文网络流量

可以通过创建网络安全配置文件来启用 localhost 域的明文网络流量。 这可以通过将名为 network_security_config.xml 的新 XML 文件添加到 .NET MAUI 应用项目中的 Platforms\Android\Resources\xml 文件夹来实现。 XML 文件应指定以下配置:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain>
  </domain-config>
</network-security-config>

注意

确保 network_security_config.xml 文件的生成操作设置为 AndroidResource。

然后,配置 .NET MAUI 应用项目中 Platforms\Android\AndroidManifest.xml 文件内 application 节点的 networkSecurityConfig 属性:

<?xml version="1.0" encoding="utf-8"?>
<manifest>
    <application android:networkSecurityConfig="@xml/network_security_config" ...>
        ...
    </application>
</manifest>

有关网络安全配置文件的详细信息,请在 developer.android.com 参阅网络安全配置

iOS ATS 配置

若要在 iOS 上启用明文本地流量,应在 .NET MAUI 应用中选择退出 Apple 传输安全性 (ATS)。 这可以通过将以下配置添加到 .NET MAUI 应用项目中的 Platforms\iOS\Info.plist 文件来实现:

<key>NSAppTransportSecurity</key>    
<dict>
    <key>NSAllowsLocalNetworking</key>
    <true/>
</dict>

有关 ATS 的详细信息,请在 developer.apple.com 参阅防止不安全的网络连接

通过 HTTPS 运行的本地 Web 服务

在 Android 模拟器或 iOS 模拟器中运行的 .NET MAUI 应用可以使用通过 HTTPS 在本地运行的 ASP.NET Core Web 服务。 启用它的过程如下所示:

  1. 信任计算机上的自签名开发证书。 有关详细信息,请参阅信任你的开发证书
  2. 指定本地计算机的地址。 有关详细信息,请参阅指定本地计算机地址
  3. 绕过本地开发证书安全检查。 有关详细信息,请参阅绕过证书安全检查

将依次讨论每项。

信任你的开发证书

安装 .NET Core SDK 会将 ASP.NET Core HTTPS 开发证书安装到本地用户证书存储。 但是,尽管证书已安装,但它不受信任。 若要信任该证书,请执行以下一次性步骤,以运行 dotnet dev-certs 工具:

dotnet dev-certs https --trust

下面的命令提供有关 dev-certs 工具的帮助:

dotnet dev-certs https --help

或者,当你运行使用 HTTPS 的 ASP.NET Core 2.1 项目(或更高版本)时,Visual Studio 将检测是否缺少开发证书并提供安装和信任。

注意

ASP.NET Core HTTPS 开发证书是自签名证书。

有关在计算机上启用本地 HTTPS 的详细信息,请参阅启用本地 HTTPS

指定本地计算机地址

在 .NET MAUI 应用中定义本地 Web 服务的 URL 的代码中,确保 Web 服务 URL 指定 HTTPS 方案和正确的主机名。 DeviceInfo 类可用于检测正在运行应用的平台。 然后,可以按如下所示设置正确的主机名:

public static string BaseAddress =
    DeviceInfo.Platform == DevicePlatform.Android ? "https://10.0.2.2:5001" : "https://localhost:5001";
public static string TodoItemsUrl = $"{BaseAddress}/api/todoitems/";

有关 DeviceInfo 类的详细信息,请参阅设备信息

绕过证书安全检查

尝试从 Android 模拟器中运行的 .NET MAUI 应用调用本地安全 Web 服务将导致引发 java.security.cert.CertPathValidatorException,并显示一条消息,指示找不到证书路径的信任定位点。 同样,尝试从 iOS 模拟器中运行的 .NET MAUI 应用调用本地安全 Web 服务将导致 NSURLErrorDomain 错误,并显示一条消息,指示服务器的证书无效。 发生这些错误的原因是本地 HTTPS 开发证书是自签名证书,而 Android 或 iOS 不信任自签名证书。 因此,当应用使用本地安全 Web 服务时,有必要忽略 SSL 错误。

这可以通过使用自定义 ServerCertificateCustomValidationCallback 配置 HttpClientHandler 实例来实现,会指示 HttpClient 类信任通过 HTTPS 的 localhost 通信。 以下示例演示如何创建将忽略 localhost 证书验证错误的实例 HttpClientHandler

var handler = new HttpClientHandler();

#if DEBUG
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
{
    if (cert != null && cert.Issuer.Equals("CN=localhost"))
        return true;
    return errors == System.Net.Security.SslPolicyErrors.None;
};
#endif

var client = new HttpClient(handler);

重要

上面的代码忽略 localhost 证书验证错误,但仅在调试版本中。 此方法可避免生产版本中的安全事件。

然后,在 Android 模拟器或 iOS 模拟器中运行的 .NET MAUI 应用可以使用通过 HTTPS 在本地运行的 ASP.NET Core Web 服务。