Подключение к локальным веб-службам из iOS Simulator и Android Emulator

Многие мобильные приложения используют веб-службы. На этапе разработки веб-службу обычно развертывают локально и подключаются к ней из мобильного приложения, выполняемого в iOS Simulator или Android Emulator. Это избавляет от необходимости развертывать веб-службу в размещенной конечной точке и позволяет упростить процесс отладки, так как и мобильное приложение, и веб-служба выполняются локально.

Мобильные приложения, выполняемые в iOS Simulator или Android Emulator, могут использовать веб-службы ASP.NET Core, запущенные в локальной среде и предоставляемые по протоколу HTTP следующим образом:

  • Приложения, выполняемые в iOS Simulator, могут подключаться к локальным веб-службам HTTP, используя IP-адрес компьютера или имя узла localhost. Например, если имеется локальная веб-служба HTTP, которая предоставляет операцию GET по относительному URI /api/todoitems/, то приложение, работающее в iOS Simulator, может использовать операцию путем отправки запроса GET к http://localhost:<port>/api/todoitems/.
  • Приложения, работающие в Android Emulator, могут подключаться к локальной веб-службе HTTP по адресу 10.0.2.2, который является псевдонимом для интерфейса замыкания узла на себя (127.0.0.1 на компьютере разработки). Например, если имеется локальная веб-служба HTTP, которая предоставляет операцию GET по относительному URI /api/todoitems/, то приложение, работающее в Android Emulator, может использовать операцию путем отправки запроса GET к http://10.0.2.2:<port>/api/todoitems/.

Но приложению, выполняемому в iOS Simulator или Android Emulator, нужна доработка, чтобы оно могло использовать локальную веб-службу, предоставляемую по протоколу HTTPS. В этом сценарии процесс выглядит следующим образом:

  1. Создайте самозаверяющий сертификат разработки на своем компьютере. Дополнительные сведения см. в разделе Создание сертификата разработки.
  2. Настройте проект на использование соответствующего сетевого стека HttpClient для отладочной сборки. Дополнительные сведения см. в разделе Настройка проекта.
  3. Укажите адрес своего локального компьютера. Дополнительные сведения см. в разделе Указание адреса локального компьютера.
  4. Выполните обход проверки безопасности сертификата разработки. Дополнительные сведения см. в разделе Обход проверки безопасности сертификата.

Далее последовательно рассматриваются все эти этапы.

Создание сертификата разработки

При установке пакета SDK для .NET Core в локальное хранилище сертификатов пользователя устанавливается сертификат разработки HTTPS ASP.NET Core. Но устанавливаемый сертификат не является доверенным. Чтобы сделать его доверенным, выполните следующее однократное действие для запуска средства .NET dev-certs.

dotnet dev-certs https --trust

Следующая команда вызывает справку по средству dev-certs.

dotnet dev-certs https --help

Кроме того, при запуске проекта ASP.NET Core 2.1 (или следующих версий), использующего протокол HTTPS, Visual Studio проверяет наличие сертификата разработки и предлагает установить его и сделать доверенным.

Примечание.

Сертификат разработки HTTPS ASP.NET Core является самозаверяющим.

Дополнительные сведения о включении протокола HTTPS в локальной среде на компьютере см. в разделе Включение локального HTTPS.

Настройка проекта

В приложении Xamarin для iOS и Android с помощью класса HttpClient можно указать, какой сетевой стек использовать: управляемый сетевой стек или собственный сетевой стек. Управляемый стек обеспечивает высокий уровень совместимости с существующим кодом .NET, но ограничен протоколом TLS 1.0, может выполняться медленнее и стать причиной большого размера исполняемого файла. Собственный стек может выполнятся быстрее и обеспечивать лучшую безопасность, но при этом не предоставлять все функциональные возможности класса HttpClient.

iOS

Приложения Xamarin под управлением iOS могут использовать управляемый сетевой стек или собственные сетевые стеки CFNetwork или NSUrlSession. По умолчанию новые проекты для платформы iOS используют сетевой стек NSUrlSession для поддержки протокола TLS 1.2 и собственные API для повышения производительности и уменьшения размера исполняемого файла. Дополнительные сведения см. в статье о селекторе реализации HttpClient и SSL/TLS для iOS и macOS.

Android

Приложения Xamarin под управлением Android могут использовать управляемый сетевой стек HttpClient или собственный сетевой стек AndroidClientHandler. По умолчанию новые проекты для платформы Android используют сетевой стек AndroidClientHandler для поддержки протокола TLS 1.2 и собственные API для повышения производительности и уменьшения размера исполняемого файла. Дополнительные сведения о сетевых стеках Android см. в статье Стек HttpClient и селектор реализации SSL/TLS для Android.

Указание адреса локального компьютера

Как iOS Simulator, так и Android Emulator предоставляют доступ к защищенным веб-службам на локальном компьютере. Но адреса локального компьютера при этом будут разными.

iOS

iOS Simulator использует сеть главного компьютера. Таким образом, приложения, выполняемые в симуляторе, могут подключаться к веб-службам, работающим на локальном компьютере, используя IP-адрес компьютера или имя узла localhost. Например, если имеется локальная защищенная веб-служба, которая предоставляет операцию GET по относительному URI /api/todoitems/, то приложение, работающее в iOS Simulator, может использовать операцию путем отправки запроса GET к https://localhost:<port>/api/todoitems/.

Примечание.

При запуске мобильного приложения в iOS Simulator из Windows приложение отображается в Remoted iOS Simulator для Windows. Но приложение выполняется на связанном компьютере Mac. Таким образом, у приложения iOS на компьютере Mac отсутствует доступ localhost к веб-службе, выполняющейся в Windows.

Android

Каждый экземпляр Android Emulator изолирован от сетевых интерфейсов компьютера разработки с помощью виртуального маршрутизатора. Таким образом, эмулируемое устройство не может видеть компьютер разработки или другие экземпляры эмулятора в сети.

Виртуальный маршрутизатор каждого эмулятора управляет специализированным сетевым пространством, которое имеет предварительно выделенные адреса, а адрес 10.0.2.2 является псевдонимом для интерфейса замыкания узла на себя (127.0.0.1 на компьютере разработки). Таким образом, если имеется локальная защищенная веб-служба, которая предоставляет операцию GET по относительному URI /api/todoitems/, то приложение, работающее в Android Emulator, может использовать операцию путем отправки запроса GET к https://10.0.2.2:<port>/api/todoitems/.

Определение операционной системы

С помощью класса 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 см. в разделе Xamarin. Essentials. Сведения об устройстве.

Обход проверки безопасности сертификата

Попытка вызвать локальную защищенную веб-службу из приложения, выполняемого в iOS Simulator или Android Emulator, приведет к исключению HttpRequestException даже при использовании управляемого сетевого стека на любой из платформ. Это обусловлено тем, что локальный сертификат разработки HTTPS является самозаверяющим, а самозаверяющие сертификаты не являются доверенными в iOS и Android. Таким образом, необходимо игнорировать ошибки SSL, когда приложение использует локальную защищенную веб-службу. Это можно сделать, используя управляемый и собственный сетевые стеки в iOS и Android и задав в качестве значения свойства ServerCertificateCustomValidationCallback объекта HttpClientHandler обратный вызов, который игнорирует результат проверки безопасности локального сертификата разработки HTTPS.

// This method must be in a class in a platform project, even if
// the HttpClient object is constructed in a shared project.
public HttpClientHandler GetInsecureHandler()
{
    HttpClientHandler handler = new HttpClientHandler();
    handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) =>
    {
        if (cert.Issuer.Equals("CN=localhost"))
            return true;
        return errors == System.Net.Security.SslPolicyErrors.None;
    };
    return handler;
}

В этом примере кода результат проверки сертификата сервера возвращается тогда, когда прошедший проверку сертификат не является сертификатом localhost. Для такого сертификата результат проверки игнорируется и возвращается значение true, подтверждающее, что сертификат действителен. Полученный объект HttpClientHandler должен передаваться в качестве аргумента в конструктор HttpClient для отладочных сборок:

#if DEBUG
    HttpClientHandler insecureHandler = GetInsecureHandler();
    HttpClient client = new HttpClient(insecureHandler);
#else
    HttpClient client = new HttpClient();
#endif

Включение HTTP-трафика с открытым текстом

При необходимости для проектов iOS и Android можно настроить разрешение HTTP-трафика с открытым текстом. Если для серверной службы настроено разрешение HTTP-трафика, в базовых URL-адресах можно указать HTTP, а затем настроить для проектов разрешение трафика с открытым текстом:

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

Отказ от ATS в iOS

Чтобы включить в iOS локальный трафик с открытым текстом, следует отказаться от ATS, добавив следующий текст в файл Info.plist:

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

Конфигурация сетевой безопасности в Android

Чтобы включить в Android локальный трафик с открытым текстом, необходимо создать конфигурацию сетевой безопасности, добавив новый XML-файл с именем network_security_config.xml в папку 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>

Затем настройте свойство networkSecurityConfig в узле приложения в манифесте Android:

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

Убедитесь, что действие сборки задано как AndroidResource, в противном случае XML-файл не будет найден во время сборки.