使用特定于平台的网络功能

已完成

注意

.NET MAUI 是 Xamarin 的下一个演变,建议你使用它来开发移动和桌面应用,你可以在多个训练模块中了解有关 .NET MAUI 的详细信息。 此 Xamarin 训练模块不会继续保留。

HttpClient 是托管实现,这意味着它无法感知本机平台网络堆栈。 因此,HttpClient 无法使用每个平台的本机网络功能,这让它达不到应有的效率且优化程度也会降低。

在本单元中,利用 HttpClient 的扩展性并添加对本机平台网络堆栈的支持。

HttpClient 的问题

默认情况下,HttpClient 使用基于较低级别的操作系统接口的托管网络堆栈。 因此,HttpClient 无法感知每个平台上的网络堆栈。 Android 和 iOS 都具有更高效的本机网络堆栈,但它们的 API 具有唯一性,这让通过 C# 进行使用变得更加困难。

因此,HttpClient 无法充分利用本机平台。 例如,本机网络堆栈有一项功能,在手机网络数据关闭时会自动尝试开启该选项。 因为 HttpClient 在默认情况下不使用本机网络堆栈,所以它不会尝试打开该选项。

什么是消息处理程序?

HttpClient 设计为可扩展,并支持消息处理程序,以影响它传输信息和处理常见 HTTP 方案的方式。 例如,Microsoft 创建了名为 HttpClientHandler 的消息处理程序。 可使用它来自定义 HttpClient 的某些功能。 以下示例显示 HttpClientHandler 的用法:

var handler = new HttpClientHandler() {
   AllowAutoRedirect = false,
   UseProxy = true,
   AutomaticDecompression = DecompressionMethods.GZip,
   Credentials = new NetworkCredential("user", "passwd")
};

var client = new HttpClient(handler);

正如你所看到的,HttpClientHandler 具有可设置为自定义 HttpClient 的行为的属性。 若要将自定义项应用于 HttpClient,请将其传入构造函数。

什么是 NSUrlSessionHandler?

Xamarin.iOS 包括名为 NSUrlSessionHandler 的消息处理程序,这有助于 HttpClient 使用其本机网络堆栈。 NSUrlSessionHandler 提供以下优势:

  • 在开始请求之前自动打开收发器。
  • 利用 iOS 连接池。
  • 使用调度队列而不是托管线程。

处理网络时,处理程序使 HttpClient 像本机应用程序一样工作。

在代码中设置 NSUrlSessionHandler 如以下示例所示:

var client = new HttpClient(new NSUrlSessionHandler());

现在,HttpClient 具有本机网络堆栈的优势。

什么是 AndroidClientHandler?

与 Xamarin.iOS 一样,Xamarin.Android 包括名为 AndroidClientHandler 消息处理程序。 AndroidClientHandler 将网络通信工作推送到 Android UrlConnection 堆栈上。 此处理程序允许 HttpClient 使用 Android 知晓如何处理的任何网络协议和加密协议,例如 TLS 1.2。

在代码中设置 AndroidClientHandler 如以下示例所示:

var client = new HttpClient(new AndroidClientHandler());

何时使用 NSUrlSessionHandler 和 AndroidClientHandler

作为通用指南,使用 HttpClient 时,始终使用 NSUrlSessionHandlerAndroidClientHandler。 它们都提供本机网络堆栈具有的优点。

使用这些处理程序是新的 Xamarin.Forms 项目的默认行为。 可以通过项目设置来更改 HttpClient 默认值。

若要更改 Xamarin.iOS 的默认 HttpClient 处理程序,请打开 iOS 项目的属性。 在“iOS 生成”选项卡下,有一个“HttpClient 实现”选项。 如果将此选项设置为 NSUrlSession,HttpClient 会使用本机 iOS 处理程序,并且不会将其传递到构造函数中。

若要更改 Xamarin.Android 的默认 HttpClient 处理程序,请打开 Android 项目的属性。 在“Android 选项”选项卡下方,单击底部的“高级”按钮。 在“高级 Android 选项”对话框中,有一个“SSL/TLS 实现”选项。 将此值设置为 Native TLS 1.2+ 会使 HttpClient 默认使用消息处理程序。

什么是应用传输安全性?

在总结本单元之前,在 iOS 上使用本机网络堆栈时,还需记住一点。 应用传输安全性 (ATS) 是一项功能,要求通过本机网络堆栈完成的每次网络通信都使用 TLS 1.2 或以上版本。 如果其中一个长期密钥泄露,现代加密算法不会泄露信息。

如果应用不遵守这些规则,则无法访问网络。 如果应用程序存在此问题,有两种选择。 第一种,可以更改终结点以遵循应用传输安全性策略。 第二种,可以通过设置 Info.plist 文件中的某些密钥来选择退出应用传输安全性。

选择退出应用传输安全性

若要选择退出应用传输安全性,必须将新的密钥添加到名为 NSAppTransportSecurityInfo.plist 文件。 在该字典中,添加另一个名为 NSExceptionDomains 的密钥。 它包含想要将其作为目标的每个终结点的子级。 以下是选择退出某个终结点时所添加内容的示例:

<key>NSAppTransportSecurity</key>
<dict>
   <key>NSExceptionDomains</key>
      <dict>
      <key>dotnet.microsoft.com</key>
      <dict>
         <!-- specific options here -->
      </dict>
   </dict>
</dict>

在此示例中,我们向位于 dotnet.microsoft.com 的终结点添加了一个异常。 如果在开发计算机上本地调试服务,则可以使用 NSAllowsLocalNetworking 键选择退出本地流量。

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

最后,如果无法识别所有终结点,请通过使用 NSAllowsArbitraryLoads 密钥禁用所有未指定终结点的应用传输安全性。 下面是代码中的一个示例:

<key>NSAppTransportSecurity</key>
<dict>
   <key>NSAllowsArbitraryLoads</key>
   <true/>
</dict>

可以添加其他选项,以便更具体地说明想要选择退出的方式。该指南超出了本模块的范畴。 Xamarin.iOS ATS 文档中介绍了这些选项。

什么是 Android 网络安全配置?

和 iOS 一样,Android 具有与 Android 9(API 级别 28)中引入的类似的网络通信安全模型。 当应用程序在 Android 9(API 级别 28)或更高版本的设备上运行并以这些版本为目标时,明文(非 HTTPS)流量默认处于禁用状态。 如果应用需要在没有配置为 HTTPS 的服务器上下载图像或文件,那么此策略可能会影响你的开发周期。 此外,你可能只是尝试在本地调试应用,而不希望安装开发证书。 你可能有强烈的业务需求,即所有 Android 版本上的所有 Web 流量都必须是 HTTPS。 这时候就需要 Android 的新网络安全配置功能,它可以帮助我们在应用中优化网络流量的安全性。

允许明文流量

若要允许明文流量,则需要创建网络安全配置。 首先,在 Resources/xml 下创建一个名为 network_security_config.xml 的新 xml 文件。 在此文件中,你将添加一个带有 domain-config 设置的 network-security-config。 以下配置将允许明文流量流向特定域和 IP 地址:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
  <domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain> <!-- Debug port -->
    <domain includeSubdomains="true">xamarin.com</domain>
  </domain-config>
</network-security-config>

无论编译和目标框架如何,还可以在所有版本的 Android 上限制明文流量,从而增强应用的安全性。 这是通过将 cleartextTrafficPermitted 设置为 false 来完成的。 启用此项将在任何时候限制任何非 HTTPS 流量。

需要完成的最后一个操作是在“属性”文件夹中的 AndroidManifest.xmlapplication 节点上配置 networkSecurityConfig 属性:

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

可以添加其他选项,以便更具体地说明想要选择退出的方式。该指南超出了本模块的范畴。 Google 网络安全配置指南中介绍了这些选项。

本地调试服务和应用

最后,使用 C# 和 .NET 构建移动应用程序的好处是,你可以与其他 .NET 应用程序共享代码和知识,如此处提供的 ASP.NET Core Web API 后端。 此外,在 iOS 模拟器或 Android 模拟器中运行的移动应用程序可使用本地运行的 ASP.NET Core Web 服务,并通过 HTTP 公开,如下所示:

在 iOS 模拟器中运行的应用程序可以通过计算机 IP 地址或 localhost 主机名连接到本地 HTTP Web 服务。 应用程序必须选择退出 ATS,以指定 NSAllowsLocalNetworking 的最小值。 例如,对于通过 /api/todoitems/ 相对 URI 公开 GET 操作的本地 HTTP Web 服务,在 iOS 模拟器中运行的应用程序可以通过向 http://localhost:<port>/api/todoitems/ 发送 GET 请求来使用操作。

在 Android 模拟器中运行的应用程序可以通过 10.0.2.2 地址连接到本地 HTTP Web 服务,该地址是你的主机环回接口的别名(在开发计算机上为 127.0.0.1)。 还必须为此特定的 IP 地址设置网络安全配置。 例如,对于通过 /api/todoitems/ 相对 URI 公开 GET 操作的本地 HTTP Web 服务,在 Android 模拟器中运行的应用程序可以通过向 http://10.0.2.2:<port>/api/todoitems/ 发送 GET 请求来使用操作。

ASP.NET Core Web 服务必须通过在 Startup.cs 文件中注释掉 app.UseHttpsRedirection(); 来禁用 HTTPS 重定向。

检测操作系统

DeviceInfo 类可用于检测应用程序的运行平台。 可将支持访问本地安全 Web 服务的相应主机名设置如下。

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

若要了解详细信息,请访问连接到本地 Web 服务文档。

知识检查

1.

以下哪个选择是通过 HttpClient 使用本地网络堆栈的最佳原因?

2.

下面哪个选项不是选择退出应用传输安全性的有效方法