Conexión a servicios web locales desde simuladores de iOS y emuladores de Android

Examinar ejemplo. Examinar el ejemplo

Muchas aplicaciones móviles y de escritorio consumen servicios web. Durante la fase de desarrollo de software, es habitual implementar un servicio web localmente y consumirlo desde una aplicación que se ejecuta en el emulador de Android o en el simulador de iOS. Esto evita tener que implementar el servicio web en un punto de conexión hospedado y permite una experiencia de depuración sencilla porque la aplicación y el servicio web se ejecutan localmente.

Las aplicaciones de interfaz de usuario de aplicaciones multiplataforma de .NET (.NET MAUI) que se ejecutan en Windows o MacCatalyst pueden consumir servicios web de ASP.NET Core que se ejecutan localmente a través de HTTP o HTTPS sin ningún trabajo adicional, siempre que haya confiado en el certificado de desarrollo. Sin embargo, se requiere trabajo adicional cuando la aplicación se ejecuta en el emulador de Android o en el simulador de iOS, y el proceso es diferente en función de si el servicio web se ejecuta a través de HTTP o HTTPS.

Dirección del equipo local

El emulador de Android y el simulador de iOS proporcionan acceso a los servicios web que se ejecutan a través de HTTP o HTTPS en la máquina local. Sin embargo, la dirección de la máquina local es diferente en cada uno.

Android

Cada instancia del emulador de Android está aislada de las interfaces de red de la máquina de desarrollo y se ejecuta detrás de un enrutador virtual. Por lo tanto, un dispositivo emulado no puede ver su máquina de desarrollo u otras instancias del emulador en la red.

Sin embargo, el enrutador virtual de cada emulador administra un espacio de red especial que incluye direcciones asignadas previamente, donde la dirección 10.0.2.2 es un alias a la interfaz de bucle invertido del host (127.0.0.1 en la máquina de desarrollo). Por tanto, dado un servicio web local que expone una operación GET a través del identificador URI relativo de /api/todoitems/, una aplicación que se ejecuta en el emulador de Android puede consumir la operación al enviar una solicitud GET a http://10.0.2.2:<port>/api/todoitems/ o https://10.0.2.2:<port>/api/todoitems/.

iOS

El simulador de iOS usa la red de la máquina host. Por tanto, las aplicaciones que se ejecutan en el simulador pueden conectarse a servicios web que se ejecutan en el equipo local a través de la dirección IP de las máquinas o mediante el nombre de host localhost. Por ejemplo, dado un servicio web local que expone una operación GET a través del identificador URI relativo de /api/todoitems/, una aplicación que se ejecuta en el simulador de iOS puede consumir la operación enviando una solicitud GET a http://localhost:<port>/api/todoitems/ o https://localhost:<port>/api/todoitems/.

Nota:

Al ejecutar una aplicación de .NET MAUI en el simulador de iOS desde Windows, la aplicación se muestra en el simulador remoto de iOS para Windows. Sin embargo, la aplicación se ejecuta en el equipo Mac emparejado. Por tanto, no hay acceso localhost a un servicio web que se ejecuta en Windows para una aplicación iOS que se ejecuta en un equipo Mac.

Servicios web locales que se ejecutan a través de HTTP

Una aplicación de .NET MAUI que se ejecuta en el emulador de Android o en el simulador de iOS puede consumir un servicio web de ASP.NET Core que se ejecuta localmente a través de HTTP. Esto se puede lograr configurando el proyecto de aplicación de .NET MAUI y el proyecto de servicio web de ASP.NET Core para permitir el tráfico HTTP de texto no cifrado.

En el código que define la dirección URL del servicio web local en la aplicación de .NET MAUI, asegúrese de que la dirección URL del servicio web especifique el esquema HTTP y el nombre de host correcto. La clase DeviceInfo se puede usar para detectar la plataforma en la que se ejecuta la aplicación. Después, puede establecer el nombre de host correcto de la siguiente manera:

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

Para obtener más información sobre la clase DeviceInfo, consulte Información del dispositivo.

Además, para ejecutar la aplicación en Android, debe agregar la configuración de red necesaria y, para ejecutar la aplicación en iOS, debe optar por no participar en Apple Transport Security (ATS). Para más información, consulte Configuración de red de Android y configuración de ATS de iOS.

También debe asegurarse de que el servicio web ASP.NET Core esté configurado para permitir el tráfico HTTP. Esto se puede lograr al agregar un perfil HTTP a la sección profiles de launchSettings.json en el proyecto de servicio web de ASP.NET Core:

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

Una aplicación .NET MAUI que se ejecuta en el emulador de Android o en el simulador de iOS puede consumir un servicio web de ASP.NET Core que se ejecuta localmente a través de HTTP, siempre que el servicio web se inicie con el perfil http.

Configuración de red de Android

Hay dos enfoques principales para habilitar el tráfico local de texto no cifrado en Android:

Habilitar tráfico de red de texto no cifrado para todos los dominios

El tráfico de red de texto no cifrado para todos los dominios se puede habilitar estableciendo la propiedad UsesCleartextTraffic del atributo Application en true. Esto debe realizarse en el archivo Plataformas > Android > MainApplication.cs del proyecto de aplicación .NET MAUI y debe encapsularse en #if DEBUG para asegurarse de que no está habilitado accidentalmente en una aplicación de producción:

#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();
}

Nota:

La propiedad UsesCleartextTraffic se omite en Android 7.0 (API 24) y versiones posteriores si existe un archivo de configuración de seguridad de red.

Habilitar tráfico de red de texto no cifrado para el dominio localhost

El tráfico de red de texto no cifrado para el dominio localhost se puede habilitar mediante la creación de un archivo de configuración de seguridad de red. Esto se puede lograr al agregar un nuevo archivo XML denominado network_security_config.xml a la carpeta Platforms\Android\Resources\xml en el proyecto de aplicación de .NET MAUI. El archivo XML debe especificar la configuración siguiente:

<?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>

Nota:

Asegúrese de que la acción de compilación del archivo network_security_config.xml esté establecida en AndroidResource.

Después, configure la propiedad networkSecurityConfig en el nodo de aplicación del archivo Platforms\Android\AndroidManifest.xml en el proyecto de aplicación de .NET MAUI:

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

Para más información sobre los archivos de configuración de seguridad de red, consulte Configuración de seguridad de red en developer.android.com.

Configuración de ATS de iOS

Para habilitar el tráfico local de texto no cifrado en iOS, debe optar por no participar en Apple Transport Security (ATS) en la aplicación .NET MAUI. Esto se puede lograr al agregar la siguiente configuración al archivo Platforms\iOS\Info.plist en el proyecto de aplicación de .NET MAUI:

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

Para obtener más información sobre ATS, consulte Prevención de conexiones de red no seguras en developer.apple.com.

Servicios web locales que se ejecutan a través de HTTPS

Una aplicación de .NET MAUI que se ejecuta en el emulador de Android o en el simulador de iOS puede consumir un servicio web de ASP.NET Core que se ejecuta localmente a través de HTTPS. El proceso para habilitar esto es el siguiente:

  1. Confíe en el certificado de desarrollo autofirmado en la máquina. Para más información, consulte Confiar en el certificado de desarrollo.
  2. Especifique la dirección de la máquina local. Para más información, consulte Especificar la dirección de la máquina local.
  3. Omita la comprobación de seguridad del certificado de desarrollo local. Para más información, consulte Omitir la comprobación de seguridad del certificado.

Cada elemento se explicará por turnos.

Confiar en el certificado de desarrollo

Al instalar el SDK de .NET Core, se instala el certificado de desarrollo HTTPS de ASP.NET Core en el almacén de certificados de usuario local. Sin embargo, aunque el certificado se ha instalado, no es de confianza. Para confiar en el certificado, realice el siguiente paso puntual para ejecutar la herramienta dev-certs de dotnet:

dotnet dev-certs https --trust

El siguiente comando proporciona ayuda sobre la herramienta dev-certs:

dotnet dev-certs https --help

De forma alternativa, cuando se ejecuta un proyecto de ASP.NET Core 2.1 (o posterior) que usa HTTPS, Visual Studio detecta si falta el certificado de desarrollo y se ofrece a instalarlo, y confía en él.

Nota:

El certificado de desarrollo HTTPS de ASP.NET Core es autofirmado.

Para más información sobre cómo habilitar HTTPS local en la máquina, consulte Habilitar HTTPS local.

Especificar la dirección de la máquina local

En el código que define la dirección URL del servicio web local en la aplicación de .NET MAUI, asegúrese de que la dirección URL del servicio web especifique el esquema HTTPS y el nombre de host correcto. La clase DeviceInfo se puede usar para detectar la plataforma en la que se ejecuta la aplicación. Después, puede establecer el nombre de host correcto de la siguiente manera:

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

Para obtener más información sobre la clase DeviceInfo, consulte Información del dispositivo.

Omitir la comprobación de seguridad de certificado

Si se intenta invocar un servicio web seguro local desde una aplicación de .NET MAUI que se ejecuta en un emulador de Android, se producirá un mensaje java.security.cert.CertPathValidatorException que indica que no se ha encontrado el anclaje de confianza para la ruta de acceso de certificación. Del mismo modo, si intenta invocar un servicio web seguro local desde una aplicación de .NET MAUI que se ejecuta en un simulador de iOS, se producirá un error NSURLErrorDomain con un mensaje que indica que el certificado del servidor no es válido. Estos errores se producen porque el certificado de desarrollo HTTPS local está autofirmado y los certificados autofirmados no son de confianza para Android o iOS. Por tanto, es necesario omitir los errores SSL cuando una aplicación consume un servicio web seguro local.

Esto se puede lograr configurando una instancia de HttpClientHandler con un ServerCertificateCustomValidationCallback personalizado, lo que indica a la clase HttpClient que confíe en la comunicación de localhost a través de HTTPS. En el ejemplo siguiente se muestra cómo crear una instancia de HttpClientHandler que omitirá los errores de validación de certificado de localhost:

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);

Importante

El código anterior omite los errores de validación de certificado de localhost, pero solo en compilaciones de depuración. Este enfoque evita incidentes de seguridad en compilaciones de producción.

Una aplicación de .NET MAUI que se ejecuta en el emulador de Android o en el simulador de iOS puede consumir un servicio web de ASP.NET Core que se ejecuta localmente a través de HTTPS.